Salome HOME
Merge branch 'master' of ssh://git.salome-platform.org/tools/medcoupling
[tools/medcoupling.git] / src / MEDCoupling / MEDCouplingUMesh.cxx
1 // Copyright (C) 2007-2016  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19 // Author : Anthony Geay (CEA/DEN)
20
21 #include "MEDCouplingUMesh.hxx"
22 #include "MEDCouplingCMesh.hxx"
23 #include "MEDCoupling1GTUMesh.hxx"
24 #include "MEDCouplingFieldDouble.hxx"
25 #include "MEDCouplingSkyLineArray.hxx"
26 #include "CellModel.hxx"
27 #include "VolSurfUser.txx"
28 #include "InterpolationUtils.hxx"
29 #include "PointLocatorAlgos.txx"
30 #include "BBTree.txx"
31 #include "BBTreeDst.txx"
32 #include "SplitterTetra.hxx"
33 #include "DiameterCalculator.hxx"
34 #include "DirectedBoundingBox.hxx"
35 #include "InterpKernelMatrixTools.hxx"
36 #include "InterpKernelMeshQuality.hxx"
37 #include "InterpKernelCellSimplify.hxx"
38 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
39 #include "InterpKernelAutoPtr.hxx"
40 #include "InterpKernelGeo2DNode.hxx"
41 #include "InterpKernelGeo2DEdgeLin.hxx"
42 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
43 #include "InterpKernelGeo2DQuadraticPolygon.hxx"
44
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 const int MEDCouplingUMesh::MEDCOUPLING2VTKTYPETRADUCER[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};
59 /// @endcond
60
61 MEDCouplingUMesh *MEDCouplingUMesh::New()
62 {
63   return new MEDCouplingUMesh;
64 }
65
66 MEDCouplingUMesh *MEDCouplingUMesh::New(const std::string& meshName, int meshDim)
67 {
68   MEDCouplingUMesh *ret=new MEDCouplingUMesh;
69   ret->setName(meshName);
70   ret->setMeshDimension(meshDim);
71   return ret;
72 }
73
74 /*!
75  * Returns a new MEDCouplingUMesh which is a full copy of \a this one. No data is shared
76  * between \a this and the new mesh.
77  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingMesh. The caller is to
78  *          delete this mesh using decrRef() as it is no more needed. 
79  */
80 MEDCouplingUMesh *MEDCouplingUMesh::deepCopy() const
81 {
82   return clone(true);
83 }
84
85
86 /*!
87  * Returns a new MEDCouplingUMesh which is a copy of \a this one.
88  *  \param [in] recDeepCpy - if \a true, the copy is deep, else all data arrays of \a
89  * this mesh are shared by the new mesh.
90  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingMesh. The caller is to
91  *          delete this mesh using decrRef() as it is no more needed. 
92  */
93 MEDCouplingUMesh *MEDCouplingUMesh::clone(bool recDeepCpy) const
94 {
95   return new MEDCouplingUMesh(*this,recDeepCpy);
96 }
97
98 /*!
99  * This method behaves mostly like MEDCouplingUMesh::deepCopy method, except that only nodal connectivity arrays are deeply copied.
100  * The coordinates are shared between \a this and the returned instance.
101  * 
102  * \return MEDCouplingUMesh * - A new object instance holding the copy of \a this (deep for connectivity, shallow for coordiantes)
103  * \sa MEDCouplingUMesh::deepCopy
104  */
105 MEDCouplingUMesh *MEDCouplingUMesh::deepCopyConnectivityOnly() const
106 {
107   checkConnectivityFullyDefined();
108   MCAuto<MEDCouplingUMesh> ret=clone(false);
109   MCAuto<DataArrayInt> c(getNodalConnectivity()->deepCopy()),ci(getNodalConnectivityIndex()->deepCopy());
110   ret->setConnectivity(c,ci);
111   return ret.retn();
112 }
113
114 void MEDCouplingUMesh::shallowCopyConnectivityFrom(const MEDCouplingPointSet *other)
115 {
116   if(!other)
117     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is null !");
118   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
119   if(!otherC)
120     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is not an MEDCouplingUMesh instance !");
121   MEDCouplingUMesh *otherC2=const_cast<MEDCouplingUMesh *>(otherC);//sorry :(
122   setConnectivity(otherC2->getNodalConnectivity(),otherC2->getNodalConnectivityIndex(),true);
123 }
124
125 std::size_t MEDCouplingUMesh::getHeapMemorySizeWithoutChildren() const
126 {
127   std::size_t ret(MEDCouplingPointSet::getHeapMemorySizeWithoutChildren());
128   return ret;
129 }
130
131 std::vector<const BigMemoryObject *> MEDCouplingUMesh::getDirectChildrenWithNull() const
132 {
133   std::vector<const BigMemoryObject *> ret(MEDCouplingPointSet::getDirectChildrenWithNull());
134   ret.push_back(_nodal_connec);
135   ret.push_back(_nodal_connec_index);
136   return ret;
137 }
138
139 void MEDCouplingUMesh::updateTime() const
140 {
141   MEDCouplingPointSet::updateTime();
142   if(_nodal_connec)
143     {
144       updateTimeWith(*_nodal_connec);
145     }
146   if(_nodal_connec_index)
147     {
148       updateTimeWith(*_nodal_connec_index);
149     }
150 }
151
152 MEDCouplingUMesh::MEDCouplingUMesh():_mesh_dim(-2),_nodal_connec(0),_nodal_connec_index(0)
153 {
154 }
155
156 /*!
157  * Checks if \a this mesh is well defined. If no exception is thrown by this method,
158  * then \a this mesh is most probably is writable, exchangeable and available for most
159  * of algorithms. When a mesh is constructed from scratch, it is a good habit to call
160  * this method to check that all is in order with \a this mesh.
161  *  \throw If the mesh dimension is not set.
162  *  \throw If the coordinates array is not set (if mesh dimension != -1 ).
163  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
164  *  \throw If the connectivity data array has more than one component.
165  *  \throw If the connectivity data array has a named component.
166  *  \throw If the connectivity index data array has more than one component.
167  *  \throw If the connectivity index data array has a named component.
168  */
169 void MEDCouplingUMesh::checkConsistencyLight() const
170 {
171   if(_mesh_dim<-1)
172     throw INTERP_KERNEL::Exception("No mesh dimension specified !");
173   if(_mesh_dim!=-1)
174     MEDCouplingPointSet::checkConsistencyLight();
175   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
176     {
177       if((int)INTERP_KERNEL::CellModel::GetCellModel(*iter).getDimension()!=_mesh_dim)
178         {
179           std::ostringstream message;
180           message << "Mesh invalid because dimension is " << _mesh_dim << " and there is presence of cell(s) with type " << (*iter);
181           throw INTERP_KERNEL::Exception(message.str().c_str());
182         }
183     }
184   if(_nodal_connec)
185     {
186       if(_nodal_connec->getNumberOfComponents()!=1)
187         throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to be with number of components set to one !");
188       if(_nodal_connec->getInfoOnComponent(0)!="")
189         throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to have no info on its single component !");
190     }
191   else
192     if(_mesh_dim!=-1)
193       throw INTERP_KERNEL::Exception("Nodal connectivity array is not defined !");
194   if(_nodal_connec_index)
195     {
196       if(_nodal_connec_index->getNumberOfComponents()!=1)
197         throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to be with number of components set to one !");
198       if(_nodal_connec_index->getInfoOnComponent(0)!="")
199         throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to have no info on its single component !");
200     }
201   else
202     if(_mesh_dim!=-1)
203       throw INTERP_KERNEL::Exception("Nodal connectivity index array is not defined !");
204 }
205
206 /*!
207  * Checks if \a this mesh is well defined. If no exception is thrown by this method,
208  * then \a this mesh is most probably is writable, exchangeable and available for all
209  * algorithms. <br> In addition to the checks performed by checkConsistencyLight(), this
210  * method thoroughly checks the nodal connectivity.
211  *  \param [in] eps - a not used parameter.
212  *  \throw If the mesh dimension is not set.
213  *  \throw If the coordinates array is not set (if mesh dimension != -1 ).
214  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
215  *  \throw If the connectivity data array has more than one component.
216  *  \throw If the connectivity data array has a named component.
217  *  \throw If the connectivity index data array has more than one component.
218  *  \throw If the connectivity index data array has a named component.
219  *  \throw If number of nodes defining an element does not correspond to the type of element.
220  *  \throw If the nodal connectivity includes an invalid node id.
221  */
222 void MEDCouplingUMesh::checkConsistency(double eps) const
223 {
224   checkConsistencyLight();
225   if(_mesh_dim==-1)
226     return ;
227   int meshDim=getMeshDimension();
228   int nbOfNodes=getNumberOfNodes();
229   int nbOfCells=getNumberOfCells();
230   const int *ptr=_nodal_connec->getConstPointer();
231   const int *ptrI=_nodal_connec_index->getConstPointer();
232   for(int i=0;i<nbOfCells;i++)
233     {
234       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)ptr[ptrI[i]]);
235       if((int)cm.getDimension()!=meshDim)
236         {
237           std::ostringstream oss;
238           oss << "MEDCouplingUMesh::checkConsistency : cell << #" << i<< " with type Type " << cm.getRepr() << " in 'this' whereas meshdim == " << meshDim << " !";
239           throw INTERP_KERNEL::Exception(oss.str());
240         }
241       int nbOfNodesInCell=ptrI[i+1]-ptrI[i]-1;
242       if(!cm.isDynamic())
243         if(nbOfNodesInCell!=(int)cm.getNumberOfNodes())
244           {
245             std::ostringstream oss;
246             oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with static Type '" << cm.getRepr() << "' has " <<  cm.getNumberOfNodes();
247             oss << " nodes whereas in connectivity there is " << nbOfNodesInCell << " nodes ! Looks very bad !";
248             throw INTERP_KERNEL::Exception(oss.str());
249           }
250       if(cm.isQuadratic() && cm.isDynamic() && meshDim == 2)
251         if (nbOfNodesInCell % 2 || nbOfNodesInCell < 4)
252           {
253             std::ostringstream oss;
254             oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with quadratic type '" << cm.getRepr() << "' has " <<  nbOfNodesInCell;
255             oss << " nodes. This should be even, and greater or equal than 4!! Looks very bad!";
256             throw INTERP_KERNEL::Exception(oss.str());
257           }
258       for(const int *w=ptr+ptrI[i]+1;w!=ptr+ptrI[i+1];w++)
259         {
260           int nodeId=*w;
261           if(nodeId>=0)
262             {
263               if(nodeId>=nbOfNodes)
264                 {
265                   std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " whereas there are only " << nbOfNodes << " nodes in the mesh !";
266                   throw INTERP_KERNEL::Exception(oss.str());
267                 }
268             }
269           else if(nodeId<-1)
270             {
271               std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " in connectivity ! sounds bad !";
272               throw INTERP_KERNEL::Exception(oss.str());
273             }
274           else
275             {
276               if((INTERP_KERNEL::NormalizedCellType)(ptr[ptrI[i]])!=INTERP_KERNEL::NORM_POLYHED)
277                 {
278                   std::ostringstream oss; oss << "Cell #" << i << " is built with node #-1 in connectivity ! sounds bad !";
279                   throw INTERP_KERNEL::Exception(oss.str());
280                 }
281             }
282         }
283     }
284 }
285
286 /*!
287  * Sets dimension of \a this mesh. The mesh dimension in general depends on types of
288  * elements contained in the mesh. For more info on the mesh dimension see
289  * \ref MEDCouplingUMeshPage.
290  *  \param [in] meshDim - a new mesh dimension.
291  *  \throw If \a meshDim is invalid. A valid range is <em> -1 <= meshDim <= 3</em>.
292  */
293 void MEDCouplingUMesh::setMeshDimension(int meshDim)
294 {
295   if(meshDim<-1 || meshDim>3)
296     throw INTERP_KERNEL::Exception("Invalid meshDim specified ! Must be greater or equal to -1 and lower or equal to 3 !");
297   _mesh_dim=meshDim;
298   declareAsNew();
299 }
300
301 /*!
302  * Allocates memory to store an estimation of the given number of cells. The closer is the estimation to the number of cells effectively inserted,
303  * 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.
304  * If a nodal connectivity previouly existed before the call of this method, it will be reset.
305  *
306  *  \param [in] nbOfCells - estimation of the number of cell \a this mesh will contain.
307  *
308  *  \if ENABLE_EXAMPLES
309  *  \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
310  *  \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
311  *  \endif
312  */
313 void MEDCouplingUMesh::allocateCells(int nbOfCells)
314 {
315   if(nbOfCells<0)
316     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::allocateCells : the input number of cells should be >= 0 !");
317   if(_nodal_connec_index)
318     {
319       _nodal_connec_index->decrRef();
320     }
321   if(_nodal_connec)
322     {
323       _nodal_connec->decrRef();
324     }
325   _nodal_connec_index=DataArrayInt::New();
326   _nodal_connec_index->reserve(nbOfCells+1);
327   _nodal_connec_index->pushBackSilent(0);
328   _nodal_connec=DataArrayInt::New();
329   _nodal_connec->reserve(2*nbOfCells);
330   _types.clear();
331   declareAsNew();
332 }
333
334 /*!
335  * Appends a cell to the connectivity array. For deeper understanding what is
336  * happening see \ref MEDCouplingUMeshNodalConnectivity.
337  *  \param [in] type - type of cell to add.
338  *  \param [in] size - number of nodes constituting this cell.
339  *  \param [in] nodalConnOfCell - the connectivity of the cell to add.
340  * 
341  *  \if ENABLE_EXAMPLES
342  *  \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
343  *  \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
344  *  \endif
345  */
346 void MEDCouplingUMesh::insertNextCell(INTERP_KERNEL::NormalizedCellType type, int size, const int *nodalConnOfCell)
347 {
348   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
349   if(_nodal_connec_index==0)
350     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::insertNextCell : nodal connectivity not set ! invoke allocateCells before calling insertNextCell !");
351   if((int)cm.getDimension()==_mesh_dim)
352     {
353       if(!cm.isDynamic())
354         if(size!=(int)cm.getNumberOfNodes())
355           {
356             std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : Trying to push a " << cm.getRepr() << " cell with a size of " << size;
357             oss << " ! Expecting " << cm.getNumberOfNodes() << " !";
358             throw INTERP_KERNEL::Exception(oss.str());
359           }
360       int idx=_nodal_connec_index->back();
361       int val=idx+size+1;
362       _nodal_connec_index->pushBackSilent(val);
363       _nodal_connec->writeOnPlace(idx,type,nodalConnOfCell,size);
364       _types.insert(type);
365     }
366   else
367     {
368       std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : cell type " << cm.getRepr() << " has a dimension " << cm.getDimension();
369       oss << " whereas Mesh Dimension of current UMesh instance is set to " << _mesh_dim << " ! Please invoke \"setMeshDimension\" method before or invoke ";
370       oss << "\"MEDCouplingUMesh::New\" static method with 2 parameters name and meshDimension !";
371       throw INTERP_KERNEL::Exception(oss.str());
372     }
373 }
374
375 /*!
376  * Compacts data arrays to release unused memory. This method is to be called after
377  * finishing cell insertion using \a this->insertNextCell().
378  * 
379  *  \if ENABLE_EXAMPLES
380  *  \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
381  *  \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
382  *  \endif
383  */
384 void MEDCouplingUMesh::finishInsertingCells()
385 {
386   _nodal_connec->pack();
387   _nodal_connec_index->pack();
388   _nodal_connec->declareAsNew();
389   _nodal_connec_index->declareAsNew();
390   updateTime();
391 }
392
393 /*!
394  * Entry point for iteration over cells of this. Warning the returned cell iterator should be deallocated.
395  * Useful for python users.
396  */
397 MEDCouplingUMeshCellIterator *MEDCouplingUMesh::cellIterator()
398 {
399   return new MEDCouplingUMeshCellIterator(this);
400 }
401
402 /*!
403  * Entry point for iteration over cells groups geo types per geotypes. Warning the returned cell iterator should be deallocated.
404  * If \a this is not so that that cells are grouped by geo types this method will throw an exception.
405  * In this case MEDCouplingUMesh::sortCellsInMEDFileFrmt or MEDCouplingUMesh::rearrange2ConsecutiveCellTypes methods for example can be called before invoking this method.
406  * Useful for python users.
407  */
408 MEDCouplingUMeshCellByTypeEntry *MEDCouplingUMesh::cellsByType()
409 {
410   if(!checkConsecutiveCellTypes())
411     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::cellsByType : this mesh is not sorted by type !");
412   return new MEDCouplingUMeshCellByTypeEntry(this);
413 }
414
415 /*!
416  * Returns a set of all cell types available in \a this mesh.
417  * \return std::set<INTERP_KERNEL::NormalizedCellType> - the set of cell types.
418  * \warning this method does not throw any exception even if \a this is not defined.
419  * \sa MEDCouplingUMesh::getAllGeoTypesSorted
420  */
421 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypes() const
422 {
423   return _types;
424 }
425
426 /*!
427  * This method returns the sorted list of geometric types in \a this.
428  * 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
429  * having the same geometric type. So a same geometric type can appear more than once if the cells are not sorted per geometric type.
430  *
431  * \throw if connectivity in \a this is not correctly defined.
432  *  
433  * \sa MEDCouplingMesh::getAllGeoTypes
434  */
435 std::vector<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypesSorted() const
436 {
437   std::vector<INTERP_KERNEL::NormalizedCellType> ret;
438   checkConnectivityFullyDefined();
439   int nbOfCells(getNumberOfCells());
440   if(nbOfCells==0)
441     return ret;
442   if(getNodalConnectivityArrayLen()<1)
443     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAllGeoTypesSorted : the connectivity in this seems invalid !");
444   const int *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin());
445   ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci++]);
446   for(int i=1;i<nbOfCells;i++,ci++)
447     if(ret.back()!=((INTERP_KERNEL::NormalizedCellType)c[*ci]))
448       ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci]);
449   return ret;
450 }
451
452 /*!
453  * This method is a method that compares \a this and \a other.
454  * This method compares \b all attributes, even names and component names.
455  */
456 bool MEDCouplingUMesh::isEqualIfNotWhy(const MEDCouplingMesh *other, double prec, std::string& reason) const
457 {
458   if(!other)
459     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isEqualIfNotWhy : input other pointer is null !");
460   std::ostringstream oss; oss.precision(15);
461   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
462   if(!otherC)
463     {
464       reason="mesh given in input is not castable in MEDCouplingUMesh !";
465       return false;
466     }
467   if(!MEDCouplingPointSet::isEqualIfNotWhy(other,prec,reason))
468     return false;
469   if(_mesh_dim!=otherC->_mesh_dim)
470     {
471       oss << "umesh dimension mismatch : this mesh dimension=" << _mesh_dim << " other mesh dimension=" <<  otherC->_mesh_dim;
472       reason=oss.str();
473       return false;
474     }
475   if(_types!=otherC->_types)
476     {
477       oss << "umesh geometric type mismatch :\nThis geometric types are :";
478       for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
479         { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
480       oss << "\nOther geometric types are :";
481       for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=otherC->_types.begin();iter!=otherC->_types.end();iter++)
482         { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
483       reason=oss.str();
484       return false;
485     }
486   if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
487     if(_nodal_connec==0 || otherC->_nodal_connec==0)
488       {
489         reason="Only one UMesh between the two this and other has its nodal connectivity DataArrayInt defined !";
490         return false;
491       }
492   if(_nodal_connec!=otherC->_nodal_connec)
493     if(!_nodal_connec->isEqualIfNotWhy(*otherC->_nodal_connec,reason))
494       {
495         reason.insert(0,"Nodal connectivity DataArrayInt differ : ");
496         return false;
497       }
498   if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
499     if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
500       {
501         reason="Only one UMesh between the two this and other has its nodal connectivity index DataArrayInt defined !";
502         return false;
503       }
504   if(_nodal_connec_index!=otherC->_nodal_connec_index)
505     if(!_nodal_connec_index->isEqualIfNotWhy(*otherC->_nodal_connec_index,reason))
506       {
507         reason.insert(0,"Nodal connectivity index DataArrayInt differ : ");
508         return false;
509       }
510   return true;
511 }
512
513 /*!
514  * Checks if data arrays of this mesh (node coordinates, nodal
515  * connectivity of cells, etc) of two meshes are same. Textual data like name etc. are
516  * not considered.
517  *  \param [in] other - the mesh to compare with.
518  *  \param [in] prec - precision value used to compare node coordinates.
519  *  \return bool - \a true if the two meshes are same.
520  */
521 bool MEDCouplingUMesh::isEqualWithoutConsideringStr(const MEDCouplingMesh *other, double prec) const
522 {
523   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
524   if(!otherC)
525     return false;
526   if(!MEDCouplingPointSet::isEqualWithoutConsideringStr(other,prec))
527     return false;
528   if(_mesh_dim!=otherC->_mesh_dim)
529     return false;
530   if(_types!=otherC->_types)
531     return false;
532   if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
533     if(_nodal_connec==0 || otherC->_nodal_connec==0)
534       return false;
535   if(_nodal_connec!=otherC->_nodal_connec)
536     if(!_nodal_connec->isEqualWithoutConsideringStr(*otherC->_nodal_connec))
537       return false;
538   if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
539     if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
540       return false;
541   if(_nodal_connec_index!=otherC->_nodal_connec_index)
542     if(!_nodal_connec_index->isEqualWithoutConsideringStr(*otherC->_nodal_connec_index))
543       return false;
544   return true;
545 }
546
547 /*!
548  * Checks if \a this and \a other meshes are geometrically equivalent with high
549  * probability, else an exception is thrown. The meshes are considered equivalent if
550  * (1) meshes contain the same number of nodes and the same number of elements of the
551  * same types (2) three cells of the two meshes (first, last and middle) are based
552  * on coincident nodes (with a specified precision).
553  *  \param [in] other - the mesh to compare with.
554  *  \param [in] prec - the precision used to compare nodes of the two meshes.
555  *  \throw If the two meshes do not match.
556  */
557 void MEDCouplingUMesh::checkFastEquivalWith(const MEDCouplingMesh *other, double prec) const
558 {
559   MEDCouplingPointSet::checkFastEquivalWith(other,prec);
560   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
561   if(!otherC)
562     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkFastEquivalWith : Two meshes are not not unstructured !"); 
563 }
564
565 /*!
566  * Returns the reverse nodal connectivity. The reverse nodal connectivity enumerates
567  * cells each node belongs to.
568  * \warning For speed reasons, this method does not check if node ids in the nodal
569  *          connectivity correspond to the size of node coordinates array.
570  * \param [in,out] revNodal - an array holding ids of cells sharing each node.
571  * \param [in,out] revNodalIndx - an array, of length \a this->getNumberOfNodes() + 1,
572  *        dividing cell ids in \a revNodal into groups each referring to one
573  *        node. Its every element (except the last one) is an index pointing to the
574  *         first id of a group of cells. For example cells sharing the node #1 are 
575  *        described by following range of indices: 
576  *        [ \a revNodalIndx[1], \a revNodalIndx[2] ) and the cell ids are
577  *        \a revNodal[ \a revNodalIndx[1] ], \a revNodal[ \a revNodalIndx[1] + 1], ...
578  *        Number of cells sharing the *i*-th node is
579  *        \a revNodalIndx[ *i*+1 ] - \a revNodalIndx[ *i* ].
580  * \throw If the coordinates array is not set.
581  * \throw If the nodal connectivity of cells is not defined.
582  * 
583  * \if ENABLE_EXAMPLES
584  * \ref cpp_mcumesh_getReverseNodalConnectivity "Here is a C++ example".<br>
585  * \ref  py_mcumesh_getReverseNodalConnectivity "Here is a Python example".
586  * \endif
587  */
588 void MEDCouplingUMesh::getReverseNodalConnectivity(DataArrayInt *revNodal, DataArrayInt *revNodalIndx) const
589 {
590   checkFullyDefined();
591   int nbOfNodes=getNumberOfNodes();
592   int *revNodalIndxPtr=(int *)malloc((nbOfNodes+1)*sizeof(int));
593   revNodalIndx->useArray(revNodalIndxPtr,true,C_DEALLOC,nbOfNodes+1,1);
594   std::fill(revNodalIndxPtr,revNodalIndxPtr+nbOfNodes+1,0);
595   const int *conn=_nodal_connec->getConstPointer();
596   const int *connIndex=_nodal_connec_index->getConstPointer();
597   int nbOfCells=getNumberOfCells();
598   int nbOfEltsInRevNodal=0;
599   for(int eltId=0;eltId<nbOfCells;eltId++)
600     {
601       const int *strtNdlConnOfCurCell=conn+connIndex[eltId]+1;
602       const int *endNdlConnOfCurCell=conn+connIndex[eltId+1];
603       for(const int *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
604         if(*iter>=0)//for polyhedrons
605           {
606             nbOfEltsInRevNodal++;
607             revNodalIndxPtr[(*iter)+1]++;
608           }
609     }
610   std::transform(revNodalIndxPtr+1,revNodalIndxPtr+nbOfNodes+1,revNodalIndxPtr,revNodalIndxPtr+1,std::plus<int>());
611   int *revNodalPtr=(int *)malloc((nbOfEltsInRevNodal)*sizeof(int));
612   revNodal->useArray(revNodalPtr,true,C_DEALLOC,nbOfEltsInRevNodal,1);
613   std::fill(revNodalPtr,revNodalPtr+nbOfEltsInRevNodal,-1);
614   for(int eltId=0;eltId<nbOfCells;eltId++)
615     {
616       const int *strtNdlConnOfCurCell=conn+connIndex[eltId]+1;
617       const int *endNdlConnOfCurCell=conn+connIndex[eltId+1];
618       for(const int *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
619         if(*iter>=0)//for polyhedrons
620           *std::find_if(revNodalPtr+revNodalIndxPtr[*iter],revNodalPtr+revNodalIndxPtr[*iter+1],std::bind2nd(std::equal_to<int>(),-1))=eltId;
621     }
622 }
623
624 /// @cond INTERNAL
625
626 int MEDCouplingFastNbrer(int id, unsigned nb, const INTERP_KERNEL::CellModel& cm, bool compute, const int *conn1, const int *conn2)
627 {
628   return id;
629 }
630
631 int MEDCouplingOrientationSensitiveNbrer(int id, unsigned nb, const INTERP_KERNEL::CellModel& cm, bool compute, const int *conn1, const int *conn2)
632 {
633   if(!compute)
634     return id+1;
635   else
636     {
637       if(cm.getOrientationStatus(nb,conn1,conn2))
638         return id+1;
639       else
640         return -(id+1);
641     }
642 }
643
644 class MinusOneSonsGenerator
645 {
646 public:
647   MinusOneSonsGenerator(const INTERP_KERNEL::CellModel& cm):_cm(cm) { }
648   unsigned getNumberOfSons2(const int *conn, int lgth) const { return _cm.getNumberOfSons2(conn,lgth); }
649   unsigned fillSonCellNodalConnectivity2(int sonId, const int *nodalConn, int lgth, int *sonNodalConn, INTERP_KERNEL::NormalizedCellType& typeOfSon) const { return _cm.fillSonCellNodalConnectivity2(sonId,nodalConn,lgth,sonNodalConn,typeOfSon); }
650   static const int DELTA=1;
651 private:
652   const INTERP_KERNEL::CellModel& _cm;
653 };
654
655 class MinusOneSonsGeneratorBiQuadratic
656 {
657 public:
658   MinusOneSonsGeneratorBiQuadratic(const INTERP_KERNEL::CellModel& cm):_cm(cm) { }
659   unsigned getNumberOfSons2(const int *conn, int lgth) const { return _cm.getNumberOfSons2(conn,lgth); }
660   unsigned fillSonCellNodalConnectivity2(int sonId, const int *nodalConn, int lgth, int *sonNodalConn, INTERP_KERNEL::NormalizedCellType& typeOfSon) const { return _cm.fillSonCellNodalConnectivity4(sonId,nodalConn,lgth,sonNodalConn,typeOfSon); }
661   static const int DELTA=1;
662 private:
663   const INTERP_KERNEL::CellModel& _cm;
664 };
665
666 class MinusTwoSonsGenerator
667 {
668 public:
669   MinusTwoSonsGenerator(const INTERP_KERNEL::CellModel& cm):_cm(cm) { }
670   unsigned getNumberOfSons2(const int *conn, int lgth) const { return _cm.getNumberOfEdgesIn3D(conn,lgth); }
671   unsigned fillSonCellNodalConnectivity2(int sonId, const int *nodalConn, int lgth, int *sonNodalConn, INTERP_KERNEL::NormalizedCellType& typeOfSon) const { return _cm.fillSonEdgesNodalConnectivity3D(sonId,nodalConn,lgth,sonNodalConn,typeOfSon); }
672   static const int DELTA=2;
673 private:
674   const INTERP_KERNEL::CellModel& _cm;
675 };
676
677 class MicroEdgesGenerator2D
678 {
679 public:
680   MicroEdgesGenerator2D(const INTERP_KERNEL::CellModel& cm):_cm(cm) { }
681   unsigned getNumberOfSons2(const int *conn, int lgth) const { return _cm.getNumberOfMicroEdges(); }
682   unsigned fillSonCellNodalConnectivity2(int sonId, const int *nodalConn, int lgth, int *sonNodalConn, INTERP_KERNEL::NormalizedCellType& typeOfSon) const { return _cm.fillMicroEdgeNodalConnectivity(sonId,nodalConn,sonNodalConn,typeOfSon); }
683   static const int DELTA=1;
684 private:
685   const INTERP_KERNEL::CellModel& _cm;
686 };
687
688 class MicroEdgesGenerator3D
689 {
690 public:
691   MicroEdgesGenerator3D(const INTERP_KERNEL::CellModel& cm):_cm(cm) { }
692   unsigned getNumberOfSons2(const int *conn, int lgth) const { return _cm.getNumberOfMicroEdges(); }
693   unsigned fillSonCellNodalConnectivity2(int sonId, const int *nodalConn, int lgth, int *sonNodalConn, INTERP_KERNEL::NormalizedCellType& typeOfSon) const { return _cm.fillMicroEdgeNodalConnectivity(sonId,nodalConn,sonNodalConn,typeOfSon); }
694   static const int DELTA=2;
695 private:
696   const INTERP_KERNEL::CellModel& _cm;
697 };
698
699 /// @endcond
700
701 /*!
702  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
703  * this->getMeshDimension(), that bound cells of \a this mesh. In addition arrays
704  * describing correspondence between cells of \a this and the result meshes are
705  * returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending connectivity,
706  * i.e. enumerate cells of the result mesh bounding each cell of \a this mesh. The
707  * arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
708  * i.e. enumerate cells of  \a this mesh bounded by each cell of the result mesh. 
709  * \warning For speed reasons, this method does not check if node ids in the nodal
710  *          connectivity correspond to the size of node coordinates array.
711  * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
712  *          to write this mesh to the MED file, its cells must be sorted using
713  *          sortCellsInMEDFileFrmt().
714  *  \param [in,out] desc - the array containing cell ids of the result mesh bounding
715  *         each cell of \a this mesh.
716  *  \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
717  *        dividing cell ids in \a desc into groups each referring to one
718  *        cell of \a this mesh. Its every element (except the last one) is an index
719  *        pointing to the first id of a group of cells. For example cells of the
720  *        result mesh bounding the cell #1 of \a this mesh are described by following
721  *        range of indices:
722  *        [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
723  *        \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
724  *        Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
725  *        \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
726  *  \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
727  *         by each cell of the result mesh.
728  *  \param [in,out] revDescIndx - the array, of length one more than number of cells
729  *        in the result mesh,
730  *        dividing cell ids in \a revDesc into groups each referring to one
731  *        cell of the result mesh the same way as \a descIndx divides \a desc.
732  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is to
733  *        delete this mesh using decrRef() as it is no more needed.
734  *  \throw If the coordinates array is not set.
735  *  \throw If the nodal connectivity of cells is node defined.
736  *  \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
737  *         revDescIndx == NULL.
738  * 
739  *  \if ENABLE_EXAMPLES
740  *  \ref cpp_mcumesh_buildDescendingConnectivity "Here is a C++ example".<br>
741  *  \ref  py_mcumesh_buildDescendingConnectivity "Here is a Python example".
742  *  \endif
743  * \sa buildDescendingConnectivity2()
744  */
745 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
746 {
747   return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
748 }
749
750 /*!
751  * \a this has to have a mesh dimension equal to 3. If it is not the case an INTERP_KERNEL::Exception will be thrown.
752  * This behaves exactly as MEDCouplingUMesh::buildDescendingConnectivity does except that this method compute directly the transition from mesh dimension 3 to sub edges (dimension 1)
753  * in one shot. That is to say that this method is equivalent to 2 successive calls to MEDCouplingUMesh::buildDescendingConnectivity.
754  * This method returns 4 arrays and a mesh as MEDCouplingUMesh::buildDescendingConnectivity does.
755  * \sa MEDCouplingUMesh::buildDescendingConnectivity
756  */
757 MEDCouplingUMesh *MEDCouplingUMesh::explode3DMeshTo1D(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
758 {
759   checkFullyDefined();
760   if(getMeshDimension()!=3)
761     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explode3DMeshTo1D : This has to have a mesh dimension to 3 !");
762   return buildDescendingConnectivityGen<MinusTwoSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
763 }
764
765 /*!
766  * This method computes the micro edges constituting each cell in \a this. Micro edge is an edge for non quadratic cells. Micro edge is an half edge for quadratic cells.
767  * This method works for both meshes with mesh dimenstion equal to 2 or 3. Dynamical cells are not supported (polygons, polyhedrons...)
768  * 
769  * \sa explode3DMeshTo1D, buildDescendingConnectiviy
770  */
771 MEDCouplingUMesh *MEDCouplingUMesh::explodeMeshIntoMicroEdges(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
772 {
773    checkFullyDefined();
774    switch(getMeshDimension())
775      {
776      case 2:
777        return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
778      case 3:
779        return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
780      default:
781        throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explodeMeshIntoMicroEdges : Only 2D and 3D supported !");
782      }
783 }
784
785 /*!
786  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
787  * this->getMeshDimension(), that bound cells of \a this mesh. In
788  * addition arrays describing correspondence between cells of \a this and the result
789  * meshes are returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending
790  * connectivity, i.e. enumerate cells of the result mesh bounding each cell of \a this
791  *  mesh. This method differs from buildDescendingConnectivity() in that apart
792  * from cell ids, \a desc returns mutual orientation of cells in \a this and the
793  * result meshes. So a positive id means that order of nodes in corresponding cells
794  * of two meshes is same, and a negative id means a reverse order of nodes. Since a
795  * cell with id #0 can't be negative, the array \a desc returns ids in FORTRAN mode,
796  * i.e. cell ids are one-based.
797  * Arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
798  * i.e. enumerate cells of  \a this mesh bounded by each cell of the result mesh. 
799  * \warning For speed reasons, this method does not check if node ids in the nodal
800  *          connectivity correspond to the size of node coordinates array.
801  * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
802  *          to write this mesh to the MED file, its cells must be sorted using
803  *          sortCellsInMEDFileFrmt().
804  *  \param [in,out] desc - the array containing cell ids of the result mesh bounding
805  *         each cell of \a this mesh.
806  *  \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
807  *        dividing cell ids in \a desc into groups each referring to one
808  *        cell of \a this mesh. Its every element (except the last one) is an index
809  *        pointing to the first id of a group of cells. For example cells of the
810  *        result mesh bounding the cell #1 of \a this mesh are described by following
811  *        range of indices:
812  *        [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
813  *        \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
814  *        Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
815  *        \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
816  *  \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
817  *         by each cell of the result mesh.
818  *  \param [in,out] revDescIndx - the array, of length one more than number of cells
819  *        in the result mesh,
820  *        dividing cell ids in \a revDesc into groups each referring to one
821  *        cell of the result mesh the same way as \a descIndx divides \a desc.
822  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This result mesh
823  *        shares the node coordinates array with \a this mesh. The caller is to
824  *        delete this mesh using decrRef() as it is no more needed.
825  *  \throw If the coordinates array is not set.
826  *  \throw If the nodal connectivity of cells is node defined.
827  *  \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
828  *         revDescIndx == NULL.
829  * 
830  *  \if ENABLE_EXAMPLES
831  *  \ref cpp_mcumesh_buildDescendingConnectivity2 "Here is a C++ example".<br>
832  *  \ref  py_mcumesh_buildDescendingConnectivity2 "Here is a Python example".
833  *  \endif
834  * \sa buildDescendingConnectivity()
835  */
836 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity2(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
837 {
838   return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingOrientationSensitiveNbrer);
839 }
840
841 /*!
842  * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
843  * For speed reasons no check of this will be done. This method calls
844  * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
845  * This method lists cell by cell in \b this which are its neighbors. To compute the result
846  * only connectivities are considered.
847  * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
848  * The format of return is hence \ref numbering-indirect.
849  *
850  * \param [out] neighbors is an array storing all the neighbors of all cells in \b this. This array is newly
851  * allocated and should be dealt by the caller. \b neighborsIndx 2nd output
852  * parameter allows to select the right part in this array (\ref numbering-indirect). The number of tuples
853  * is equal to the last values in \b neighborsIndx.
854  * \param [out] neighborsIndx is an array of size this->getNumberOfCells()+1 newly allocated and should be
855  * dealt by the caller. This arrays allow to use the first output parameter \b neighbors (\ref numbering-indirect).
856  */
857 void MEDCouplingUMesh::computeNeighborsOfCells(DataArrayInt *&neighbors, DataArrayInt *&neighborsIndx) const
858 {
859   MCAuto<DataArrayInt> desc=DataArrayInt::New();
860   MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
861   MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
862   MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
863   MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
864   meshDM1=0;
865   ComputeNeighborsOfCellsAdv(desc,descIndx,revDesc,revDescIndx,neighbors,neighborsIndx);
866 }
867
868 void MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne(const DataArrayInt *nodeNeigh, const DataArrayInt *nodeNeighI, MCAuto<DataArrayInt>& cellNeigh, MCAuto<DataArrayInt>& cellNeighIndex) const
869 {
870   if(!nodeNeigh || !nodeNeighI)
871     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : null pointer !");
872   checkConsistencyLight();
873   nodeNeigh->checkAllocated(); nodeNeighI->checkAllocated();
874   nodeNeigh->checkNbOfComps(1,"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : node neigh");
875   nodeNeighI->checkNbOfComps(1,"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : node neigh index");
876   nodeNeighI->checkNbOfTuples(1+getNumberOfNodes(),"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : invalid length");
877   int nbCells(getNumberOfCells());
878   const int *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin()),*ne(nodeNeigh->begin()),*nei(nodeNeighI->begin());
879   cellNeigh=DataArrayInt::New(); cellNeigh->alloc(0,1); cellNeighIndex=DataArrayInt::New(); cellNeighIndex->alloc(1,1); cellNeighIndex->setIJ(0,0,0);
880   for(int i=0;i<nbCells;i++)
881     {
882       std::set<int> s;
883       for(const int *it=c+ci[i]+1;it!=c+ci[i+1];it++)
884         if(*it>=0)
885           s.insert(ne+nei[*it],ne+nei[*it+1]);
886       s.erase(i);
887       cellNeigh->insertAtTheEnd(s.begin(),s.end());
888       cellNeighIndex->pushBackSilent(cellNeigh->getNumberOfTuples());
889     }
890 }
891
892 /*!
893  * This method is called by MEDCouplingUMesh::computeNeighborsOfCells. This methods performs the algorithm
894  * of MEDCouplingUMesh::computeNeighborsOfCells.
895  * This method is useful for users that want to reduce along a criterion the set of neighbours cell. This is
896  * typically the case to extract a set a neighbours,
897  * excluding a set of meshdim-1 cells in input descending connectivity.
898  * Typically \b desc, \b descIndx, \b revDesc and \b revDescIndx (\ref numbering-indirect) input params are
899  * the result of MEDCouplingUMesh::buildDescendingConnectivity.
900  * This method lists cell by cell in \b this which are its neighbors. To compute the result only connectivities
901  * are considered.
902  * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
903  *
904  * \param [in] desc descending connectivity array.
905  * \param [in] descIndx descending connectivity index array used to walk through \b desc (\ref numbering-indirect).
906  * \param [in] revDesc reverse descending connectivity array.
907  * \param [in] revDescIndx reverse descending connectivity index array used to walk through \b revDesc (\ref numbering-indirect).
908  * \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
909  *                        parameter allows to select the right part in this array. The number of tuples is equal to the last values in \b neighborsIndx.
910  * \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.
911  */
912 void MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(const DataArrayInt *desc, const DataArrayInt *descIndx, const DataArrayInt *revDesc, const DataArrayInt *revDescIndx,
913                                                   DataArrayInt *&neighbors, DataArrayInt *&neighborsIndx)
914 {
915   if(!desc || !descIndx || !revDesc || !revDescIndx)
916     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeNeighborsOfCellsAdv some input array is empty !");
917   const int *descPtr=desc->getConstPointer();
918   const int *descIPtr=descIndx->getConstPointer();
919   const int *revDescPtr=revDesc->getConstPointer();
920   const int *revDescIPtr=revDescIndx->getConstPointer();
921   //
922   int nbCells=descIndx->getNumberOfTuples()-1;
923   MCAuto<DataArrayInt> out0=DataArrayInt::New();
924   MCAuto<DataArrayInt> out1=DataArrayInt::New(); out1->alloc(nbCells+1,1);
925   int *out1Ptr=out1->getPointer();
926   *out1Ptr++=0;
927   out0->reserve(desc->getNumberOfTuples());
928   for(int i=0;i<nbCells;i++,descIPtr++,out1Ptr++)
929     {
930       for(const int *w1=descPtr+descIPtr[0];w1!=descPtr+descIPtr[1];w1++)
931         {
932           std::set<int> s(revDescPtr+revDescIPtr[*w1],revDescPtr+revDescIPtr[(*w1)+1]);
933           s.erase(i);
934           out0->insertAtTheEnd(s.begin(),s.end());
935         }
936       *out1Ptr=out0->getNumberOfTuples();
937     }
938   neighbors=out0.retn();
939   neighborsIndx=out1.retn();
940 }
941
942 /*!
943  * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
944  * For speed reasons no check of this will be done. This method calls
945  * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
946  * This method lists node by node in \b this which are its neighbors. To compute the result
947  * only connectivities are considered.
948  * The neighbor nodes of node having id 'nodeId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
949  *
950  * \param [out] neighbors is an array storing all the neighbors of all nodes in \b this. This array
951  * is newly allocated and should be dealt by the caller. \b neighborsIndx 2nd output
952  * parameter allows to select the right part in this array (\ref numbering-indirect).
953  * The number of tuples is equal to the last values in \b neighborsIndx.
954  * \param [out] neighborsIdx is an array of size this->getNumberOfCells()+1 newly allocated and should
955  * be dealt by the caller. This arrays allow to use the first output parameter \b neighbors.
956  */
957 void MEDCouplingUMesh::computeNeighborsOfNodes(DataArrayInt *&neighbors, DataArrayInt *&neighborsIdx) const
958 {
959   checkFullyDefined();
960   int mdim(getMeshDimension()),nbNodes(getNumberOfNodes());
961   MCAuto<DataArrayInt> desc(DataArrayInt::New()),descIndx(DataArrayInt::New()),revDesc(DataArrayInt::New()),revDescIndx(DataArrayInt::New());
962   MCAuto<MEDCouplingUMesh> mesh1D;
963   switch(mdim)
964   {
965     case 3:
966       {
967         mesh1D=explode3DMeshTo1D(desc,descIndx,revDesc,revDescIndx);
968         break;
969       }
970     case 2:
971       {
972         mesh1D=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
973         break;
974       }
975     case 1:
976       {
977         mesh1D=const_cast<MEDCouplingUMesh *>(this);
978         mesh1D->incrRef();
979         break;
980       }
981     default:
982       {
983         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2,1] !");
984       }
985   }
986   desc=DataArrayInt::New(); descIndx=DataArrayInt::New(); revDesc=0; revDescIndx=0;
987   mesh1D->getReverseNodalConnectivity(desc,descIndx);
988   MCAuto<DataArrayInt> ret0(DataArrayInt::New());
989   ret0->alloc(desc->getNumberOfTuples(),1);
990   int *r0Pt(ret0->getPointer());
991   const int *c1DPtr(mesh1D->getNodalConnectivity()->begin()),*rn(desc->begin()),*rni(descIndx->begin());
992   for(int i=0;i<nbNodes;i++,rni++)
993     {
994       for(const int *oneDCellIt=rn+rni[0];oneDCellIt!=rn+rni[1];oneDCellIt++)
995         *r0Pt++=c1DPtr[3*(*oneDCellIt)+1]==i?c1DPtr[3*(*oneDCellIt)+2]:c1DPtr[3*(*oneDCellIt)+1];
996     }
997   neighbors=ret0.retn();
998   neighborsIdx=descIndx.retn();
999 }
1000
1001 /// @cond INTERNAL
1002
1003 /*!
1004  * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
1005  * For speed reasons no check of this will be done.
1006  */
1007 template<class SonsGenerator>
1008 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivityGen(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx, DimM1DescNbrer nbrer) const
1009 {
1010   if(!desc || !descIndx || !revDesc || !revDescIndx)
1011     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildDescendingConnectivityGen : present of a null pointer in input !");
1012   checkConnectivityFullyDefined();
1013   int nbOfCells=getNumberOfCells();
1014   int nbOfNodes=getNumberOfNodes();
1015   MCAuto<DataArrayInt> revNodalIndx=DataArrayInt::New(); revNodalIndx->alloc(nbOfNodes+1,1); revNodalIndx->fillWithZero();
1016   int *revNodalIndxPtr=revNodalIndx->getPointer();
1017   const int *conn=_nodal_connec->getConstPointer();
1018   const int *connIndex=_nodal_connec_index->getConstPointer();
1019   std::string name="Mesh constituent of "; name+=getName();
1020   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(name,getMeshDimension()-SonsGenerator::DELTA);
1021   ret->setCoords(getCoords());
1022   ret->allocateCells(2*nbOfCells);
1023   descIndx->alloc(nbOfCells+1,1);
1024   MCAuto<DataArrayInt> revDesc2(DataArrayInt::New()); revDesc2->reserve(2*nbOfCells);
1025   int *descIndxPtr=descIndx->getPointer(); *descIndxPtr++=0;
1026   for(int eltId=0;eltId<nbOfCells;eltId++,descIndxPtr++)
1027     {
1028       int pos=connIndex[eltId];
1029       int posP1=connIndex[eltId+1];
1030       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[pos]);
1031       SonsGenerator sg(cm);
1032       unsigned nbOfSons=sg.getNumberOfSons2(conn+pos+1,posP1-pos-1);
1033       INTERP_KERNEL::AutoPtr<int> tmp=new int[posP1-pos];
1034       for(unsigned i=0;i<nbOfSons;i++)
1035         {
1036           INTERP_KERNEL::NormalizedCellType cmsId;
1037           unsigned nbOfNodesSon=sg.fillSonCellNodalConnectivity2(i,conn+pos+1,posP1-pos-1,tmp,cmsId);
1038           for(unsigned k=0;k<nbOfNodesSon;k++)
1039             if(tmp[k]>=0)
1040               revNodalIndxPtr[tmp[k]+1]++;
1041           ret->insertNextCell(cmsId,nbOfNodesSon,tmp);
1042           revDesc2->pushBackSilent(eltId);
1043         }
1044       descIndxPtr[0]=descIndxPtr[-1]+(int)nbOfSons;
1045     }
1046   int nbOfCellsM1=ret->getNumberOfCells();
1047   std::transform(revNodalIndxPtr+1,revNodalIndxPtr+nbOfNodes+1,revNodalIndxPtr,revNodalIndxPtr+1,std::plus<int>());
1048   MCAuto<DataArrayInt> revNodal=DataArrayInt::New(); revNodal->alloc(revNodalIndx->back(),1);
1049   std::fill(revNodal->getPointer(),revNodal->getPointer()+revNodalIndx->back(),-1);
1050   int *revNodalPtr=revNodal->getPointer();
1051   const int *connM1=ret->getNodalConnectivity()->getConstPointer();
1052   const int *connIndexM1=ret->getNodalConnectivityIndex()->getConstPointer();
1053   for(int eltId=0;eltId<nbOfCellsM1;eltId++)
1054     {
1055       const int *strtNdlConnOfCurCell=connM1+connIndexM1[eltId]+1;
1056       const int *endNdlConnOfCurCell=connM1+connIndexM1[eltId+1];
1057       for(const int *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
1058         if(*iter>=0)//for polyhedrons
1059           *std::find_if(revNodalPtr+revNodalIndxPtr[*iter],revNodalPtr+revNodalIndxPtr[*iter+1],std::bind2nd(std::equal_to<int>(),-1))=eltId;
1060     }
1061   //
1062   DataArrayInt *commonCells=0,*commonCellsI=0;
1063   FindCommonCellsAlg(3,0,ret->getNodalConnectivity(),ret->getNodalConnectivityIndex(),revNodal,revNodalIndx,commonCells,commonCellsI);
1064   MCAuto<DataArrayInt> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1065   const int *commonCellsPtr(commonCells->getConstPointer()),*commonCellsIPtr(commonCellsI->getConstPointer());
1066   int newNbOfCellsM1=-1;
1067   MCAuto<DataArrayInt> o2nM1=DataArrayInt::ConvertIndexArrayToO2N(nbOfCellsM1,commonCells->begin(),
1068                                                                                                             commonCellsI->begin(),commonCellsI->end(),newNbOfCellsM1);
1069   std::vector<bool> isImpacted(nbOfCellsM1,false);
1070   for(const int *work=commonCellsI->begin();work!=commonCellsI->end()-1;work++)
1071     for(int work2=work[0];work2!=work[1];work2++)
1072       isImpacted[commonCellsPtr[work2]]=true;
1073   const int *o2nM1Ptr=o2nM1->getConstPointer();
1074   MCAuto<DataArrayInt> n2oM1=o2nM1->invertArrayO2N2N2OBis(newNbOfCellsM1);
1075   const int *n2oM1Ptr=n2oM1->getConstPointer();
1076   MCAuto<MEDCouplingUMesh> ret2=static_cast<MEDCouplingUMesh *>(ret->buildPartOfMySelf(n2oM1->begin(),n2oM1->end(),true));
1077   ret2->copyTinyInfoFrom(this);
1078   desc->alloc(descIndx->back(),1);
1079   int *descPtr=desc->getPointer();
1080   const INTERP_KERNEL::CellModel& cmsDft=INTERP_KERNEL::CellModel::GetCellModel(INTERP_KERNEL::NORM_POINT1);
1081   for(int i=0;i<nbOfCellsM1;i++,descPtr++)
1082     {
1083       if(!isImpacted[i])
1084         *descPtr=nbrer(o2nM1Ptr[i],0,cmsDft,false,0,0);
1085       else
1086         {
1087           if(i!=n2oM1Ptr[o2nM1Ptr[i]])
1088             {
1089               const INTERP_KERNEL::CellModel& cms=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connM1[connIndexM1[i]]);
1090               *descPtr=nbrer(o2nM1Ptr[i],connIndexM1[i+1]-connIndexM1[i]-1,cms,true,connM1+connIndexM1[n2oM1Ptr[o2nM1Ptr[i]]]+1,connM1+connIndexM1[i]+1);
1091             }
1092           else
1093             *descPtr=nbrer(o2nM1Ptr[i],0,cmsDft,false,0,0);
1094         }
1095     }
1096   revDesc->reserve(newNbOfCellsM1);
1097   revDescIndx->alloc(newNbOfCellsM1+1,1);
1098   int *revDescIndxPtr=revDescIndx->getPointer(); *revDescIndxPtr++=0;
1099   const int *revDesc2Ptr=revDesc2->getConstPointer();
1100   for(int i=0;i<newNbOfCellsM1;i++,revDescIndxPtr++)
1101     {
1102       int oldCellIdM1=n2oM1Ptr[i];
1103       if(!isImpacted[oldCellIdM1])
1104         {
1105           revDesc->pushBackSilent(revDesc2Ptr[oldCellIdM1]);
1106           revDescIndxPtr[0]=revDescIndxPtr[-1]+1;
1107         }
1108       else
1109         {
1110           for(int j=commonCellsIPtr[0];j<commonCellsIPtr[1];j++)
1111             revDesc->pushBackSilent(revDesc2Ptr[commonCellsPtr[j]]);
1112           revDescIndxPtr[0]=revDescIndxPtr[-1]+commonCellsIPtr[1]-commonCellsIPtr[0];
1113           commonCellsIPtr++;
1114         }
1115     }
1116   //
1117   return ret2.retn();
1118 }
1119
1120 struct MEDCouplingAccVisit
1121 {
1122   MEDCouplingAccVisit():_new_nb_of_nodes(0) { }
1123   int operator()(int val) { if(val!=-1) return _new_nb_of_nodes++; else return -1; }
1124   int _new_nb_of_nodes;
1125 };
1126
1127 /// @endcond
1128
1129 /*!
1130  * Converts specified cells to either polygons (if \a this is a 2D mesh) or
1131  * polyhedrons (if \a this is a 3D mesh). The cells to convert are specified by an
1132  * array of cell ids. Pay attention that after conversion all algorithms work slower
1133  * with \a this mesh than before conversion. <br> If an exception is thrown during the
1134  * conversion due presence of invalid ids in the array of cells to convert, as a
1135  * result \a this mesh contains some already converted elements. In this case the 2D
1136  * mesh remains valid but 3D mesh becomes \b inconsistent!
1137  *  \warning This method can significantly modify the order of geometric types in \a this,
1138  *          hence, to write this mesh to the MED file, its cells must be sorted using
1139  *          sortCellsInMEDFileFrmt().
1140  *  \param [in] cellIdsToConvertBg - the array holding ids of cells to convert.
1141  *  \param [in] cellIdsToConvertEnd - a pointer to the last-plus-one-th element of \a
1142  *         cellIdsToConvertBg.
1143  *  \throw If the coordinates array is not set.
1144  *  \throw If the nodal connectivity of cells is node defined.
1145  *  \throw If dimension of \a this mesh is not either 2 or 3.
1146  *
1147  *  \if ENABLE_EXAMPLES
1148  *  \ref cpp_mcumesh_convertToPolyTypes "Here is a C++ example".<br>
1149  *  \ref  py_mcumesh_convertToPolyTypes "Here is a Python example".
1150  *  \endif
1151  */
1152 void MEDCouplingUMesh::convertToPolyTypes(const int *cellIdsToConvertBg, const int *cellIdsToConvertEnd)
1153 {
1154   checkFullyDefined();
1155   int dim=getMeshDimension();
1156   if(dim<2 || dim>3)
1157     throw INTERP_KERNEL::Exception("Invalid mesh dimension : must be 2 or 3 !");
1158   int nbOfCells(getNumberOfCells());
1159   if(dim==2)
1160     {
1161       const int *connIndex=_nodal_connec_index->getConstPointer();
1162       int *conn=_nodal_connec->getPointer();
1163       for(const int *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1164         {
1165           if(*iter>=0 && *iter<nbOfCells)
1166             {
1167               const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*iter]]);
1168               if(!cm.isQuadratic())
1169                 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_POLYGON;
1170               else
1171                 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_QPOLYG;
1172             }
1173           else
1174             {
1175               std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1176               oss << " in range [0," << nbOfCells << ") !";
1177               throw INTERP_KERNEL::Exception(oss.str());
1178             }
1179         }
1180     }
1181   else
1182     {
1183       int *connIndex(_nodal_connec_index->getPointer());
1184       const int *connOld(_nodal_connec->getConstPointer());
1185       MCAuto<DataArrayInt> connNew(DataArrayInt::New()),connNewI(DataArrayInt::New()); connNew->alloc(0,1); connNewI->alloc(1,1); connNewI->setIJ(0,0,0);
1186       std::vector<bool> toBeDone(nbOfCells,false);
1187       for(const int *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1188         {
1189           if(*iter>=0 && *iter<nbOfCells)
1190             toBeDone[*iter]=true;
1191           else
1192             {
1193               std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1194               oss << " in range [0," << nbOfCells << ") !";
1195               throw INTERP_KERNEL::Exception(oss.str());
1196             }
1197         }
1198       for(int cellId=0;cellId<nbOfCells;cellId++)
1199         {
1200           int pos(connIndex[cellId]),posP1(connIndex[cellId+1]);
1201           int lgthOld(posP1-pos-1);
1202           if(toBeDone[cellId])
1203             {
1204               const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connOld[pos]);
1205               unsigned nbOfFaces(cm.getNumberOfSons2(connOld+pos+1,lgthOld));
1206               int *tmp(new int[nbOfFaces*lgthOld+1]);
1207               int *work=tmp; *work++=INTERP_KERNEL::NORM_POLYHED;
1208               for(unsigned j=0;j<nbOfFaces;j++)
1209                 {
1210                   INTERP_KERNEL::NormalizedCellType type;
1211                   unsigned offset=cm.fillSonCellNodalConnectivity2(j,connOld+pos+1,lgthOld,work,type);
1212                   work+=offset;
1213                   *work++=-1;
1214                 }
1215               std::size_t newLgth(std::distance(tmp,work)-1);//-1 for last -1
1216               connNew->pushBackValsSilent(tmp,tmp+newLgth);
1217               connNewI->pushBackSilent(connNewI->back()+(int)newLgth);
1218               delete [] tmp;
1219             }
1220           else
1221             {
1222               connNew->pushBackValsSilent(connOld+pos,connOld+posP1);
1223               connNewI->pushBackSilent(connNewI->back()+posP1-pos);
1224             }
1225         }
1226       setConnectivity(connNew,connNewI,false);//false because computeTypes called just behind.
1227     }
1228   computeTypes();
1229 }
1230
1231 /*!
1232  * Converts all cells to either polygons (if \a this is a 2D mesh) or
1233  * polyhedrons (if \a this is a 3D mesh).
1234  *  \warning As this method is purely for user-friendliness and no optimization is
1235  *          done to avoid construction of a useless vector, this method can be costly
1236  *          in memory.
1237  *  \throw If the coordinates array is not set.
1238  *  \throw If the nodal connectivity of cells is node defined.
1239  *  \throw If dimension of \a this mesh is not either 2 or 3.
1240  */
1241 void MEDCouplingUMesh::convertAllToPoly()
1242 {
1243   int nbOfCells=getNumberOfCells();
1244   std::vector<int> cellIds(nbOfCells);
1245   for(int i=0;i<nbOfCells;i++)
1246     cellIds[i]=i;
1247   convertToPolyTypes(&cellIds[0],&cellIds[0]+cellIds.size());
1248 }
1249
1250 /*!
1251  * Fixes nodal connectivity of invalid cells of type NORM_POLYHED. This method
1252  * expects that all NORM_POLYHED cells have connectivity similar to that of prismatic
1253  * volumes like NORM_HEXA8, NORM_PENTA6 etc., i.e. the first half of nodes describes a
1254  * base facet of the volume and the second half of nodes describes an opposite facet
1255  * having the same number of nodes as the base one. This method converts such
1256  * connectivity to a valid polyhedral format where connectivity of each facet is
1257  * explicitly described and connectivity of facets are separated by -1. If \a this mesh
1258  * contains a NORM_POLYHED cell with a valid connectivity, or an invalid connectivity is
1259  * not as expected, an exception is thrown and the mesh remains unchanged. Care of
1260  * a correct orientation of the first facet of a polyhedron, else orientation of a
1261  * corrected cell is reverse.<br>
1262  * This method is useful to build an extruded unstructured mesh with polyhedrons as
1263  * it releases the user from boring description of polyhedra connectivity in the valid
1264  * format.
1265  *  \throw If \a this->getMeshDimension() != 3.
1266  *  \throw If \a this->getSpaceDimension() != 3.
1267  *  \throw If the nodal connectivity of cells is not defined.
1268  *  \throw If the coordinates array is not set.
1269  *  \throw If \a this mesh contains polyhedrons with the valid connectivity.
1270  *  \throw If \a this mesh contains polyhedrons with odd number of nodes.
1271  *
1272  *  \if ENABLE_EXAMPLES
1273  *  \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
1274  *  \ref  py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
1275  *  \endif
1276  */
1277 void MEDCouplingUMesh::convertExtrudedPolyhedra()
1278 {
1279   checkFullyDefined();
1280   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1281     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertExtrudedPolyhedra works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
1282   int nbOfCells=getNumberOfCells();
1283   MCAuto<DataArrayInt> newCi=DataArrayInt::New();
1284   newCi->alloc(nbOfCells+1,1);
1285   int *newci=newCi->getPointer();
1286   const int *ci=_nodal_connec_index->getConstPointer();
1287   const int *c=_nodal_connec->getConstPointer();
1288   newci[0]=0;
1289   for(int i=0;i<nbOfCells;i++)
1290     {
1291       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1292       if(type==INTERP_KERNEL::NORM_POLYHED)
1293         {
1294           if(std::count(c+ci[i]+1,c+ci[i+1],-1)!=0)
1295             {
1296               std::ostringstream oss; oss << "MEDCouplingUMesh::convertExtrudedPolyhedra : cell # " << i << " is a polhedron BUT it has NOT exactly 1 face !";
1297               throw INTERP_KERNEL::Exception(oss.str());
1298             }
1299           std::size_t n2=std::distance(c+ci[i]+1,c+ci[i+1]);
1300           if(n2%2!=0)
1301             {
1302               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 !";
1303               throw INTERP_KERNEL::Exception(oss.str());
1304             }
1305           int n1=(int)(n2/2);
1306           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)
1307         }
1308       else
1309         newci[i+1]=(ci[i+1]-ci[i])+newci[i];
1310     }
1311   MCAuto<DataArrayInt> newC=DataArrayInt::New();
1312   newC->alloc(newci[nbOfCells],1);
1313   int *newc=newC->getPointer();
1314   for(int i=0;i<nbOfCells;i++)
1315     {
1316       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1317       if(type==INTERP_KERNEL::NORM_POLYHED)
1318         {
1319           std::size_t n1=std::distance(c+ci[i]+1,c+ci[i+1])/2;
1320           newc=std::copy(c+ci[i],c+ci[i]+n1+1,newc);
1321           *newc++=-1;
1322           for(std::size_t j=0;j<n1;j++)
1323             {
1324               newc[j]=c[ci[i]+1+n1+(n1-j)%n1];
1325               newc[n1+5*j]=-1;
1326               newc[n1+5*j+1]=c[ci[i]+1+j];
1327               newc[n1+5*j+2]=c[ci[i]+1+j+n1];
1328               newc[n1+5*j+3]=c[ci[i]+1+(j+1)%n1+n1];
1329               newc[n1+5*j+4]=c[ci[i]+1+(j+1)%n1];
1330             }
1331           newc+=n1*6;
1332         }
1333       else
1334         newc=std::copy(c+ci[i],c+ci[i+1],newc);
1335     }
1336   _nodal_connec_index->decrRef(); _nodal_connec_index=newCi.retn();
1337   _nodal_connec->decrRef(); _nodal_connec=newC.retn();
1338 }
1339
1340
1341 /*!
1342  * Converts all polygons (if \a this is a 2D mesh) or polyhedrons (if \a this is a 3D
1343  * mesh) to cells of classical types. This method is opposite to convertToPolyTypes().
1344  * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
1345  *          to write this mesh to the MED file, its cells must be sorted using
1346  *          sortCellsInMEDFileFrmt().
1347  * \warning Cells (and most notably polyhedrons) must be correctly oriented for this to work
1348  *          properly. See orientCorrectlyPolyhedrons() and arePolyhedronsNotCorrectlyOriented().
1349  * \return \c true if at least one cell has been converted, \c false else. In the
1350  *         last case the nodal connectivity remains unchanged.
1351  * \throw If the coordinates array is not set.
1352  * \throw If the nodal connectivity of cells is not defined.
1353  * \throw If \a this->getMeshDimension() < 0.
1354  */
1355 bool MEDCouplingUMesh::unPolyze()
1356 {
1357   checkFullyDefined();
1358   int mdim=getMeshDimension();
1359   if(mdim<0)
1360     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::unPolyze works on umeshes with meshdim equals to 0, 1 2 or 3 !");
1361   if(mdim<=1)
1362     return false;
1363   int nbOfCells=getNumberOfCells();
1364   if(nbOfCells<1)
1365     return false;
1366   int initMeshLgth=getNodalConnectivityArrayLen();
1367   int *conn=_nodal_connec->getPointer();
1368   int *index=_nodal_connec_index->getPointer();
1369   int posOfCurCell=0;
1370   int newPos=0;
1371   int lgthOfCurCell;
1372   bool ret=false;
1373   for(int i=0;i<nbOfCells;i++)
1374     {
1375       lgthOfCurCell=index[i+1]-posOfCurCell;
1376       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
1377       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
1378       INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::NORM_ERROR;
1379       int newLgth;
1380       if(cm.isDynamic())
1381         {
1382           switch(cm.getDimension())
1383           {
1384             case 2:
1385               {
1386                 INTERP_KERNEL::AutoPtr<int> tmp=new int[lgthOfCurCell-1];
1387                 std::copy(conn+posOfCurCell+1,conn+posOfCurCell+lgthOfCurCell,(int *)tmp);
1388                 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly2D(cm.isQuadratic(),tmp,lgthOfCurCell-1,conn+newPos+1,newLgth);
1389                 break;
1390               }
1391             case 3:
1392               {
1393                 int nbOfFaces,lgthOfPolyhConn;
1394                 INTERP_KERNEL::AutoPtr<int> zipFullReprOfPolyh=INTERP_KERNEL::CellSimplify::getFullPolyh3DCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,nbOfFaces,lgthOfPolyhConn);
1395                 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly3D(zipFullReprOfPolyh,nbOfFaces,lgthOfPolyhConn,conn+newPos+1,newLgth);
1396                 break;
1397               }
1398             case 1:
1399               {
1400                 newType=(lgthOfCurCell==3)?INTERP_KERNEL::NORM_SEG2:INTERP_KERNEL::NORM_POLYL;
1401                 break;
1402               }
1403           }
1404           ret=ret || (newType!=type);
1405           conn[newPos]=newType;
1406           newPos+=newLgth+1;
1407           posOfCurCell=index[i+1];
1408           index[i+1]=newPos;
1409         }
1410       else
1411         {
1412           std::copy(conn+posOfCurCell,conn+posOfCurCell+lgthOfCurCell,conn+newPos);
1413           newPos+=lgthOfCurCell;
1414           posOfCurCell+=lgthOfCurCell;
1415           index[i+1]=newPos;
1416         }
1417     }
1418   if(newPos!=initMeshLgth)
1419     _nodal_connec->reAlloc(newPos);
1420   if(ret)
1421     computeTypes();
1422   return ret;
1423 }
1424
1425 /*!
1426  * This method expects that spaceDimension is equal to 3 and meshDimension equal to 3.
1427  * This method performs operation only on polyhedrons in \b this. If no polyhedrons exists in \b this, \b this remains unchanged.
1428  * This method allows to merge if any coplanar 3DSurf cells that may appear in some polyhedrons cells. 
1429  *
1430  * \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 
1431  *             precision.
1432  */
1433 void MEDCouplingUMesh::simplifyPolyhedra(double eps)
1434 {
1435   checkFullyDefined();
1436   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1437     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplifyPolyhedra : works on meshdimension 3 and spaceDimension 3 !");
1438   MCAuto<DataArrayDouble> coords=getCoords()->deepCopy();
1439   coords->recenterForMaxPrecision(eps);
1440   //
1441   int nbOfCells=getNumberOfCells();
1442   const int *conn=_nodal_connec->getConstPointer();
1443   const int *index=_nodal_connec_index->getConstPointer();
1444   MCAuto<DataArrayInt> connINew=DataArrayInt::New();
1445   connINew->alloc(nbOfCells+1,1);
1446   int *connINewPtr=connINew->getPointer(); *connINewPtr++=0;
1447   MCAuto<DataArrayInt> connNew=DataArrayInt::New(); connNew->alloc(0,1);
1448   bool changed=false;
1449   for(int i=0;i<nbOfCells;i++,connINewPtr++)
1450     {
1451       if(conn[index[i]]==(int)INTERP_KERNEL::NORM_POLYHED)
1452         {
1453           SimplifyPolyhedronCell(eps,coords,conn+index[i],conn+index[i+1],connNew);
1454           changed=true;
1455         }
1456       else
1457         connNew->insertAtTheEnd(conn+index[i],conn+index[i+1]);
1458       *connINewPtr=connNew->getNumberOfTuples();
1459     }
1460   if(changed)
1461     setConnectivity(connNew,connINew,false);
1462 }
1463
1464 /*!
1465  * This method returns all node ids used in the connectivity of \b this. The data array returned has to be dealt by the caller.
1466  * The returned node ids are sorted ascendingly. This method is close to MEDCouplingUMesh::getNodeIdsInUse except
1467  * the format of the returned DataArrayInt instance.
1468  * 
1469  * \return a newly allocated DataArrayInt sorted ascendingly of fetched node ids.
1470  * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1471  */
1472 DataArrayInt *MEDCouplingUMesh::computeFetchedNodeIds() const
1473 {
1474   checkConnectivityFullyDefined();
1475   const int *maxEltPt(std::max_element(_nodal_connec->begin(),_nodal_connec->end()));
1476   int maxElt(maxEltPt==_nodal_connec->end()?0:std::abs(*maxEltPt)+1);
1477   std::vector<bool> retS(maxElt,false);
1478   computeNodeIdsAlg(retS);
1479   return DataArrayInt::BuildListOfSwitchedOn(retS);
1480 }
1481
1482 /*!
1483  * \param [in,out] nodeIdsInUse an array of size typically equal to nbOfNodes.
1484  * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1485  */
1486 void MEDCouplingUMesh::computeNodeIdsAlg(std::vector<bool>& nodeIdsInUse) const
1487 {
1488   int nbOfNodes((int)nodeIdsInUse.size()),nbOfCells(getNumberOfCells());
1489   const int *connIndex(_nodal_connec_index->getConstPointer()),*conn(_nodal_connec->getConstPointer());
1490   for(int i=0;i<nbOfCells;i++)
1491     for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1492       if(conn[j]>=0)
1493         {
1494           if(conn[j]<nbOfNodes)
1495             nodeIdsInUse[conn[j]]=true;
1496           else
1497             {
1498               std::ostringstream oss; oss << "MEDCouplingUMesh::computeNodeIdsAlg : In cell #" << i  << " presence of node id " <<  conn[j] << " not in [0," << nbOfNodes << ") !";
1499               throw INTERP_KERNEL::Exception(oss.str());
1500             }
1501         }
1502 }
1503
1504 /*!
1505  * Finds nodes not used in any cell and returns an array giving a new id to every node
1506  * by excluding the unused nodes, for which the array holds -1. The result array is
1507  * a mapping in "Old to New" mode. 
1508  *  \param [out] nbrOfNodesInUse - number of node ids present in the nodal connectivity.
1509  *  \return DataArrayInt * - a new instance of DataArrayInt. Its length is \a
1510  *          this->getNumberOfNodes(). It holds for each node of \a this mesh either -1
1511  *          if the node is unused or a new id else. The caller is to delete this
1512  *          array using decrRef() as it is no more needed.  
1513  *  \throw If the coordinates array is not set.
1514  *  \throw If the nodal connectivity of cells is not defined.
1515  *  \throw If the nodal connectivity includes an invalid id.
1516  *
1517  *  \if ENABLE_EXAMPLES
1518  *  \ref cpp_mcumesh_getNodeIdsInUse "Here is a C++ example".<br>
1519  *  \ref  py_mcumesh_getNodeIdsInUse "Here is a Python example".
1520  *  \endif
1521  * \sa computeFetchedNodeIds, computeNodeIdsAlg()
1522  */
1523 DataArrayInt *MEDCouplingUMesh::getNodeIdsInUse(int& nbrOfNodesInUse) const
1524 {
1525   nbrOfNodesInUse=-1;
1526   int nbOfNodes(getNumberOfNodes());
1527   MCAuto<DataArrayInt> ret=DataArrayInt::New();
1528   ret->alloc(nbOfNodes,1);
1529   int *traducer=ret->getPointer();
1530   std::fill(traducer,traducer+nbOfNodes,-1);
1531   int nbOfCells=getNumberOfCells();
1532   const int *connIndex=_nodal_connec_index->getConstPointer();
1533   const int *conn=_nodal_connec->getConstPointer();
1534   for(int i=0;i<nbOfCells;i++)
1535     for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1536       if(conn[j]>=0)
1537         {
1538           if(conn[j]<nbOfNodes)
1539             traducer[conn[j]]=1;
1540           else
1541             {
1542               std::ostringstream oss; oss << "MEDCouplingUMesh::getNodeIdsInUse : In cell #" << i  << " presence of node id " <<  conn[j] << " not in [0," << nbOfNodes << ") !";
1543               throw INTERP_KERNEL::Exception(oss.str());
1544             }
1545         }
1546   nbrOfNodesInUse=(int)std::count(traducer,traducer+nbOfNodes,1);
1547   std::transform(traducer,traducer+nbOfNodes,traducer,MEDCouplingAccVisit());
1548   return ret.retn();
1549 }
1550
1551 /*!
1552  * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1553  * For each cell in \b this the number of nodes constituting cell is computed.
1554  * For each polyhedron cell, the sum of the number of nodes of each face constituting polyhedron cell is returned.
1555  * So for pohyhedrons some nodes can be counted several times in the returned result.
1556  * 
1557  * \return a newly allocated array
1558  * \sa MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell
1559  */
1560 DataArrayInt *MEDCouplingUMesh::computeNbOfNodesPerCell() const
1561 {
1562   checkConnectivityFullyDefined();
1563   int nbOfCells=getNumberOfCells();
1564   MCAuto<DataArrayInt> ret=DataArrayInt::New();
1565   ret->alloc(nbOfCells,1);
1566   int *retPtr=ret->getPointer();
1567   const int *conn=getNodalConnectivity()->getConstPointer();
1568   const int *connI=getNodalConnectivityIndex()->getConstPointer();
1569   for(int i=0;i<nbOfCells;i++,retPtr++)
1570     {
1571       if(conn[connI[i]]!=(int)INTERP_KERNEL::NORM_POLYHED)
1572         *retPtr=connI[i+1]-connI[i]-1;
1573       else
1574         *retPtr=connI[i+1]-connI[i]-1-std::count(conn+connI[i]+1,conn+connI[i+1],-1);
1575     }
1576   return ret.retn();
1577 }
1578
1579 /*!
1580  * This method computes effective number of nodes per cell. That is to say nodes appearing several times in nodal connectivity of a cell,
1581  * will be counted only once here whereas it will be counted several times in MEDCouplingUMesh::computeNbOfNodesPerCell method.
1582  *
1583  * \return DataArrayInt * - new object to be deallocated by the caller.
1584  * \sa MEDCouplingUMesh::computeNbOfNodesPerCell
1585  */
1586 DataArrayInt *MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell() const
1587 {
1588   checkConnectivityFullyDefined();
1589   int nbOfCells=getNumberOfCells();
1590   MCAuto<DataArrayInt> ret=DataArrayInt::New();
1591   ret->alloc(nbOfCells,1);
1592   int *retPtr=ret->getPointer();
1593   const int *conn=getNodalConnectivity()->getConstPointer();
1594   const int *connI=getNodalConnectivityIndex()->getConstPointer();
1595   for(int i=0;i<nbOfCells;i++,retPtr++)
1596     {
1597       std::set<int> s(conn+connI[i]+1,conn+connI[i+1]);
1598       if(conn[connI[i]]!=(int)INTERP_KERNEL::NORM_POLYHED)
1599         *retPtr=(int)s.size();
1600       else
1601         {
1602           s.erase(-1);
1603           *retPtr=(int)s.size();
1604         }
1605     }
1606   return ret.retn();
1607 }
1608
1609 /*!
1610  * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1611  * For each cell in \b this the number of faces constituting (entity of dimension this->getMeshDimension()-1) cell is computed.
1612  * 
1613  * \return a newly allocated array
1614  */
1615 DataArrayInt *MEDCouplingUMesh::computeNbOfFacesPerCell() const
1616 {
1617   checkConnectivityFullyDefined();
1618   int nbOfCells=getNumberOfCells();
1619   MCAuto<DataArrayInt> ret=DataArrayInt::New();
1620   ret->alloc(nbOfCells,1);
1621   int *retPtr=ret->getPointer();
1622   const int *conn=getNodalConnectivity()->getConstPointer();
1623   const int *connI=getNodalConnectivityIndex()->getConstPointer();
1624   for(int i=0;i<nbOfCells;i++,retPtr++,connI++)
1625     {
1626       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]);
1627       *retPtr=cm.getNumberOfSons2(conn+connI[0]+1,connI[1]-connI[0]-1);
1628     }
1629   return ret.retn();
1630 }
1631
1632 /*!
1633  * Removes unused nodes (the node coordinates array is shorten) and returns an array
1634  * mapping between new and old node ids in "Old to New" mode. -1 values in the returned
1635  * array mean that the corresponding old node is no more used. 
1636  *  \return DataArrayInt * - a new instance of DataArrayInt of length \a
1637  *           this->getNumberOfNodes() before call of this method. The caller is to
1638  *           delete this array using decrRef() as it is no more needed. 
1639  *  \throw If the coordinates array is not set.
1640  *  \throw If the nodal connectivity of cells is not defined.
1641  *  \throw If the nodal connectivity includes an invalid id.
1642  *  \sa areAllNodesFetched
1643  *
1644  *  \if ENABLE_EXAMPLES
1645  *  \ref cpp_mcumesh_zipCoordsTraducer "Here is a C++ example".<br>
1646  *  \ref  py_mcumesh_zipCoordsTraducer "Here is a Python example".
1647  *  \endif
1648  */
1649 DataArrayInt *MEDCouplingUMesh::zipCoordsTraducer()
1650 {
1651   return MEDCouplingPointSet::zipCoordsTraducer();
1652 }
1653
1654 /*!
1655  * This method stands if 'cell1' and 'cell2' are equals regarding 'compType' policy.
1656  * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1657  */
1658 int MEDCouplingUMesh::AreCellsEqual(const int *conn, const int *connI, int cell1, int cell2, int compType)
1659 {
1660   switch(compType)
1661   {
1662     case 0:
1663       return AreCellsEqualPolicy0(conn,connI,cell1,cell2);
1664     case 1:
1665       return AreCellsEqualPolicy1(conn,connI,cell1,cell2);
1666     case 2:
1667       return AreCellsEqualPolicy2(conn,connI,cell1,cell2);
1668     case 3:
1669       return AreCellsEqualPolicy2NoType(conn,connI,cell1,cell2);
1670     case 7:
1671       return AreCellsEqualPolicy7(conn,connI,cell1,cell2);
1672   }
1673   throw INTERP_KERNEL::Exception("Unknown comparison asked ! Must be in 0,1,2,3 or 7.");
1674 }
1675
1676 /*!
1677  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 0.
1678  */
1679 int MEDCouplingUMesh::AreCellsEqualPolicy0(const int *conn, const int *connI, int cell1, int cell2)
1680 {
1681   if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1682     return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;
1683   return 0;
1684 }
1685
1686 /*!
1687  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 1.
1688  */
1689 int MEDCouplingUMesh::AreCellsEqualPolicy1(const int *conn, const int *connI, int cell1, int cell2)
1690 {
1691   int sz=connI[cell1+1]-connI[cell1];
1692   if(sz==connI[cell2+1]-connI[cell2])
1693     {
1694       if(conn[connI[cell1]]==conn[connI[cell2]])
1695         {
1696           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1697           unsigned dim=cm.getDimension();
1698           if(dim!=3)
1699             {
1700               if(dim!=1)
1701                 {
1702                   int sz1=2*(sz-1);
1703                   INTERP_KERNEL::AutoPtr<int> tmp=new int[sz1];
1704                   int *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(int *)tmp);
1705                   std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1706                   work=std::search((int *)tmp,(int *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1707                   return work!=tmp+sz1?1:0;
1708                 }
1709               else
1710                 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;//case of SEG2 and SEG3
1711             }
1712           else
1713             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy1 : not implemented yet for meshdim == 3 !");
1714         }
1715     }
1716   return 0;
1717 }
1718
1719 /*!
1720  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 2.
1721  */
1722 int MEDCouplingUMesh::AreCellsEqualPolicy2(const int *conn, const int *connI, int cell1, int cell2)
1723 {
1724   if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1725     {
1726       if(conn[connI[cell1]]==conn[connI[cell2]])
1727         {
1728           std::set<int> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1729           std::set<int> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1730           return s1==s2?1:0;
1731         }
1732     }
1733   return 0;
1734 }
1735
1736 /*!
1737  * This method is less restrictive than AreCellsEqualPolicy2. Here the geometric type is absolutely not taken into account !
1738  */
1739 int MEDCouplingUMesh::AreCellsEqualPolicy2NoType(const int *conn, const int *connI, int cell1, int cell2)
1740 {
1741   if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1742     {
1743       std::set<int> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1744       std::set<int> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1745       return s1==s2?1:0;
1746     }
1747   return 0;
1748 }
1749
1750 /*!
1751  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 7.
1752  */
1753 int MEDCouplingUMesh::AreCellsEqualPolicy7(const int *conn, const int *connI, int cell1, int cell2)
1754 {
1755   int sz=connI[cell1+1]-connI[cell1];
1756   if(sz==connI[cell2+1]-connI[cell2])
1757     {
1758       if(conn[connI[cell1]]==conn[connI[cell2]])
1759         {
1760           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1761           unsigned dim=cm.getDimension();
1762           if(dim!=3)
1763             {
1764               if(dim!=1)
1765                 {
1766                   int sz1=2*(sz-1);
1767                   INTERP_KERNEL::AutoPtr<int> tmp=new int[sz1];
1768                   int *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(int *)tmp);
1769                   std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1770                   work=std::search((int *)tmp,(int *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1771                   if(work!=tmp+sz1)
1772                     return 1;
1773                   else
1774                     {
1775                       std::reverse_iterator<int *> it1((int *)tmp+sz1);
1776                       std::reverse_iterator<int *> it2((int *)tmp);
1777                       if(std::search(it1,it2,conn+connI[cell2]+1,conn+connI[cell2+1])!=it2)
1778                         return 2;
1779                       else
1780                         return 0;
1781                     }
1782
1783                   return work!=tmp+sz1?1:0;
1784                 }
1785               else
1786                 {//case of SEG2 and SEG3
1787                   if(std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1))
1788                     return 1;
1789                   if(!cm.isQuadratic())
1790                     {
1791                       std::reverse_iterator<const int *> it1(conn+connI[cell1+1]);
1792                       std::reverse_iterator<const int *> it2(conn+connI[cell1]+1);
1793                       if(std::equal(it1,it2,conn+connI[cell2]+1))
1794                         return 2;
1795                       return 0;
1796                     }
1797                   else
1798                     {
1799                       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])
1800                         return 2;
1801                       return 0;
1802                     }
1803                 }
1804             }
1805           else
1806             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy7 : not implemented yet for meshdim == 3 !");
1807         }
1808     }
1809   return 0;
1810 }
1811
1812 /*!
1813  * This method find in candidate pool defined by 'candidates' the cells equal following the polycy 'compType'.
1814  * If any true is returned and the results will be put at the end of 'result' output parameter. If not false is returned
1815  * and result remains unchanged.
1816  * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1817  * If in 'candidates' pool -1 value is considered as an empty value.
1818  * WARNING this method returns only ONE set of result !
1819  */
1820 bool MEDCouplingUMesh::AreCellsEqualInPool(const std::vector<int>& candidates, int compType, const int *conn, const int *connI, DataArrayInt *result)
1821 {
1822   if(candidates.size()<1)
1823     return false;
1824   bool ret=false;
1825   std::vector<int>::const_iterator iter=candidates.begin();
1826   int start=(*iter++);
1827   for(;iter!=candidates.end();iter++)
1828     {
1829       int status=AreCellsEqual(conn,connI,start,*iter,compType);
1830       if(status!=0)
1831         {
1832           if(!ret)
1833             {
1834               result->pushBackSilent(start);
1835               ret=true;
1836             }
1837           if(status==1)
1838             result->pushBackSilent(*iter);
1839           else
1840             result->pushBackSilent(status==2?(*iter+1):-(*iter+1));
1841         }
1842     }
1843   return ret;
1844 }
1845
1846 /*!
1847  * This method find cells that are equal (regarding \a compType) in \a this. The comparison is specified
1848  * by \a compType.
1849  * This method keeps the coordiantes of \a this. This method is time consuming.
1850  *
1851  * \param [in] compType input specifying the technique used to compare cells each other.
1852  *   - 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.
1853  *   - 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)
1854  * and their type equal. For 1D mesh the policy 1 is equivalent to 0.
1855  *   - 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
1856  * can be used for users not sensitive to orientation of cell
1857  * \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.
1858  * \param [out] commonCellsArr common cells ids (\ref numbering-indirect)
1859  * \param [out] commonCellsIArr common cells ids (\ref numbering-indirect)
1860  * \return the correspondance array old to new in a newly allocated array.
1861  * 
1862  */
1863 void MEDCouplingUMesh::findCommonCells(int compType, int startCellId, DataArrayInt *& commonCellsArr, DataArrayInt *& commonCellsIArr) const
1864 {
1865   MCAuto<DataArrayInt> revNodal=DataArrayInt::New(),revNodalI=DataArrayInt::New();
1866   getReverseNodalConnectivity(revNodal,revNodalI);
1867   FindCommonCellsAlg(compType,startCellId,_nodal_connec,_nodal_connec_index,revNodal,revNodalI,commonCellsArr,commonCellsIArr);
1868 }
1869
1870 void MEDCouplingUMesh::FindCommonCellsAlg(int compType, int startCellId, const DataArrayInt *nodal, const DataArrayInt *nodalI, const DataArrayInt *revNodal, const DataArrayInt *revNodalI,
1871                                           DataArrayInt *& commonCellsArr, DataArrayInt *& commonCellsIArr)
1872 {
1873   MCAuto<DataArrayInt> commonCells=DataArrayInt::New(),commonCellsI=DataArrayInt::New(); commonCells->alloc(0,1);
1874   int nbOfCells=nodalI->getNumberOfTuples()-1;
1875   commonCellsI->reserve(1); commonCellsI->pushBackSilent(0);
1876   const int *revNodalPtr=revNodal->getConstPointer(),*revNodalIPtr=revNodalI->getConstPointer();
1877   const int *connPtr=nodal->getConstPointer(),*connIPtr=nodalI->getConstPointer();
1878   std::vector<bool> isFetched(nbOfCells,false);
1879   if(startCellId==0)
1880     {
1881       for(int i=0;i<nbOfCells;i++)
1882         {
1883           if(!isFetched[i])
1884             {
1885               const int *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind2nd(std::not_equal_to<int>(),-1));
1886               std::vector<int> v,v2;
1887               if(connOfNode!=connPtr+connIPtr[i+1])
1888                 {
1889                   const int *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1890                   v2.insert(v2.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1]);
1891                   connOfNode++;
1892                 }
1893               for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1894                 if(*connOfNode>=0)
1895                   {
1896                     v=v2;
1897                     const int *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1898                     std::vector<int>::iterator it=std::set_intersection(v.begin(),v.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1899                     v2.resize(std::distance(v2.begin(),it));
1900                   }
1901               if(v2.size()>1)
1902                 {
1903                   if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1904                     {
1905                       int pos=commonCellsI->back();
1906                       commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1907                       for(const int *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1908                         isFetched[*it]=true;
1909                     }
1910                 }
1911             }
1912         }
1913     }
1914   else
1915     {
1916       for(int i=startCellId;i<nbOfCells;i++)
1917         {
1918           if(!isFetched[i])
1919             {
1920               const int *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind2nd(std::not_equal_to<int>(),-1));
1921               std::vector<int> v,v2;
1922               if(connOfNode!=connPtr+connIPtr[i+1])
1923                 {
1924                   v2.insert(v2.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1]);
1925                   connOfNode++;
1926                 }
1927               for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1928                 if(*connOfNode>=0)
1929                   {
1930                     v=v2;
1931                     std::vector<int>::iterator it=std::set_intersection(v.begin(),v.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1932                     v2.resize(std::distance(v2.begin(),it));
1933                   }
1934               if(v2.size()>1)
1935                 {
1936                   if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1937                     {
1938                       int pos=commonCellsI->back();
1939                       commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1940                       for(const int *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1941                         isFetched[*it]=true;
1942                     }
1943                 }
1944             }
1945         }
1946     }
1947   commonCellsArr=commonCells.retn();
1948   commonCellsIArr=commonCellsI.retn();
1949 }
1950
1951 /*!
1952  * Checks if \a this mesh includes all cells of an \a other mesh, and returns an array
1953  * giving for each cell of the \a other an id of a cell in \a this mesh. A value larger
1954  * than \a this->getNumberOfCells() in the returned array means that there is no
1955  * corresponding cell in \a this mesh.
1956  * It is expected that \a this and \a other meshes share the same node coordinates
1957  * array, if it is not so an exception is thrown. 
1958  *  \param [in] other - the mesh to compare with.
1959  *  \param [in] compType - specifies a cell comparison technique. For meaning of its
1960  *         valid values [0,1,2], see zipConnectivityTraducer().
1961  *  \param [out] arr - a new instance of DataArrayInt returning correspondence
1962  *         between cells of the two meshes. It contains \a other->getNumberOfCells()
1963  *         values. The caller is to delete this array using
1964  *         decrRef() as it is no more needed.
1965  *  \return bool - \c true if all cells of \a other mesh are present in the \a this
1966  *         mesh.
1967  *
1968  *  \if ENABLE_EXAMPLES
1969  *  \ref cpp_mcumesh_areCellsIncludedIn "Here is a C++ example".<br>
1970  *  \ref  py_mcumesh_areCellsIncludedIn "Here is a Python example".
1971  *  \endif
1972  *  \sa checkDeepEquivalOnSameNodesWith()
1973  *  \sa checkGeoEquivalWith()
1974  */
1975 bool MEDCouplingUMesh::areCellsIncludedIn(const MEDCouplingUMesh *other, int compType, DataArrayInt *& arr) const
1976 {
1977   MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1978   int nbOfCells=getNumberOfCells();
1979   static const int possibleCompType[]={0,1,2};
1980   if(std::find(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),compType)==possibleCompType+sizeof(possibleCompType)/sizeof(int))
1981     {
1982       std::ostringstream oss; oss << "MEDCouplingUMesh::areCellsIncludedIn : only following policies are possible : ";
1983       std::copy(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),std::ostream_iterator<int>(oss," "));
1984       oss << " !";
1985       throw INTERP_KERNEL::Exception(oss.str());
1986     }
1987   MCAuto<DataArrayInt> o2n=mesh->zipConnectivityTraducer(compType,nbOfCells);
1988   arr=o2n->subArray(nbOfCells);
1989   arr->setName(other->getName());
1990   int tmp;
1991   if(other->getNumberOfCells()==0)
1992     return true;
1993   return arr->getMaxValue(tmp)<nbOfCells;
1994 }
1995
1996 /*!
1997  * This method makes the assumption that \a this and \a other share the same coords. If not an exception will be thrown !
1998  * This method tries to determine if \b other is fully included in \b this.
1999  * The main difference is that this method is not expected to throw exception.
2000  * This method has two outputs :
2001  *
2002  * \param other other mesh
2003  * \param arr is an output parameter that returns a \b newly created instance. This array is of size 'other->getNumberOfCells()'.
2004  * \return If \a other is fully included in 'this 'true is returned. If not false is returned.
2005  */
2006 bool MEDCouplingUMesh::areCellsIncludedInPolicy7(const MEDCouplingUMesh *other, DataArrayInt *& arr) const
2007 {
2008   MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
2009   DataArrayInt *commonCells=0,*commonCellsI=0;
2010   int thisNbCells=getNumberOfCells();
2011   mesh->findCommonCells(7,thisNbCells,commonCells,commonCellsI);
2012   MCAuto<DataArrayInt> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
2013   const int *commonCellsPtr=commonCells->getConstPointer(),*commonCellsIPtr=commonCellsI->getConstPointer();
2014   int otherNbCells=other->getNumberOfCells();
2015   MCAuto<DataArrayInt> arr2=DataArrayInt::New();
2016   arr2->alloc(otherNbCells,1);
2017   arr2->fillWithZero();
2018   int *arr2Ptr=arr2->getPointer();
2019   int nbOfCommon=commonCellsI->getNumberOfTuples()-1;
2020   for(int i=0;i<nbOfCommon;i++)
2021     {
2022       int start=commonCellsPtr[commonCellsIPtr[i]];
2023       if(start<thisNbCells)
2024         {
2025           for(int j=commonCellsIPtr[i]+1;j!=commonCellsIPtr[i+1];j++)
2026             {
2027               int sig=commonCellsPtr[j]>0?1:-1;
2028               int val=std::abs(commonCellsPtr[j])-1;
2029               if(val>=thisNbCells)
2030                 arr2Ptr[val-thisNbCells]=sig*(start+1);
2031             }
2032         }
2033     }
2034   arr2->setName(other->getName());
2035   if(arr2->presenceOfValue(0))
2036     return false;
2037   arr=arr2.retn();
2038   return true;
2039 }
2040
2041 MEDCouplingUMesh *MEDCouplingUMesh::mergeMyselfWithOnSameCoords(const MEDCouplingPointSet *other) const
2042 {
2043   if(!other)
2044     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : input other is null !");
2045   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
2046   if(!otherC)
2047     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : the input other mesh is not of type unstructured !");
2048   std::vector<const MEDCouplingUMesh *> ms(2);
2049   ms[0]=this;
2050   ms[1]=otherC;
2051   return MergeUMeshesOnSameCoords(ms);
2052 }
2053
2054 /*!
2055  * Build a sub part of \b this lying or not on the same coordinates than \b this (regarding value of \b keepCoords).
2056  * By default coordinates are kept. This method is close to MEDCouplingUMesh::buildPartOfMySelf except that here input
2057  * cellIds is not given explicitely but by a range python like.
2058  * 
2059  * \param start
2060  * \param end
2061  * \param step
2062  * \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.
2063  * \return a newly allocated
2064  * 
2065  * \warning This method modifies can generate an unstructured mesh whose cells are not sorted by geometric type order.
2066  * In view of the MED file writing, a renumbering of cells of returned unstructured mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
2067  */
2068 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfSlice(int start, int end, int step, bool keepCoords) const
2069 {
2070   if(getMeshDimension()!=-1)
2071     return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelfSlice(start,end,step,keepCoords));
2072   else
2073     {
2074       int newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfSlice for -1 dimension mesh ");
2075       if(newNbOfCells!=1)
2076         throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
2077       if(start!=0)
2078         throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
2079       incrRef();
2080       return const_cast<MEDCouplingUMesh *>(this);
2081     }
2082 }
2083
2084 /*!
2085  * Creates a new MEDCouplingUMesh containing specified cells of \a this mesh.
2086  * The result mesh shares or not the node coordinates array with \a this mesh depending
2087  * on \a keepCoords parameter.
2088  *  \warning Cells of the result mesh can be \b not sorted by geometric type, hence,
2089  *           to write this mesh to the MED file, its cells must be sorted using
2090  *           sortCellsInMEDFileFrmt().
2091  *  \param [in] begin - an array of cell ids to include to the new mesh.
2092  *  \param [in] end - a pointer to last-plus-one-th element of \a begin.
2093  *  \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2094  *         array of \a this mesh, else "free" nodes are removed from the result mesh
2095  *         by calling zipCoords().
2096  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2097  *         to delete this mesh using decrRef() as it is no more needed. 
2098  *  \throw If the coordinates array is not set.
2099  *  \throw If the nodal connectivity of cells is not defined.
2100  *  \throw If any cell id in the array \a begin is not valid.
2101  *
2102  *  \if ENABLE_EXAMPLES
2103  *  \ref cpp_mcumesh_buildPartOfMySelf "Here is a C++ example".<br>
2104  *  \ref  py_mcumesh_buildPartOfMySelf "Here is a Python example".
2105  *  \endif
2106  */
2107 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelf(const int *begin, const int *end, bool keepCoords) const
2108 {
2109   if(getMeshDimension()!=-1)
2110     return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelf(begin,end,keepCoords));
2111   else
2112     {
2113       if(end-begin!=1)
2114         throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
2115       if(begin[0]!=0)
2116         throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
2117       incrRef();
2118       return const_cast<MEDCouplingUMesh *>(this);
2119     }
2120 }
2121
2122 /*!
2123  * This method operates only on nodal connectivity on \b this. Coordinates of \b this is completely ignored here.
2124  *
2125  * 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.
2126  * Size of [ \b cellIdsBg, \b cellIdsEnd ) ) must be equal to the number of cells of otherOnSameCoordsThanThis.
2127  * The number of cells of \b this will remain the same with this method.
2128  *
2129  * \param [in] cellIdsBg begin of cell ids (included) of cells in this to assign
2130  * \param [in] cellIdsEnd end of cell ids (excluded) of cells in this to assign
2131  * \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 ).
2132  *             Coordinate pointer of \b this and those of \b otherOnSameCoordsThanThis must be the same
2133  */
2134 void MEDCouplingUMesh::setPartOfMySelf(const int *cellIdsBg, const int *cellIdsEnd, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2135 {
2136   checkConnectivityFullyDefined();
2137   otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2138   if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2139     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelf : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2140   if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2141     {
2142       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2143       oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2144       throw INTERP_KERNEL::Exception(oss.str());
2145     }
2146   int nbOfCellsToModify=(int)std::distance(cellIdsBg,cellIdsEnd);
2147   if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2148     {
2149       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : cells ids length (" <<  nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2150       throw INTERP_KERNEL::Exception(oss.str());
2151     }
2152   int nbOfCells=getNumberOfCells();
2153   bool easyAssign=true;
2154   const int *connI=_nodal_connec_index->getConstPointer();
2155   const int *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2156   for(const int *it=cellIdsBg;it!=cellIdsEnd && easyAssign;it++,connIOther++)
2157     {
2158       if(*it>=0 && *it<nbOfCells)
2159         {
2160           easyAssign=(connIOther[1]-connIOther[0])==(connI[*it+1]-connI[*it]);
2161         }
2162       else
2163         {
2164           std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : On pos #" << std::distance(cellIdsBg,it) << " id is equal to " << *it << " which is not in [0," << nbOfCells << ") !";
2165           throw INTERP_KERNEL::Exception(oss.str());
2166         }
2167     }
2168   if(easyAssign)
2169     {
2170       MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2171       computeTypes();
2172     }
2173   else
2174     {
2175       DataArrayInt *arrOut=0,*arrIOut=0;
2176       MEDCouplingUMesh::SetPartOfIndexedArrays(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2177                                                arrOut,arrIOut);
2178       MCAuto<DataArrayInt> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2179       setConnectivity(arrOut,arrIOut,true);
2180     }
2181 }
2182
2183 void MEDCouplingUMesh::setPartOfMySelfSlice(int start, int end, int step, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2184 {
2185   checkConnectivityFullyDefined();
2186   otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2187   if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2188     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelfSlice : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2189   if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2190     {
2191       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2192       oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2193       throw INTERP_KERNEL::Exception(oss.str());
2194     }
2195   int nbOfCellsToModify=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::setPartOfMySelfSlice : ");
2196   if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2197     {
2198       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : cells ids length (" <<  nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2199       throw INTERP_KERNEL::Exception(oss.str());
2200     }
2201   int nbOfCells=getNumberOfCells();
2202   bool easyAssign=true;
2203   const int *connI=_nodal_connec_index->getConstPointer();
2204   const int *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2205   int it=start;
2206   for(int i=0;i<nbOfCellsToModify && easyAssign;i++,it+=step,connIOther++)
2207     {
2208       if(it>=0 && it<nbOfCells)
2209         {
2210           easyAssign=(connIOther[1]-connIOther[0])==(connI[it+1]-connI[it]);
2211         }
2212       else
2213         {
2214           std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : On pos #" << i << " id is equal to " << it << " which is not in [0," << nbOfCells << ") !";
2215           throw INTERP_KERNEL::Exception(oss.str());
2216         }
2217     }
2218   if(easyAssign)
2219     {
2220       MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2221       computeTypes();
2222     }
2223   else
2224     {
2225       DataArrayInt *arrOut=0,*arrIOut=0;
2226       MEDCouplingUMesh::SetPartOfIndexedArraysSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2227                                                 arrOut,arrIOut);
2228       MCAuto<DataArrayInt> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2229       setConnectivity(arrOut,arrIOut,true);
2230     }
2231 }                      
2232
2233 /*!
2234  * Keeps from \a this only cells which constituing point id are in the ids specified by [ \a begin,\a end ).
2235  * The resulting cell ids are stored at the end of the 'cellIdsKept' parameter.
2236  * Parameter \a fullyIn specifies if a cell that has part of its nodes in ids array is kept or not.
2237  * If \a fullyIn is true only cells whose ids are \b fully contained in [ \a begin,\a end ) tab will be kept.
2238  *
2239  * \param [in] begin input start of array of node ids.
2240  * \param [in] end input end of array of node ids.
2241  * \param [in] fullyIn input that specifies if all node ids must be in [ \a begin,\a end ) array to consider cell to be in.
2242  * \param [in,out] cellIdsKeptArr array where all candidate cell ids are put at the end.
2243  */
2244 void MEDCouplingUMesh::fillCellIdsToKeepFromNodeIds(const int *begin, const int *end, bool fullyIn, DataArrayInt *&cellIdsKeptArr) const
2245 {
2246   MCAuto<DataArrayInt> cellIdsKept=DataArrayInt::New(); cellIdsKept->alloc(0,1);
2247   checkConnectivityFullyDefined();
2248   int tmp=-1;
2249   int sz=getNodalConnectivity()->getMaxValue(tmp); sz=std::max(sz,0)+1;
2250   std::vector<bool> fastFinder(sz,false);
2251   for(const int *work=begin;work!=end;work++)
2252     if(*work>=0 && *work<sz)
2253       fastFinder[*work]=true;
2254   int nbOfCells=getNumberOfCells();
2255   const int *conn=getNodalConnectivity()->getConstPointer();
2256   const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2257   for(int i=0;i<nbOfCells;i++)
2258     {
2259       int ref=0,nbOfHit=0;
2260       for(const int *work2=conn+connIndex[i]+1;work2!=conn+connIndex[i+1];work2++)
2261         if(*work2>=0)
2262           {
2263             ref++;
2264             if(fastFinder[*work2])
2265               nbOfHit++;
2266           }
2267       if((ref==nbOfHit && fullyIn) || (nbOfHit!=0 && !fullyIn))
2268         cellIdsKept->pushBackSilent(i);
2269     }
2270   cellIdsKeptArr=cellIdsKept.retn();
2271 }
2272
2273 /*!
2274  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2275  * this->getMeshDimension(), that bound some cells of \a this mesh.
2276  * The cells of lower dimension to include to the result mesh are selected basing on
2277  * specified node ids and the value of \a fullyIn parameter. If \a fullyIn ==\c true, a
2278  * cell is copied if its all nodes are in the array \a begin of node ids. If \a fullyIn
2279  * ==\c false, a cell is copied if any its node is in the array of node ids. The
2280  * created mesh shares the node coordinates array with \a this mesh. 
2281  *  \param [in] begin - the array of node ids.
2282  *  \param [in] end - a pointer to the (last+1)-th element of \a begin.
2283  *  \param [in] fullyIn - if \c true, then cells whose all nodes are in the
2284  *         array \a begin are added, else cells whose any node is in the
2285  *         array \a begin are added.
2286  *  \return MEDCouplingUMesh * - new instance of MEDCouplingUMesh. The caller is
2287  *         to delete this mesh using decrRef() as it is no more needed. 
2288  *  \throw If the coordinates array is not set.
2289  *  \throw If the nodal connectivity of cells is not defined.
2290  *  \throw If any node id in \a begin is not valid.
2291  *
2292  *  \if ENABLE_EXAMPLES
2293  *  \ref cpp_mcumesh_buildFacePartOfMySelfNode "Here is a C++ example".<br>
2294  *  \ref  py_mcumesh_buildFacePartOfMySelfNode "Here is a Python example".
2295  *  \endif
2296  */
2297 MEDCouplingUMesh *MEDCouplingUMesh::buildFacePartOfMySelfNode(const int *begin, const int *end, bool fullyIn) const
2298 {
2299   MCAuto<DataArrayInt> desc,descIndx,revDesc,revDescIndx;
2300   desc=DataArrayInt::New(); descIndx=DataArrayInt::New(); revDesc=DataArrayInt::New(); revDescIndx=DataArrayInt::New();
2301   MCAuto<MEDCouplingUMesh> subMesh=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2302   desc=0; descIndx=0; revDesc=0; revDescIndx=0;
2303   return static_cast<MEDCouplingUMesh*>(subMesh->buildPartOfMySelfNode(begin,end,fullyIn));
2304 }
2305
2306 /*!
2307  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2308  * this->getMeshDimension(), which bound only one cell of \a this mesh.
2309  *  \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2310  *         array of \a this mesh, else "free" nodes are removed from the result mesh
2311  *         by calling zipCoords().
2312  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2313  *         to delete this mesh using decrRef() as it is no more needed. 
2314  *  \throw If the coordinates array is not set.
2315  *  \throw If the nodal connectivity of cells is not defined.
2316  *
2317  *  \if ENABLE_EXAMPLES
2318  *  \ref cpp_mcumesh_buildBoundaryMesh "Here is a C++ example".<br>
2319  *  \ref  py_mcumesh_buildBoundaryMesh "Here is a Python example".
2320  *  \endif
2321  */
2322 MEDCouplingUMesh *MEDCouplingUMesh::buildBoundaryMesh(bool keepCoords) const
2323 {
2324   DataArrayInt *desc=DataArrayInt::New();
2325   DataArrayInt *descIndx=DataArrayInt::New();
2326   DataArrayInt *revDesc=DataArrayInt::New();
2327   DataArrayInt *revDescIndx=DataArrayInt::New();
2328   //
2329   MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2330   revDesc->decrRef();
2331   desc->decrRef();
2332   descIndx->decrRef();
2333   int nbOfCells=meshDM1->getNumberOfCells();
2334   const int *revDescIndxC=revDescIndx->getConstPointer();
2335   std::vector<int> boundaryCells;
2336   for(int i=0;i<nbOfCells;i++)
2337     if(revDescIndxC[i+1]-revDescIndxC[i]==1)
2338       boundaryCells.push_back(i);
2339   revDescIndx->decrRef();
2340   MEDCouplingUMesh *ret=meshDM1->buildPartOfMySelf(&boundaryCells[0],&boundaryCells[0]+boundaryCells.size(),keepCoords);
2341   return ret;
2342 }
2343
2344 /*!
2345  * This method returns a newly created DataArrayInt instance containing ids of cells located in boundary.
2346  * A cell is detected to be on boundary if it contains one or more than one face having only one father.
2347  * This method makes the assumption that \a this is fully defined (coords,connectivity). If not an exception will be thrown. 
2348  */
2349 DataArrayInt *MEDCouplingUMesh::findCellIdsOnBoundary() const
2350 {
2351   checkFullyDefined();
2352   MCAuto<DataArrayInt> desc=DataArrayInt::New();
2353   MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
2354   MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
2355   MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
2356   //
2357   buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx)->decrRef();
2358   desc=(DataArrayInt*)0; descIndx=(DataArrayInt*)0;
2359   //
2360   MCAuto<DataArrayInt> tmp=revDescIndx->deltaShiftIndex();
2361   MCAuto<DataArrayInt> faceIds=tmp->findIdsEqual(1); tmp=(DataArrayInt*)0;
2362   const int *revDescPtr=revDesc->getConstPointer();
2363   const int *revDescIndxPtr=revDescIndx->getConstPointer();
2364   int nbOfCells=getNumberOfCells();
2365   std::vector<bool> ret1(nbOfCells,false);
2366   int sz=0;
2367   for(const int *pt=faceIds->begin();pt!=faceIds->end();pt++)
2368     if(!ret1[revDescPtr[revDescIndxPtr[*pt]]])
2369       { ret1[revDescPtr[revDescIndxPtr[*pt]]]=true; sz++; }
2370   //
2371   DataArrayInt *ret2=DataArrayInt::New();
2372   ret2->alloc(sz,1);
2373   int *ret2Ptr=ret2->getPointer();
2374   sz=0;
2375   for(std::vector<bool>::const_iterator it=ret1.begin();it!=ret1.end();it++,sz++)
2376     if(*it)
2377       *ret2Ptr++=sz;
2378   ret2->setName("BoundaryCells");
2379   return ret2;
2380 }
2381
2382 /*!
2383  * This method finds in \b this the cell ids that lie on mesh \b otherDimM1OnSameCoords.
2384  * \b this and \b otherDimM1OnSameCoords have to lie on the same coordinate array pointer. The coherency of that coords array with connectivity
2385  * of \b this and \b otherDimM1OnSameCoords is not important here because this method works only on connectivity.
2386  * this->getMeshDimension() - 1 must be equal to otherDimM1OnSameCoords.getMeshDimension()
2387  *
2388  * s0 is the cell ids set in \b this lying on at least one node in the fetched nodes in \b otherDimM1OnSameCoords.
2389  * 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
2390  * equals a cell in \b otherDimM1OnSameCoords.
2391  *
2392  * \throw if \b otherDimM1OnSameCoords is not part of constituent of \b this, or if coordinate pointer of \b this and \b otherDimM1OnSameCoords
2393  *        are not same, or if this->getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension()
2394  *
2395  * \param [in] otherDimM1OnSameCoords
2396  * \param [out] cellIdsRk0 a newly allocated array containing the cell ids of s0 (which are cell ids of \b this) in the above algorithm.
2397  * \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
2398  *              cellIdsRk1->transformWithIndArr(cellIdsRk0->begin(),cellIdsRk0->end());
2399  */
2400 void MEDCouplingUMesh::findCellIdsLyingOn(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayInt *&cellIdsRk0, DataArrayInt *&cellIdsRk1) const
2401 {
2402   if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2403     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : coordinates pointer are not the same ! Use tryToShareSameCoords method !");
2404   checkConnectivityFullyDefined();
2405   otherDimM1OnSameCoords.checkConnectivityFullyDefined();
2406   if(getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension())
2407     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : invalid mesh dimension of input mesh regarding meshdimesion of this !");
2408   MCAuto<DataArrayInt> fetchedNodeIds1=otherDimM1OnSameCoords.computeFetchedNodeIds();
2409   MCAuto<DataArrayInt> s0arr=getCellIdsLyingOnNodes(fetchedNodeIds1->begin(),fetchedNodeIds1->end(),false);
2410   MCAuto<MEDCouplingUMesh> thisPart=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(s0arr->begin(),s0arr->end(),true));
2411   MCAuto<DataArrayInt> descThisPart=DataArrayInt::New(),descIThisPart=DataArrayInt::New(),revDescThisPart=DataArrayInt::New(),revDescIThisPart=DataArrayInt::New();
2412   MCAuto<MEDCouplingUMesh> thisPartConsti=thisPart->buildDescendingConnectivity(descThisPart,descIThisPart,revDescThisPart,revDescIThisPart);
2413   const int *revDescThisPartPtr=revDescThisPart->getConstPointer(),*revDescIThisPartPtr=revDescIThisPart->getConstPointer();
2414   DataArrayInt *idsOtherInConsti=0;
2415   bool b=thisPartConsti->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsOtherInConsti);
2416   MCAuto<DataArrayInt> idsOtherInConstiAuto(idsOtherInConsti);
2417   if(!b)
2418     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : the given mdim-1 mesh in other is not a constituent of this !");
2419   std::set<int> s1;
2420   for(const int *idOther=idsOtherInConsti->begin();idOther!=idsOtherInConsti->end();idOther++)
2421     s1.insert(revDescThisPartPtr+revDescIThisPartPtr[*idOther],revDescThisPartPtr+revDescIThisPartPtr[*idOther+1]);
2422   MCAuto<DataArrayInt> s1arr_renum1=DataArrayInt::New(); s1arr_renum1->alloc((int)s1.size(),1); std::copy(s1.begin(),s1.end(),s1arr_renum1->getPointer());
2423   s1arr_renum1->sort();
2424   cellIdsRk0=s0arr.retn();
2425   //cellIdsRk1=s_renum1.retn();
2426   cellIdsRk1=s1arr_renum1.retn();
2427 }
2428
2429 /*!
2430  * 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
2431  * returned. This subpart of meshdim-1 mesh is built using meshdim-1 cells in it shared only one cell in \b this.
2432  * 
2433  * \return a newly allocated mesh lying on the same coordinates than \b this. The caller has to deal with returned mesh.
2434  */
2435 MEDCouplingUMesh *MEDCouplingUMesh::computeSkin() const
2436 {
2437   MCAuto<DataArrayInt> desc=DataArrayInt::New();
2438   MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
2439   MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
2440   MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
2441   //
2442   MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2443   revDesc=0; desc=0; descIndx=0;
2444   MCAuto<DataArrayInt> revDescIndx2=revDescIndx->deltaShiftIndex();
2445   MCAuto<DataArrayInt> part=revDescIndx2->findIdsEqual(1);
2446   return static_cast<MEDCouplingUMesh *>(meshDM1->buildPartOfMySelf(part->begin(),part->end(),true));
2447 }
2448
2449 /*!
2450  * Finds nodes lying on the boundary of \a this mesh.
2451  *  \return DataArrayInt * - a new instance of DataArrayInt holding ids of found
2452  *          nodes. The caller is to delete this array using decrRef() as it is no
2453  *          more needed.
2454  *  \throw If the coordinates array is not set.
2455  *  \throw If the nodal connectivity of cells is node defined.
2456  *
2457  *  \if ENABLE_EXAMPLES
2458  *  \ref cpp_mcumesh_findBoundaryNodes "Here is a C++ example".<br>
2459  *  \ref  py_mcumesh_findBoundaryNodes "Here is a Python example".
2460  *  \endif
2461  */
2462 DataArrayInt *MEDCouplingUMesh::findBoundaryNodes() const
2463 {
2464   MCAuto<MEDCouplingUMesh> skin=computeSkin();
2465   return skin->computeFetchedNodeIds();
2466 }
2467
2468 MEDCouplingUMesh *MEDCouplingUMesh::buildUnstructured() const
2469 {
2470   incrRef();
2471   return const_cast<MEDCouplingUMesh *>(this);
2472 }
2473
2474 /*!
2475  * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2476  * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2477  * 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.
2478  * 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.
2479  * 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.
2480  *
2481  * \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
2482  *             parameter is altered during the call.
2483  * \param [out] nodeIdsToDuplicate node ids needed to be duplicated following the algorithm explain above.
2484  * \param [out] cellIdsNeededToBeRenum cell ids in \b this in which the renumber of nodes should be performed.
2485  * \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.
2486  *
2487  * \warning This method modifies param \b otherDimM1OnSameCoords (for speed reasons).
2488  */
2489 void MEDCouplingUMesh::findNodesToDuplicate(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayInt *& nodeIdsToDuplicate,
2490                                             DataArrayInt *& cellIdsNeededToBeRenum, DataArrayInt *& cellIdsNotModified) const
2491 {
2492   typedef MCAuto<DataArrayInt> DAInt;
2493   typedef MCAuto<MEDCouplingUMesh> MCUMesh;
2494
2495   checkFullyDefined();
2496   otherDimM1OnSameCoords.checkFullyDefined();
2497   if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2498     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : meshes do not share the same coords array !");
2499   if(otherDimM1OnSameCoords.getMeshDimension()!=getMeshDimension()-1)
2500     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the mesh given in other parameter must have this->getMeshDimension()-1 !");
2501
2502   // Checking star-shaped M1 group:
2503   DAInt dt0=DataArrayInt::New(),dit0=DataArrayInt::New(),rdt0=DataArrayInt::New(),rdit0=DataArrayInt::New();
2504   MCUMesh meshM2 = otherDimM1OnSameCoords.buildDescendingConnectivity(dt0, dit0, rdt0, rdit0);
2505   DAInt dsi = rdit0->deltaShiftIndex();
2506   DAInt idsTmp0 = dsi->findIdsNotInRange(-1, 3);
2507   if(idsTmp0->getNumberOfTuples())
2508     throw INTERP_KERNEL::Exception("MEDFileUMesh::buildInnerBoundaryAlongM1Group: group is too complex: some points (or edges) have more than two connected segments (or faces)!");
2509   dt0=0; dit0=0; rdt0=0; rdit0=0; idsTmp0=0;
2510
2511   // Get extreme nodes from the group (they won't be duplicated), ie nodes belonging to boundary cells of M1
2512   DAInt xtremIdsM2 = dsi->findIdsEqual(1); dsi = 0;
2513   MCUMesh meshM2Part = static_cast<MEDCouplingUMesh *>(meshM2->buildPartOfMySelf(xtremIdsM2->begin(), xtremIdsM2->end(),true));
2514   DAInt xtrem = meshM2Part->computeFetchedNodeIds();
2515   // Remove from the list points on the boundary of the M0 mesh (those need duplication!)
2516   dt0=DataArrayInt::New(),dit0=DataArrayInt::New(),rdt0=DataArrayInt::New(),rdit0=DataArrayInt::New();
2517   MCUMesh m0desc = buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); dt0=0; dit0=0; rdt0=0;
2518   dsi = rdit0->deltaShiftIndex();
2519   DAInt boundSegs = dsi->findIdsEqual(1);   // boundary segs/faces of the M0 mesh
2520   MCUMesh m0descSkin = static_cast<MEDCouplingUMesh *>(m0desc->buildPartOfMySelf(boundSegs->begin(),boundSegs->end(), true));
2521   DAInt fNodes = m0descSkin->computeFetchedNodeIds();
2522   // In 3D, some points on the boundary of M0 still need duplication:
2523   DAInt notDup = 0;
2524   if (getMeshDimension() == 3)
2525     {
2526       DAInt dnu1=DataArrayInt::New(), dnu2=DataArrayInt::New(), dnu3=DataArrayInt::New(), dnu4=DataArrayInt::New();
2527       MCUMesh m0descSkinDesc = m0descSkin->buildDescendingConnectivity(dnu1, dnu2, dnu3, dnu4);
2528       dnu1=0;dnu2=0;dnu3=0;dnu4=0;
2529       DataArrayInt * corresp=0;
2530       meshM2->areCellsIncludedIn(m0descSkinDesc,2,corresp);
2531       DAInt validIds = corresp->findIdsInRange(0, meshM2->getNumberOfCells());
2532       corresp->decrRef();
2533       if (validIds->getNumberOfTuples())
2534         {
2535           MCUMesh m1IntersecSkin = static_cast<MEDCouplingUMesh *>(m0descSkinDesc->buildPartOfMySelf(validIds->begin(), validIds->end(), true));
2536           DAInt notDuplSkin = m1IntersecSkin->findBoundaryNodes();
2537           DAInt fNodes1 = fNodes->buildSubstraction(notDuplSkin);
2538           notDup = xtrem->buildSubstraction(fNodes1);
2539         }
2540       else
2541         notDup = xtrem->buildSubstraction(fNodes);
2542     }
2543   else
2544     notDup = xtrem->buildSubstraction(fNodes);
2545
2546   // Now compute cells around group (i.e. cells where we will do the propagation to identify the two sub-sets delimited by the group)
2547   DAInt m1Nodes = otherDimM1OnSameCoords.computeFetchedNodeIds();
2548   DAInt dupl = m1Nodes->buildSubstraction(notDup);
2549   DAInt cellsAroundGroup = getCellIdsLyingOnNodes(dupl->begin(), dupl->end(), false);  // false= take cell in, even if not all nodes are in notDup
2550
2551   //
2552   MCUMesh m0Part2=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(cellsAroundGroup->begin(),cellsAroundGroup->end(),true));
2553   int nCells2 = m0Part2->getNumberOfCells();
2554   DAInt desc00=DataArrayInt::New(),descI00=DataArrayInt::New(),revDesc00=DataArrayInt::New(),revDescI00=DataArrayInt::New();
2555   MCUMesh m01=m0Part2->buildDescendingConnectivity(desc00,descI00,revDesc00,revDescI00);
2556
2557   // Neighbor information of the mesh without considering the crack (serves to count how many connex pieces it is made of)
2558   DataArrayInt *tmp00=0,*tmp11=0;
2559   MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00, tmp00, tmp11);
2560   DAInt neighInit00(tmp00);
2561   DAInt neighIInit00(tmp11);
2562   // Neighbor information of the mesh WITH the crack (some neighbors are removed):
2563   DataArrayInt *idsTmp=0;
2564   bool b=m01->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsTmp);
2565   DAInt ids(idsTmp);
2566   // In the neighbor information remove the connection between high dimension cells and its low level constituents which are part
2567   // of the frontier given in parameter (i.e. the cells of low dimension from the group delimiting the crack):
2568   MEDCouplingUMesh::RemoveIdsFromIndexedArrays(ids->begin(),ids->end(),desc00,descI00);
2569   DataArrayInt *tmp0=0,*tmp1=0;
2570   // Compute the neighbor of each cell in m0Part2, taking into account the broken link above. Two
2571   // cells on either side of the crack (defined by the mesh of low dimension) are not neighbor anymore.
2572   ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00,tmp0,tmp1);
2573   DAInt neigh00(tmp0);
2574   DAInt neighI00(tmp1);
2575
2576   // For each initial connex part of the sub-mesh (or said differently for each independent crack):
2577   int seed = 0, nIter = 0;
2578   int nIterMax = nCells2+1; // Safety net for the loop
2579   DAInt hitCells = DataArrayInt::New(); hitCells->alloc(nCells2);
2580   hitCells->fillWithValue(-1);
2581   DAInt cellsToModifyConn0_torenum = DataArrayInt::New();
2582   cellsToModifyConn0_torenum->alloc(0,1);
2583   while (nIter < nIterMax)
2584     {
2585       DAInt t = hitCells->findIdsEqual(-1);
2586       if (!t->getNumberOfTuples())
2587         break;
2588       // Connex zone without the crack (to compute the next seed really)
2589       int dnu;
2590       DAInt connexCheck = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neighInit00,neighIInit00, -1, dnu);
2591       int cnt = 0;
2592       for (int * ptr = connexCheck->getPointer(); cnt < connexCheck->getNumberOfTuples(); ptr++, cnt++)
2593         hitCells->setIJ(*ptr,0,1);
2594       // Connex zone WITH the crack (to identify cells lying on either part of the crack)
2595       DAInt spreadZone = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neigh00,neighI00, -1, dnu);
2596       cellsToModifyConn0_torenum = DataArrayInt::Aggregate(cellsToModifyConn0_torenum, spreadZone, 0);
2597       // Compute next seed, i.e. a cell in another connex part, which was not covered by the previous iterations
2598       DAInt comple = cellsToModifyConn0_torenum->buildComplement(nCells2);
2599       DAInt nonHitCells = hitCells->findIdsEqual(-1);
2600       DAInt intersec = nonHitCells->buildIntersection(comple);
2601       if (intersec->getNumberOfTuples())
2602         { seed = intersec->getIJ(0,0); }
2603       else
2604         { break; }
2605       nIter++;
2606     }
2607   if (nIter >= nIterMax)
2608     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate(): internal error - too many iterations.");
2609
2610   DAInt cellsToModifyConn1_torenum=cellsToModifyConn0_torenum->buildComplement(neighI00->getNumberOfTuples()-1);
2611   cellsToModifyConn0_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2612   cellsToModifyConn1_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2613   //
2614   cellIdsNeededToBeRenum=cellsToModifyConn0_torenum.retn();
2615   cellIdsNotModified=cellsToModifyConn1_torenum.retn();
2616   nodeIdsToDuplicate=dupl.retn();
2617 }
2618
2619 /*!
2620  * This method operates a modification of the connectivity and coords in \b this.
2621  * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this 
2622  * its ids will be modified to id this->getNumberOfNodes()+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2623  * 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
2624  * renumbered. The node id nodeIdsToDuplicateBg[0] will have id this->getNumberOfNodes()+0, node id nodeIdsToDuplicateBg[1] will have id this->getNumberOfNodes()+1,
2625  * node id nodeIdsToDuplicateBg[2] will have id this->getNumberOfNodes()+2...
2626  * 
2627  * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2628  * 
2629  * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2630  * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2631  */
2632 void MEDCouplingUMesh::duplicateNodes(const int *nodeIdsToDuplicateBg, const int *nodeIdsToDuplicateEnd)
2633 {
2634   int nbOfNodes=getNumberOfNodes();
2635   duplicateNodesInCoords(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd);
2636   duplicateNodesInConn(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,nbOfNodes);
2637 }
2638
2639 /*!
2640  * This method renumbers only nodal connectivity in \a this. The renumbering is only an offset applied. So this method is a specialization of
2641  * \a renumberNodesInConn. \b WARNING, this method does not check that the resulting node ids in the nodal connectivity is in a valid range !
2642  *
2643  * \param [in] offset - specifies the offset to be applied on each element of connectivity.
2644  *
2645  * \sa renumberNodesInConn
2646  */
2647 void MEDCouplingUMesh::renumberNodesWithOffsetInConn(int offset)
2648 {
2649   checkConnectivityFullyDefined();
2650   int *conn(getNodalConnectivity()->getPointer());
2651   const int *connIndex(getNodalConnectivityIndex()->getConstPointer());
2652   int nbOfCells(getNumberOfCells());
2653   for(int i=0;i<nbOfCells;i++)
2654     for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2655       {
2656         int& node=conn[iconn];
2657         if(node>=0)//avoid polyhedron separator
2658           {
2659             node+=offset;
2660           }
2661       }
2662   _nodal_connec->declareAsNew();
2663   updateTime();
2664 }
2665
2666 /*!
2667  *  Same than renumberNodesInConn(const int *) except that here the format of old-to-new traducer is using map instead
2668  *  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
2669  *  of a big mesh.
2670  */
2671 void MEDCouplingUMesh::renumberNodesInConn(const INTERP_KERNEL::HashMap<int,int>& newNodeNumbersO2N)
2672 {
2673   checkConnectivityFullyDefined();
2674   int *conn(getNodalConnectivity()->getPointer());
2675   const int *connIndex(getNodalConnectivityIndex()->getConstPointer());
2676   int nbOfCells(getNumberOfCells());
2677   for(int i=0;i<nbOfCells;i++)
2678     for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2679       {
2680         int& node=conn[iconn];
2681         if(node>=0)//avoid polyhedron separator
2682           {
2683             INTERP_KERNEL::HashMap<int,int>::const_iterator it(newNodeNumbersO2N.find(node));
2684             if(it!=newNodeNumbersO2N.end())
2685               {
2686                 node=(*it).second;
2687               }
2688             else
2689               {
2690                 std::ostringstream oss; oss << "MEDCouplingUMesh::renumberNodesInConn(map) : presence in connectivity for cell #" << i << " of node #" << node << " : Not in map !";
2691                 throw INTERP_KERNEL::Exception(oss.str());
2692               }
2693           }
2694       }
2695   _nodal_connec->declareAsNew();
2696   updateTime();
2697 }
2698
2699 /*!
2700  * Changes ids of nodes within the nodal connectivity arrays according to a permutation
2701  * array in "Old to New" mode. The node coordinates array is \b not changed by this method.
2702  * This method is a generalization of shiftNodeNumbersInConn().
2703  *  \warning This method performs no check of validity of new ids. **Use it with care !**
2704  *  \param [in] newNodeNumbersO2N - a permutation array, of length \a
2705  *         this->getNumberOfNodes(), in "Old to New" mode. 
2706  *         See \ref numbering for more info on renumbering modes.
2707  *  \throw If the nodal connectivity of cells is not defined.
2708  *
2709  *  \if ENABLE_EXAMPLES
2710  *  \ref cpp_mcumesh_renumberNodesInConn "Here is a C++ example".<br>
2711  *  \ref  py_mcumesh_renumberNodesInConn "Here is a Python example".
2712  *  \endif
2713  */
2714 void MEDCouplingUMesh::renumberNodesInConn(const int *newNodeNumbersO2N)
2715 {
2716   checkConnectivityFullyDefined();
2717   int *conn=getNodalConnectivity()->getPointer();
2718   const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2719   int nbOfCells(getNumberOfCells());
2720   for(int i=0;i<nbOfCells;i++)
2721     for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2722       {
2723         int& node=conn[iconn];
2724         if(node>=0)//avoid polyhedron separator
2725           {
2726             node=newNodeNumbersO2N[node];
2727           }
2728       }
2729   _nodal_connec->declareAsNew();
2730   updateTime();
2731 }
2732
2733 /*!
2734  * This method renumbers nodes \b in \b connectivity \b only \b without \b any \b reference \b to \b coords.
2735  * This method performs no check on the fact that new coordinate ids are valid. \b Use \b it \b with \b care !
2736  * This method is an specialization of \ref MEDCoupling::MEDCouplingUMesh::renumberNodesInConn "renumberNodesInConn method".
2737  * 
2738  * \param [in] delta specifies the shift size applied to nodeId in nodal connectivity in \b this.
2739  */
2740 void MEDCouplingUMesh::shiftNodeNumbersInConn(int delta)
2741 {
2742   checkConnectivityFullyDefined();
2743   int *conn=getNodalConnectivity()->getPointer();
2744   const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2745   int nbOfCells=getNumberOfCells();
2746   for(int i=0;i<nbOfCells;i++)
2747     for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2748       {
2749         int& node=conn[iconn];
2750         if(node>=0)//avoid polyhedron separator
2751           {
2752             node+=delta;
2753           }
2754       }
2755   _nodal_connec->declareAsNew();
2756   updateTime();
2757 }
2758
2759 /*!
2760  * This method operates a modification of the connectivity in \b this.
2761  * 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.
2762  * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this 
2763  * its ids will be modified to id offset+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2764  * 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
2765  * renumbered. The node id nodeIdsToDuplicateBg[0] will have id offset+0, node id nodeIdsToDuplicateBg[1] will have id offset+1,
2766  * node id nodeIdsToDuplicateBg[2] will have id offset+2...
2767  * 
2768  * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2769  * As an another consequense after the call of this method \b this can be transiently non cohrent.
2770  * 
2771  * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2772  * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2773  * \param [in] offset the offset applied to all node ids in connectivity that are in [ \a nodeIdsToDuplicateBg, \a nodeIdsToDuplicateEnd ). 
2774  */
2775 void MEDCouplingUMesh::duplicateNodesInConn(const int *nodeIdsToDuplicateBg, const int *nodeIdsToDuplicateEnd, int offset)
2776 {
2777   checkConnectivityFullyDefined();
2778   std::map<int,int> m;
2779   int val=offset;
2780   for(const int *work=nodeIdsToDuplicateBg;work!=nodeIdsToDuplicateEnd;work++,val++)
2781     m[*work]=val;
2782   int *conn=getNodalConnectivity()->getPointer();
2783   const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2784   int nbOfCells=getNumberOfCells();
2785   for(int i=0;i<nbOfCells;i++)
2786     for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2787       {
2788         int& node=conn[iconn];
2789         if(node>=0)//avoid polyhedron separator
2790           {
2791             std::map<int,int>::iterator it=m.find(node);
2792             if(it!=m.end())
2793               node=(*it).second;
2794           }
2795       }
2796   updateTime();
2797 }
2798
2799 /*!
2800  * This method renumbers cells of \a this using the array specified by [old2NewBg;old2NewBg+getNumberOfCells())
2801  *
2802  * Contrary to MEDCouplingPointSet::renumberNodes, this method makes a permutation without any fuse of cell.
2803  * After the call of this method the number of cells remains the same as before.
2804  *
2805  * If 'check' equals true the method will check that any elements in [ \a old2NewBg; \a old2NewEnd ) is unique ; if not
2806  * an INTERP_KERNEL::Exception will be thrown. When 'check' equals true [ \a old2NewBg ; \a old2NewEnd ) is not expected to
2807  * be strictly in [0;this->getNumberOfCells()).
2808  *
2809  * If 'check' equals false the method will not check the content of [ \a old2NewBg ; \a old2NewEnd ).
2810  * To avoid any throw of SIGSEGV when 'check' equals false, the elements in [ \a old2NewBg ; \a old2NewEnd ) should be unique and
2811  * should be contained in[0;this->getNumberOfCells()).
2812  * 
2813  * \param [in] old2NewBg is expected to be a dynamically allocated pointer of size at least equal to this->getNumberOfCells()
2814  * \param check
2815  */
2816 void MEDCouplingUMesh::renumberCells(const int *old2NewBg, bool check)
2817 {
2818   checkConnectivityFullyDefined();
2819   int nbCells=getNumberOfCells();
2820   const int *array=old2NewBg;
2821   if(check)
2822     array=DataArrayInt::CheckAndPreparePermutation(old2NewBg,old2NewBg+nbCells);
2823   //
2824   const int *conn=_nodal_connec->getConstPointer();
2825   const int *connI=_nodal_connec_index->getConstPointer();
2826   MCAuto<DataArrayInt> o2n=DataArrayInt::New(); o2n->useArray(array,false,C_DEALLOC,nbCells,1);
2827   MCAuto<DataArrayInt> n2o=o2n->invertArrayO2N2N2O(nbCells);
2828   const int *n2oPtr=n2o->begin();
2829   MCAuto<DataArrayInt> newConn=DataArrayInt::New();
2830   newConn->alloc(_nodal_connec->getNumberOfTuples(),_nodal_connec->getNumberOfComponents());
2831   newConn->copyStringInfoFrom(*_nodal_connec);
2832   MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
2833   newConnI->alloc(_nodal_connec_index->getNumberOfTuples(),_nodal_connec_index->getNumberOfComponents());
2834   newConnI->copyStringInfoFrom(*_nodal_connec_index);
2835   //
2836   int *newC=newConn->getPointer();
2837   int *newCI=newConnI->getPointer();
2838   int loc=0;
2839   newCI[0]=loc;
2840   for(int i=0;i<nbCells;i++)
2841     {
2842       int pos=n2oPtr[i];
2843       int nbOfElts=connI[pos+1]-connI[pos];
2844       newC=std::copy(conn+connI[pos],conn+connI[pos+1],newC);
2845       loc+=nbOfElts;
2846       newCI[i+1]=loc;
2847     }
2848   //
2849   setConnectivity(newConn,newConnI);
2850   if(check)
2851     free(const_cast<int *>(array));
2852 }
2853
2854 /*!
2855  * Finds cells whose bounding boxes intersect a given bounding box.
2856  *  \param [in] bbox - an array defining the bounding box via coordinates of its
2857  *         extremum points in "no interlace" mode, i.e. xMin, xMax, yMin, yMax, zMin,
2858  *         zMax (if in 3D). 
2859  *  \param [in] eps - a factor used to increase size of the bounding box of cell
2860  *         before comparing it with \a bbox. This factor is multiplied by the maximal
2861  *         extent of the bounding box of cell to produce an addition to this bounding box.
2862  *  \return DataArrayInt * - a new instance of DataArrayInt holding ids for found
2863  *         cells. The caller is to delete this array using decrRef() as it is no more
2864  *         needed. 
2865  *  \throw If the coordinates array is not set.
2866  *  \throw If the nodal connectivity of cells is not defined.
2867  *
2868  *  \if ENABLE_EXAMPLES
2869  *  \ref cpp_mcumesh_getCellsInBoundingBox "Here is a C++ example".<br>
2870  *  \ref  py_mcumesh_getCellsInBoundingBox "Here is a Python example".
2871  *  \endif
2872  */
2873 DataArrayInt *MEDCouplingUMesh::getCellsInBoundingBox(const double *bbox, double eps) const
2874 {
2875   MCAuto<DataArrayInt> elems=DataArrayInt::New(); elems->alloc(0,1);
2876   if(getMeshDimension()==-1)
2877     {
2878       elems->pushBackSilent(0);
2879       return elems.retn();
2880     }
2881   int dim=getSpaceDimension();
2882   INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2883   const int* conn      = getNodalConnectivity()->getConstPointer();
2884   const int* conn_index= getNodalConnectivityIndex()->getConstPointer();
2885   const double* coords = getCoords()->getConstPointer();
2886   int nbOfCells=getNumberOfCells();
2887   for ( int ielem=0; ielem<nbOfCells;ielem++ )
2888     {
2889       for (int i=0; i<dim; i++)
2890         {
2891           elem_bb[i*2]=std::numeric_limits<double>::max();
2892           elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2893         }
2894
2895       for (int inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2896         {
2897           int node= conn[inode];
2898           if(node>=0)//avoid polyhedron separator
2899             {
2900               for (int idim=0; idim<dim; idim++)
2901                 {
2902                   if ( coords[node*dim+idim] < elem_bb[idim*2] )
2903                     {
2904                       elem_bb[idim*2] = coords[node*dim+idim] ;
2905                     }
2906                   if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2907                     {
2908                       elem_bb[idim*2+1] = coords[node*dim+idim] ;
2909                     }
2910                 }
2911             }
2912         }
2913       if (intersectsBoundingBox(elem_bb, bbox, dim, eps))
2914         elems->pushBackSilent(ielem);
2915     }
2916   return elems.retn();
2917 }
2918
2919 /*!
2920  * Given a boundary box 'bbox' returns elements 'elems' contained in this 'bbox' or touching 'bbox' (within 'eps' distance).
2921  * Warning 'elems' is incremented during the call so if elems is not empty before call returned elements will be
2922  * added in 'elems' parameter.
2923  */
2924 DataArrayInt *MEDCouplingUMesh::getCellsInBoundingBox(const INTERP_KERNEL::DirectedBoundingBox& bbox, double eps)
2925 {
2926   MCAuto<DataArrayInt> elems=DataArrayInt::New(); elems->alloc(0,1);
2927   if(getMeshDimension()==-1)
2928     {
2929       elems->pushBackSilent(0);
2930       return elems.retn();
2931     }
2932   int dim=getSpaceDimension();
2933   INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2934   const int* conn      = getNodalConnectivity()->getConstPointer();
2935   const int* conn_index= getNodalConnectivityIndex()->getConstPointer();
2936   const double* coords = getCoords()->getConstPointer();
2937   int nbOfCells=getNumberOfCells();
2938   for ( int ielem=0; ielem<nbOfCells;ielem++ )
2939     {
2940       for (int i=0; i<dim; i++)
2941         {
2942           elem_bb[i*2]=std::numeric_limits<double>::max();
2943           elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2944         }
2945
2946       for (int inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2947         {
2948           int node= conn[inode];
2949           if(node>=0)//avoid polyhedron separator
2950             {
2951               for (int idim=0; idim<dim; idim++)
2952                 {
2953                   if ( coords[node*dim+idim] < elem_bb[idim*2] )
2954                     {
2955                       elem_bb[idim*2] = coords[node*dim+idim] ;
2956                     }
2957                   if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2958                     {
2959                       elem_bb[idim*2+1] = coords[node*dim+idim] ;
2960                     }
2961                 }
2962             }
2963         }
2964       if(intersectsBoundingBox(bbox, elem_bb, dim, eps))
2965         elems->pushBackSilent(ielem);
2966     }
2967   return elems.retn();
2968 }
2969
2970 /*!
2971  * Returns a type of a cell by its id.
2972  *  \param [in] cellId - the id of the cell of interest.
2973  *  \return INTERP_KERNEL::NormalizedCellType - enumeration item describing the cell type.
2974  *  \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2975  */
2976 INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::getTypeOfCell(int cellId) const
2977 {
2978   const int *ptI=_nodal_connec_index->getConstPointer();
2979   const int *pt=_nodal_connec->getConstPointer();
2980   if(cellId>=0 && cellId<(int)_nodal_connec_index->getNbOfElems()-1)
2981     return (INTERP_KERNEL::NormalizedCellType) pt[ptI[cellId]];
2982   else
2983     {
2984       std::ostringstream oss; oss << "MEDCouplingUMesh::getTypeOfCell : Requesting type of cell #" << cellId << " but it should be in [0," << _nodal_connec_index->getNbOfElems()-1 << ") !";
2985       throw INTERP_KERNEL::Exception(oss.str());
2986     }
2987 }
2988
2989 /*!
2990  * This method returns a newly allocated array containing cell ids (ascendingly sorted) whose geometric type are equal to type.
2991  * This method does not throw exception if geometric type \a type is not in \a this.
2992  * This method throws an INTERP_KERNEL::Exception if meshdimension of \b this is not equal to those of \b type.
2993  * The coordinates array is not considered here.
2994  *
2995  * \param [in] type the geometric type
2996  * \return cell ids in this having geometric type \a type.
2997  */
2998 DataArrayInt *MEDCouplingUMesh::giveCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2999 {
3000
3001   MCAuto<DataArrayInt> ret=DataArrayInt::New();
3002   ret->alloc(0,1);
3003   checkConnectivityFullyDefined();
3004   int nbCells=getNumberOfCells();
3005   int mdim=getMeshDimension();
3006   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
3007   if(mdim!=(int)cm.getDimension())
3008     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::giveCellsWithType : Mismatch between mesh dimension and dimension of the cell !");
3009   const int *ptI=_nodal_connec_index->getConstPointer();
3010   const int *pt=_nodal_connec->getConstPointer();
3011   for(int i=0;i<nbCells;i++)
3012     {
3013       if((INTERP_KERNEL::NormalizedCellType)pt[ptI[i]]==type)
3014         ret->pushBackSilent(i);
3015     }
3016   return ret.retn();
3017 }
3018
3019 /*!
3020  * Returns nb of cells having the geometric type \a type. No throw if no cells in \a this has the geometric type \a type.
3021  */
3022 int MEDCouplingUMesh::getNumberOfCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
3023 {
3024   const int *ptI=_nodal_connec_index->getConstPointer();
3025   const int *pt=_nodal_connec->getConstPointer();
3026   int nbOfCells=getNumberOfCells();
3027   int ret=0;
3028   for(int i=0;i<nbOfCells;i++)
3029     if((INTERP_KERNEL::NormalizedCellType) pt[ptI[i]]==type)
3030       ret++;
3031   return ret;
3032 }
3033
3034 /*!
3035  * Returns the nodal connectivity of a given cell.
3036  * The separator of faces within polyhedron connectivity (-1) is not returned, thus
3037  * all returned node ids can be used in getCoordinatesOfNode().
3038  *  \param [in] cellId - an id of the cell of interest.
3039  *  \param [in,out] conn - a vector where the node ids are appended. It is not
3040  *         cleared before the appending.
3041  *  \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
3042  */
3043 void MEDCouplingUMesh::getNodeIdsOfCell(int cellId, std::vector<int>& conn) const
3044 {
3045   const int *ptI=_nodal_connec_index->getConstPointer();
3046   const int *pt=_nodal_connec->getConstPointer();
3047   for(const int *w=pt+ptI[cellId]+1;w!=pt+ptI[cellId+1];w++)
3048     if(*w>=0)
3049       conn.push_back(*w);
3050 }
3051
3052 std::string MEDCouplingUMesh::simpleRepr() const
3053 {
3054   static const char msg0[]="No coordinates specified !";
3055   std::ostringstream ret;
3056   ret << "Unstructured mesh with name : \"" << getName() << "\"\n";
3057   ret << "Description of mesh : \"" << getDescription() << "\"\n";
3058   int tmpp1,tmpp2;
3059   double tt=getTime(tmpp1,tmpp2);
3060   ret << "Time attached to the mesh [unit] : " << tt << " [" << getTimeUnit() << "]\n";
3061   ret << "Iteration : " << tmpp1  << " Order : " << tmpp2 << "\n";
3062   if(_mesh_dim>=-1)
3063     { ret << "Mesh dimension : " << _mesh_dim << "\nSpace dimension : "; }
3064   else
3065     { ret << " Mesh dimension has not been set or is invalid !"; }
3066   if(_coords!=0)
3067     {
3068       const int spaceDim=getSpaceDimension();
3069       ret << spaceDim << "\nInfo attached on space dimension : ";
3070       for(int i=0;i<spaceDim;i++)
3071         ret << "\"" << _coords->getInfoOnComponent(i) << "\" ";
3072       ret << "\n";
3073     }
3074   else
3075     ret << msg0 << "\n";
3076   ret << "Number of nodes : ";
3077   if(_coords!=0)
3078     ret << getNumberOfNodes() << "\n";
3079   else
3080     ret << msg0 << "\n";
3081   ret << "Number of cells : ";
3082   if(_nodal_connec!=0 && _nodal_connec_index!=0)
3083     ret << getNumberOfCells() << "\n";
3084   else
3085     ret << "No connectivity specified !" << "\n";
3086   ret << "Cell types present : ";
3087   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
3088     {
3089       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter);
3090       ret << cm.getRepr() << " ";
3091     }
3092   ret << "\n";
3093   return ret.str();
3094 }
3095
3096 std::string MEDCouplingUMesh::advancedRepr() const
3097 {
3098   std::ostringstream ret;
3099   ret << simpleRepr();
3100   ret << "\nCoordinates array : \n___________________\n\n";
3101   if(_coords)
3102     _coords->reprWithoutNameStream(ret);
3103   else
3104     ret << "No array set !\n";
3105   ret << "\n\nConnectivity arrays : \n_____________________\n\n";
3106   reprConnectivityOfThisLL(ret);
3107   return ret.str();
3108 }
3109
3110 /*!
3111  * This method returns a C++ code that is a dump of \a this.
3112  * This method will throw if this is not fully defined.
3113  */
3114 std::string MEDCouplingUMesh::cppRepr() const
3115 {
3116   static const char coordsName[]="coords";
3117   static const char connName[]="conn";
3118   static const char connIName[]="connI";
3119   checkFullyDefined();
3120   std::ostringstream ret; ret << "// coordinates" << std::endl;
3121   _coords->reprCppStream(coordsName,ret); ret << std::endl << "// connectivity" << std::endl;
3122   _nodal_connec->reprCppStream(connName,ret); ret << std::endl;
3123   _nodal_connec_index->reprCppStream(connIName,ret); ret << std::endl;
3124   ret << "MEDCouplingUMesh *mesh=MEDCouplingUMesh::New(\"" << getName() << "\"," << getMeshDimension() << ");" << std::endl;
3125   ret << "mesh->setCoords(" << coordsName << ");" << std::endl;
3126   ret << "mesh->setConnectivity(" << connName << "," << connIName << ",true);" << std::endl;
3127   ret << coordsName << "->decrRef(); " << connName << "->decrRef(); " << connIName << "->decrRef();" << std::endl;
3128   return ret.str();
3129 }
3130
3131 std::string MEDCouplingUMesh::reprConnectivityOfThis() const
3132 {
3133   std::ostringstream ret;
3134   reprConnectivityOfThisLL(ret);
3135   return ret.str();
3136 }
3137
3138 /*!
3139  * This method builds a newly allocated instance (with the same name than \a this) that the caller has the responsability to deal with.
3140  * This method returns an instance with all arrays allocated (connectivity, connectivity index, coordinates)
3141  * but with length of these arrays set to 0. It allows to define an "empty" mesh (with nor cells nor nodes but compliant with
3142  * some algos).
3143  * 
3144  * This method expects that \a this has a mesh dimension set and higher or equal to 0. If not an exception will be thrown.
3145  * 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
3146  * with number of tuples set to 0, if not the array is taken as this in the returned instance.
3147  */
3148 MEDCouplingUMesh *MEDCouplingUMesh::buildSetInstanceFromThis(int spaceDim) const
3149 {
3150   int mdim=getMeshDimension();
3151   if(mdim<0)
3152     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSetInstanceFromThis : invalid mesh dimension ! Should be >= 0 !");
3153   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
3154   MCAuto<DataArrayInt> tmp1,tmp2;
3155   bool needToCpyCT=true;
3156   if(!_nodal_connec)
3157     {
3158       tmp1=DataArrayInt::New(); tmp1->alloc(0,1);
3159       needToCpyCT=false;
3160     }
3161   else
3162     {
3163       tmp1=_nodal_connec;
3164       tmp1->incrRef();
3165     }
3166   if(!_nodal_connec_index)
3167     {
3168       tmp2=DataArrayInt::New(); tmp2->alloc(1,1); tmp2->setIJ(0,0,0);
3169       needToCpyCT=false;
3170     }
3171   else
3172     {
3173       tmp2=_nodal_connec_index;
3174       tmp2->incrRef();
3175     }
3176   ret->setConnectivity(tmp1,tmp2,false);
3177   if(needToCpyCT)
3178     ret->_types=_types;
3179   if(!_coords)
3180     {
3181       MCAuto<DataArrayDouble> coords=DataArrayDouble::New(); coords->alloc(0,spaceDim);
3182       ret->setCoords(coords);
3183     }
3184   else
3185     ret->setCoords(_coords);
3186   return ret.retn();
3187 }
3188
3189 void MEDCouplingUMesh::reprConnectivityOfThisLL(std::ostringstream& stream) const
3190 {
3191   if(_nodal_connec!=0 && _nodal_connec_index!=0)
3192     {
3193       int nbOfCells=getNumberOfCells();
3194       const int *c=_nodal_connec->getConstPointer();
3195       const int *ci=_nodal_connec_index->getConstPointer();
3196       for(int i=0;i<nbOfCells;i++)
3197         {
3198           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c[ci[i]]);
3199           stream << "Cell #" << i << " " << cm.getRepr() << " : ";
3200           std::copy(c+ci[i]+1,c+ci[i+1],std::ostream_iterator<int>(stream," "));
3201           stream << "\n";
3202         }
3203     }
3204   else
3205     stream << "Connectivity not defined !\n";
3206 }
3207
3208 int MEDCouplingUMesh::getNumberOfNodesInCell(int cellId) const
3209 {
3210   const int *ptI=_nodal_connec_index->getConstPointer();
3211   const int *pt=_nodal_connec->getConstPointer();
3212   if(pt[ptI[cellId]]!=INTERP_KERNEL::NORM_POLYHED)
3213     return ptI[cellId+1]-ptI[cellId]-1;
3214   else
3215     return (int)std::count_if(pt+ptI[cellId]+1,pt+ptI[cellId+1],std::bind2nd(std::not_equal_to<int>(),-1));
3216 }
3217
3218 /*!
3219  * Returns types of cells of the specified part of \a this mesh.
3220  * This method avoids computing sub-mesh explicitely to get its types.
3221  *  \param [in] begin - an array of cell ids of interest.
3222  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3223  *  \return std::set<INTERP_KERNEL::NormalizedCellType> - a set of enumeration items
3224  *         describing the cell types. 
3225  *  \throw If the coordinates array is not set.
3226  *  \throw If the nodal connectivity of cells is not defined.
3227  *  \sa getAllGeoTypes()
3228  */
3229 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getTypesOfPart(const int *begin, const int *end) const
3230 {
3231   checkFullyDefined();
3232   std::set<INTERP_KERNEL::NormalizedCellType> ret;
3233   const int *conn=_nodal_connec->getConstPointer();
3234   const int *connIndex=_nodal_connec_index->getConstPointer();
3235   for(const int *w=begin;w!=end;w++)
3236     ret.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]);
3237   return ret;
3238 }
3239
3240 /*!
3241  * Defines the nodal connectivity using given connectivity arrays in \ref numbering-indirect format.
3242  * Optionally updates
3243  * a set of types of cells constituting \a this mesh. 
3244  * This method is for advanced users having prepared their connectivity before. For
3245  * more info on using this method see \ref MEDCouplingUMeshAdvBuild.
3246  *  \param [in] conn - the nodal connectivity array. 
3247  *  \param [in] connIndex - the nodal connectivity index array.
3248  *  \param [in] isComputingTypes - if \c true, the set of types constituting \a this
3249  *         mesh is updated.
3250  */
3251 void MEDCouplingUMesh::setConnectivity(DataArrayInt *conn, DataArrayInt *connIndex, bool isComputingTypes)
3252 {
3253   DataArrayInt::SetArrayIn(conn,_nodal_connec);
3254   DataArrayInt::SetArrayIn(connIndex,_nodal_connec_index);
3255   if(isComputingTypes)
3256     computeTypes();
3257   declareAsNew();
3258 }
3259
3260 /*!
3261  * Copy constructor. If 'deepCopy' is false \a this is a shallow copy of other.
3262  * If 'deeCpy' is true all arrays (coordinates and connectivities) are deeply copied.
3263  */
3264 MEDCouplingUMesh::MEDCouplingUMesh(const MEDCouplingUMesh& other, bool deepCopy):MEDCouplingPointSet(other,deepCopy),_mesh_dim(other._mesh_dim),
3265     _nodal_connec(0),_nodal_connec_index(0),
3266     _types(other._types)
3267 {
3268   if(other._nodal_connec)
3269     _nodal_connec=other._nodal_connec->performCopyOrIncrRef(deepCopy);
3270   if(other._nodal_connec_index)
3271     _nodal_connec_index=other._nodal_connec_index->performCopyOrIncrRef(deepCopy);
3272 }
3273
3274 MEDCouplingUMesh::~MEDCouplingUMesh()
3275 {
3276   if(_nodal_connec)
3277     _nodal_connec->decrRef();
3278   if(_nodal_connec_index)
3279     _nodal_connec_index->decrRef();
3280 }
3281
3282 /*!
3283  * Recomputes a set of cell types of \a this mesh. For more info see
3284  * \ref MEDCouplingUMeshNodalConnectivity.
3285  */
3286 void MEDCouplingUMesh::computeTypes()
3287 {
3288   ComputeAllTypesInternal(_types,_nodal_connec,_nodal_connec_index);
3289 }
3290
3291 /*!
3292  * This method checks that all arrays are set. If yes nothing done if no an exception is thrown.
3293  */
3294 void MEDCouplingUMesh::checkFullyDefined() const
3295 {
3296   if(!_nodal_connec_index || !_nodal_connec || !_coords)
3297     throw INTERP_KERNEL::Exception("Reverse nodal connectivity computation requires full connectivity and coordinates set in unstructured mesh.");
3298 }
3299
3300 /*!
3301  * This method checks that all connectivity arrays are set. If yes nothing done if no an exception is thrown.
3302  */
3303 void MEDCouplingUMesh::checkConnectivityFullyDefined() const
3304 {
3305   if(!_nodal_connec_index || !_nodal_connec)
3306     throw INTERP_KERNEL::Exception("Reverse nodal connectivity computation requires full connectivity set in unstructured mesh.");
3307 }
3308
3309 /*!
3310  * Returns a number of cells constituting \a this mesh. 
3311  *  \return int - the number of cells in \a this mesh.
3312  *  \throw If the nodal connectivity of cells is not defined.
3313  */
3314 int MEDCouplingUMesh::getNumberOfCells() const
3315
3316   if(_nodal_connec_index)
3317     return _nodal_connec_index->getNumberOfTuples()-1;
3318   else
3319     if(_mesh_dim==-1)
3320       return 1;
3321     else
3322       throw INTERP_KERNEL::Exception("Unable to get number of cells because no connectivity specified !");
3323 }
3324
3325 /*!
3326  * Returns a dimension of \a this mesh, i.e. a dimension of cells constituting \a this
3327  * mesh. For more info see \ref meshes.
3328  *  \return int - the dimension of \a this mesh.
3329  *  \throw If the mesh dimension is not defined using setMeshDimension().
3330  */
3331 int MEDCouplingUMesh::getMeshDimension() const
3332 {
3333   if(_mesh_dim<-1)
3334     throw INTERP_KERNEL::Exception("No mesh dimension specified !");
3335   return _mesh_dim;
3336 }
3337
3338 /*!
3339  * Returns a length of the nodal connectivity array.
3340  * This method is for test reason. Normally the integer returned is not useable by
3341  * user.  For more info see \ref MEDCouplingUMeshNodalConnectivity.
3342  *  \return int - the length of the nodal connectivity array.
3343  */
3344 int MEDCouplingUMesh::getNodalConnectivityArrayLen() const
3345 {
3346   return _nodal_connec->getNbOfElems();
3347 }
3348
3349 /*!
3350  * First step of serialization process. Used by ParaMEDMEM and MEDCouplingCorba to transfert data between process.
3351  */
3352 void MEDCouplingUMesh::getTinySerializationInformation(std::vector<double>& tinyInfoD, std::vector<int>& tinyInfo, std::vector<std::string>& littleStrings) const
3353 {
3354   MEDCouplingPointSet::getTinySerializationInformation(tinyInfoD,tinyInfo,littleStrings);
3355   tinyInfo.push_back(getMeshDimension());
3356   tinyInfo.push_back(getNumberOfCells());
3357   if(_nodal_connec)
3358     tinyInfo.push_back(getNodalConnectivityArrayLen());
3359   else
3360     tinyInfo.push_back(-1);
3361 }
3362
3363 /*!
3364  * First step of unserialization process.
3365  */
3366 bool MEDCouplingUMesh::isEmptyMesh(const std::vector<int>& tinyInfo) const
3367 {
3368   return tinyInfo[6]<=0;
3369 }
3370
3371 /*!
3372  * Second step of serialization process.
3373  * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3374  * \param a1
3375  * \param a2
3376  * \param littleStrings
3377  */
3378 void MEDCouplingUMesh::resizeForUnserialization(const std::vector<int>& tinyInfo, DataArrayInt *a1, DataArrayDouble *a2, std::vector<std::string>& littleStrings) const
3379 {
3380   MEDCouplingPointSet::resizeForUnserialization(tinyInfo,a1,a2,littleStrings);
3381   if(tinyInfo[5]!=-1)
3382     a1->alloc(tinyInfo[7]+tinyInfo[6]+1,1);
3383 }
3384
3385 /*!
3386  * Third and final step of serialization process.
3387  */
3388 void MEDCouplingUMesh::serialize(DataArrayInt *&a1, DataArrayDouble *&a2) const
3389 {
3390   MEDCouplingPointSet::serialize(a1,a2);
3391   if(getMeshDimension()>-1)
3392     {
3393       a1=DataArrayInt::New();
3394       a1->alloc(getNodalConnectivityArrayLen()+getNumberOfCells()+1,1);
3395       int *ptA1=a1->getPointer();
3396       const int *conn=getNodalConnectivity()->getConstPointer();
3397       const int *index=getNodalConnectivityIndex()->getConstPointer();
3398       ptA1=std::copy(index,index+getNumberOfCells()+1,ptA1);
3399       std::copy(conn,conn+getNodalConnectivityArrayLen(),ptA1);
3400     }
3401   else
3402     a1=0;
3403 }
3404
3405 /*!
3406  * Second and final unserialization process.
3407  * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3408  */
3409 void MEDCouplingUMesh::unserialization(const std::vector<double>& tinyInfoD, const std::vector<int>& tinyInfo, const DataArrayInt *a1, DataArrayDouble *a2, const std::vector<std::string>& littleStrings)
3410 {
3411   MEDCouplingPointSet::unserialization(tinyInfoD,tinyInfo,a1,a2,littleStrings);
3412   setMeshDimension(tinyInfo[5]);
3413   if(tinyInfo[7]!=-1)
3414     {
3415       // Connectivity
3416       const int *recvBuffer=a1->getConstPointer();
3417       MCAuto<DataArrayInt> myConnecIndex=DataArrayInt::New();
3418       myConnecIndex->alloc(tinyInfo[6]+1,1);
3419       std::copy(recvBuffer,recvBuffer+tinyInfo[6]+1,myConnecIndex->getPointer());
3420       MCAuto<DataArrayInt> myConnec=DataArrayInt::New();
3421       myConnec->alloc(tinyInfo[7],1);
3422       std::copy(recvBuffer+tinyInfo[6]+1,recvBuffer+tinyInfo[6]+1+tinyInfo[7],myConnec->getPointer());
3423       setConnectivity(myConnec, myConnecIndex);
3424     }
3425 }
3426
3427 /*!
3428  * This is the low algorithm of MEDCouplingUMesh::buildPartOfMySelfSlice.
3429  * CellIds are given using range specified by a start an end and step.
3430  */
3431 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfKeepCoordsSlice(int start, int end, int step) const
3432 {
3433   checkFullyDefined();
3434   int ncell=getNumberOfCells();
3435   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New();
3436   ret->_mesh_dim=_mesh_dim;
3437   ret->setCoords(_coords);
3438   int newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfKeepCoordsSlice : ");
3439   MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(newNbOfCells+1,1);
3440   int *newConnIPtr=newConnI->getPointer(); *newConnIPtr=0;
3441   int work=start;
3442   const int *conn=_nodal_connec->getConstPointer();
3443   const int *connIndex=_nodal_connec_index->getConstPointer();
3444   for(int i=0;i<newNbOfCells;i++,newConnIPtr++,work+=step)
3445     {
3446       if(work>=0 && work<ncell)
3447         {
3448           newConnIPtr[1]=newConnIPtr[0]+connIndex[work+1]-connIndex[work];
3449         }
3450       else
3451         {
3452           std::ostringstream oss; oss << "MEDCouplingUMesh::buildPartOfMySelfKeepCoordsSlice : On pos #" << i << " input cell id =" << work << " should be in [0," << ncell << ") !";
3453           throw INTERP_KERNEL::Exception(oss.str());
3454         }
3455     }
3456   MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(newConnIPtr[0],1);
3457   int *newConnPtr=newConn->getPointer();
3458   std::set<INTERP_KERNEL::NormalizedCellType> types;
3459   work=start;
3460   for(int i=0;i<newNbOfCells;i++,newConnIPtr++,work+=step)
3461     {
3462       types.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[work]]);
3463       newConnPtr=std::copy(conn+connIndex[work],conn+connIndex[work+1],newConnPtr);
3464     }
3465   ret->setConnectivity(newConn,newConnI,false);
3466   ret->_types=types;
3467   ret->copyTinyInfoFrom(this);
3468   return ret.retn();
3469 }
3470
3471 /*!
3472  * This is the low algorithm of MEDCouplingUMesh::buildPartOfMySelf.
3473  * Keeps from \a this only cells which constituing point id are in the ids specified by [ \a begin,\a end ).
3474  * The return newly allocated mesh will share the same coordinates as \a this.
3475  */
3476 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfKeepCoords(const int *begin, const int *end) const
3477 {
3478   checkConnectivityFullyDefined();
3479   int ncell=getNumberOfCells();
3480   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New();
3481   ret->_mesh_dim=_mesh_dim;
3482   ret->setCoords(_coords);
3483   std::size_t nbOfElemsRet=std::distance(begin,end);
3484   int *connIndexRet=(int *)malloc((nbOfElemsRet+1)*sizeof(int));
3485   connIndexRet[0]=0;
3486   const int *conn=_nodal_connec->getConstPointer();
3487   const int *connIndex=_nodal_connec_index->getConstPointer();
3488   int newNbring=0;
3489   for(const int *work=begin;work!=end;work++,newNbring++)
3490     {
3491       if(*work>=0 && *work<ncell)
3492         connIndexRet[newNbring+1]=connIndexRet[newNbring]+connIndex[*work+1]-connIndex[*work];
3493       else
3494         {
3495           free(connIndexRet);
3496           std::ostringstream oss; oss << "MEDCouplingUMesh::buildPartOfMySelfKeepCoords : On pos #" << std::distance(begin,work) << " input cell id =" << *work << " should be in [0," << ncell << ") !";
3497           throw INTERP_KERNEL::Exception(oss.str());
3498         }
3499     }
3500   int *connRet=(int *)malloc(connIndexRet[nbOfElemsRet]*sizeof(int));
3501   int *connRetWork=connRet;
3502   std::set<INTERP_KERNEL::NormalizedCellType> types;
3503   for(const int *work=begin;work!=end;work++)
3504     {
3505       types.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*work]]);
3506       connRetWork=std::copy(conn+connIndex[*work],conn+connIndex[*work+1],connRetWork);
3507     }
3508   MCAuto<DataArrayInt> connRetArr=DataArrayInt::New();
3509   connRetArr->useArray(connRet,true,C_DEALLOC,connIndexRet[nbOfElemsRet],1);
3510   MCAuto<DataArrayInt> connIndexRetArr=DataArrayInt::New();
3511   connIndexRetArr->useArray(connIndexRet,true,C_DEALLOC,(int)nbOfElemsRet+1,1);
3512   ret->setConnectivity(connRetArr,connIndexRetArr,false);
3513   ret->_types=types;
3514   ret->copyTinyInfoFrom(this);
3515   return ret.retn();
3516 }
3517
3518 /*!
3519  * Returns a new MEDCouplingFieldDouble containing volumes of cells constituting \a this
3520  * mesh.<br>
3521  * For 1D cells, the returned field contains lengths.<br>
3522  * For 2D cells, the returned field contains areas.<br>
3523  * For 3D cells, the returned field contains volumes.
3524  *  \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3525  *         orientation, i.e. the volume is always positive.
3526  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on cells
3527  *         and one time . The caller is to delete this field using decrRef() as it is no
3528  *         more needed.
3529  */
3530 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureField(bool isAbs) const
3531 {
3532   std::string name="MeasureOfMesh_";
3533   name+=getName();
3534   int nbelem=getNumberOfCells();
3535   MCAuto<MEDCouplingFieldDouble> field=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3536   field->setName(name);
3537   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3538   array->alloc(nbelem,1);
3539   double *area_vol=array->getPointer();
3540   field->setArray(array) ; array=0;
3541   field->setMesh(const_cast<MEDCouplingUMesh *>(this));
3542   field->synchronizeTimeWithMesh();
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(int iel=0;iel<nbelem;iel++)
3552         {
3553           ipt=connec_index[iel];
3554           type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3555           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);
3556         }
3557       if(isAbs)
3558         std::transform(area_vol,area_vol+nbelem,area_vol,std::ptr_fun<double,double>(fabs));
3559     }
3560   else
3561     {
3562       area_vol[0]=std::numeric_limits<double>::max();
3563     }
3564   return field.retn();
3565 }
3566
3567 /*!
3568  * Returns a new DataArrayDouble containing volumes of specified cells of \a this
3569  * mesh.<br>
3570  * For 1D cells, the returned array contains lengths.<br>
3571  * For 2D cells, the returned array contains areas.<br>
3572  * For 3D cells, the returned array contains volumes.
3573  * This method avoids building explicitly a part of \a this mesh to perform the work.
3574  *  \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3575  *         orientation, i.e. the volume is always positive.
3576  *  \param [in] begin - an array of cell ids of interest.
3577  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3578  *  \return DataArrayDouble * - a new instance of DataArrayDouble. The caller is to
3579  *          delete this array using decrRef() as it is no more needed.
3580  * 
3581  *  \if ENABLE_EXAMPLES
3582  *  \ref cpp_mcumesh_getPartMeasureField "Here is a C++ example".<br>
3583  *  \ref  py_mcumesh_getPartMeasureField "Here is a Python example".
3584  *  \endif
3585  *  \sa getMeasureField()
3586  */
3587 DataArrayDouble *MEDCouplingUMesh::getPartMeasureField(bool isAbs, const int *begin, const int *end) const
3588 {
3589   std::string name="PartMeasureOfMesh_";
3590   name+=getName();
3591   int nbelem=(int)std::distance(begin,end);
3592   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3593   array->setName(name);
3594   array->alloc(nbelem,1);
3595   double *area_vol=array->getPointer();
3596   if(getMeshDimension()!=-1)
3597     {
3598       int ipt;
3599       INTERP_KERNEL::NormalizedCellType type;
3600       int dim_space=getSpaceDimension();
3601       const double *coords=getCoords()->getConstPointer();
3602       const int *connec=getNodalConnectivity()->getConstPointer();
3603       const int *connec_index=getNodalConnectivityIndex()->getConstPointer();
3604       for(const int *iel=begin;iel!=end;iel++)
3605         {
3606           ipt=connec_index[*iel];
3607           type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3608           *area_vol++=INTERP_KERNEL::computeVolSurfOfCell2<int,INTERP_KERNEL::ALL_C_MODE>(type,connec+ipt+1,connec_index[*iel+1]-ipt-1,coords,dim_space);
3609         }
3610       if(isAbs)
3611         std::transform(array->getPointer(),area_vol,array->getPointer(),std::ptr_fun<double,double>(fabs));
3612     }
3613   else
3614     {
3615       area_vol[0]=std::numeric_limits<double>::max();
3616     }
3617   return array.retn();
3618 }
3619
3620 /*!
3621  * Returns a new MEDCouplingFieldDouble containing volumes of cells of a dual mesh of
3622  * \a this one. The returned field contains the dual cell volume for each corresponding
3623  * node in \a this mesh. In other words, the field returns the getMeasureField() of
3624  *  the dual mesh in P1 sens of \a this.<br>
3625  * For 1D cells, the returned field contains lengths.<br>
3626  * For 2D cells, the returned field contains areas.<br>
3627  * For 3D cells, the returned field contains volumes.
3628  * This method is useful to check "P1*" conservative interpolators.
3629  *  \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3630  *         orientation, i.e. the volume is always positive.
3631  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3632  *          nodes and one time. The caller is to delete this array using decrRef() as
3633  *          it is no more needed.
3634  */
3635 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureFieldOnNode(bool isAbs) const
3636 {
3637   MCAuto<MEDCouplingFieldDouble> tmp=getMeasureField(isAbs);
3638   std::string name="MeasureOnNodeOfMesh_";
3639   name+=getName();
3640   int nbNodes=getNumberOfNodes();
3641   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_NODES);
3642   double cst=1./((double)getMeshDimension()+1.);
3643   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3644   array->alloc(nbNodes,1);
3645   double *valsToFill=array->getPointer();
3646   std::fill(valsToFill,valsToFill+nbNodes,0.);
3647   const double *values=tmp->getArray()->getConstPointer();
3648   MCAuto<DataArrayInt> da=DataArrayInt::New();
3649   MCAuto<DataArrayInt> daInd=DataArrayInt::New();
3650   getReverseNodalConnectivity(da,daInd);
3651   const int *daPtr=da->getConstPointer();
3652   const int *daIPtr=daInd->getConstPointer();
3653   for(int i=0;i<nbNodes;i++)
3654     for(const int *cell=daPtr+daIPtr[i];cell!=daPtr+daIPtr[i+1];cell++)
3655       valsToFill[i]+=cst*values[*cell];
3656   ret->setMesh(this);
3657   ret->setArray(array);
3658   return ret.retn();
3659 }
3660
3661 /*!
3662  * Returns a new MEDCouplingFieldDouble holding normal vectors to cells of \a this
3663  * mesh. The returned normal vectors to each cell have a norm2 equal to 1.
3664  * The computed vectors have <em> this->getMeshDimension()+1 </em> components
3665  * and are normalized.
3666  * <br> \a this can be either 
3667  * - a  2D mesh in 2D or 3D space or 
3668  * - an 1D mesh in 2D space.
3669  * 
3670  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3671  *          cells and one time. The caller is to delete this field using decrRef() as
3672  *          it is no more needed.
3673  *  \throw If the nodal connectivity of cells is not defined.
3674  *  \throw If the coordinates array is not set.
3675  *  \throw If the mesh dimension is not set.
3676  *  \throw If the mesh and space dimension is not as specified above.
3677  */
3678 MEDCouplingFieldDouble *MEDCouplingUMesh::buildOrthogonalField() const
3679 {
3680   if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3681     throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3682   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3683   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3684   int nbOfCells=getNumberOfCells();
3685   int nbComp=getMeshDimension()+1;
3686   array->alloc(nbOfCells,nbComp);
3687   double *vals=array->getPointer();
3688   const int *connI=_nodal_connec_index->getConstPointer();
3689   const int *conn=_nodal_connec->getConstPointer();
3690   const double *coords=_coords->getConstPointer();
3691   if(getMeshDimension()==2)
3692     {
3693       if(getSpaceDimension()==3)
3694         {
3695           MCAuto<DataArrayDouble> loc=computeCellCenterOfMass();
3696           const double *locPtr=loc->getConstPointer();
3697           for(int i=0;i<nbOfCells;i++,vals+=3)
3698             {
3699               int offset=connI[i];
3700               INTERP_KERNEL::crossprod<3>(locPtr+3*i,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3701               double n=INTERP_KERNEL::norm<3>(vals);
3702               std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3703             }
3704         }
3705       else
3706         {
3707           MCAuto<MEDCouplingFieldDouble> isAbs=getMeasureField(false);
3708           const double *isAbsPtr=isAbs->getArray()->begin();
3709           for(int i=0;i<nbOfCells;i++,isAbsPtr++)
3710             { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=*isAbsPtr>0.?1.:-1.; }
3711         }
3712     }
3713   else//meshdimension==1
3714     {
3715       double tmp[2];
3716       for(int i=0;i<nbOfCells;i++)
3717         {
3718           int offset=connI[i];
3719           std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3720           double n=INTERP_KERNEL::norm<2>(tmp);
3721           std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3722           *vals++=-tmp[1];
3723           *vals++=tmp[0];
3724         }
3725     }
3726   ret->setArray(array);
3727   ret->setMesh(this);
3728   ret->synchronizeTimeWithSupport();
3729   return ret.retn();
3730 }
3731
3732 /*!
3733  * Returns a new MEDCouplingFieldDouble holding normal vectors to specified cells of
3734  * \a this mesh. The computed vectors have <em> this->getMeshDimension()+1 </em> components
3735  * and are normalized.
3736  * <br> \a this can be either 
3737  * - a  2D mesh in 2D or 3D space or 
3738  * - an 1D mesh in 2D space.
3739  * 
3740  * This method avoids building explicitly a part of \a this mesh to perform the work.
3741  *  \param [in] begin - an array of cell ids of interest.
3742  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3743  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3744  *          cells and one time. The caller is to delete this field using decrRef() as
3745  *          it is no more needed.
3746  *  \throw If the nodal connectivity of cells is not defined.
3747  *  \throw If the coordinates array is not set.
3748  *  \throw If the mesh dimension is not set.
3749  *  \throw If the mesh and space dimension is not as specified above.
3750  *  \sa buildOrthogonalField()
3751  *
3752  *  \if ENABLE_EXAMPLES
3753  *  \ref cpp_mcumesh_buildPartOrthogonalField "Here is a C++ example".<br>
3754  *  \ref  py_mcumesh_buildPartOrthogonalField "Here is a Python example".
3755  *  \endif
3756  */
3757 MEDCouplingFieldDouble *MEDCouplingUMesh::buildPartOrthogonalField(const int *begin, const int *end) const
3758 {
3759   if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3760     throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3761   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3762   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3763   std::size_t nbelems=std::distance(begin,end);
3764   int nbComp=getMeshDimension()+1;
3765   array->alloc((int)nbelems,nbComp);
3766   double *vals=array->getPointer();
3767   const int *connI=_nodal_connec_index->getConstPointer();
3768   const int *conn=_nodal_connec->getConstPointer();
3769   const double *coords=_coords->getConstPointer();
3770   if(getMeshDimension()==2)
3771     {
3772       if(getSpaceDimension()==3)
3773         {
3774           MCAuto<DataArrayDouble> loc=getPartBarycenterAndOwner(begin,end);
3775           const double *locPtr=loc->getConstPointer();
3776           for(const int *i=begin;i!=end;i++,vals+=3,locPtr+=3)
3777             {
3778               int offset=connI[*i];
3779               INTERP_KERNEL::crossprod<3>(locPtr,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3780               double n=INTERP_KERNEL::norm<3>(vals);
3781               std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3782             }
3783         }
3784       else
3785         {
3786           for(std::size_t i=0;i<nbelems;i++)
3787             { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=1.; }
3788         }
3789     }
3790   else//meshdimension==1
3791     {
3792       double tmp[2];
3793       for(const int *i=begin;i!=end;i++)
3794         {
3795           int offset=connI[*i];
3796           std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3797           double n=INTERP_KERNEL::norm<2>(tmp);
3798           std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3799           *vals++=-tmp[1];
3800           *vals++=tmp[0];
3801         }
3802     }
3803   ret->setArray(array);
3804   ret->setMesh(this);
3805   ret->synchronizeTimeWithSupport();
3806   return ret.retn();
3807 }
3808
3809 /*!
3810  * Returns a new MEDCouplingFieldDouble holding a direction vector for each SEG2 in \a
3811  * this 1D mesh. The computed vectors have <em> this->getSpaceDimension() </em> components
3812  * and are \b not normalized.
3813  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3814  *          cells and one time. The caller is to delete this field using decrRef() as
3815  *          it is no more needed.
3816  *  \throw If the nodal connectivity of cells is not defined.
3817  *  \throw If the coordinates array is not set.
3818  *  \throw If \a this->getMeshDimension() != 1.
3819  *  \throw If \a this mesh includes cells of type other than SEG2.
3820  */
3821 MEDCouplingFieldDouble *MEDCouplingUMesh::buildDirectionVectorField() const
3822 {
3823   if(getMeshDimension()!=1)
3824     throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for buildDirectionVectorField !");
3825   if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3826     throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for buildDirectionVectorField !");
3827   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3828   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3829   int nbOfCells=getNumberOfCells();
3830   int spaceDim=getSpaceDimension();
3831   array->alloc(nbOfCells,spaceDim);
3832   double *pt=array->getPointer();
3833   const double *coo=getCoords()->getConstPointer();
3834   std::vector<int> conn;
3835   conn.reserve(2);
3836   for(int i=0;i<nbOfCells;i++)
3837     {
3838       conn.resize(0);
3839       getNodeIdsOfCell(i,conn);
3840       pt=std::transform(coo+conn[1]*spaceDim,coo+(conn[1]+1)*spaceDim,coo+conn[0]*spaceDim,pt,std::minus<double>());
3841     }
3842   ret->setArray(array);
3843   ret->setMesh(this);
3844   ret->synchronizeTimeWithSupport();
3845   return ret.retn();
3846 }
3847
3848 /*!
3849  * Creates a 2D mesh by cutting \a this 3D mesh with a plane. In addition to the mesh,
3850  * returns a new DataArrayInt, of length equal to the number of 2D cells in the result
3851  * mesh, holding, for each cell in the result mesh, an id of a 3D cell it comes
3852  * from. If a result face is shared by two 3D cells, then the face in included twice in
3853  * the result mesh.
3854  *  \param [in] origin - 3 components of a point defining location of the plane.
3855  *  \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3856  *         must be greater than 1e-6.
3857  *  \param [in] eps - half-thickness of the plane.
3858  *  \param [out] cellIds - a new instance of DataArrayInt holding ids of 3D cells
3859  *         producing correspondent 2D cells. The caller is to delete this array
3860  *         using decrRef() as it is no more needed.
3861  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This mesh does
3862  *         not share the node coordinates array with \a this mesh. The caller is to
3863  *         delete this mesh using decrRef() as it is no more needed.  
3864  *  \throw If the coordinates array is not set.
3865  *  \throw If the nodal connectivity of cells is not defined.
3866  *  \throw If \a this->getMeshDimension() != 3 or \a this->getSpaceDimension() != 3.
3867  *  \throw If magnitude of \a vec is less than 1e-6.
3868  *  \throw If the plane does not intersect any 3D cell of \a this mesh.
3869  *  \throw If \a this includes quadratic cells.
3870  */
3871 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3D(const double *origin, const double *vec, double eps, DataArrayInt *&cellIds) const
3872 {
3873   checkFullyDefined();
3874   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3875     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3876   MCAuto<DataArrayInt> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3877   if(candidates->empty())
3878     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane considering bounding boxes !");
3879   std::vector<int> nodes;
3880   DataArrayInt *cellIds1D=0;
3881   MCAuto<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3882   subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3883   MCAuto<DataArrayInt> desc1=DataArrayInt::New(),desc2=DataArrayInt::New();
3884   MCAuto<DataArrayInt> descIndx1=DataArrayInt::New(),descIndx2=DataArrayInt::New();
3885   MCAuto<DataArrayInt> revDesc1=DataArrayInt::New(),revDesc2=DataArrayInt::New();
3886   MCAuto<DataArrayInt> revDescIndx1=DataArrayInt::New(),revDescIndx2=DataArrayInt::New();
3887   MCAuto<MEDCouplingUMesh> mDesc2=subMesh->buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2);//meshDim==2 spaceDim==3
3888   revDesc2=0; revDescIndx2=0;
3889   MCAuto<MEDCouplingUMesh> mDesc1=mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3890   revDesc1=0; revDescIndx1=0;
3891   mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3892   MCAuto<DataArrayInt> cellIds1DTmp(cellIds1D);
3893   //
3894   std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3895   for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3896     cut3DCurve[*it]=-1;
3897   mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3898   std::vector< std::pair<int,int> > cut3DSurf(mDesc2->getNumberOfCells());
3899   AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->getConstPointer(),mDesc2->getNodalConnectivityIndex()->getConstPointer(),
3900                               mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3901                               desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3902   MCAuto<DataArrayInt> conn(DataArrayInt::New()),connI(DataArrayInt::New()),cellIds2(DataArrayInt::New());
3903   connI->pushBackSilent(0); conn->alloc(0,1); cellIds2->alloc(0,1);
3904   subMesh->assemblyForSplitFrom3DSurf(cut3DSurf,desc2->getConstPointer(),descIndx2->getConstPointer(),conn,connI,cellIds2);
3905   if(cellIds2->empty())
3906     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3907   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3D",2);
3908   ret->setCoords(mDesc1->getCoords());
3909   ret->setConnectivity(conn,connI,true);
3910   cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3911   return ret.retn();
3912 }
3913
3914 /*!
3915  * Creates an 1D mesh by cutting \a this 2D mesh in 3D space with a plane. In
3916 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
3917 from. If a result segment is shared by two 2D cells, then the segment in included twice in
3918 the result mesh.
3919  *  \param [in] origin - 3 components of a point defining location of the plane.
3920  *  \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3921  *         must be greater than 1e-6.
3922  *  \param [in] eps - half-thickness of the plane.
3923  *  \param [out] cellIds - a new instance of DataArrayInt holding ids of faces
3924  *         producing correspondent segments. The caller is to delete this array
3925  *         using decrRef() as it is no more needed.
3926  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This is an 1D
3927  *         mesh in 3D space. This mesh does not share the node coordinates array with
3928  *         \a this mesh. The caller is to delete this mesh using decrRef() as it is
3929  *         no more needed. 
3930  *  \throw If the coordinates array is not set.
3931  *  \throw If the nodal connectivity of cells is not defined.
3932  *  \throw If \a this->getMeshDimension() != 2 or \a this->getSpaceDimension() != 3.
3933  *  \throw If magnitude of \a vec is less than 1e-6.
3934  *  \throw If the plane does not intersect any 2D cell of \a this mesh.
3935  *  \throw If \a this includes quadratic cells.
3936  */
3937 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3DSurf(const double *origin, const double *vec, double eps, DataArrayInt *&cellIds) const
3938 {
3939   checkFullyDefined();
3940   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
3941     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf works on umeshes with meshdim equal to 2 and spaceDim equal to 3 !");
3942   MCAuto<DataArrayInt> candidates(getCellIdsCrossingPlane(origin,vec,eps));
3943   if(candidates->empty())
3944     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3D surf cells in this intercepts the specified plane considering bounding boxes !");
3945   std::vector<int> nodes;
3946   DataArrayInt *cellIds1D(0);
3947   MCAuto<MEDCouplingUMesh> subMesh(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3948   subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3949   MCAuto<DataArrayInt> desc1(DataArrayInt::New()),descIndx1(DataArrayInt::New()),revDesc1(DataArrayInt::New()),revDescIndx1(DataArrayInt::New());
3950   MCAuto<MEDCouplingUMesh> mDesc1(subMesh->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3951   mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3952   MCAuto<DataArrayInt> cellIds1DTmp(cellIds1D);
3953   //
3954   std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3955   for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3956     cut3DCurve[*it]=-1;
3957   mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3958   int ncellsSub=subMesh->getNumberOfCells();
3959   std::vector< std::pair<int,int> > cut3DSurf(ncellsSub);
3960   AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,subMesh->getNodalConnectivity()->getConstPointer(),subMesh->getNodalConnectivityIndex()->getConstPointer(),
3961                               mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3962                               desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3963   MCAuto<DataArrayInt> conn(DataArrayInt::New()),connI(DataArrayInt::New()),cellIds2(DataArrayInt::New()); connI->pushBackSilent(0);
3964   conn->alloc(0,1);
3965   const int *nodal=subMesh->getNodalConnectivity()->getConstPointer();
3966   const int *nodalI=subMesh->getNodalConnectivityIndex()->getConstPointer();
3967   for(int i=0;i<ncellsSub;i++)
3968     {
3969       if(cut3DSurf[i].first!=-1 && cut3DSurf[i].second!=-1)
3970         {
3971           if(cut3DSurf[i].first!=-2)
3972             {
3973               conn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG2); conn->pushBackSilent(cut3DSurf[i].first); conn->pushBackSilent(cut3DSurf[i].second);
3974               connI->pushBackSilent(conn->getNumberOfTuples());
3975               cellIds2->pushBackSilent(i);
3976             }
3977           else
3978             {
3979               int cellId3DSurf=cut3DSurf[i].second;
3980               int offset=nodalI[cellId3DSurf]+1;
3981               int nbOfEdges=nodalI[cellId3DSurf+1]-offset;
3982               for(int j=0;j<nbOfEdges;j++)
3983                 {
3984                   conn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG2); conn->pushBackSilent(nodal[offset+j]); conn->pushBackSilent(nodal[offset+(j+1)%nbOfEdges]);
3985                   connI->pushBackSilent(conn->getNumberOfTuples());
3986                   cellIds2->pushBackSilent(cellId3DSurf);
3987                 }
3988             }
3989         }
3990     }
3991   if(cellIds2->empty())
3992     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3DSurf cells in this intercepts the specified plane !");
3993   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3DSurf",1);
3994   ret->setCoords(mDesc1->getCoords());
3995   ret->setConnectivity(conn,connI,true);
3996   cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3997   return ret.retn();
3998 }
3999
4000 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::clipSingle3DCellByPlane(const double origin[3], const double vec[3], double eps) const
4001 {
4002   checkFullyDefined();
4003   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
4004     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
4005   if(getNumberOfCells()!=1)
4006     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works only on mesh containing exactly one cell !");
4007   //
4008   std::vector<int> nodes;
4009   findNodesOnPlane(origin,vec,eps,nodes);
4010   MCAuto<DataArrayInt> desc1(DataArrayInt::New()),desc2(DataArrayInt::New()),descIndx1(DataArrayInt::New()),descIndx2(DataArrayInt::New()),revDesc1(DataArrayInt::New()),revDesc2(DataArrayInt::New()),revDescIndx1(DataArrayInt::New()),revDescIndx2(DataArrayInt::New());
4011   MCAuto<MEDCouplingUMesh> mDesc2(buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2));//meshDim==2 spaceDim==3
4012   revDesc2=0; revDescIndx2=0;
4013   MCAuto<MEDCouplingUMesh> mDesc1(mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
4014   revDesc1=0; revDescIndx1=0;
4015   DataArrayInt *cellIds1D(0);
4016   mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
4017   MCAuto<DataArrayInt> cellIds1DTmp(cellIds1D);
4018   std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
4019   for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++)
4020     cut3DCurve[*it]=-1;
4021   mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
4022   std::vector< std::pair<int,int> > cut3DSurf(mDesc2->getNumberOfCells());
4023   AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->begin(),mDesc2->getNodalConnectivityIndex()->begin(),
4024                               mDesc1->getNodalConnectivity()->begin(),mDesc1->getNodalConnectivityIndex()->begin(),
4025                               desc1->begin(),descIndx1->begin(),cut3DSurf);
4026   MCAuto<DataArrayInt> conn(DataArrayInt::New()),connI(DataArrayInt::New());
4027   connI->pushBackSilent(0); conn->alloc(0,1);
4028   {
4029     MCAuto<DataArrayInt> cellIds2(DataArrayInt::New()); cellIds2->alloc(0,1);
4030     assemblyForSplitFrom3DSurf(cut3DSurf,desc2->begin(),descIndx2->begin(),conn,connI,cellIds2);
4031     if(cellIds2->empty())
4032       throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
4033   }
4034   std::vector<std::vector<int> > res;
4035   buildSubCellsFromCut(cut3DSurf,desc2->begin(),descIndx2->begin(),mDesc1->getCoords()->begin(),eps,res);
4036   std::size_t sz(res.size());
4037   if(res.size()==mDesc1->getNumberOfCells())
4038     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane : cell is not clipped !");
4039   for(std::size_t i=0;i<sz;i++)
4040     {
4041       conn->pushBackSilent((int)INTERP_KERNEL::NORM_POLYGON);
4042       conn->insertAtTheEnd(res[i].begin(),res[i].end());
4043       connI->pushBackSilent(conn->getNumberOfTuples());
4044     }
4045   MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
4046   ret->setCoords(mDesc1->getCoords());
4047   ret->setConnectivity(conn,connI,true);
4048   int nbCellsRet(ret->getNumberOfCells());
4049   //
4050   MCAuto<DataArrayDouble> vec2(DataArrayDouble::New()); vec2->alloc(1,3); std::copy(vec,vec+3,vec2->getPointer());
4051   MCAuto<MEDCouplingFieldDouble> ortho(ret->buildOrthogonalField());
4052   MCAuto<DataArrayDouble> ortho2(ortho->getArray()->selectByTupleIdSafeSlice(0,1,1));
4053   MCAuto<DataArrayDouble> dott(DataArrayDouble::Dot(ortho2,vec2));
4054   MCAuto<DataArrayDouble> ccm(ret->computeCellCenterOfMass());
4055   MCAuto<DataArrayDouble> occm;
4056   {
4057     MCAuto<DataArrayDouble> pt(DataArrayDouble::New()); pt->alloc(1,3); std::copy(origin,origin+3,pt->getPointer());
4058     occm=DataArrayDouble::Substract(ccm,pt);
4059   }
4060   vec2=DataArrayDouble::New(); vec2->alloc(nbCellsRet,3);
4061   vec2->setPartOfValuesSimple1(vec[0],0,nbCellsRet,1,0,1,1); vec2->setPartOfValuesSimple1(vec[1],0,nbCellsRet,1,1,2,1); vec2->setPartOfValuesSimple1(vec[2],0,nbCellsRet,1,2,3,1);
4062   MCAuto<DataArrayDouble> dott2(DataArrayDouble::Dot(occm,vec2));
4063   //
4064   const int *cPtr(ret->getNodalConnectivity()->begin()),*ciPtr(ret->getNodalConnectivityIndex()->begin());
4065   MCAuto<MEDCouplingUMesh> ret2(MEDCouplingUMesh::New("Clip3D",3));
4066   ret2->setCoords(mDesc1->getCoords());
4067   MCAuto<DataArrayInt> conn2(DataArrayInt::New()),conn2I(DataArrayInt::New());
4068   conn2I->pushBackSilent(0); conn2->alloc(0,1);
4069   std::vector<int> cell0(1,(int)INTERP_KERNEL::NORM_POLYHED);
4070   std::vector<int> cell1(1,(int)INTERP_KERNEL::NORM_POLYHED);
4071   if(dott->getIJ(0,0)>0)
4072     {
4073       cell0.insert(cell0.end(),cPtr+1,cPtr+ciPtr[1]);
4074       std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell1,cell1.end()));
4075     }
4076   else
4077     {
4078       cell1.insert(cell1.end(),cPtr+1,cPtr+ciPtr[1]);
4079       std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell0,cell0.end()));
4080     }
4081   for(int i=1;i<nbCellsRet;i++)
4082     {
4083       if(dott2->getIJ(i,0)<0)
4084         {
4085           if(ciPtr[i+1]-ciPtr[i]>=4)
4086             {
4087               cell0.push_back(-1);
4088               cell0.insert(cell0.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
4089             }
4090         }
4091       else
4092         {
4093           if(ciPtr[i+1]-ciPtr[i]>=4)
4094             {
4095               cell1.push_back(-1);
4096               cell1.insert(cell1.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
4097             }
4098         }
4099     }
4100   conn2->insertAtTheEnd(cell0.begin(),cell0.end());
4101   conn2I->pushBackSilent(conn2->getNumberOfTuples());
4102   conn2->insertAtTheEnd(cell1.begin(),cell1.end());
4103   conn2I->pushBackSilent(conn2->getNumberOfTuples());
4104   ret2->setConnectivity(conn2,conn2I,true);
4105   ret2->checkConsistencyLight();
4106   ret2->writeVTK("ret2.vtu");
4107   ret2->orientCorrectlyPolyhedrons();
4108   return ret2;
4109 }
4110
4111 /*!
4112  * Finds cells whose bounding boxes intersect a given plane.
4113  *  \param [in] origin - 3 components of a point defining location of the plane.
4114  *  \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
4115  *         must be greater than 1e-6.
4116  *  \param [in] eps - half-thickness of the plane.
4117  *  \return DataArrayInt * - a new instance of DataArrayInt holding ids of the found
4118  *         cells. The caller is to delete this array using decrRef() as it is no more
4119  *         needed.
4120  *  \throw If the coordinates array is not set.
4121  *  \throw If the nodal connectivity of cells is not defined.
4122  *  \throw If \a this->getSpaceDimension() != 3.
4123  *  \throw If magnitude of \a vec is less than 1e-6.
4124  *  \sa buildSlice3D()
4125  */
4126 DataArrayInt *MEDCouplingUMesh::getCellIdsCrossingPlane(const double *origin, const double *vec, double eps) const
4127 {
4128   checkFullyDefined();
4129   if(getSpaceDimension()!=3)
4130     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with spaceDim equal to 3 !");
4131   double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
4132   if(normm<1e-6)
4133     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellIdsCrossingPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
4134   double vec2[3];
4135   vec2[0]=vec[1]; vec2[1]=-vec[0]; vec2[2]=0.;//vec2 is the result of cross product of vec with (0,0,1)
4136   double angle=acos(vec[2]/normm);
4137   MCAuto<DataArrayInt> cellIds;
4138   double bbox[6];
4139   if(angle>eps)
4140     {
4141       MCAuto<DataArrayDouble> coo=_coords->deepCopy();
4142       double normm2(sqrt(vec2[0]*vec2[0]+vec2[1]*vec2[1]+vec2[2]*vec2[2]));
4143       if(normm2/normm>1e-6)
4144         DataArrayDouble::Rotate3DAlg(origin,vec2,angle,coo->getNumberOfTuples(),coo->getPointer(),coo->getPointer());
4145       MCAuto<MEDCouplingUMesh> mw=clone(false);//false -> shallow copy
4146       mw->setCoords(coo);
4147       mw->getBoundingBox(bbox);
4148       bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
4149       cellIds=mw->getCellsInBoundingBox(bbox,eps);
4150     }
4151   else
4152     {
4153       getBoundingBox(bbox);
4154       bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
4155       cellIds=getCellsInBoundingBox(bbox,eps);
4156     }
4157   return cellIds.retn();
4158 }
4159
4160 /*!
4161  * This method checks that \a this is a contiguous mesh. The user is expected to call this method on a mesh with meshdim==1.
4162  * If not an exception will thrown. If this is an empty mesh with no cell an exception will be thrown too.
4163  * No consideration of coordinate is done by this method.
4164  * 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)
4165  * If not false is returned. In case that false is returned a call to MEDCoupling::MEDCouplingUMesh::mergeNodes could be usefull.
4166  */
4167 bool MEDCouplingUMesh::isContiguous1D() const
4168 {
4169   if(getMeshDimension()!=1)
4170     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense only for 1D mesh !");
4171   int nbCells=getNumberOfCells();
4172   if(nbCells<1)
4173     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense for non empty mesh !");
4174   const int *connI(_nodal_connec_index->begin()),*conn(_nodal_connec->begin());
4175   int ref=conn[connI[0]+2];
4176   for(int i=1;i<nbCells;i++)
4177     {
4178       if(conn[connI[i]+1]!=ref)
4179         return false;
4180       ref=conn[connI[i]+2];
4181     }
4182   return true;
4183 }
4184
4185 /*!
4186  * This method is only callable on mesh with meshdim == 1 containing only SEG2 and spaceDim==3.
4187  * This method projects this on the 3D line defined by (pt,v). This methods first checks that all SEG2 are along v vector.
4188  * \param pt reference point of the line
4189  * \param v normalized director vector of the line
4190  * \param eps max precision before throwing an exception
4191  * \param res output of size this->getNumberOfCells
4192  */
4193 void MEDCouplingUMesh::project1D(const double *pt, const double *v, double eps, double *res) const
4194 {
4195   if(getMeshDimension()!=1)
4196     throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for project1D !");
4197   if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
4198     throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for project1D !");
4199   if(getSpaceDimension()!=3)
4200     throw INTERP_KERNEL::Exception("Expected a umesh with spaceDim==3 for project1D !");
4201   MCAuto<MEDCouplingFieldDouble> f=buildDirectionVectorField();
4202   const double *fPtr=f->getArray()->getConstPointer();
4203   double tmp[3];
4204   for(int i=0;i<getNumberOfCells();i++)
4205     {
4206       const double *tmp1=fPtr+3*i;
4207       tmp[0]=tmp1[1]*v[2]-tmp1[2]*v[1];
4208       tmp[1]=tmp1[2]*v[0]-tmp1[0]*v[2];
4209       tmp[2]=tmp1[0]*v[1]-tmp1[1]*v[0];
4210       double n1=INTERP_KERNEL::norm<3>(tmp);
4211       n1/=INTERP_KERNEL::norm<3>(tmp1);
4212       if(n1>eps)
4213         throw INTERP_KERNEL::Exception("UMesh::Projection 1D failed !");
4214     }
4215   const double *coo=getCoords()->getConstPointer();
4216   for(int i=0;i<getNumberOfNodes();i++)
4217     {
4218       std::transform(coo+i*3,coo+i*3+3,pt,tmp,std::minus<double>());
4219       std::transform(tmp,tmp+3,v,tmp,std::multiplies<double>());
4220       res[i]=std::accumulate(tmp,tmp+3,0.);
4221     }
4222 }
4223
4224 /*!
4225  * 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. 
4226  * \a this is expected to be a mesh so that its space dimension is equal to its
4227  * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4228  * 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).
4229  *
4230  * 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
4231  * 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).
4232  * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4233  *
4234  * So this method is more accurate (so, more costly) than simply searching for the closest point in \a this.
4235  * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4236  *
4237  * \param [in] ptBg the start pointer (included) of the coordinates of the point
4238  * \param [in] ptEnd the end pointer (not included) of the coordinates of the point
4239  * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4240  * \return the positive value of the distance.
4241  * \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
4242  * dimension - 1.
4243  * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoints
4244  */
4245 double MEDCouplingUMesh::distanceToPoint(const double *ptBg, const double *ptEnd, int& cellId) const
4246 {
4247   int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4248   if(meshDim!=spaceDim-1)
4249     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint works only for spaceDim=meshDim+1 !");
4250   if(meshDim!=2 && meshDim!=1)
4251     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint : only mesh dimension 2 and 1 are implemented !");
4252   checkFullyDefined();
4253   if((int)std::distance(ptBg,ptEnd)!=spaceDim)
4254     { 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()); }
4255   DataArrayInt *ret1=0;
4256   MCAuto<DataArrayDouble> pts=DataArrayDouble::New(); pts->useArray(ptBg,false,C_DEALLOC,1,spaceDim);
4257   MCAuto<DataArrayDouble> ret0=distanceToPoints(pts,ret1);
4258   MCAuto<DataArrayInt> ret1Safe(ret1);
4259   cellId=*ret1Safe->begin();
4260   return *ret0->begin();
4261 }
4262
4263 /*!
4264  * This method computes the distance from each point of points serie \a pts (stored in a DataArrayDouble in which each tuple represents a point)
4265  *  to \a this  and the first \a cellId in \a this corresponding to the returned distance. 
4266  * 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
4267  * 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).
4268  * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4269  * 
4270  * \a this is expected to be a mesh so that its space dimension is equal to its
4271  * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4272  * 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).
4273  *
4274  * So this method is more accurate (so, more costly) than simply searching for each point in \a pts the closest point in \a this.
4275  * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4276  *
4277  * \param [in] pts the list of points in which each tuple represents a point
4278  * \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.
4279  * \return a newly allocated object to be dealed by the caller that tells for each point in \a pts the distance to \a this.
4280  * \throw if number of components of \a pts is not equal to the space dimension.
4281  * \throw if mesh dimension of \a this is not equal to space dimension - 1.
4282  * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoint
4283  */
4284 DataArrayDouble *MEDCouplingUMesh::distanceToPoints(const DataArrayDouble *pts, DataArrayInt *& cellIds) const
4285 {
4286   if(!pts)
4287     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : input points pointer is NULL !");
4288   pts->checkAllocated();
4289   int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4290   if(meshDim!=spaceDim-1)
4291     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints works only for spaceDim=meshDim+1 !");
4292   if(meshDim!=2 && meshDim!=1)
4293     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only mesh dimension 2 and 1 are implemented !");
4294   if(pts->getNumberOfComponents()!=spaceDim)
4295     {
4296       std::ostringstream oss; oss << "MEDCouplingUMesh::distanceToPoints : input pts DataArrayDouble has " << pts->getNumberOfComponents() << " components whereas it should be equal to " << spaceDim << " (mesh spaceDimension) !";
4297       throw INTERP_KERNEL::Exception(oss.str());
4298     }
4299   checkFullyDefined();
4300   int nbCells=getNumberOfCells();
4301   if(nbCells==0)
4302     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : no cells in this !");
4303   int nbOfPts=pts->getNumberOfTuples();
4304   MCAuto<DataArrayDouble> ret0=DataArrayDouble::New(); ret0->alloc(nbOfPts,1);
4305   MCAuto<DataArrayInt> ret1=DataArrayInt::New(); ret1->alloc(nbOfPts,1);
4306   const int *nc=_nodal_connec->begin(),*ncI=_nodal_connec_index->begin(); const double *coords=_coords->begin();
4307   double *ret0Ptr=ret0->getPointer(); int *ret1Ptr=ret1->getPointer(); const double *ptsPtr=pts->begin();
4308   MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree());
4309   const double *bbox(bboxArr->begin());
4310   switch(spaceDim)
4311   {
4312     case 3:
4313       {
4314         BBTreeDst<3> myTree(bbox,0,0,nbCells);
4315         for(int i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=3)
4316           {
4317             double x=std::numeric_limits<double>::max();
4318             std::vector<int> elems;
4319             myTree.getMinDistanceOfMax(ptsPtr,x);
4320             myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4321             DistanceToPoint3DSurfAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4322           }
4323         break;
4324       }
4325     case 2:
4326       {
4327         BBTreeDst<2> myTree(bbox,0,0,nbCells);
4328         for(int i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=2)
4329           {
4330             double x=std::numeric_limits<double>::max();
4331             std::vector<int> elems;
4332             myTree.getMinDistanceOfMax(ptsPtr,x);
4333             myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4334             DistanceToPoint2DCurveAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4335           }
4336         break;
4337       }
4338     default:
4339       throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only spacedim 2 and 3 supported !");
4340   }
4341   cellIds=ret1.retn();
4342   return ret0.retn();
4343 }
4344
4345 /// @cond INTERNAL
4346
4347 /*!
4348  * \param [in] pt the start pointer (included) of the coordinates of the point
4349  * \param [in] cellIdsBg the start pointer (included) of cellIds
4350  * \param [in] cellIdsEnd the end pointer (excluded) of cellIds
4351  * \param [in] nc nodal connectivity
4352  * \param [in] ncI nodal connectivity index
4353  * \param [in,out] ret0 the min distance between \a this and the external input point
4354  * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4355  * \sa MEDCouplingUMesh::distanceToPoint, MEDCouplingUMesh::distanceToPoints
4356  */
4357 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)
4358 {
4359   cellId=-1;
4360   ret0=std::numeric_limits<double>::max();
4361   for(const int *zeCell=cellIdsBg;zeCell!=cellIdsEnd;zeCell++)
4362     {
4363       switch((INTERP_KERNEL::NormalizedCellType)nc[ncI[*zeCell]])
4364       {
4365         case INTERP_KERNEL::NORM_TRI3:
4366           {
4367             double tmp=INTERP_KERNEL::DistanceFromPtToTriInSpaceDim3(pt,coords+3*nc[ncI[*zeCell]+1],coords+3*nc[ncI[*zeCell]+2],coords+3*nc[ncI[*zeCell]+3]);
4368             if(tmp<ret0)
4369               { ret0=tmp; cellId=*zeCell; }
4370             break;
4371           }
4372         case INTERP_KERNEL::NORM_QUAD4:
4373         case INTERP_KERNEL::NORM_POLYGON:
4374           {
4375             double tmp=INTERP_KERNEL::DistanceFromPtToPolygonInSpaceDim3(pt,nc+ncI[*zeCell]+1,nc+ncI[*zeCell+1],coords);
4376             if(tmp<ret0)
4377               { ret0=tmp; cellId=*zeCell; }
4378             break;
4379           }
4380         default:
4381           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint3DSurfAlg : not managed cell type ! Supporting TRI3, QUAD4 and POLYGON !");
4382       }
4383     }
4384 }
4385
4386 /*!
4387  * \param [in] pt the start pointer (included) of the coordinates of the point
4388  * \param [in] cellIdsBg the start pointer (included) of cellIds
4389  * \param [in] cellIdsEnd the end pointer (excluded) of cellIds
4390  * \param [in] nc nodal connectivity
4391  * \param [in] ncI nodal connectivity index
4392  * \param [in,out] ret0 the min distance between \a this and the external input point
4393  * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4394  * \sa MEDCouplingUMesh::distanceToPoint, MEDCouplingUMesh::distanceToPoints
4395  */
4396 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)
4397 {
4398   cellId=-1;
4399   ret0=std::numeric_limits<double>::max();
4400   for(const int *zeCell=cellIdsBg;zeCell!=cellIdsEnd;zeCell++)
4401     {
4402       switch((INTERP_KERNEL::NormalizedCellType)nc[ncI[*zeCell]])
4403       {
4404         case INTERP_KERNEL::NORM_SEG2:
4405           {
4406             std::size_t uselessEntry=0;
4407             double tmp=INTERP_KERNEL::SquareDistanceFromPtToSegInSpaceDim2(pt,coords+2*nc[ncI[*zeCell]+1],coords+2*nc[ncI[*zeCell]+2],uselessEntry);
4408             tmp=sqrt(tmp);
4409             if(tmp<ret0)
4410               { ret0=tmp; cellId=*zeCell; }
4411             break;
4412           }
4413         default:
4414           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint2DCurveAlg : not managed cell type ! Supporting SEG2 !");
4415       }
4416     }
4417 }
4418 /// @endcond
4419
4420 /*!
4421  * Finds cells in contact with a ball (i.e. a point with precision). 
4422  * 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.
4423  * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4424  *
4425  * \warning This method is suitable if the caller intends to evaluate only one
4426  *          point, for more points getCellsContainingPoints() is recommended as it is
4427  *          faster. 
4428  *  \param [in] pos - array of coordinates of the ball central point.
4429  *  \param [in] eps - ball radius.
4430  *  \return int - a smallest id of cells being in contact with the ball, -1 in case
4431  *         if there are no such cells.
4432  *  \throw If the coordinates array is not set.
4433  *  \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4434  */
4435 int MEDCouplingUMesh::getCellContainingPoint(const double *pos, double eps) const
4436 {
4437   std::vector<int> elts;
4438   getCellsContainingPoint(pos,eps,elts);
4439   if(elts.empty())
4440     return -1;
4441   return elts.front();
4442 }
4443
4444 /*!
4445  * Finds cells in contact with a ball (i.e. a point with precision).
4446  * 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.
4447  * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4448  * \warning This method is suitable if the caller intends to evaluate only one
4449  *          point, for more points getCellsContainingPoints() is recommended as it is
4450  *          faster. 
4451  *  \param [in] pos - array of coordinates of the ball central point.
4452  *  \param [in] eps - ball radius.
4453  *  \param [out] elts - vector returning ids of the found cells. It is cleared
4454  *         before inserting ids.
4455  *  \throw If the coordinates array is not set.
4456  *  \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4457  *
4458  *  \if ENABLE_EXAMPLES
4459  *  \ref cpp_mcumesh_getCellsContainingPoint "Here is a C++ example".<br>
4460  *  \ref  py_mcumesh_getCellsContainingPoint "Here is a Python example".
4461  *  \endif
4462  */
4463 void MEDCouplingUMesh::getCellsContainingPoint(const double *pos, double eps, std::vector<int>& elts) const
4464 {
4465   MCAuto<DataArrayInt> eltsUg,eltsIndexUg;
4466   getCellsContainingPoints(pos,1,eps,eltsUg,eltsIndexUg);
4467   elts.clear(); elts.insert(elts.end(),eltsUg->begin(),eltsUg->end());
4468 }
4469
4470 /// @cond INTERNAL
4471
4472 namespace MEDCoupling
4473 {
4474   template<const int SPACEDIMM>
4475   class DummyClsMCUG
4476   {
4477   public:
4478     static const int MY_SPACEDIM=SPACEDIMM;
4479     static const int MY_MESHDIM=8;
4480     typedef int MyConnType;
4481     static const INTERP_KERNEL::NumberingPolicy My_numPol=INTERP_KERNEL::ALL_C_MODE;
4482     // begin
4483     // useless, but for windows compilation ...
4484     const double* getCoordinatesPtr() const { return 0; }
4485     const int* getConnectivityPtr() const { return 0; }
4486     const int* getConnectivityIndexPtr() const { return 0; }
4487     INTERP_KERNEL::NormalizedCellType getTypeOfElement(int) const { return (INTERP_KERNEL::NormalizedCellType)0; }
4488     // end
4489   };
4490
4491   INTERP_KERNEL::Edge *MEDCouplingUMeshBuildQPFromEdge2(INTERP_KERNEL::NormalizedCellType typ, const int *bg, const double *coords2D, std::map< MCAuto<INTERP_KERNEL::Node>,int>& m)
4492   {
4493     INTERP_KERNEL::Edge *ret(0);
4494     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]));
4495     m[n0]=bg[0]; m[n1]=bg[1];
4496     switch(typ)
4497     {
4498       case INTERP_KERNEL::NORM_SEG2:
4499         {
4500           ret=new INTERP_KERNEL::EdgeLin(n0,n1);
4501           break;
4502         }
4503       case INTERP_KERNEL::NORM_SEG3:
4504         {
4505           INTERP_KERNEL::Node *n2(new INTERP_KERNEL::Node(coords2D[2*bg[2]],coords2D[2*bg[2]+1])); m[n2]=bg[2];
4506           INTERP_KERNEL::EdgeLin *e1(new INTERP_KERNEL::EdgeLin(n0,n2)),*e2(new INTERP_KERNEL::EdgeLin(n2,n1));
4507           INTERP_KERNEL::SegSegIntersector inters(*e1,*e2);
4508           // is the SEG3 degenerated, and thus can be reduced to a SEG2?
4509           bool colinearity(inters.areColinears());
4510           delete e1; delete e2;
4511           if(colinearity)
4512             { ret=new INTERP_KERNEL::EdgeLin(n0,n1); }
4513           else
4514             { ret=new INTERP_KERNEL::EdgeArcCircle(n0,n2,n1); }
4515           break;
4516         }
4517       default:
4518         throw INTERP_KERNEL::Exception("MEDCouplingUMeshBuildQPFromEdge2 : Expecting a mesh with spaceDim==2 and meshDim==1 !");
4519     }
4520     return ret;
4521   }
4522
4523   INTERP_KERNEL::Edge *MEDCouplingUMeshBuildQPFromEdge(INTERP_KERNEL::NormalizedCellType typ, std::map<int, std::pair<INTERP_KERNEL::Node *,bool> >& mapp2, const int *bg)
4524   {
4525     INTERP_KERNEL::Edge *ret=0;
4526     switch(typ)
4527     {
4528       case INTERP_KERNEL::NORM_SEG2:
4529         {
4530           ret=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[1]].first);
4531           break;
4532         }
4533       case INTERP_KERNEL::NORM_SEG3:
4534         {
4535           INTERP_KERNEL::EdgeLin *e1=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[2]].first);
4536           INTERP_KERNEL::EdgeLin *e2=new INTERP_KERNEL::EdgeLin(mapp2[bg[2]].first,mapp2[bg[1]].first);
4537           INTERP_KERNEL::SegSegIntersector inters(*e1,*e2);
4538           // is the SEG3 degenerated, and thus can be reduced to a SEG2?
4539           bool colinearity=inters.areColinears();
4540           delete e1; delete e2;
4541           if(colinearity)
4542             ret=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[1]].first);
4543           else
4544             ret=new INTERP_KERNEL::EdgeArcCircle(mapp2[bg[0]].first,mapp2[bg[2]].first,mapp2[bg[1]].first);
4545           mapp2[bg[2]].second=false;
4546           break;
4547         }
4548       default:
4549         throw INTERP_KERNEL::Exception("MEDCouplingUMeshBuildQPFromEdge : Expecting a mesh with spaceDim==2 and meshDim==1 !");
4550     }
4551     return ret;
4552   }
4553
4554   /*!
4555    * This method creates a sub mesh in Geometric2D DS. The sub mesh is composed by the sub set of cells in 'candidates' taken from
4556    * the global mesh 'mDesc'.
4557    * The input mesh 'mDesc' must be so that mDim==1 and spaceDim==2.
4558    * 'mapp' returns a mapping between local numbering in submesh (represented by a Node*) and the global node numbering in 'mDesc'.
4559    */
4560   INTERP_KERNEL::QuadraticPolygon *MEDCouplingUMeshBuildQPFromMesh(const MEDCouplingUMesh *mDesc, const std::vector<int>& candidates,
4561                                                                    std::map<INTERP_KERNEL::Node *,int>& mapp)
4562   {
4563     mapp.clear();
4564     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.
4565     const double *coo=mDesc->getCoords()->getConstPointer();
4566     const int *c=mDesc->getNodalConnectivity()->getConstPointer();
4567     const int *cI=mDesc->getNodalConnectivityIndex()->getConstPointer();
4568     std::set<int> s;
4569     for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
4570       s.insert(c+cI[*it]+1,c+cI[(*it)+1]);
4571     for(std::set<int>::const_iterator it2=s.begin();it2!=s.end();it2++)
4572       {
4573         INTERP_KERNEL::Node *n=new INTERP_KERNEL::Node(coo[2*(*it2)],coo[2*(*it2)+1]);
4574         mapp2[*it2]=std::pair<INTERP_KERNEL::Node *,bool>(n,true);
4575       }
4576     INTERP_KERNEL::QuadraticPolygon *ret=new INTERP_KERNEL::QuadraticPolygon;
4577     for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
4578       {
4579         INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[*it]];
4580         ret->pushBack(MEDCouplingUMeshBuildQPFromEdge(typ,mapp2,c+cI[*it]+1));
4581       }
4582     for(std::map<int, std::pair<INTERP_KERNEL::Node *,bool> >::const_iterator it2=mapp2.begin();it2!=mapp2.end();it2++)
4583       {
4584         if((*it2).second.second)
4585           mapp[(*it2).second.first]=(*it2).first;
4586         ((*it2).second.first)->decrRef();
4587       }
4588     return ret;
4589   }
4590
4591   INTERP_KERNEL::Node *MEDCouplingUMeshBuildQPNode(int nodeId, const double *coo1, int offset1, const double *coo2, int offset2, const std::vector<double>& addCoo)
4592   {
4593     if(nodeId>=offset2)
4594       {
4595         int locId=nodeId-offset2;
4596         return new INTERP_KERNEL::Node(addCoo[2*locId],addCoo[2*locId+1]);
4597       }
4598     if(nodeId>=offset1)
4599       {
4600         int locId=nodeId-offset1;
4601         return new INTERP_KERNEL::Node(coo2[2*locId],coo2[2*locId+1]);
4602       }
4603     return new INTERP_KERNEL::Node(coo1[2*nodeId],coo1[2*nodeId+1]);
4604   }
4605
4606   /**
4607    * Construct a mapping between set of Nodes and the standart MEDCoupling connectivity format (c, cI).
4608    */
4609   void MEDCouplingUMeshBuildQPFromMesh3(const double *coo1, int offset1, const double *coo2, int offset2, const std::vector<double>& addCoo,
4610                                         const int *desc1Bg, const int *desc1End, const std::vector<std::vector<int> >& intesctEdges1,
4611                                         /*output*/std::map<INTERP_KERNEL::Node *,int>& mapp, std::map<int,INTERP_KERNEL::Node *>& mappRev)
4612   {
4613     for(const int *desc1=desc1Bg;desc1!=desc1End;desc1++)
4614       {
4615         int eltId1=abs(*desc1)-1;
4616         for(std::vector<int>::const_iterator it1=intesctEdges1[eltId1].begin();it1!=intesctEdges1[eltId1].end();it1++)
4617           {
4618             std::map<int,INTERP_KERNEL::Node *>::const_iterator it=mappRev.find(*it1);
4619             if(it==mappRev.end())
4620               {
4621                 INTERP_KERNEL::Node *node=MEDCouplingUMeshBuildQPNode(*it1,coo1,offset1,coo2,offset2,addCoo);
4622                 mapp[node]=*it1;
4623                 mappRev[*it1]=node;
4624               }
4625           }
4626       }
4627   }
4628 }
4629
4630 /// @endcond
4631
4632 template<int SPACEDIM>
4633 void MEDCouplingUMesh::getCellsContainingPointsAlg(const double *coords, const double *pos, int nbOfPoints,
4634                                                    double eps, MCAuto<DataArrayInt>& elts, MCAuto<DataArrayInt>& eltsIndex) const
4635 {
4636   elts=DataArrayInt::New(); eltsIndex=DataArrayInt::New(); eltsIndex->alloc(nbOfPoints+1,1); eltsIndex->setIJ(0,0,0); elts->alloc(0,1);
4637   int *eltsIndexPtr(eltsIndex->getPointer());
4638   MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree(eps));
4639   const double *bbox(bboxArr->begin());
4640   int nbOfCells=getNumberOfCells();
4641   const int *conn=_nodal_connec->getConstPointer();
4642   const int *connI=_nodal_connec_index->getConstPointer();
4643   double bb[2*SPACEDIM];
4644   BBTree<SPACEDIM,int> myTree(&bbox[0],0,0,nbOfCells,-eps);
4645   for(int i=0;i<nbOfPoints;i++)
4646     {
4647       eltsIndexPtr[i+1]=eltsIndexPtr[i];
4648       for(int j=0;j<SPACEDIM;j++)
4649         {
4650           bb[2*j]=pos[SPACEDIM*i+j];
4651           bb[2*j+1]=pos[SPACEDIM*i+j];
4652         }
4653       std::vector<int> candidates;
4654       myTree.getIntersectingElems(bb,candidates);
4655       for(std::vector<int>::const_iterator iter=candidates.begin();iter!=candidates.end();iter++)
4656         {
4657           int sz(connI[(*iter)+1]-connI[*iter]-1);
4658           INTERP_KERNEL::NormalizedCellType ct((INTERP_KERNEL::NormalizedCellType)conn[connI[*iter]]);
4659           bool status(false);
4660           if(ct!=INTERP_KERNEL::NORM_POLYGON && ct!=INTERP_KERNEL::NORM_QPOLYG)
4661             status=INTERP_KERNEL::PointLocatorAlgos<DummyClsMCUG<SPACEDIM> >::isElementContainsPoint(pos+i*SPACEDIM,ct,coords,conn+connI[*iter]+1,sz,eps);
4662           else
4663             {
4664               if(SPACEDIM!=2)
4665                 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPointsAlg : not implemented yet for POLYGON and QPOLYGON in spaceDim 3 !");
4666               INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
4667               INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
4668               std::vector<INTERP_KERNEL::Node *> nodes(sz);
4669               INTERP_KERNEL::QuadraticPolygon *pol(0);
4670               for(int j=0;j<sz;j++)
4671                 {
4672                   int nodeId(conn[connI[*iter]+1+j]);
4673                   nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*SPACEDIM],coords[nodeId*SPACEDIM+1]);
4674                 }
4675               if(!INTERP_KERNEL::CellModel::GetCellModel(ct).isQuadratic())
4676                 pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
4677               else
4678                 pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
4679               INTERP_KERNEL::Node *n(new INTERP_KERNEL::Node(pos[i*SPACEDIM],pos[i*SPACEDIM+1]));
4680               double a(0.),b(0.),c(0.);
4681               a=pol->normalizeMe(b,c); n->applySimilarity(b,c,a);
4682               status=pol->isInOrOut2(n);
4683               delete pol; n->decrRef();
4684             }
4685           if(status)
4686             {
4687               eltsIndexPtr[i+1]++;
4688               elts->pushBackSilent(*iter);
4689             }
4690         }
4691     }
4692 }
4693 /*!
4694  * Finds cells in contact with several balls (i.e. points with precision).
4695  * This method is an extension of getCellContainingPoint() and
4696  * getCellsContainingPoint() for the case of multiple points.
4697  * 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.
4698  * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4699  *  \param [in] pos - an array of coordinates of points in full interlace mode :
4700  *         X0,Y0,Z0,X1,Y1,Z1,... Size of the array must be \a
4701  *         this->getSpaceDimension() * \a nbOfPoints 
4702  *  \param [in] nbOfPoints - number of points to locate within \a this mesh.
4703  *  \param [in] eps - radius of balls (i.e. the precision).
4704  *  \param [out] elts - vector returning ids of found cells.
4705  *  \param [out] eltsIndex - an array, of length \a nbOfPoints + 1,
4706  *         dividing cell ids in \a elts into groups each referring to one
4707  *         point. Its every element (except the last one) is an index pointing to the
4708  *         first id of a group of cells. For example cells in contact with the *i*-th
4709  *         point are described by following range of indices:
4710  *         [ \a eltsIndex[ *i* ], \a eltsIndex[ *i*+1 ] ) and the cell ids are
4711  *         \a elts[ \a eltsIndex[ *i* ]], \a elts[ \a eltsIndex[ *i* ] + 1 ], ...
4712  *         Number of cells in contact with the *i*-th point is
4713  *         \a eltsIndex[ *i*+1 ] - \a eltsIndex[ *i* ].
4714  *  \throw If the coordinates array is not set.
4715  *  \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4716  *
4717  *  \if ENABLE_EXAMPLES
4718  *  \ref cpp_mcumesh_getCellsContainingPoints "Here is a C++ example".<br>
4719  *  \ref  py_mcumesh_getCellsContainingPoints "Here is a Python example".
4720  *  \endif
4721  */
4722 void MEDCouplingUMesh::getCellsContainingPoints(const double *pos, int nbOfPoints, double eps,
4723                                                 MCAuto<DataArrayInt>& elts, MCAuto<DataArrayInt>& eltsIndex) const
4724 {
4725   int spaceDim=getSpaceDimension();
4726   int mDim=getMeshDimension();
4727   if(spaceDim==3)
4728     {
4729       if(mDim==3)
4730         {
4731           const double *coords=_coords->getConstPointer();
4732           getCellsContainingPointsAlg<3>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4733         }
4734       /*else if(mDim==2)
4735         {
4736
4737         }*/
4738       else
4739         throw INTERP_KERNEL::Exception("For spaceDim==3 only meshDim==3 implemented for getelementscontainingpoints !");
4740     }
4741   else if(spaceDim==2)
4742     {
4743       if(mDim==2)
4744         {
4745           const double *coords=_coords->getConstPointer();
4746           getCellsContainingPointsAlg<2>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4747         }
4748       else
4749         throw INTERP_KERNEL::Exception("For spaceDim==2 only meshDim==2 implemented for getelementscontainingpoints !");
4750     }
4751   else if(spaceDim==1)
4752     {
4753       if(mDim==1)
4754         {
4755           const double *coords=_coords->getConstPointer();
4756           getCellsContainingPointsAlg<1>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4757         }
4758       else
4759         throw INTERP_KERNEL::Exception("For spaceDim==1 only meshDim==1 implemented for getelementscontainingpoints !");
4760     }
4761   else
4762     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPoints : not managed for mdim not in [1,2,3] !");
4763 }
4764
4765 /*!
4766  * Finds butterfly cells in \a this mesh. A 2D cell is considered to be butterfly if at
4767  * least two its edges intersect each other anywhere except their extremities. An
4768  * INTERP_KERNEL::NORM_NORI3 cell can \b not be butterfly.
4769  *  \param [in,out] cells - a vector returning ids of the found cells. It is not
4770  *         cleared before filling in.
4771  *  \param [in] eps - precision.
4772  *  \throw If \a this->getMeshDimension() != 2.
4773  *  \throw If \a this->getSpaceDimension() != 2 && \a this->getSpaceDimension() != 3.
4774  */
4775 void MEDCouplingUMesh::checkButterflyCells(std::vector<int>& cells, double eps) const
4776 {
4777   const char msg[]="Butterfly detection work only for 2D cells with spaceDim==2 or 3!";
4778   if(getMeshDimension()!=2)
4779     throw INTERP_KERNEL::Exception(msg);
4780   int spaceDim=getSpaceDimension();
4781   if(spaceDim!=2 && spaceDim!=3)
4782     throw INTERP_KERNEL::Exception(msg);
4783   const int *conn=_nodal_connec->getConstPointer();
4784   const int *connI=_nodal_connec_index->getConstPointer();
4785   int nbOfCells=getNumberOfCells();
4786   std::vector<double> cell2DinS2;
4787   for(int i=0;i<nbOfCells;i++)
4788     {
4789       int offset=connI[i];
4790       int nbOfNodesForCell=connI[i+1]-offset-1;
4791       if(nbOfNodesForCell<=3)
4792         continue;
4793       bool isQuad=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[offset]).isQuadratic();
4794       project2DCellOnXY(conn+offset+1,conn+connI[i+1],cell2DinS2);
4795       if(isButterfly2DCell(cell2DinS2,isQuad,eps))
4796         cells.push_back(i);
4797       cell2DinS2.clear();
4798     }
4799 }
4800
4801 /*!
4802  * This method is typically requested to unbutterfly 2D linear cells in \b this.
4803  *
4804  * 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.
4805  * 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.
4806  * 
4807  * For each 2D linear cell in \b this, this method builds the convex envelop (or the convex hull) of the current cell.
4808  * This convex envelop is computed using Jarvis march algorithm.
4809  * The coordinates and the number of cells of \b this remain unchanged on invocation of this method.
4810  * 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)
4811  * 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.
4812  *
4813  * \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.
4814  * \sa MEDCouplingUMesh::colinearize2D
4815  */
4816 DataArrayInt *MEDCouplingUMesh::convexEnvelop2D()
4817 {
4818   if(getMeshDimension()!=2 || getSpaceDimension()!=2)
4819     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convexEnvelop2D  works only for meshDim=2 and spaceDim=2 !");
4820   checkFullyDefined();
4821   const double *coords=getCoords()->getConstPointer();
4822   int nbOfCells=getNumberOfCells();
4823   MCAuto<DataArrayInt> nodalConnecIndexOut=DataArrayInt::New();
4824   nodalConnecIndexOut->alloc(nbOfCells+1,1);
4825   MCAuto<DataArrayInt> nodalConnecOut(DataArrayInt::New());
4826   int *workIndexOut=nodalConnecIndexOut->getPointer();
4827   *workIndexOut=0;
4828   const int *nodalConnecIn=_nodal_connec->getConstPointer();
4829   const int *nodalConnecIndexIn=_nodal_connec_index->getConstPointer();
4830   std::set<INTERP_KERNEL::NormalizedCellType> types;
4831   MCAuto<DataArrayInt> isChanged(DataArrayInt::New());
4832   isChanged->alloc(0,1);
4833   for(int i=0;i<nbOfCells;i++,workIndexOut++)
4834     {
4835       int pos=nodalConnecOut->getNumberOfTuples();
4836       if(BuildConvexEnvelopOf2DCellJarvis(coords,nodalConnecIn+nodalConnecIndexIn[i],nodalConnecIn+nodalConnecIndexIn[i+1],nodalConnecOut))
4837         isChanged->pushBackSilent(i);
4838       types.insert((INTERP_KERNEL::NormalizedCellType)nodalConnecOut->getIJ(pos,0));
4839       workIndexOut[1]=nodalConnecOut->getNumberOfTuples();
4840     }
4841   if(isChanged->empty())
4842     return 0;
4843   setConnectivity(nodalConnecOut,nodalConnecIndexOut,false);
4844   _types=types;
4845   return isChanged.retn();
4846 }
4847
4848 /*!
4849  * This method is \b NOT const because it can modify \a this.
4850  * \a this is expected to be an unstructured mesh with meshDim==2 and spaceDim==3. If not an exception will be thrown.
4851  * \param mesh1D is an unstructured mesh with MeshDim==1 and spaceDim==3. If not an exception will be thrown.
4852  * \param policy specifies the type of extrusion chosen:
4853  *   - \b 0 for translation only (most simple): the cells of the 1D mesh represent the vectors along which the 2D mesh
4854  *   will be repeated to build each level
4855  *   - \b 1 for translation and rotation: the translation is done as above. For each level, an arc of circle is fitted on
4856  *   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
4857  *   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
4858  *   arc.
4859  * \return an unstructured mesh with meshDim==3 and spaceDim==3. The returned mesh has the same coords than \a this.  
4860  */
4861 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMesh(const MEDCouplingUMesh *mesh1D, int policy)
4862 {
4863   checkFullyDefined();
4864   mesh1D->checkFullyDefined();
4865   if(!mesh1D->isContiguous1D())
4866     throw INTERP_KERNEL::Exception("buildExtrudedMesh : 1D mesh passed in parameter is not contiguous !");
4867   if(getSpaceDimension()!=mesh1D->getSpaceDimension())
4868     throw INTERP_KERNEL::Exception("Invalid call to buildExtrudedMesh this and mesh1D must have same space dimension !");
4869   if((getMeshDimension()!=2 || getSpaceDimension()!=3) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
4870     throw INTERP_KERNEL::Exception("Invalid 'this' for buildExtrudedMesh method : must be (meshDim==2 and spaceDim==3) or (meshDim==1 and spaceDim==2) !");
4871   if(mesh1D->getMeshDimension()!=1)
4872     throw INTERP_KERNEL::Exception("Invalid 'mesh1D' for buildExtrudedMesh method : must be meshDim==1 !");
4873   bool isQuad=false;
4874   if(isPresenceOfQuadratic())
4875     {
4876       if(mesh1D->isFullyQuadratic())
4877         isQuad=true;
4878       else
4879         throw INTERP_KERNEL::Exception("Invalid 2D mesh and 1D mesh because 2D mesh has quadratic cells and 1D is not fully quadratic !");
4880     }
4881   int oldNbOfNodes(getNumberOfNodes());
4882   MCAuto<DataArrayDouble> newCoords;
4883   switch(policy)
4884   {
4885     case 0:
4886       {
4887         newCoords=fillExtCoordsUsingTranslation(mesh1D,isQuad);
4888         break;
4889       }
4890     case 1:
4891       {
4892         newCoords=fillExtCoordsUsingTranslAndAutoRotation(mesh1D,isQuad);
4893         break;
4894       }
4895     default:
4896       throw INTERP_KERNEL::Exception("Not implemented extrusion policy : must be in (0) !");
4897   }
4898   setCoords(newCoords);
4899   MCAuto<MEDCouplingUMesh> ret(buildExtrudedMeshFromThisLowLev(oldNbOfNodes,isQuad));
4900   updateTime();
4901   return ret.retn();
4902 }
4903
4904 /*!
4905  * This method works on a 3D curve linear mesh that is to say (meshDim==1 and spaceDim==3).
4906  * If it is not the case an exception will be thrown.
4907  * This method is non const because the coordinate of \a this can be appended with some new points issued from
4908  * intersection of plane defined by ('origin','vec').
4909  * This method has one in/out parameter : 'cut3DCurve'.
4910  * Param 'cut3DCurve' is expected to be of size 'this->getNumberOfCells()'. For each i in [0,'this->getNumberOfCells()')
4911  * if cut3DCurve[i]==-2, it means that for cell #i in \a this nothing has been detected previously.
4912  * if cut3DCurve[i]==-1, it means that cell#i has been already detected to be fully part of plane defined by ('origin','vec').
4913  * This method will throw an exception if \a this contains a non linear segment.
4914  */
4915 void MEDCouplingUMesh::split3DCurveWithPlane(const double *origin, const double *vec, double eps, std::vector<int>& cut3DCurve)
4916 {
4917   checkFullyDefined();
4918   if(getMeshDimension()!=1 || getSpaceDimension()!=3)
4919     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane works on umeshes with meshdim equal to 1 and spaceDim equal to 3 !");
4920   int ncells=getNumberOfCells();
4921   int nnodes=getNumberOfNodes();
4922   double vec2[3],vec3[3],vec4[3];
4923   double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
4924   if(normm<1e-6)
4925     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
4926   vec2[0]=vec[0]/normm; vec2[1]=vec[1]/normm; vec2[2]=vec[2]/normm;
4927   const int *conn=_nodal_connec->getConstPointer();
4928   const int *connI=_nodal_connec_index->getConstPointer();
4929   const double *coo=_coords->getConstPointer();
4930   std::vector<double> addCoo;
4931   for(int i=0;i<ncells;i++)
4932     {
4933       if(conn[connI[i]]==(int)INTERP_KERNEL::NORM_SEG2)
4934         {
4935           if(cut3DCurve[i]==-2)
4936             {
4937               int st=conn[connI[i]+1],endd=conn[connI[i]+2];
4938               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];
4939               double normm2=sqrt(vec3[0]*vec3[0]+vec3[1]*vec3[1]+vec3[2]*vec3[2]);
4940               double colin=std::abs((vec3[0]*vec2[0]+vec3[1]*vec2[1]+vec3[2]*vec2[2])/normm2);
4941               if(colin>eps)//if colin<=eps -> current SEG2 is colinear to the input plane
4942                 {
4943                   const double *st2=coo+3*st;
4944                   vec4[0]=st2[0]-origin[0]; vec4[1]=st2[1]-origin[1]; vec4[2]=st2[2]-origin[2];
4945                   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]));
4946                   if(pos>eps && pos<1-eps)
4947                     {
4948                       int nNode=((int)addCoo.size())/3;
4949                       vec4[0]=st2[0]+pos*vec3[0]; vec4[1]=st2[1]+pos*vec3[1]; vec4[2]=st2[2]+pos*vec3[2];
4950                       addCoo.insert(addCoo.end(),vec4,vec4+3);
4951                       cut3DCurve[i]=nnodes+nNode;
4952                     }
4953                 }
4954             }
4955         }
4956       else
4957         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane : this method is only available for linear cell (NORM_SEG2) !");
4958     }
4959   if(!addCoo.empty())
4960     {
4961       int newNbOfNodes=nnodes+((int)addCoo.size())/3;
4962       MCAuto<DataArrayDouble> coo2=DataArrayDouble::New();
4963       coo2->alloc(newNbOfNodes,3);
4964       double *tmp=coo2->getPointer();
4965       tmp=std::copy(_coords->begin(),_coords->end(),tmp);
4966       std::copy(addCoo.begin(),addCoo.end(),tmp);
4967       DataArrayDouble::SetArrayIn(coo2,_coords);
4968     }
4969 }
4970
4971 /*!
4972  * This method incarnates the policy 0 for MEDCouplingUMesh::buildExtrudedMesh method.
4973  * \param mesh1D is the input 1D mesh used for translation computation.
4974  * \return newCoords new coords filled by this method. 
4975  */
4976 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslation(const MEDCouplingUMesh *mesh1D, bool isQuad) const
4977 {
4978   int oldNbOfNodes=getNumberOfNodes();
4979   int nbOf1DCells=mesh1D->getNumberOfCells();
4980   int spaceDim=getSpaceDimension();
4981   DataArrayDouble *ret=DataArrayDouble::New();
4982   std::vector<bool> isQuads;
4983   int nbOfLevsInVec=isQuad?2*nbOf1DCells+1:nbOf1DCells+1;
4984   ret->alloc(oldNbOfNodes*nbOfLevsInVec,spaceDim);
4985   double *retPtr=ret->getPointer();
4986   const double *coords=getCoords()->getConstPointer();
4987   double *work=std::copy(coords,coords+spaceDim*oldNbOfNodes,retPtr);
4988   std::vector<int> v;
4989   std::vector<double> c;
4990   double vec[3];
4991   v.reserve(3);
4992   c.reserve(6);
4993   for(int i=0;i<nbOf1DCells;i++)
4994     {
4995       v.resize(0);
4996       mesh1D->getNodeIdsOfCell(i,v);
4997       c.resize(0);
4998       mesh1D->getCoordinatesOfNode(v[isQuad?2:1],c);
4999       mesh1D->getCoordinatesOfNode(v[0],c);
5000       std::transform(c.begin(),c.begin()+spaceDim,c.begin()+spaceDim,vec,std::minus<double>());
5001       for(int j=0;j<oldNbOfNodes;j++)
5002         work=std::transform(vec,vec+spaceDim,retPtr+spaceDim*(i*oldNbOfNodes+j),work,std::plus<double>());
5003       if(isQuad)
5004         {
5005           c.resize(0);
5006           mesh1D->getCoordinatesOfNode(v[1],c);
5007           mesh1D->getCoordinatesOfNode(v[0],c);
5008           std::transform(c.begin(),c.begin()+spaceDim,c.begin()+spaceDim,vec,std::minus<double>());
5009           for(int j=0;j<oldNbOfNodes;j++)
5010             work=std::transform(vec,vec+spaceDim,retPtr+spaceDim*(i*oldNbOfNodes+j),work,std::plus<double>());
5011         }
5012     }
5013   ret->copyStringInfoFrom(*getCoords());
5014   return ret;
5015 }
5016
5017 /*!
5018  * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method.
5019  * \param mesh1D is the input 1D mesh used for translation and automatic rotation computation.
5020  * \return newCoords new coords filled by this method. 
5021  */
5022 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation(const MEDCouplingUMesh *mesh1D, bool isQuad) const
5023 {
5024   if(mesh1D->getSpaceDimension()==2)
5025     return fillExtCoordsUsingTranslAndAutoRotation2D(mesh1D,isQuad);
5026   if(mesh1D->getSpaceDimension()==3)
5027     return fillExtCoordsUsingTranslAndAutoRotation3D(mesh1D,isQuad);
5028   throw INTERP_KERNEL::Exception("Not implemented rotation and translation alg. for spacedim other than 2 and 3 !");
5029 }
5030
5031 /*!
5032  * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method.
5033  * \param mesh1D is the input 1D mesh used for translation and automatic rotation computation.
5034  * \return newCoords new coords filled by this method. 
5035  */
5036 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D(const MEDCouplingUMesh *mesh1D, bool isQuad) const
5037 {
5038   if(isQuad)
5039     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D : not implemented for quadratic cells !");
5040   int oldNbOfNodes=getNumberOfNodes();
5041   int nbOf1DCells=mesh1D->getNumberOfCells();
5042   if(nbOf1DCells<2)
5043     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D : impossible to detect any angle of rotation ! Change extrusion policy 1->0 !");
5044   MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
5045   int nbOfLevsInVec=nbOf1DCells+1;
5046   ret->alloc(oldNbOfNodes*nbOfLevsInVec,2);
5047   double *retPtr=ret->getPointer();
5048   retPtr=std::copy(getCoords()->getConstPointer(),getCoords()->getConstPointer()+getCoords()->getNbOfElems(),retPtr);
5049   MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
5050   MCAuto<DataArrayDouble> tmp2=getCoords()->deepCopy();
5051   tmp->setCoords(tmp2);
5052   const double *coo1D=mesh1D->getCoords()->getConstPointer();
5053   const int *conn1D=mesh1D->getNodalConnectivity()->getConstPointer();
5054   const int *connI1D=mesh1D->getNodalConnectivityIndex()->getConstPointer();
5055   for(int i=1;i<nbOfLevsInVec;i++)
5056     {
5057       const double *begin=coo1D+2*conn1D[connI1D[i-1]+1];
5058       const double *end=coo1D+2*conn1D[connI1D[i-1]+2];
5059       const double *third=i+1<nbOfLevsInVec?coo1D+2*conn1D[connI1D[i]+2]:coo1D+2*conn1D[connI1D[i-2]+1];
5060       const double vec[2]={end[0]-begin[0],end[1]-begin[1]};
5061       tmp->translate(vec);
5062       double tmp3[2],radius,alpha,alpha0;
5063       const double *p0=i+1<nbOfLevsInVec?begin:third;
5064       const double *p1=i+1<nbOfLevsInVec?end:begin;
5065       const double *p2=i+1<nbOfLevsInVec?third:end;
5066       INTERP_KERNEL::EdgeArcCircle::GetArcOfCirclePassingThru(p0,p1,p2,tmp3,radius,alpha,alpha0);
5067       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]);
5068       double angle=acos(cosangle/(radius*radius));
5069       tmp->rotate(end,0,angle);
5070       retPtr=std::copy(tmp2->getConstPointer(),tmp2->getConstPointer()+tmp2->getNbOfElems(),retPtr);
5071     }
5072   return ret.retn();
5073 }
5074
5075 /*!
5076  * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method.
5077  * \param mesh1D is the input 1D mesh used for translation and automatic rotation computation.
5078  * \return newCoords new coords filled by this method. 
5079  */
5080 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D(const MEDCouplingUMesh *mesh1D, bool isQuad) const
5081 {
5082   if(isQuad)
5083     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D : not implemented for quadratic cells !");
5084   int oldNbOfNodes=getNumberOfNodes();
5085   int nbOf1DCells=mesh1D->getNumberOfCells();
5086   if(nbOf1DCells<2)
5087     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D : impossible to detect any angle of rotation ! Change extrusion policy 1->0 !");
5088   MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
5089   int nbOfLevsInVec=nbOf1DCells+1;
5090   ret->alloc(oldNbOfNodes*nbOfLevsInVec,3);
5091   double *retPtr=ret->getPointer();
5092   retPtr=std::copy(getCoords()->getConstPointer(),getCoords()->getConstPointer()+getCoords()->getNbOfElems(),retPtr);
5093   MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
5094   MCAuto<DataArrayDouble> tmp2=getCoords()->deepCopy();
5095   tmp->setCoords(tmp2);
5096   const double *coo1D=mesh1D->getCoords()->getConstPointer();
5097   const int *conn1D=mesh1D->getNodalConnectivity()->getConstPointer();
5098   const int *connI1D=mesh1D->getNodalConnectivityIndex()->getConstPointer();
5099   for(int i=1;i<nbOfLevsInVec;i++)
5100     {
5101       const double *begin=coo1D+3*conn1D[connI1D[i-1]+1];
5102       const double *end=coo1D+3*conn1D[connI1D[i-1]+2];
5103       const double *third=i+1<nbOfLevsInVec?coo1D+3*conn1D[connI1D[i]+2]:coo1D+3*conn1D[connI1D[i-2]+1];
5104       const double vec[3]={end[0]-begin[0],end[1]-begin[1],end[2]-begin[2]};
5105       tmp->translate(vec);
5106       double tmp3[2],radius,alpha,alpha0;
5107       const double *p0=i+1<nbOfLevsInVec?begin:third;
5108       const double *p1=i+1<nbOfLevsInVec?end:begin;
5109       const double *p2=i+1<nbOfLevsInVec?third:end;
5110       double vecPlane[3]={
5111         (p1[1]-p0[1])*(p2[2]-p1[2])-(p1[2]-p0[2])*(p2[1]-p1[1]),
5112         (p1[2]-p0[2])*(p2[0]-p1[0])-(p1[0]-p0[0])*(p2[2]-p1[2]),
5113         (p1[0]-p0[0])*(p2[1]-p1[1])-(p1[1]-p0[1])*(p2[0]-p1[0]),
5114       };
5115       double norm=sqrt(vecPlane[0]*vecPlane[0]+vecPlane[1]*vecPlane[1]+vecPlane[2]*vecPlane[2]);
5116       if(norm>1.e-7)
5117         {
5118           vecPlane[0]/=norm; vecPlane[1]/=norm; vecPlane[2]/=norm;
5119           double norm2=sqrt(vecPlane[0]*vecPlane[0]+vecPlane[1]*vecPlane[1]);
5120           double vec2[2]={vecPlane[1]/norm2,-vecPlane[0]/norm2};
5121           double s2=norm2;
5122           double c2=cos(asin(s2));
5123           double m[3][3]={
5124             {vec2[0]*vec2[0]*(1-c2)+c2, vec2[0]*vec2[1]*(1-c2), vec2[1]*s2},
5125             {vec2[0]*vec2[1]*(1-c2), vec2[1]*vec2[1]*(1-c2)+c2, -vec2[0]*s2},
5126             {-vec2[1]*s2, vec2[0]*s2, c2}
5127           };
5128           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]};
5129           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]};
5130           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]};
5131           INTERP_KERNEL::EdgeArcCircle::GetArcOfCirclePassingThru(p0r,p1r,p2r,tmp3,radius,alpha,alpha0);
5132           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]);
5133           double angle=acos(cosangle/(radius*radius));
5134           tmp->rotate(end,vecPlane,angle);
5135         }
5136       retPtr=std::copy(tmp2->getConstPointer(),tmp2->getConstPointer()+tmp2->getNbOfElems(),retPtr);
5137     }
5138   return ret.retn();
5139 }
5140
5141 /*!
5142  * This method is private because not easy to use for end user. This method is const contrary to
5143  * MEDCouplingUMesh::buildExtrudedMesh method because this->_coords are expected to contain
5144  * the coords sorted slice by slice.
5145  * \param isQuad specifies presence of quadratic cells.
5146  */
5147 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMeshFromThisLowLev(int nbOfNodesOf1Lev, bool isQuad) const
5148 {
5149   int nbOf1DCells(getNumberOfNodes()/nbOfNodesOf1Lev-1);
5150   int nbOf2DCells(getNumberOfCells());
5151   int nbOf3DCells(nbOf2DCells*nbOf1DCells);
5152   MEDCouplingUMesh *ret(MEDCouplingUMesh::New("Extruded",getMeshDimension()+1));
5153   const int *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5154   MCAuto<DataArrayInt> newConn(DataArrayInt::New()),newConnI(DataArrayInt::New());
5155   newConnI->alloc(nbOf3DCells+1,1);
5156   int *newConnIPtr(newConnI->getPointer());
5157   *newConnIPtr++=0;
5158   std::vector<int> newc;
5159   for(int j=0;j<nbOf2DCells;j++)
5160     {
5161       AppendExtrudedCell(conn+connI[j],conn+connI[j+1],nbOfNodesOf1Lev,isQuad,newc);
5162       *newConnIPtr++=(int)newc.size();
5163     }
5164   newConn->alloc((int)(newc.size())*nbOf1DCells,1);
5165   int *newConnPtr(newConn->getPointer());
5166   int deltaPerLev(isQuad?2*nbOfNodesOf1Lev:nbOfNodesOf1Lev);
5167   newConnIPtr=newConnI->getPointer();
5168   for(int iz=0;iz<nbOf1DCells;iz++)
5169     {
5170       if(iz!=0)
5171         std::transform(newConnIPtr+1,newConnIPtr+1+nbOf2DCells,newConnIPtr+1+iz*nbOf2DCells,std::bind2nd(std::plus<int>(),newConnIPtr[iz*nbOf2DCells]));
5172       const int *posOfTypeOfCell(newConnIPtr);
5173       for(std::vector<int>::const_iterator iter=newc.begin();iter!=newc.end();iter++,newConnPtr++)
5174         {
5175           int icell((int)(iter-newc.begin()));//std::distance unfortunately cannot been called here in C++98
5176           if(icell!=*posOfTypeOfCell)
5177             {
5178               if(*iter!=-1)
5179                 *newConnPtr=(*iter)+iz*deltaPerLev;
5180               else
5181                 *newConnPtr=-1;
5182             }
5183           else
5184             {
5185               *newConnPtr=*iter;
5186               posOfTypeOfCell++;
5187             }
5188         }
5189     }
5190   ret->setConnectivity(newConn,newConnI,true);
5191   ret->setCoords(getCoords());
5192   return ret;
5193 }
5194
5195 /*!
5196  * Checks if \a this mesh is constituted by only quadratic cells.
5197  *  \return bool - \c true if there are only quadratic cells in \a this mesh.
5198  *  \throw If the coordinates array is not set.
5199  *  \throw If the nodal connectivity of cells is not defined.
5200  */
5201 bool MEDCouplingUMesh::isFullyQuadratic() const
5202 {
5203   checkFullyDefined();
5204   bool ret=true;
5205   int nbOfCells=getNumberOfCells();
5206   for(int i=0;i<nbOfCells && ret;i++)
5207     {
5208       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
5209       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5210       ret=cm.isQuadratic();
5211     }
5212   return ret;
5213 }
5214
5215 /*!
5216  * Checks if \a this mesh includes any quadratic cell.
5217  *  \return bool - \c true if there is at least one quadratic cells in \a this mesh.
5218  *  \throw If the coordinates array is not set.
5219  *  \throw If the nodal connectivity of cells is not defined.
5220  */
5221 bool MEDCouplingUMesh::isPresenceOfQuadratic() const
5222 {
5223   checkFullyDefined();
5224   bool ret=false;
5225   int nbOfCells=getNumberOfCells();
5226   for(int i=0;i<nbOfCells && !ret;i++)
5227     {
5228       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
5229       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5230       ret=cm.isQuadratic();
5231     }
5232   return ret;
5233 }
5234
5235 /*!
5236  * Converts all quadratic cells to linear ones. If there are no quadratic cells in \a
5237  * this mesh, it remains unchanged.
5238  *  \throw If the coordinates array is not set.
5239  *  \throw If the nodal connectivity of cells is not defined.
5240  */
5241 void MEDCouplingUMesh::convertQuadraticCellsToLinear()
5242 {
5243   checkFullyDefined();
5244   int nbOfCells(getNumberOfCells());
5245   int delta=0;
5246   const int *iciptr=_nodal_connec_index->begin();
5247   for(int i=0;i<nbOfCells;i++)
5248     {
5249       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
5250       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5251       if(cm.isQuadratic())
5252         {
5253           INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
5254           const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
5255           if(!cml.isDynamic())
5256             delta+=cm.getNumberOfNodes()-cml.getNumberOfNodes();
5257           else
5258             delta+=(iciptr[i+1]-iciptr[i]-1)/2;
5259         }
5260     }
5261   if(delta==0)
5262     return ;
5263   MCAuto<DataArrayInt> newConn(DataArrayInt::New()),newConnI(DataArrayInt::New());
5264   const int *icptr(_nodal_connec->begin());
5265   newConn->alloc(getNodalConnectivityArrayLen()-delta,1);
5266   newConnI->alloc(nbOfCells+1,1);
5267   int *ocptr(newConn->getPointer()),*ociptr(newConnI->getPointer());
5268   *ociptr=0;
5269   _types.clear();
5270   for(int i=0;i<nbOfCells;i++,ociptr++)
5271     {
5272       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)icptr[iciptr[i]];
5273       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5274       if(!cm.isQuadratic())
5275         {
5276           _types.insert(type);
5277           ocptr=std::copy(icptr+iciptr[i],icptr+iciptr[i+1],ocptr);
5278           ociptr[1]=ociptr[0]+iciptr[i+1]-iciptr[i];
5279         }
5280       else
5281         {
5282           INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
5283           _types.insert(typel);
5284           const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
5285           int newNbOfNodes=cml.getNumberOfNodes();
5286           if(cml.isDynamic())
5287             newNbOfNodes=(iciptr[i+1]-iciptr[i]-1)/2;
5288           *ocptr++=(int)typel;
5289           ocptr=std::copy(icptr+iciptr[i]+1,icptr+iciptr[i]+newNbOfNodes+1,ocptr);
5290           ociptr[1]=ociptr[0]+newNbOfNodes+1;
5291         }
5292     }
5293   setConnectivity(newConn,newConnI,false);
5294 }
5295
5296 /*!
5297  * This method converts all linear cell in \a this to quadratic one.
5298  * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, here it is needed to specify the target
5299  * 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)
5300  * 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.
5301  * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, the coordinates in \a this can be become bigger. All created nodes will be put at the
5302  * end of the existing coordinates.
5303  * 
5304  * \param [in] conversionType specifies the type of conversion expected. Only 0 (default) and 1 are supported presently. 0 those that creates the 'most' simple
5305  *             corresponding quadratic cells. 1 is those creating the 'most' complex.
5306  * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5307  * 
5308  * \throw if \a this is not fully defined. It throws too if \a conversionType is not in [0,1].
5309  *
5310  * \sa MEDCouplingUMesh::convertQuadraticCellsToLinear
5311  */
5312 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic(int conversionType)
5313 {
5314   DataArrayInt *conn=0,*connI=0;
5315   DataArrayDouble *coords=0;
5316   std::set<INTERP_KERNEL::NormalizedCellType> types;
5317   checkFullyDefined();
5318   MCAuto<DataArrayInt> ret,connSafe,connISafe;
5319   MCAuto<DataArrayDouble> coordsSafe;
5320   int meshDim=getMeshDimension();
5321   switch(conversionType)
5322   {
5323     case 0:
5324       switch(meshDim)
5325       {
5326         case 1:
5327           ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);
5328           connSafe=conn; connISafe=connI; coordsSafe=coords;
5329           break;
5330         case 2:
5331           ret=convertLinearCellsToQuadratic2D0(conn,connI,coords,types);
5332           connSafe=conn; connISafe=connI; coordsSafe=coords;
5333           break;
5334         case 3:
5335           ret=convertLinearCellsToQuadratic3D0(conn,connI,coords,types);
5336           connSafe=conn; connISafe=connI; coordsSafe=coords;
5337           break;
5338         default:
5339           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 0 mesh dimensions available are [1,2,3] !");
5340       }
5341       break;
5342         case 1:
5343           {
5344             switch(meshDim)
5345             {
5346               case 1:
5347                 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);//it is not a bug. In 1D policy 0 and 1 are equals
5348                 connSafe=conn; connISafe=connI; coordsSafe=coords;
5349                 break;
5350               case 2:
5351                 ret=convertLinearCellsToQuadratic2D1(conn,connI,coords,types);
5352                 connSafe=conn; connISafe=connI; coordsSafe=coords;
5353                 break;
5354               case 3:
5355                 ret=convertLinearCellsToQuadratic3D1(conn,connI,coords,types);
5356                 connSafe=conn; connISafe=connI; coordsSafe=coords;
5357                 break;
5358               default:
5359                 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 1 mesh dimensions available are [1,2,3] !");
5360             }
5361             break;
5362           }
5363         default:
5364           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion type available are 0 (default, the simplest) and 1 (the most complex) !");
5365   }
5366   setConnectivity(connSafe,connISafe,false);
5367   _types=types;
5368   setCoords(coordsSafe);
5369   return ret.retn();
5370 }
5371
5372 /*!
5373  * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
5374  * so that the number of cells remains the same. Quadratic faces are converted to
5375  * polygons. This method works only for 2D meshes in
5376  * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
5377  * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
5378  * \warning This method can lead to a huge amount of nodes if \a eps is very low.
5379  *  \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
5380  *         a polylinized edge constituting the input polygon.
5381  *  \throw If the coordinates array is not set.
5382  *  \throw If the nodal connectivity of cells is not defined.
5383  *  \throw If \a this->getMeshDimension() != 2.
5384  *  \throw If \a this->getSpaceDimension() != 2.
5385  */
5386 void MEDCouplingUMesh::tessellate2D(double eps)
5387 {
5388   int meshDim(getMeshDimension()),spaceDim(getSpaceDimension());
5389   if(spaceDim!=2)
5390     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : works only with space dimension equal to 2 !");
5391   switch(meshDim)
5392     {
5393     case 1:
5394       return tessellate2DCurveInternal(eps);
5395     case 2:
5396       return tessellate2DInternal(eps);
5397     default:
5398       throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : mesh dimension must be in [1,2] !");
5399     }
5400 }
5401 /*!
5402  * Tessellates \a this 1D mesh in 2D space by dividing not straight quadratic edges.
5403  * \warning This method can lead to a huge amount of nodes if \a eps is very low.
5404  *  \param [in] eps - specifies the maximal angle (in radian) between 2 sub-edges of
5405  *         a sub-divided edge.
5406  *  \throw If the coordinates array is not set.
5407  *  \throw If the nodal connectivity of cells is not defined.
5408  *  \throw If \a this->getMeshDimension() != 1.
5409  *  \throw If \a this->getSpaceDimension() != 2.
5410  */
5411
5412 #if 0
5413 /*!
5414  * This method only works if \a this has spaceDimension equal to 2 and meshDimension also equal to 2.
5415  * This method allows to modify connectivity of cells in \a this that shares some edges in \a edgeIdsToBeSplit.
5416  * The nodes to be added in those 2D cells are defined by the pair of \a  nodeIdsToAdd and \a nodeIdsIndexToAdd.
5417  * Length of \a nodeIdsIndexToAdd is expected to equal to length of \a edgeIdsToBeSplit + 1.
5418  * The node ids in \a nodeIdsToAdd should be valid. Those nodes have to be sorted exactly following exactly the direction of the edge.
5419  * This method can be seen as the opposite method of colinearize2D.
5420  * 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
5421  * to avoid to modify the numbering of existing nodes.
5422  *
5423  * \param [in] nodeIdsToAdd - the list of node ids to be added (\a nodeIdsIndexToAdd array allows to walk on this array)
5424  * \param [in] nodeIdsIndexToAdd - the entry point of \a nodeIdsToAdd to point to the corresponding nodes to be added.
5425  * \param [in] mesh1Desc - 1st output of buildDescendingConnectivity2 on \a this.
5426  * \param [in] desc - 2nd output of buildDescendingConnectivity2 on \a this.
5427  * \param [in] descI - 3rd output of buildDescendingConnectivity2 on \a this.
5428  * \param [in] revDesc - 4th output of buildDescendingConnectivity2 on \a this.
5429  * \param [in] revDescI - 5th output of buildDescendingConnectivity2 on \a this.
5430  *
5431  * \sa buildDescendingConnectivity2
5432  */
5433 void MEDCouplingUMesh::splitSomeEdgesOf2DMesh(const DataArrayInt *nodeIdsToAdd, const DataArrayInt *nodeIdsIndexToAdd, const DataArrayInt *edgeIdsToBeSplit,
5434                                               const MEDCouplingUMesh *mesh1Desc, const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *revDesc, const DataArrayInt *revDescI)
5435 {
5436   if(!nodeIdsToAdd || !nodeIdsIndexToAdd || !edgeIdsToBeSplit || !mesh1Desc || !desc || !descI || !revDesc || !revDescI)
5437     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : input pointers must be not NULL !");
5438   nodeIdsToAdd->checkAllocated(); nodeIdsIndexToAdd->checkAllocated(); edgeIdsToBeSplit->checkAllocated(); desc->checkAllocated(); descI->checkAllocated(); revDesc->checkAllocated(); revDescI->checkAllocated();
5439   if(getSpaceDimension()!=2 || getMeshDimension()!=2)
5440     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : this must have spacedim=meshdim=2 !");
5441   if(mesh1Desc->getSpaceDimension()!=2 || mesh1Desc->getMeshDimension()!=1)
5442     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : mesh1Desc must be the explosion of this with spaceDim=2 and meshDim = 1 !");
5443   //DataArrayInt *out0(0),*outi0(0);
5444   //MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
5445   //MCAuto<DataArrayInt> out0s(out0),outi0s(outi0);
5446   //out0s=out0s->buildUnique(); out0s->sort(true);
5447 }
5448 #endif
5449
5450 /*!
5451  * Implementes \a conversionType 0 for meshes with meshDim = 1, of MEDCouplingUMesh::convertLinearCellsToQuadratic method.
5452  * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5453  * \sa MEDCouplingUMesh::convertLinearCellsToQuadratic.
5454  */
5455 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic1D0(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5456 {
5457   MCAuto<DataArrayDouble> bary=computeCellCenterOfMass();
5458   MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5459   MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5460   MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
5461   int nbOfCells=getNumberOfCells();
5462   int nbOfNodes=getNumberOfNodes();
5463   const int *cPtr=_nodal_connec->begin();
5464   const int *icPtr=_nodal_connec_index->begin();
5465   int lastVal=0,offset=nbOfNodes;
5466   for(int i=0;i<nbOfCells;i++,icPtr++)
5467     {
5468       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5469       if(type==INTERP_KERNEL::NORM_SEG2)
5470         {
5471           types.insert(INTERP_KERNEL::NORM_SEG3);
5472           newConn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG3);
5473           newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[0]+3);
5474           newConn->pushBackSilent(offset++);
5475           lastVal+=4;
5476           newConnI->pushBackSilent(lastVal);
5477           ret->pushBackSilent(i);
5478         }
5479       else
5480         {
5481           types.insert(type);
5482           lastVal+=(icPtr[1]-icPtr[0]);
5483           newConnI->pushBackSilent(lastVal);
5484           newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5485         }
5486     }
5487   MCAuto<DataArrayDouble> tmp=bary->selectByTupleIdSafe(ret->begin(),ret->end());
5488   coords=DataArrayDouble::Aggregate(getCoords(),tmp); conn=newConn.retn(); connI=newConnI.retn();
5489   return ret.retn();
5490 }
5491
5492 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
5493 {
5494   MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5495   MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5496   MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
5497   //
5498   const int *descPtr(desc->begin()),*descIPtr(descI->begin());
5499   DataArrayInt *conn1D=0,*conn1DI=0;
5500   std::set<INTERP_KERNEL::NormalizedCellType> types1D;
5501   DataArrayDouble *coordsTmp=0;
5502   MCAuto<DataArrayInt> ret1D=m1D->convertLinearCellsToQuadratic1D0(conn1D,conn1DI,coordsTmp,types1D); ret1D=0;
5503   MCAuto<DataArrayDouble> coordsTmpSafe(coordsTmp);
5504   MCAuto<DataArrayInt> conn1DSafe(conn1D),conn1DISafe(conn1DI);
5505   const int *c1DPtr=conn1D->begin();
5506   const int *c1DIPtr=conn1DI->begin();
5507   int nbOfCells=getNumberOfCells();
5508   const int *cPtr=_nodal_connec->begin();
5509   const int *icPtr=_nodal_connec_index->begin();
5510   int lastVal=0;
5511   for(int i=0;i<nbOfCells;i++,icPtr++,descIPtr++)
5512     {
5513       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5514       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
5515       if(!cm.isQuadratic())
5516         {
5517           INTERP_KERNEL::NormalizedCellType typ2=cm.getQuadraticType();
5518           types.insert(typ2); newConn->pushBackSilent(typ2);
5519           newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[1]);
5520           for(const int *d=descPtr+descIPtr[0];d!=descPtr+descIPtr[1];d++)
5521             newConn->pushBackSilent(c1DPtr[c1DIPtr[*d]+3]);
5522           lastVal+=(icPtr[1]-icPtr[0])+(descIPtr[1]-descIPtr[0]);
5523           newConnI->pushBackSilent(lastVal);
5524           ret->pushBackSilent(i);
5525         }
5526       else
5527         {
5528           types.insert(typ);
5529           lastVal+=(icPtr[1]-icPtr[0]);
5530           newConnI->pushBackSilent(lastVal);
5531           newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5532         }
5533     }
5534   conn=newConn.retn(); connI=newConnI.retn(); coords=coordsTmpSafe.retn();
5535   return ret.retn();
5536 }
5537
5538 /*!
5539  * Implementes \a conversionType 0 for meshes with meshDim = 2, of MEDCouplingUMesh::convertLinearCellsToQuadratic method.
5540  * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5541  * \sa MEDCouplingUMesh::convertLinearCellsToQuadratic.
5542  */
5543 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic2D0(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5544 {
5545   MCAuto<DataArrayInt> desc(DataArrayInt::New()),descI(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5546   MCAuto<MEDCouplingUMesh> m1D=buildDescendingConnectivity(desc,descI,tmp2,tmp3); tmp2=0; tmp3=0;
5547   return convertLinearCellsToQuadratic2DAnd3D0(m1D,desc,descI,conn,connI,coords,types);
5548 }
5549
5550 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic2D1(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5551 {
5552   MCAuto<DataArrayInt> desc(DataArrayInt::New()),descI(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5553   MCAuto<MEDCouplingUMesh> m1D=buildDescendingConnectivity(desc,descI,tmp2,tmp3); tmp2=0; tmp3=0;
5554   //
5555   MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5556   MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5557   MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
5558   //
5559   MCAuto<DataArrayDouble> bary=computeCellCenterOfMass();
5560   const int *descPtr(desc->begin()),*descIPtr(descI->begin());
5561   DataArrayInt *conn1D=0,*conn1DI=0;
5562   std::set<INTERP_KERNEL::NormalizedCellType> types1D;
5563   DataArrayDouble *coordsTmp=0;
5564   MCAuto<DataArrayInt> ret1D=m1D->convertLinearCellsToQuadratic1D0(conn1D,conn1DI,coordsTmp,types1D); ret1D=0;
5565   MCAuto<DataArrayDouble> coordsTmpSafe(coordsTmp);
5566   MCAuto<DataArrayInt> conn1DSafe(conn1D),conn1DISafe(conn1DI);
5567   const int *c1DPtr=conn1D->begin();
5568   const int *c1DIPtr=conn1DI->begin();
5569   int nbOfCells=getNumberOfCells();
5570   const int *cPtr=_nodal_connec->begin();
5571   const int *icPtr=_nodal_connec_index->begin();
5572   int lastVal=0,offset=coordsTmpSafe->getNumberOfTuples();
5573   for(int i=0;i<nbOfCells;i++,icPtr++,descIPtr++)
5574     {
5575       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5576       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
5577       if(!cm.isQuadratic())
5578         {
5579           INTERP_KERNEL::NormalizedCellType typ2=cm.getQuadraticType2();
5580           types.insert(typ2); newConn->pushBackSilent(typ2);
5581           newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[1]);
5582           for(const int *d=descPtr+descIPtr[0];d!=descPtr+descIPtr[1];d++)
5583             newConn->pushBackSilent(c1DPtr[c1DIPtr[*d]+3]);
5584           newConn->pushBackSilent(offset+ret->getNumberOfTuples());
5585           lastVal+=(icPtr[1]-icPtr[0])+(descIPtr[1]-descIPtr[0])+1;
5586           newConnI->pushBackSilent(lastVal);
5587           ret->pushBackSilent(i);
5588         }
5589       else
5590         {
5591           types.insert(typ);
5592           lastVal+=(icPtr[1]-icPtr[0]);
5593           newConnI->pushBackSilent(lastVal);
5594           newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5595         }
5596     }
5597   MCAuto<DataArrayDouble> tmp=bary->selectByTupleIdSafe(ret->begin(),ret->end());
5598   coords=DataArrayDouble::Aggregate(coordsTmpSafe,tmp); conn=newConn.retn(); connI=newConnI.retn();
5599   return ret.retn();
5600 }
5601
5602 /*!
5603  * Implementes \a conversionType 0 for meshes with meshDim = 3, of MEDCouplingUMesh::convertLinearCellsToQuadratic method.
5604  * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5605  * \sa MEDCouplingUMesh::convertLinearCellsToQuadratic.
5606  */
5607 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic3D0(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5608 {
5609   MCAuto<DataArrayInt> desc(DataArrayInt::New()),descI(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5610   MCAuto<MEDCouplingUMesh> m1D=explode3DMeshTo1D(desc,descI,tmp2,tmp3); tmp2=0; tmp3=0;
5611   return convertLinearCellsToQuadratic2DAnd3D0(m1D,desc,descI,conn,connI,coords,types);
5612 }
5613
5614 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic3D1(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5615 {
5616   MCAuto<DataArrayInt> desc2(DataArrayInt::New()),desc2I(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5617   MCAuto<MEDCouplingUMesh> m2D=buildDescendingConnectivityGen<MinusOneSonsGeneratorBiQuadratic>(desc2,desc2I,tmp2,tmp3,MEDCouplingFastNbrer); tmp2=0; tmp3=0;
5618   MCAuto<DataArrayInt> desc1(DataArrayInt::New()),desc1I(DataArrayInt::New()),tmp4(DataArrayInt::New()),tmp5(DataArrayInt::New());
5619   MCAuto<MEDCouplingUMesh> m1D=explode3DMeshTo1D(desc1,desc1I,tmp4,tmp5); tmp4=0; tmp5=0;
5620   //
5621   MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5622   MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5623   MCAuto<DataArrayInt> ret=DataArrayInt::New(),ret2=DataArrayInt::New(); ret->alloc(0,1); ret2->alloc(0,1);
5624   //
5625   MCAuto<DataArrayDouble> bary=computeCellCenterOfMass();
5626   const int *descPtr(desc1->begin()),*descIPtr(desc1I->begin()),*desc2Ptr(desc2->begin()),*desc2IPtr(desc2I->begin());
5627   DataArrayInt *conn1D=0,*conn1DI=0,*conn2D=0,*conn2DI=0;
5628   std::set<INTERP_KERNEL::NormalizedCellType> types1D,types2D;
5629   DataArrayDouble *coordsTmp=0,*coordsTmp2=0;
5630   MCAuto<DataArrayInt> ret1D=m1D->convertLinearCellsToQuadratic1D0(conn1D,conn1DI,coordsTmp,types1D); ret1D=DataArrayInt::New(); ret1D->alloc(0,1);
5631   MCAuto<DataArrayInt> conn1DSafe(conn1D),conn1DISafe(conn1DI);
5632   MCAuto<DataArrayDouble> coordsTmpSafe(coordsTmp);
5633   MCAuto<DataArrayInt> ret2D=m2D->convertLinearCellsToQuadratic2D1(conn2D,conn2DI,coordsTmp2,types2D); ret2D=DataArrayInt::New(); ret2D->alloc(0,1);
5634   MCAuto<DataArrayDouble> coordsTmp2Safe(coordsTmp2);
5635   MCAuto<DataArrayInt> conn2DSafe(conn2D),conn2DISafe(conn2DI);
5636   const int *c1DPtr=conn1D->begin(),*c1DIPtr=conn1DI->begin(),*c2DPtr=conn2D->begin(),*c2DIPtr=conn2DI->begin();
5637   int nbOfCells=getNumberOfCells();
5638   const int *cPtr=_nodal_connec->begin();
5639   const int *icPtr=_nodal_connec_index->begin();
5640   int lastVal=0,offset=coordsTmpSafe->getNumberOfTuples();
5641   for(int i=0;i<nbOfCells;i++,icPtr++,descIPtr++,desc2IPtr++)
5642     {
5643       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5644       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
5645       if(!cm.isQuadratic())
5646         {
5647           INTERP_KERNEL::NormalizedCellType typ2=cm.getQuadraticType2();
5648           if(typ2==INTERP_KERNEL::NORM_ERROR)
5649             {
5650               std::ostringstream oss; oss << "MEDCouplingUMesh::convertLinearCellsToQuadratic3D1 : On cell #" << i << " the linear cell type does not support advanced quadratization !";
5651               throw INTERP_KERNEL::Exception(oss.str());
5652             }
5653           types.insert(typ2); newConn->pushBackSilent(typ2);
5654           newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[1]);
5655           for(const int *d=descPtr+descIPtr[0];d!=descPtr+descIPtr[1];d++)
5656             newConn->pushBackSilent(c1DPtr[c1DIPtr[*d]+3]);
5657           for(const int *d=desc2Ptr+desc2IPtr[0];d!=desc2Ptr+desc2IPtr[1];d++)
5658             {
5659               int nodeId2=c2DPtr[c2DIPtr[(*d)+1]-1];
5660               int tmpPos=newConn->getNumberOfTuples();
5661               newConn->pushBackSilent(nodeId2);
5662               ret2D->pushBackSilent(nodeId2); ret1D->pushBackSilent(tmpPos);
5663             }
5664           newConn->pushBackSilent(offset+ret->getNumberOfTuples());
5665           lastVal+=(icPtr[1]-icPtr[0])+(descIPtr[1]-descIPtr[0])+(desc2IPtr[1]-desc2IPtr[0])+1;
5666           newConnI->pushBackSilent(lastVal);
5667           ret->pushBackSilent(i);
5668         }
5669       else
5670         {
5671           types.insert(typ);
5672           lastVal+=(icPtr[1]-icPtr[0]);
5673           newConnI->pushBackSilent(lastVal);
5674           newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5675         }
5676     }
5677   MCAuto<DataArrayInt> diffRet2D=ret2D->getDifferentValues();
5678   MCAuto<DataArrayInt> o2nRet2D=diffRet2D->invertArrayN2O2O2N(coordsTmp2Safe->getNumberOfTuples());
5679   coordsTmp2Safe=coordsTmp2Safe->selectByTupleId(diffRet2D->begin(),diffRet2D->end());
5680   MCAuto<DataArrayDouble> tmp=bary->selectByTupleIdSafe(ret->begin(),ret->end());
5681   std::vector<const DataArrayDouble *> v(3); v[0]=coordsTmpSafe; v[1]=coordsTmp2Safe; v[2]=tmp;
5682   int *c=newConn->getPointer();
5683   const int *cI(newConnI->begin());
5684   for(const int *elt=ret1D->begin();elt!=ret1D->end();elt++)
5685     c[*elt]=o2nRet2D->getIJ(c[*elt],0)+offset;
5686   offset=coordsTmp2Safe->getNumberOfTuples();
5687   for(const int *elt=ret->begin();elt!=ret->end();elt++)
5688     c[cI[(*elt)+1]-1]+=offset;
5689   coords=DataArrayDouble::Aggregate(v); conn=newConn.retn(); connI=newConnI.retn();
5690   return ret.retn();
5691 }
5692
5693 /*!
5694  * Divides every cell of \a this mesh into simplices (triangles in 2D and tetrahedra in 3D).
5695  * In addition, returns an array mapping new cells to old ones. <br>
5696  * This method typically increases the number of cells in \a this mesh
5697  * but the number of nodes remains \b unchanged.
5698  * That's why the 3D splitting policies
5699  * INTERP_KERNEL::GENERAL_24 and INTERP_KERNEL::GENERAL_48 are not available here.
5700  *  \param [in] policy - specifies a pattern used for splitting.
5701  * The semantic of \a policy is:
5702  * - 0 - to split QUAD4 by cutting it along 0-2 diagonal (for 2D mesh only).
5703  * - 1 - to split QUAD4 by cutting it along 1-3 diagonal (for 2D mesh only).
5704  * - INTERP_KERNEL::PLANAR_FACE_5 - to split HEXA8  into 5 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
5705  * - INTERP_KERNEL::PLANAR_FACE_6 - to split HEXA8  into 6 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
5706  *
5707  *
5708  *  \return DataArrayInt * - a new instance of DataArrayInt holding, for each new cell,
5709  *          an id of old cell producing it. The caller is to delete this array using
5710  *         decrRef() as it is no more needed.
5711  *
5712  *  \throw If \a policy is 0 or 1 and \a this->getMeshDimension() != 2.
5713  *  \throw If \a policy is INTERP_KERNEL::PLANAR_FACE_5 or INTERP_KERNEL::PLANAR_FACE_6
5714  *          and \a this->getMeshDimension() != 3. 
5715  *  \throw If \a policy is not one of the four discussed above.
5716  *  \throw If the nodal connectivity of cells is not defined.
5717  * \sa MEDCouplingUMesh::tetrahedrize, MEDCoupling1SGTUMesh::sortHexa8EachOther
5718  */
5719 DataArrayInt *MEDCouplingUMesh::simplexize(int policy)
5720 {
5721   switch(policy)
5722   {
5723     case 0:
5724       return simplexizePol0();
5725     case 1:
5726       return simplexizePol1();
5727     case (int) INTERP_KERNEL::PLANAR_FACE_5:
5728         return simplexizePlanarFace5();
5729     case (int) INTERP_KERNEL::PLANAR_FACE_6:
5730         return simplexizePlanarFace6();
5731     default:
5732       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)");
5733   }
5734 }
5735
5736 /*!
5737  * Checks if \a this mesh is constituted by simplex cells only. Simplex cells are:
5738  * - 1D: INTERP_KERNEL::NORM_SEG2
5739  * - 2D: INTERP_KERNEL::NORM_TRI3
5740  * - 3D: INTERP_KERNEL::NORM_TETRA4.
5741  *
5742  * This method is useful for users that need to use P1 field services as
5743  * MEDCouplingFieldDouble::getValueOn(), MEDCouplingField::buildMeasureField() etc.
5744  * All these methods need mesh support containing only simplex cells.
5745  *  \return bool - \c true if there are only simplex cells in \a this mesh.
5746  *  \throw If the coordinates array is not set.
5747  *  \throw If the nodal connectivity of cells is not defined.
5748  *  \throw If \a this->getMeshDimension() < 1.
5749  */
5750 bool MEDCouplingUMesh::areOnlySimplexCells() const
5751 {
5752   checkFullyDefined();
5753   int mdim=getMeshDimension();
5754   if(mdim<1 || mdim>3)
5755     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::areOnlySimplexCells : only available with meshes having a meshdim 1, 2 or 3 !");
5756   int nbCells=getNumberOfCells();
5757   const int *conn=_nodal_connec->begin();
5758   const int *connI=_nodal_connec_index->begin();
5759   for(int i=0;i<nbCells;i++)
5760     {
5761       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5762       if(!cm.isSimplex())
5763         return false;
5764     }
5765   return true;
5766 }
5767
5768 /*!
5769  * This method implements policy 0 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5770  */
5771 DataArrayInt *MEDCouplingUMesh::simplexizePol0()
5772 {
5773   checkConnectivityFullyDefined();
5774   if(getMeshDimension()!=2)
5775     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePol0 : this policy is only available for mesh with meshdim == 2 !");
5776   int nbOfCells=getNumberOfCells();
5777   MCAuto<DataArrayInt> ret=DataArrayInt::New();
5778   int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_QUAD4);
5779   ret->alloc(nbOfCells+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+nbOfCutCells+1,1);
5785   newConn->alloc(getNodalConnectivityArrayLen()+3*nbOfCutCells,1);
5786   int *pt=newConn->getPointer();
5787   int *ptI=newConnI->getPointer();
5788   ptI[0]=0;
5789   const int *oldc=_nodal_connec->begin();
5790   const int *ci=_nodal_connec_index->begin();
5791   for(int i=0;i<nbOfCells;i++,ci++)
5792     {
5793       if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_QUAD4)
5794         {
5795           const int tmp[8]={(int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+1],oldc[ci[0]+2],oldc[ci[0]+3],
5796             (int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+1],oldc[ci[0]+3],oldc[ci[0]+4]};
5797           pt=std::copy(tmp,tmp+8,pt);
5798           ptI[1]=ptI[0]+4;
5799           ptI[2]=ptI[0]+8;
5800           *retPt++=i;
5801           *retPt++=i;
5802           ptI+=2;
5803         }
5804       else
5805         {
5806           pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5807           ptI[1]=ptI[0]+ci[1]-ci[0];
5808           ptI++;
5809           *retPt++=i;
5810         }
5811     }
5812   _nodal_connec->decrRef();
5813   _nodal_connec=newConn.retn();
5814   _nodal_connec_index->decrRef();
5815   _nodal_connec_index=newConnI.retn();
5816   computeTypes();
5817   updateTime();
5818   return ret.retn();
5819 }
5820
5821 /*!
5822  * This method implements policy 1 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5823  */
5824 DataArrayInt *MEDCouplingUMesh::simplexizePol1()
5825 {
5826   checkConnectivityFullyDefined();
5827   if(getMeshDimension()!=2)
5828     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePol0 : this policy is only available for mesh with meshdim == 2 !");
5829   int nbOfCells=getNumberOfCells();
5830   MCAuto<DataArrayInt> ret=DataArrayInt::New();
5831   int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_QUAD4);
5832   ret->alloc(nbOfCells+nbOfCutCells,1);
5833   if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5834   int *retPt=ret->getPointer();
5835   MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5836   MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5837   newConnI->alloc(nbOfCells+nbOfCutCells+1,1);
5838   newConn->alloc(getNodalConnectivityArrayLen()+3*nbOfCutCells,1);
5839   int *pt=newConn->getPointer();
5840   int *ptI=newConnI->getPointer();
5841   ptI[0]=0;
5842   const int *oldc=_nodal_connec->begin();
5843   const int *ci=_nodal_connec_index->begin();
5844   for(int i=0;i<nbOfCells;i++,ci++)
5845     {
5846       if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_QUAD4)
5847         {
5848           const int tmp[8]={(int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+1],oldc[ci[0]+2],oldc[ci[0]+4],
5849             (int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+2],oldc[ci[0]+3],oldc[ci[0]+4]};
5850           pt=std::copy(tmp,tmp+8,pt);
5851           ptI[1]=ptI[0]+4;
5852           ptI[2]=ptI[0]+8;
5853           *retPt++=i;
5854           *retPt++=i;
5855           ptI+=2;
5856         }
5857       else
5858         {
5859           pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5860           ptI[1]=ptI[0]+ci[1]-ci[0];
5861           ptI++;
5862           *retPt++=i;
5863         }
5864     }
5865   _nodal_connec->decrRef();
5866   _nodal_connec=newConn.retn();
5867   _nodal_connec_index->decrRef();
5868   _nodal_connec_index=newConnI.retn();
5869   computeTypes();
5870   updateTime();
5871   return ret.retn();
5872 }
5873
5874 /*!
5875  * This method implements policy INTERP_KERNEL::PLANAR_FACE_5 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5876  */
5877 DataArrayInt *MEDCouplingUMesh::simplexizePlanarFace5()
5878 {
5879   checkConnectivityFullyDefined();
5880   if(getMeshDimension()!=3)
5881     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePlanarFace5 : this policy is only available for mesh with meshdim == 3 !");
5882   int nbOfCells=getNumberOfCells();
5883   MCAuto<DataArrayInt> ret=DataArrayInt::New();
5884   int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_HEXA8);
5885   ret->alloc(nbOfCells+4*nbOfCutCells,1);
5886   if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5887   int *retPt=ret->getPointer();
5888   MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5889   MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5890   newConnI->alloc(nbOfCells+4*nbOfCutCells+1,1);
5891   newConn->alloc(getNodalConnectivityArrayLen()+16*nbOfCutCells,1);//21
5892   int *pt=newConn->getPointer();
5893   int *ptI=newConnI->getPointer();
5894   ptI[0]=0;
5895   const int *oldc=_nodal_connec->begin();
5896   const int *ci=_nodal_connec_index->begin();
5897   for(int i=0;i<nbOfCells;i++,ci++)
5898     {
5899       if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_HEXA8)
5900         {
5901           for(int j=0;j<5;j++,pt+=5,ptI++)
5902             {
5903               pt[0]=(int)INTERP_KERNEL::NORM_TETRA4;
5904               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];
5905               *retPt++=i;
5906               ptI[1]=ptI[0]+5;
5907             }
5908         }
5909       else
5910         {
5911           pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5912           ptI[1]=ptI[0]+ci[1]-ci[0];
5913           ptI++;
5914           *retPt++=i;
5915         }
5916     }
5917   _nodal_connec->decrRef();
5918   _nodal_connec=newConn.retn();
5919   _nodal_connec_index->decrRef();
5920   _nodal_connec_index=newConnI.retn();
5921   computeTypes();
5922   updateTime();
5923   return ret.retn();
5924 }
5925
5926 /*!
5927  * This method implements policy INTERP_KERNEL::PLANAR_FACE_6 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5928  */
5929 DataArrayInt *MEDCouplingUMesh::simplexizePlanarFace6()
5930 {
5931   checkConnectivityFullyDefined();
5932   if(getMeshDimension()!=3)
5933     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePlanarFace6 : this policy is only available for mesh with meshdim == 3 !");
5934   int nbOfCells=getNumberOfCells();
5935   MCAuto<DataArrayInt> ret=DataArrayInt::New();
5936   int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_HEXA8);
5937   ret->alloc(nbOfCells+5*nbOfCutCells,1);
5938   if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5939   int *retPt=ret->getPointer();
5940   MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5941   MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5942   newConnI->alloc(nbOfCells+5*nbOfCutCells+1,1);
5943   newConn->alloc(getNodalConnectivityArrayLen()+21*nbOfCutCells,1);
5944   int *pt=newConn->getPointer();
5945   int *ptI=newConnI->getPointer();
5946   ptI[0]=0;
5947   const int *oldc=_nodal_connec->begin();
5948   const int *ci=_nodal_connec_index->begin();
5949   for(int i=0;i<nbOfCells;i++,ci++)
5950     {
5951       if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_HEXA8)
5952         {
5953           for(int j=0;j<6;j++,pt+=5,ptI++)
5954             {
5955               pt[0]=(int)INTERP_KERNEL::NORM_TETRA4;
5956               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];
5957               *retPt++=i;
5958               ptI[1]=ptI[0]+5;
5959             }
5960         }
5961       else
5962         {
5963           pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5964           ptI[1]=ptI[0]+ci[1]-ci[0];
5965           ptI++;
5966           *retPt++=i;
5967         }
5968     }
5969   _nodal_connec->decrRef();
5970   _nodal_connec=newConn.retn();
5971   _nodal_connec_index->decrRef();
5972   _nodal_connec_index=newConnI.retn();
5973   computeTypes();
5974   updateTime();
5975   return ret.retn();
5976 }
5977
5978 /*!
5979  * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
5980  * so that the number of cells remains the same. Quadratic faces are converted to
5981  * polygons. This method works only for 2D meshes in
5982  * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
5983  * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
5984  * \warning This method can lead to a huge amount of nodes if \a eps is very low.
5985  *  \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
5986  *         a polylinized edge constituting the input polygon.
5987  *  \throw If the coordinates array is not set.
5988  *  \throw If the nodal connectivity of cells is not defined.
5989  *  \throw If \a this->getMeshDimension() != 2.
5990  *  \throw If \a this->getSpaceDimension() != 2.
5991  */
5992 void MEDCouplingUMesh::tessellate2DInternal(double eps)
5993 {
5994   checkFullyDefined();
5995   if(getMeshDimension()!=2 || getSpaceDimension()!=2)  
5996     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2DInternal works on umeshes with meshdim equal to 2 and spaceDim equal to 2 too!");
5997   double epsa=fabs(eps);
5998   if(epsa<std::numeric_limits<double>::min())
5999     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 !");
6000   MCAuto<DataArrayInt> desc1(DataArrayInt::New()),descIndx1(DataArrayInt::New()),revDesc1(DataArrayInt::New()),revDescIndx1(DataArrayInt::New());
6001   MCAuto<MEDCouplingUMesh> mDesc(buildDescendingConnectivity2(desc1,descIndx1,revDesc1,revDescIndx1));
6002   revDesc1=0; revDescIndx1=0;
6003   mDesc->tessellate2D(eps);
6004   subDivide2DMesh(mDesc->_nodal_connec->begin(),mDesc->_nodal_connec_index->begin(),desc1->begin(),descIndx1->begin());
6005   setCoords(mDesc->getCoords());
6006 }
6007
6008 /*!
6009  * Tessellates \a this 1D mesh in 2D space by dividing not straight quadratic edges.
6010  * \warning This method can lead to a huge amount of nodes if \a eps is very low.
6011  *  \param [in] eps - specifies the maximal angle (in radian) between 2 sub-edges of
6012  *         a sub-divided edge.
6013  *  \throw If the coordinates array is not set.
6014  *  \throw If the nodal connectivity of cells is not defined.
6015  *  \throw If \a this->getMeshDimension() != 1.
6016  *  \throw If \a this->getSpaceDimension() != 2.
6017  */
6018 void MEDCouplingUMesh::tessellate2DCurveInternal(double eps)
6019 {
6020   checkFullyDefined();
6021   if(getMeshDimension()!=1 || getSpaceDimension()!=2)
6022     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2DCurveInternal works on umeshes with meshdim equal to 1 and spaceDim equal to 2 too!");
6023   double epsa=fabs(eps);
6024   if(epsa<std::numeric_limits<double>::min())
6025     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 !");
6026   INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=1.e-10;
6027   int nbCells=getNumberOfCells();
6028   int nbNodes=getNumberOfNodes();
6029   const int *conn=_nodal_connec->begin();
6030   const int *connI=_nodal_connec_index->begin();
6031   const double *coords=_coords->begin();
6032   std::vector<double> addCoo;
6033   std::vector<int> newConn;//no direct DataArrayInt because interface with Geometric2D
6034   MCAuto<DataArrayInt> newConnI(DataArrayInt::New());
6035   newConnI->alloc(nbCells+1,1);
6036   int *newConnIPtr=newConnI->getPointer();
6037   *newConnIPtr=0;
6038   int tmp1[3];
6039   INTERP_KERNEL::Node *tmp2[3];
6040   std::set<INTERP_KERNEL::NormalizedCellType> types;
6041   for(int i=0;i<nbCells;i++,newConnIPtr++)
6042     {
6043       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6044       if(cm.isQuadratic())
6045         {//assert(connI[i+1]-connI[i]-1==3)
6046           tmp1[0]=conn[connI[i]+1+0]; tmp1[1]=conn[connI[i]+1+1]; tmp1[2]=conn[connI[i]+1+2];
6047           tmp2[0]=new INTERP_KERNEL::Node(coords[2*tmp1[0]],coords[2*tmp1[0]+1]);
6048           tmp2[1]=new INTERP_KERNEL::Node(coords[2*tmp1[1]],coords[2*tmp1[1]+1]);
6049           tmp2[2]=new INTERP_KERNEL::Node(coords[2*tmp1[2]],coords[2*tmp1[2]+1]);
6050           INTERP_KERNEL::EdgeArcCircle *eac=INTERP_KERNEL::EdgeArcCircle::BuildFromNodes(tmp2[0],tmp2[2],tmp2[1]);
6051           if(eac)
6052             {
6053               eac->tesselate(tmp1,nbNodes,epsa,newConn,addCoo);
6054               types.insert((INTERP_KERNEL::NormalizedCellType)newConn[newConnIPtr[0]]);
6055               delete eac;
6056               newConnIPtr[1]=(int)newConn.size();
6057             }
6058           else
6059             {
6060               types.insert(INTERP_KERNEL::NORM_SEG2);
6061               newConn.push_back(INTERP_KERNEL::NORM_SEG2);
6062               newConn.insert(newConn.end(),conn+connI[i]+1,conn+connI[i]+3);
6063               newConnIPtr[1]=newConnIPtr[0]+3;
6064             }
6065         }
6066       else
6067         {
6068           types.insert((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6069           newConn.insert(newConn.end(),conn+connI[i],conn+connI[i+1]);
6070           newConnIPtr[1]=newConnIPtr[0]+3;
6071         }
6072     }
6073   if(addCoo.empty() && ((int)newConn.size())==_nodal_connec->getNumberOfTuples())//nothing happens during tessellation : no update needed
6074     return ;
6075   _types=types;
6076   DataArrayInt::SetArrayIn(newConnI,_nodal_connec_index);
6077   MCAuto<DataArrayInt> newConnArr=DataArrayInt::New();
6078   newConnArr->alloc((int)newConn.size(),1);
6079   std::copy(newConn.begin(),newConn.end(),newConnArr->getPointer());
6080   DataArrayInt::SetArrayIn(newConnArr,_nodal_connec);
6081   MCAuto<DataArrayDouble> newCoords=DataArrayDouble::New();
6082   newCoords->alloc(nbNodes+((int)addCoo.size())/2,2);
6083   double *work=std::copy(_coords->begin(),_coords->end(),newCoords->getPointer());
6084   std::copy(addCoo.begin(),addCoo.end(),work);
6085   DataArrayDouble::SetArrayIn(newCoords,_coords);
6086   updateTime();
6087 }
6088
6089 /*!
6090  * 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.
6091  * This method completly ignore coordinates.
6092  * \param nodeSubdived is the nodal connectivity of subdivision of edges
6093  * \param nodeIndxSubdived is the nodal connectivity index of subdivision of edges
6094  * \param desc is descending connectivity in format specified in MEDCouplingUMesh::buildDescendingConnectivity2
6095  * \param descIndex is descending connectivity index in format specified in MEDCouplingUMesh::buildDescendingConnectivity2
6096  */
6097 void MEDCouplingUMesh::subDivide2DMesh(const int *nodeSubdived, const int *nodeIndxSubdived, const int *desc, const int *descIndex)
6098 {
6099   checkFullyDefined();
6100   if(getMeshDimension()!=2)
6101     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::subDivide2DMesh : works only on umesh with meshdim==2 !");
6102   int nbOfCells=getNumberOfCells();
6103   int *connI=_nodal_connec_index->getPointer();
6104   int newConnLgth=0;
6105   for(int i=0;i<nbOfCells;i++,connI++)
6106     {
6107       int offset=descIndex[i];
6108       int nbOfEdges=descIndex[i+1]-offset;
6109       //
6110       bool ddirect=desc[offset+nbOfEdges-1]>0;
6111       int eedgeId=std::abs(desc[offset+nbOfEdges-1])-1;
6112       int ref=ddirect?nodeSubdived[nodeIndxSubdived[eedgeId+1]-1]:nodeSubdived[nodeIndxSubdived[eedgeId]+1];
6113       for(int j=0;j<nbOfEdges;j++)
6114         {
6115           bool direct=desc[offset+j]>0;
6116           int edgeId=std::abs(desc[offset+j])-1;
6117           if(!INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)nodeSubdived[nodeIndxSubdived[edgeId]]).isQuadratic())
6118             {
6119               int id1=nodeSubdived[nodeIndxSubdived[edgeId]+1];
6120               int id2=nodeSubdived[nodeIndxSubdived[edgeId+1]-1];
6121               int ref2=direct?id1:id2;
6122               if(ref==ref2)
6123                 {
6124                   int nbOfSubNodes=nodeIndxSubdived[edgeId+1]-nodeIndxSubdived[edgeId]-1;
6125                   newConnLgth+=nbOfSubNodes-1;
6126                   ref=direct?id2:id1;
6127                 }
6128               else
6129                 {
6130                   std::ostringstream oss; oss << "MEDCouplingUMesh::subDivide2DMesh : On polygon #" << i << " edgeid #" << j << " subedges mismatch : end subedge k!=start subedge k+1 !";
6131                   throw INTERP_KERNEL::Exception(oss.str());
6132                 }
6133             }
6134           else
6135             {
6136               throw INTERP_KERNEL::Exception("MEDCouplingUMesh::subDivide2DMesh : this method only subdivides into linear edges !");
6137             }
6138         }
6139       newConnLgth++;//+1 is for cell type
6140       connI[1]=newConnLgth;
6141     }
6142   //
6143   MCAuto<DataArrayInt> newConn=DataArrayInt::New();
6144   newConn->alloc(newConnLgth,1);
6145   int *work=newConn->getPointer();
6146   for(int i=0;i<nbOfCells;i++)
6147     {
6148       *work++=INTERP_KERNEL::NORM_POLYGON;
6149       int offset=descIndex[i];
6150       int nbOfEdges=descIndex[i+1]-offset;
6151       for(int j=0;j<nbOfEdges;j++)
6152         {
6153           bool direct=desc[offset+j]>0;
6154           int edgeId=std::abs(desc[offset+j])-1;
6155           if(direct)
6156             work=std::copy(nodeSubdived+nodeIndxSubdived[edgeId]+1,nodeSubdived+nodeIndxSubdived[edgeId+1]-1,work);
6157           else
6158             {
6159               int nbOfSubNodes=nodeIndxSubdived[edgeId+1]-nodeIndxSubdived[edgeId]-1;
6160               std::reverse_iterator<const int *> it(nodeSubdived+nodeIndxSubdived[edgeId+1]);
6161               work=std::copy(it,it+nbOfSubNodes-1,work);
6162             }
6163         }
6164     }
6165   DataArrayInt::SetArrayIn(newConn,_nodal_connec);
6166   _types.clear();
6167   if(nbOfCells>0)
6168     _types.insert(INTERP_KERNEL::NORM_POLYGON);
6169 }
6170
6171 /*!
6172  * Converts degenerated 2D or 3D linear cells of \a this mesh into cells of simpler
6173  * type. For example an INTERP_KERNEL::NORM_QUAD4 cell having only three unique nodes in
6174  * its connectivity is transformed into an INTERP_KERNEL::NORM_TRI3 cell. This method
6175  * does \b not perform geometrical checks and checks only nodal connectivity of cells,
6176  * so it can be useful to call mergeNodes() before calling this method.
6177  *  \throw If \a this->getMeshDimension() <= 1.
6178  *  \throw If the coordinates array is not set.
6179  *  \throw If the nodal connectivity of cells is not defined.
6180  */
6181 void MEDCouplingUMesh::convertDegeneratedCells()
6182 {
6183   checkFullyDefined();
6184   if(getMeshDimension()<=1)
6185     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
6186   int nbOfCells=getNumberOfCells();
6187   if(nbOfCells<1)
6188     return ;
6189   int initMeshLgth=getNodalConnectivityArrayLen();
6190   int *conn=_nodal_connec->getPointer();
6191   int *index=_nodal_connec_index->getPointer();
6192   int posOfCurCell=0;
6193   int newPos=0;
6194   int lgthOfCurCell;
6195   for(int i=0;i<nbOfCells;i++)
6196     {
6197       lgthOfCurCell=index[i+1]-posOfCurCell;
6198       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
6199       int newLgth;
6200       INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
6201                                                                                                      conn+newPos+1,newLgth);
6202       conn[newPos]=newType;
6203       newPos+=newLgth+1;
6204       posOfCurCell=index[i+1];
6205       index[i+1]=newPos;
6206     }
6207   if(newPos!=initMeshLgth)
6208     _nodal_connec->reAlloc(newPos);
6209   computeTypes();
6210 }
6211
6212 /*!
6213  * Finds incorrectly oriented cells of this 2D mesh in 3D space.
6214  * A cell is considered to be oriented correctly if an angle between its
6215  * normal vector and a given vector is less than \c PI / \c 2.
6216  *  \param [in] vec - 3 components of the vector specifying the correct orientation of
6217  *         cells. 
6218  *  \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
6219  *         checked.
6220  *  \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
6221  *         is not cleared before filling in.
6222  *  \throw If \a this->getMeshDimension() != 2.
6223  *  \throw If \a this->getSpaceDimension() != 3.
6224  *
6225  *  \if ENABLE_EXAMPLES
6226  *  \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
6227  *  \ref  py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
6228  *  \endif
6229  */
6230 void MEDCouplingUMesh::are2DCellsNotCorrectlyOriented(const double *vec, bool polyOnly, std::vector<int>& cells) const
6231 {
6232   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
6233     throw INTERP_KERNEL::Exception("Invalid mesh to apply are2DCellsNotCorrectlyOriented on it : must be meshDim==2 and spaceDim==3 !");
6234   int nbOfCells=getNumberOfCells();
6235   const int *conn=_nodal_connec->begin();
6236   const int *connI=_nodal_connec_index->begin();
6237   const double *coordsPtr=_coords->begin();
6238   for(int i=0;i<nbOfCells;i++)
6239     {
6240       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6241       if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
6242         {
6243           bool isQuadratic=INTERP_KERNEL::CellModel::GetCellModel(type).isQuadratic();
6244           if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6245             cells.push_back(i);
6246         }
6247     }
6248 }
6249
6250 /*!
6251  * Reverse connectivity of 2D cells whose orientation is not correct. A cell is
6252  * considered to be oriented correctly if an angle between its normal vector and a
6253  * given vector is less than \c PI / \c 2. 
6254  *  \param [in] vec - 3 components of the vector specifying the correct orientation of
6255  *         cells. 
6256  *  \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
6257  *         checked.
6258  *  \throw If \a this->getMeshDimension() != 2.
6259  *  \throw If \a this->getSpaceDimension() != 3.
6260  *
6261  *  \if ENABLE_EXAMPLES
6262  *  \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
6263  *  \ref  py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
6264  *  \endif
6265  *
6266  *  \sa changeOrientationOfCells
6267  */
6268 void MEDCouplingUMesh::orientCorrectly2DCells(const double *vec, bool polyOnly)
6269 {
6270   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
6271     throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectly2DCells on it : must be meshDim==2 and spaceDim==3 !");
6272   int nbOfCells(getNumberOfCells()),*conn(_nodal_connec->getPointer());
6273   const int *connI(_nodal_connec_index->begin());
6274   const double *coordsPtr(_coords->begin());
6275   bool isModified(false);
6276   for(int i=0;i<nbOfCells;i++)
6277     {
6278       INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6279       if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
6280         {
6281           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
6282           bool isQuadratic(cm.isQuadratic());
6283           if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6284             {
6285               isModified=true;
6286               cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
6287             }
6288         }
6289     }
6290   if(isModified)
6291     _nodal_connec->declareAsNew();
6292   updateTime();
6293 }
6294
6295 /*!
6296  * This method change the orientation of cells in \a this without any consideration of coordinates. Only connectivity is impacted.
6297  *
6298  * \sa orientCorrectly2DCells
6299  */
6300 void MEDCouplingUMesh::changeOrientationOfCells()
6301 {
6302   int mdim(getMeshDimension());
6303   if(mdim!=2 && mdim!=1)
6304     throw INTERP_KERNEL::Exception("Invalid mesh to apply changeOrientationOfCells on it : must be meshDim==2 or meshDim==1 !");
6305   int nbOfCells(getNumberOfCells()),*conn(_nodal_connec->getPointer());
6306   const int *connI(_nodal_connec_index->begin());
6307   if(mdim==2)
6308     {//2D
6309       for(int i=0;i<nbOfCells;i++)
6310         {
6311           INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6312           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
6313           cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
6314         }
6315     }
6316   else
6317     {//1D
6318       for(int i=0;i<nbOfCells;i++)
6319         {
6320           INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6321           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
6322           cm.changeOrientationOf1D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
6323         }
6324     }
6325 }
6326
6327 /*!
6328  * Finds incorrectly oriented polyhedral cells, i.e. polyhedrons having correctly
6329  * oriented facets. The normal vector of the facet should point out of the cell.
6330  *  \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
6331  *         is not cleared before filling in.
6332  *  \throw If \a this->getMeshDimension() != 3.
6333  *  \throw If \a this->getSpaceDimension() != 3.
6334  *  \throw If the coordinates array is not set.
6335  *  \throw If the nodal connectivity of cells is not defined.
6336  *
6337  *  \if ENABLE_EXAMPLES
6338  *  \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
6339  *  \ref  py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
6340  *  \endif
6341  */
6342 void MEDCouplingUMesh::arePolyhedronsNotCorrectlyOriented(std::vector<int>& cells) const
6343 {
6344   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
6345     throw INTERP_KERNEL::Exception("Invalid mesh to apply arePolyhedronsNotCorrectlyOriented on it : must be meshDim==3 and spaceDim==3 !");
6346   int nbOfCells=getNumberOfCells();
6347   const int *conn=_nodal_connec->begin();
6348   const int *connI=_nodal_connec_index->begin();
6349   const double *coordsPtr=_coords->begin();
6350   for(int i=0;i<nbOfCells;i++)
6351     {
6352       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6353       if(type==INTERP_KERNEL::NORM_POLYHED)
6354         {
6355           if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6356             cells.push_back(i);
6357         }
6358     }
6359 }
6360
6361 /*!
6362  * Tries to fix connectivity of polyhedra, so that normal vector of all facets to point
6363  * out of the cell. 
6364  *  \throw If \a this->getMeshDimension() != 3.
6365  *  \throw If \a this->getSpaceDimension() != 3.
6366  *  \throw If the coordinates array is not set.
6367  *  \throw If the nodal connectivity of cells is not defined.
6368  *  \throw If the reparation fails.
6369  *
6370  *  \if ENABLE_EXAMPLES
6371  *  \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
6372  *  \ref  py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
6373  *  \endif
6374  * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
6375  */
6376 void MEDCouplingUMesh::orientCorrectlyPolyhedrons()
6377 {
6378   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
6379     throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectlyPolyhedrons on it : must be meshDim==3 and spaceDim==3 !");
6380   int nbOfCells=getNumberOfCells();
6381   int *conn=_nodal_connec->getPointer();
6382   const int *connI=_nodal_connec_index->begin();
6383   const double *coordsPtr=_coords->begin();
6384   for(int i=0;i<nbOfCells;i++)
6385     {
6386       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6387       if(type==INTERP_KERNEL::NORM_POLYHED)
6388         {
6389           try
6390           {
6391               if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6392                 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
6393           }
6394           catch(INTERP_KERNEL::Exception& e)
6395           {
6396               std::ostringstream oss; oss << "Something wrong in polyhedron #" << i << " : " << e.what();
6397               throw INTERP_KERNEL::Exception(oss.str());
6398           }
6399         }
6400     }
6401   updateTime();
6402 }
6403
6404 /*!
6405  * Finds and fixes incorrectly oriented linear extruded volumes (INTERP_KERNEL::NORM_HEXA8,
6406  * INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXGP12 etc) to respect the MED convention
6407  * according to which the first facet of the cell should be oriented to have the normal vector
6408  * pointing out of cell.
6409  *  \return DataArrayInt * - a new instance of DataArrayInt holding ids of fixed
6410  *         cells. The caller is to delete this array using decrRef() as it is no more
6411  *         needed. 
6412  *  \throw If \a this->getMeshDimension() != 3.
6413  *  \throw If \a this->getSpaceDimension() != 3.
6414  *  \throw If the coordinates array is not set.
6415  *  \throw If the nodal connectivity of cells is not defined.
6416  *
6417  *  \if ENABLE_EXAMPLES
6418  *  \ref cpp_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a C++ example".<br>
6419  *  \ref  py_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a Python example".
6420  *  \endif
6421  * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
6422  */
6423 DataArrayInt *MEDCouplingUMesh::findAndCorrectBadOriented3DExtrudedCells()
6424 {
6425   const char msg[]="check3DCellsWellOriented detection works only for 3D cells !";
6426   if(getMeshDimension()!=3)
6427     throw INTERP_KERNEL::Exception(msg);
6428   int spaceDim=getSpaceDimension();
6429   if(spaceDim!=3)
6430     throw INTERP_KERNEL::Exception(msg);
6431   //
6432   int nbOfCells=getNumberOfCells();
6433   int *conn=_nodal_connec->getPointer();
6434   const int *connI=_nodal_connec_index->begin();
6435   const double *coo=getCoords()->begin();
6436   MCAuto<DataArrayInt> cells(DataArrayInt::New()); cells->alloc(0,1);
6437   for(int i=0;i<nbOfCells;i++)
6438     {
6439       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6440       if(cm.isExtruded() && !cm.isDynamic() && !cm.isQuadratic())
6441         {
6442           if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coo))
6443             {
6444               CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
6445               cells->pushBackSilent(i);
6446             }
6447         }
6448     }
6449   return cells.retn();
6450 }
6451
6452 /*!
6453  * This method is a faster method to correct orientation of all 3D cells in \a this.
6454  * 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.
6455  * This method makes the hypothesis that \a this a coherent that is to say MEDCouplingUMesh::checkConsistency should throw no exception.
6456  * 
6457  * \return a newly allocated int array with one components containing cell ids renumbered to fit the convention of MED (MED file and MEDCoupling)
6458  * \sa MEDCouplingUMesh::orientCorrectlyPolyhedrons, 
6459  */
6460 DataArrayInt *MEDCouplingUMesh::findAndCorrectBadOriented3DCells()
6461 {
6462   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
6463     throw INTERP_KERNEL::Exception("Invalid mesh to apply findAndCorrectBadOriented3DCells on it : must be meshDim==3 and spaceDim==3 !");
6464   int nbOfCells=getNumberOfCells();
6465   int *conn=_nodal_connec->getPointer();
6466   const int *connI=_nodal_connec_index->begin();
6467   const double *coordsPtr=_coords->begin();
6468   MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
6469   for(int i=0;i<nbOfCells;i++)
6470     {
6471       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6472       switch(type)
6473       {
6474         case INTERP_KERNEL::NORM_TETRA4:
6475           {
6476             if(!IsTetra4WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6477               {
6478                 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+3));
6479                 ret->pushBackSilent(i);
6480               }
6481             break;
6482           }
6483         case INTERP_KERNEL::NORM_PYRA5:
6484           {
6485             if(!IsPyra5WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6486               {
6487                 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+4));
6488                 ret->pushBackSilent(i);
6489               }
6490             break;
6491           }
6492         case INTERP_KERNEL::NORM_PENTA6:
6493         case INTERP_KERNEL::NORM_HEXA8:
6494         case INTERP_KERNEL::NORM_HEXGP12:
6495           {
6496             if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6497               {
6498                 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
6499                 ret->pushBackSilent(i);
6500               }
6501             break;
6502           }
6503         case INTERP_KERNEL::NORM_POLYHED:
6504           {
6505             if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6506               {
6507                 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
6508                 ret->pushBackSilent(i);
6509               }
6510             break;
6511           }
6512         default:
6513           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 !");
6514       }
6515     }
6516   updateTime();
6517   return ret.retn();
6518 }
6519
6520 /*!
6521  * This method has a sense for meshes with spaceDim==3 and meshDim==2.
6522  * If it is not the case an exception will be thrown.
6523  * This method is fast because the first cell of \a this is used to compute the plane.
6524  * \param vec output of size at least 3 used to store the normal vector (with norm equal to Area ) of searched plane.
6525  * \param pos output of size at least 3 used to store a point owned of searched plane.
6526  */
6527 void MEDCouplingUMesh::getFastAveragePlaneOfThis(double *vec, double *pos) const
6528 {
6529   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
6530     throw INTERP_KERNEL::Exception("Invalid mesh to apply getFastAveragePlaneOfThis on it : must be meshDim==2 and spaceDim==3 !");
6531   const int *conn=_nodal_connec->begin();
6532   const int *connI=_nodal_connec_index->begin();
6533   const double *coordsPtr=_coords->begin();
6534   INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(conn+1,connI[1]-connI[0]-1,coordsPtr,vec);
6535   std::copy(coordsPtr+3*conn[1],coordsPtr+3*conn[1]+3,pos);
6536 }
6537
6538 /*!
6539  * Creates a new MEDCouplingFieldDouble holding Edge Ratio values of all
6540  * cells. Currently cells of the following types are treated:
6541  * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
6542  * For a cell of other type an exception is thrown.
6543  * Space dimension of a 2D mesh can be either 2 or 3.
6544  * The Edge Ratio of a cell \f$t\f$ is: 
6545  *  \f$\frac{|t|_\infty}{|t|_0}\f$,
6546  *  where \f$|t|_\infty\f$ and \f$|t|_0\f$ respectively denote the greatest and
6547  *  the smallest edge lengths of \f$t\f$.
6548  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6549  *          cells and one time, lying on \a this mesh. The caller is to delete this
6550  *          field using decrRef() as it is no more needed. 
6551  *  \throw If the coordinates array is not set.
6552  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6553  *  \throw If the connectivity data array has more than one component.
6554  *  \throw If the connectivity data array has a named component.
6555  *  \throw If the connectivity index data array has more than one component.
6556  *  \throw If the connectivity index data array has a named component.
6557  *  \throw If \a this->getMeshDimension() is neither 2 nor 3.
6558  *  \throw If \a this->getSpaceDimension() is neither 2 nor 3.
6559  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
6560  */
6561 MEDCouplingFieldDouble *MEDCouplingUMesh::getEdgeRatioField() const
6562 {
6563   checkConsistencyLight();
6564   int spaceDim=getSpaceDimension();
6565   int meshDim=getMeshDimension();
6566   if(spaceDim!=2 && spaceDim!=3)
6567     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : SpaceDimension must be equal to 2 or 3 !");
6568   if(meshDim!=2 && meshDim!=3)
6569     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : MeshDimension must be equal to 2 or 3 !");
6570   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6571   ret->setMesh(this);
6572   int nbOfCells=getNumberOfCells();
6573   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6574   arr->alloc(nbOfCells,1);
6575   double *pt=arr->getPointer();
6576   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6577   const int *conn=_nodal_connec->begin();
6578   const int *connI=_nodal_connec_index->begin();
6579   const double *coo=_coords->begin();
6580   double tmp[12];
6581   for(int i=0;i<nbOfCells;i++,pt++)
6582     {
6583       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6584       switch(t)
6585       {
6586         case INTERP_KERNEL::NORM_TRI3:
6587           {
6588             FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
6589             *pt=INTERP_KERNEL::triEdgeRatio(tmp);
6590             break;
6591           }
6592         case INTERP_KERNEL::NORM_QUAD4:
6593           {
6594             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6595             *pt=INTERP_KERNEL::quadEdgeRatio(tmp);
6596             break;
6597           }
6598         case INTERP_KERNEL::NORM_TETRA4:
6599           {
6600             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6601             *pt=INTERP_KERNEL::tetraEdgeRatio(tmp);
6602             break;
6603           }
6604         default:
6605           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
6606       }
6607       conn+=connI[i+1]-connI[i];
6608     }
6609   ret->setName("EdgeRatio");
6610   ret->synchronizeTimeWithSupport();
6611   return ret.retn();
6612 }
6613
6614 /*!
6615  * Creates a new MEDCouplingFieldDouble holding Aspect Ratio values of all
6616  * cells. Currently cells of the following types are treated:
6617  * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
6618  * For a cell of other type an exception is thrown.
6619  * Space dimension of a 2D mesh can be either 2 or 3.
6620  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6621  *          cells and one time, lying on \a this mesh. The caller is to delete this
6622  *          field using decrRef() as it is no more needed. 
6623  *  \throw If the coordinates array is not set.
6624  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6625  *  \throw If the connectivity data array has more than one component.
6626  *  \throw If the connectivity data array has a named component.
6627  *  \throw If the connectivity index data array has more than one component.
6628  *  \throw If the connectivity index data array has a named component.
6629  *  \throw If \a this->getMeshDimension() is neither 2 nor 3.
6630  *  \throw If \a this->getSpaceDimension() is neither 2 nor 3.
6631  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
6632  */
6633 MEDCouplingFieldDouble *MEDCouplingUMesh::getAspectRatioField() const
6634 {
6635   checkConsistencyLight();
6636   int spaceDim=getSpaceDimension();
6637   int meshDim=getMeshDimension();
6638   if(spaceDim!=2 && spaceDim!=3)
6639     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : SpaceDimension must be equal to 2 or 3 !");
6640   if(meshDim!=2 && meshDim!=3)
6641     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : MeshDimension must be equal to 2 or 3 !");
6642   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6643   ret->setMesh(this);
6644   int nbOfCells=getNumberOfCells();
6645   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6646   arr->alloc(nbOfCells,1);
6647   double *pt=arr->getPointer();
6648   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6649   const int *conn=_nodal_connec->begin();
6650   const int *connI=_nodal_connec_index->begin();
6651   const double *coo=_coords->begin();
6652   double tmp[12];
6653   for(int i=0;i<nbOfCells;i++,pt++)
6654     {
6655       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6656       switch(t)
6657       {
6658         case INTERP_KERNEL::NORM_TRI3:
6659           {
6660             FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
6661             *pt=INTERP_KERNEL::triAspectRatio(tmp);
6662             break;
6663           }
6664         case INTERP_KERNEL::NORM_QUAD4:
6665           {
6666             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6667             *pt=INTERP_KERNEL::quadAspectRatio(tmp);
6668             break;
6669           }
6670         case INTERP_KERNEL::NORM_TETRA4:
6671           {
6672             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6673             *pt=INTERP_KERNEL::tetraAspectRatio(tmp);
6674             break;
6675           }
6676         default:
6677           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
6678       }
6679       conn+=connI[i+1]-connI[i];
6680     }
6681   ret->setName("AspectRatio");
6682   ret->synchronizeTimeWithSupport();
6683   return ret.retn();
6684 }
6685
6686 /*!
6687  * Creates a new MEDCouplingFieldDouble holding Warping factor values of all
6688  * cells of \a this 2D mesh in 3D space. It is a measure of the "planarity" of 2D cell
6689  * in 3D space. Currently only cells of the following types are
6690  * treated: INTERP_KERNEL::NORM_QUAD4.
6691  * For a cell of other type an exception is thrown.
6692  * The warp field is computed as follows: let (a,b,c,d) be the points of the quad.
6693  * Defining
6694  * \f$t=\vec{da}\times\vec{ab}\f$,
6695  * \f$u=\vec{ab}\times\vec{bc}\f$
6696  * \f$v=\vec{bc}\times\vec{cd}\f$
6697  * \f$w=\vec{cd}\times\vec{da}\f$, the warp is defined as \f$W^3\f$ with
6698  *  \f[
6699  *     W=min(\frac{t}{|t|}\cdot\frac{v}{|v|}, \frac{u}{|u|}\cdot\frac{w}{|w|})
6700  *  \f]
6701  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6702  *          cells and one time, lying on \a this mesh. The caller is to delete this
6703  *          field using decrRef() as it is no more needed. 
6704  *  \throw If the coordinates array is not set.
6705  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6706  *  \throw If the connectivity data array has more than one component.
6707  *  \throw If the connectivity data array has a named component.
6708  *  \throw If the connectivity index data array has more than one component.
6709  *  \throw If the connectivity index data array has a named component.
6710  *  \throw If \a this->getMeshDimension() != 2.
6711  *  \throw If \a this->getSpaceDimension() != 3.
6712  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
6713  */
6714 MEDCouplingFieldDouble *MEDCouplingUMesh::getWarpField() const
6715 {
6716   checkConsistencyLight();
6717   int spaceDim=getSpaceDimension();
6718   int meshDim=getMeshDimension();
6719   if(spaceDim!=3)
6720     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : SpaceDimension must be equal to 3 !");
6721   if(meshDim!=2)
6722     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : MeshDimension must be equal to 2 !");
6723   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6724   ret->setMesh(this);
6725   int nbOfCells=getNumberOfCells();
6726   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6727   arr->alloc(nbOfCells,1);
6728   double *pt=arr->getPointer();
6729   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6730   const int *conn=_nodal_connec->begin();
6731   const int *connI=_nodal_connec_index->begin();
6732   const double *coo=_coords->begin();
6733   double tmp[12];
6734   for(int i=0;i<nbOfCells;i++,pt++)
6735     {
6736       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6737       switch(t)
6738       {
6739         case INTERP_KERNEL::NORM_QUAD4:
6740           {
6741             FillInCompact3DMode(3,4,conn+1,coo,tmp);
6742             *pt=INTERP_KERNEL::quadWarp(tmp);
6743             break;
6744           }
6745         default:
6746           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : A cell with not manged type (NORM_QUAD4) has been detected !");
6747       }
6748       conn+=connI[i+1]-connI[i];
6749     }
6750   ret->setName("Warp");
6751   ret->synchronizeTimeWithSupport();
6752   return ret.retn();
6753 }
6754
6755
6756 /*!
6757  * Creates a new MEDCouplingFieldDouble holding Skew factor values of all
6758  * cells of \a this 2D mesh in 3D space. Currently cells of the following types are
6759  * treated: INTERP_KERNEL::NORM_QUAD4.
6760  * The skew is computed as follow for a quad with points (a,b,c,d): let
6761  * \f$u=\vec{ab}+\vec{dc}\f$ and \f$v=\vec{ac}+\vec{bd}\f$
6762  * then the skew is computed as:
6763  *  \f[
6764  *    s=\frac{u}{|u|}\cdot\frac{v}{|v|}
6765  *  \f]
6766  *
6767  * For a cell of other type an exception is thrown.
6768  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6769  *          cells and one time, lying on \a this mesh. The caller is to delete this
6770  *          field using decrRef() as it is no more needed. 
6771  *  \throw If the coordinates array is not set.
6772  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6773  *  \throw If the connectivity data array has more than one component.
6774  *  \throw If the connectivity data array has a named component.
6775  *  \throw If the connectivity index data array has more than one component.
6776  *  \throw If the connectivity index data array has a named component.
6777  *  \throw If \a this->getMeshDimension() != 2.
6778  *  \throw If \a this->getSpaceDimension() != 3.
6779  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
6780  */
6781 MEDCouplingFieldDouble *MEDCouplingUMesh::getSkewField() const
6782 {
6783   checkConsistencyLight();
6784   int spaceDim=getSpaceDimension();
6785   int meshDim=getMeshDimension();
6786   if(spaceDim!=3)
6787     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : SpaceDimension must be equal to 3 !");
6788   if(meshDim!=2)
6789     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : MeshDimension must be equal to 2 !");
6790   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6791   ret->setMesh(this);
6792   int nbOfCells=getNumberOfCells();
6793   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6794   arr->alloc(nbOfCells,1);
6795   double *pt=arr->getPointer();
6796   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6797   const int *conn=_nodal_connec->begin();
6798   const int *connI=_nodal_connec_index->begin();
6799   const double *coo=_coords->begin();
6800   double tmp[12];
6801   for(int i=0;i<nbOfCells;i++,pt++)
6802     {
6803       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6804       switch(t)
6805       {
6806         case INTERP_KERNEL::NORM_QUAD4:
6807           {
6808             FillInCompact3DMode(3,4,conn+1,coo,tmp);
6809             *pt=INTERP_KERNEL::quadSkew(tmp);
6810             break;
6811           }
6812         default:
6813           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : A cell with not manged type (NORM_QUAD4) has been detected !");
6814       }
6815       conn+=connI[i+1]-connI[i];
6816     }
6817   ret->setName("Skew");
6818   ret->synchronizeTimeWithSupport();
6819   return ret.retn();
6820 }
6821
6822 /*!
6823  * 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.
6824  *
6825  * \return a new instance of field containing the result. The returned instance has to be deallocated by the caller.
6826  *
6827  * \sa getSkewField, getWarpField, getAspectRatioField, getEdgeRatioField
6828  */
6829 MEDCouplingFieldDouble *MEDCouplingUMesh::computeDiameterField() const
6830 {
6831   checkConsistencyLight();
6832   MCAuto<MEDCouplingFieldDouble> ret(MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME));
6833   ret->setMesh(this);
6834   std::set<INTERP_KERNEL::NormalizedCellType> types;
6835   ComputeAllTypesInternal(types,_nodal_connec,_nodal_connec_index);
6836   int spaceDim(getSpaceDimension()),nbCells(getNumberOfCells());
6837   MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
6838   arr->alloc(nbCells,1);
6839   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++)
6840     {
6841       INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::DiameterCalculator> dc(INTERP_KERNEL::CellModel::GetCellModel(*it).buildInstanceOfDiameterCalulator(spaceDim));
6842       MCAuto<DataArrayInt> cellIds(giveCellsWithType(*it));
6843       dc->computeForListOfCellIdsUMeshFrmt(cellIds->begin(),cellIds->end(),_nodal_connec_index->begin(),_nodal_connec->begin(),getCoords()->begin(),arr->getPointer());
6844     }
6845   ret->setArray(arr);
6846   ret->setName("Diameter");
6847   return ret.retn();
6848 }
6849
6850 /*!
6851  * This method aggregate the bbox of each cell and put it into bbox parameter (xmin,xmax,ymin,ymax,zmin,zmax).
6852  * 
6853  * \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)
6854  *                         For all other cases this input parameter is ignored.
6855  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6856  * 
6857  * \throw If \a this is not fully set (coordinates and connectivity).
6858  * \throw If a cell in \a this has no valid nodeId.
6859  * \sa MEDCouplingUMesh::getBoundingBoxForBBTreeFast, MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
6860  */
6861 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree(double arcDetEps) const
6862 {
6863   int mDim(getMeshDimension()),sDim(getSpaceDimension());
6864   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.
6865     return getBoundingBoxForBBTreeFast();
6866   if((mDim==2 && sDim==2) || (mDim==1 && sDim==2))
6867     {
6868       bool presenceOfQuadratic(false);
6869       for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=_types.begin();it!=_types.end();it++)
6870         {
6871           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(*it));
6872           if(cm.isQuadratic())
6873             presenceOfQuadratic=true;
6874         }
6875       if(!presenceOfQuadratic)
6876         return getBoundingBoxForBBTreeFast();
6877       if(mDim==2 && sDim==2)
6878         return getBoundingBoxForBBTree2DQuadratic(arcDetEps);
6879       else
6880         return getBoundingBoxForBBTree1DQuadratic(arcDetEps);
6881     }
6882   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) !");
6883 }
6884
6885 /*!
6886  * This method aggregate the bbox of each cell only considering the nodes constituting each cell and put it into bbox parameter.
6887  * So meshes having quadratic cells the computed bounding boxes can be invalid !
6888  * 
6889  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6890  * 
6891  * \throw If \a this is not fully set (coordinates and connectivity).
6892  * \throw If a cell in \a this has no valid nodeId.
6893  */
6894 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTreeFast() const
6895 {
6896   checkFullyDefined();
6897   int spaceDim(getSpaceDimension()),nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
6898   MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
6899   double *bbox(ret->getPointer());
6900   for(int i=0;i<nbOfCells*spaceDim;i++)
6901     {
6902       bbox[2*i]=std::numeric_limits<double>::max();
6903       bbox[2*i+1]=-std::numeric_limits<double>::max();
6904     }
6905   const double *coordsPtr(_coords->begin());
6906   const int *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
6907   for(int i=0;i<nbOfCells;i++)
6908     {
6909       int offset=connI[i]+1;
6910       int nbOfNodesForCell(connI[i+1]-offset),kk(0);
6911       for(int j=0;j<nbOfNodesForCell;j++)
6912         {
6913           int nodeId=conn[offset+j];
6914           if(nodeId>=0 && nodeId<nbOfNodes)
6915             {
6916               for(int k=0;k<spaceDim;k++)
6917                 {
6918                   bbox[2*spaceDim*i+2*k]=std::min(bbox[2*spaceDim*i+2*k],coordsPtr[spaceDim*nodeId+k]);
6919                   bbox[2*spaceDim*i+2*k+1]=std::max(bbox[2*spaceDim*i+2*k+1],coordsPtr[spaceDim*nodeId+k]);
6920                 }
6921               kk++;
6922             }
6923         }
6924       if(kk==0)
6925         {
6926           std::ostringstream oss; oss << "MEDCouplingUMesh::getBoundingBoxForBBTree : cell #" << i << " contains no valid nodeId !";
6927           throw INTERP_KERNEL::Exception(oss.str());
6928         }
6929     }
6930   return ret.retn();
6931 }
6932
6933 /*!
6934  * This method aggregates the bbox of each 2D cell in \a this considering the whole shape. This method is particularly
6935  * useful for 2D meshes having quadratic cells
6936  * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
6937  * the two extremities of the arc of circle).
6938  * 
6939  * \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)
6940  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6941  * \throw If \a this is not fully defined.
6942  * \throw If \a this is not a mesh with meshDimension equal to 2.
6943  * \throw If \a this is not a mesh with spaceDimension equal to 2.
6944  * \sa MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic
6945  */
6946 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic(double arcDetEps) const
6947 {
6948   checkFullyDefined();
6949   int spaceDim(getSpaceDimension()),mDim(getMeshDimension()),nbOfCells(getNumberOfCells());
6950   if(spaceDim!=2 || mDim!=2)
6951     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!");
6952   MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
6953   double *bbox(ret->getPointer());
6954   const double *coords(_coords->begin());
6955   const int *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
6956   for(int i=0;i<nbOfCells;i++,bbox+=4,connI++)
6957     {
6958       const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
6959       int sz(connI[1]-connI[0]-1);
6960       INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=arcDetEps;
6961       std::vector<INTERP_KERNEL::Node *> nodes(sz);
6962       INTERP_KERNEL::QuadraticPolygon *pol(0);
6963       for(int j=0;j<sz;j++)
6964         {
6965           int nodeId(conn[*connI+1+j]);
6966           nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
6967         }
6968       if(!cm.isQuadratic())
6969         pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
6970       else
6971         pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
6972       INTERP_KERNEL::Bounds b; b.prepareForAggregation(); pol->fillBounds(b); delete pol;
6973       bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax(); 
6974     }
6975   return ret.retn();
6976 }
6977
6978 /*!
6979  * This method aggregates the bbox of each 1D cell in \a this considering the whole shape. This method is particularly
6980  * useful for 2D meshes having quadratic cells
6981  * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
6982  * the two extremities of the arc of circle).
6983  * 
6984  * \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)
6985  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6986  * \throw If \a this is not fully defined.
6987  * \throw If \a this is not a mesh with meshDimension equal to 1.
6988  * \throw If \a this is not a mesh with spaceDimension equal to 2.
6989  * \sa MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
6990  */
6991 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic(double arcDetEps) const
6992 {
6993   checkFullyDefined();
6994   int spaceDim(getSpaceDimension()),mDim(getMeshDimension()),nbOfCells(getNumberOfCells());
6995   if(spaceDim!=2 || mDim!=1)
6996     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!");
6997   MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
6998   double *bbox(ret->getPointer());
6999   const double *coords(_coords->begin());
7000   const int *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
7001   for(int i=0;i<nbOfCells;i++,bbox+=4,connI++)
7002     {
7003       const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
7004       int sz(connI[1]-connI[0]-1);
7005       INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=arcDetEps;
7006       std::vector<INTERP_KERNEL::Node *> nodes(sz);
7007       INTERP_KERNEL::Edge *edge(0);
7008       for(int j=0;j<sz;j++)
7009         {
7010           int nodeId(conn[*connI+1+j]);
7011           nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
7012         }
7013       if(!cm.isQuadratic())
7014         edge=INTERP_KERNEL::QuadraticPolygon::BuildLinearEdge(nodes);
7015       else
7016         edge=INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(nodes);
7017       const INTERP_KERNEL::Bounds& b(edge->getBounds());
7018       bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax(); edge->decrRef();
7019     }
7020   return ret.retn();
7021 }
7022
7023 /// @cond INTERNAL
7024
7025 namespace MEDCouplingImpl
7026 {
7027   class ConnReader
7028   {
7029   public:
7030     ConnReader(const int *c, int val):_conn(c),_val(val) { }
7031     bool operator() (const int& pos) { return _conn[pos]!=_val; }
7032   private:
7033     const int *_conn;
7034     int _val;
7035   };
7036
7037   class ConnReader2
7038   {
7039   public:
7040     ConnReader2(const int *c, int val):_conn(c),_val(val) { }
7041     bool operator() (const int& pos) { return _conn[pos]==_val; }
7042   private:
7043     const int *_conn;
7044     int _val;
7045   };
7046 }
7047
7048 /// @endcond
7049
7050 /*!
7051  * This method expects that \a this is sorted by types. If not an exception will be thrown.
7052  * This method returns in the same format as code (see MEDCouplingUMesh::checkTypeConsistencyAndContig or MEDCouplingUMesh::splitProfilePerType) how
7053  * \a this is composed in cell types.
7054  * The returned array is of size 3*n where n is the number of different types present in \a this. 
7055  * For every k in [0,n] ret[3*k+2]==-1 because it has no sense here. 
7056  * This parameter is kept only for compatibility with other methode listed above.
7057  */
7058 std::vector<int> MEDCouplingUMesh::getDistributionOfTypes() const
7059 {
7060   checkConnectivityFullyDefined();
7061   const int *conn=_nodal_connec->begin();
7062   const int *connI=_nodal_connec_index->begin();
7063   const int *work=connI;
7064   int nbOfCells=getNumberOfCells();
7065   std::size_t n=getAllGeoTypes().size();
7066   std::vector<int> ret(3*n,-1); //ret[3*k+2]==-1 because it has no sense here
7067   std::set<INTERP_KERNEL::NormalizedCellType> types;
7068   for(std::size_t i=0;work!=connI+nbOfCells;i++)
7069     {
7070       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn[*work];
7071       if(types.find(typ)!=types.end())
7072         {
7073           std::ostringstream oss; oss << "MEDCouplingUMesh::getDistributionOfTypes : Type " << INTERP_KERNEL::CellModel::GetCellModel(typ).getRepr();
7074           oss << " is not contiguous !";
7075           throw INTERP_KERNEL::Exception(oss.str());
7076         }
7077       types.insert(typ);
7078       ret[3*i]=typ;
7079       const int *work2=std::find_if(work+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,typ));
7080       ret[3*i+1]=(int)std::distance(work,work2);
7081       work=work2;
7082     }
7083   return ret;
7084 }
7085
7086 /*!
7087  * This method is used to check that this has contiguous cell type in same order than described in \a code.
7088  * only for types cell, type node is not managed.
7089  * Format of \a code is the following. \a code should be of size 3*n and non empty. If not an exception is thrown.
7090  * foreach k in [0,n) on 3*k pos represent the geometric type and 3*k+1 number of elements of type 3*k.
7091  * 3*k+2 refers if different from -1 the pos in 'idsPerType' to get the corresponding array.
7092  * If 2 or more same geometric type is in \a code and exception is thrown too.
7093  *
7094  * This method firstly checks
7095  * If it exists k so that 3*k geometric type is not in geometric types of this an exception will be thrown.
7096  * If it exists k so that 3*k geometric type exists but the number of consecutive cell types does not match,
7097  * an exception is thrown too.
7098  * 
7099  * If all geometric types in \a code are exactly those in \a this null pointer is returned.
7100  * If it exists a geometric type in \a this \b not in \a code \b no exception is thrown 
7101  * and a DataArrayInt instance is returned that the user has the responsability to deallocate.
7102  */
7103 DataArrayInt *MEDCouplingUMesh::checkTypeConsistencyAndContig(const std::vector<int>& code, const std::vector<const DataArrayInt *>& idsPerType) const
7104 {
7105   if(code.empty())
7106     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code is empty, should not !");
7107   std::size_t sz=code.size();
7108   std::size_t n=sz/3;
7109   if(sz%3!=0)
7110     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code size is NOT %3 !");
7111   std::vector<INTERP_KERNEL::NormalizedCellType> types;
7112   int nb=0;
7113   bool isNoPflUsed=true;
7114   for(std::size_t i=0;i<n;i++)
7115     if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)code[3*i])==types.end())
7116       {
7117         types.push_back((INTERP_KERNEL::NormalizedCellType)code[3*i]);
7118         nb+=code[3*i+1];
7119         if(_types.find((INTERP_KERNEL::NormalizedCellType)code[3*i])==_types.end())
7120           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : expected geo types not in this !");
7121         isNoPflUsed=isNoPflUsed && (code[3*i+2]==-1);
7122       }
7123   if(types.size()!=n)
7124     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code contains duplication of types in unstructured mesh !");
7125   if(isNoPflUsed)
7126     {
7127       if(!checkConsecutiveCellTypesAndOrder(&types[0],&types[0]+types.size()))
7128         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : non contiguous type !");
7129       if(types.size()==_types.size())
7130         return 0;
7131     }
7132   MCAuto<DataArrayInt> ret=DataArrayInt::New();
7133   ret->alloc(nb,1);
7134   int *retPtr=ret->getPointer();
7135   const int *connI=_nodal_connec_index->begin();
7136   const int *conn=_nodal_connec->begin();
7137   int nbOfCells=getNumberOfCells();
7138   const int *i=connI;
7139   int kk=0;
7140   for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++,kk++)
7141     {
7142       i=std::find_if(i,connI+nbOfCells,MEDCouplingImpl::ConnReader2(conn,(int)(*it)));
7143       int offset=(int)std::distance(connI,i);
7144       const int *j=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)(*it)));
7145       int nbOfCellsOfCurType=(int)std::distance(i,j);
7146       if(code[3*kk+2]==-1)
7147         for(int k=0;k<nbOfCellsOfCurType;k++)
7148           *retPtr++=k+offset;
7149       else
7150         {
7151           int idInIdsPerType=code[3*kk+2];
7152           if(idInIdsPerType>=0 && idInIdsPerType<(int)idsPerType.size())
7153             {
7154               const DataArrayInt *zePfl=idsPerType[idInIdsPerType];
7155               if(zePfl)
7156                 {
7157                   zePfl->checkAllocated();
7158                   if(zePfl->getNumberOfComponents()==1)
7159                     {
7160                       for(const int *k=zePfl->begin();k!=zePfl->end();k++,retPtr++)
7161                         {
7162                           if(*k>=0 && *k<nbOfCellsOfCurType)
7163                             *retPtr=(*k)+offset;
7164                           else
7165                             {
7166                               std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : the section " << kk << " points to the profile #" << idInIdsPerType;
7167                               oss << ", and this profile contains a value " << *k << " should be in [0," << nbOfCellsOfCurType << ") !";
7168                               throw INTERP_KERNEL::Exception(oss.str());
7169                             }
7170                         }
7171                     }
7172                   else
7173                     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of a profile with nb of compo != 1 !");
7174                 }
7175               else
7176                 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of null profile !");
7177             }
7178           else
7179             {
7180               std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : at section " << kk << " of code it points to the array #" << idInIdsPerType;
7181               oss << " should be in [0," << idsPerType.size() << ") !";
7182               throw INTERP_KERNEL::Exception(oss.str());
7183             }
7184         }
7185       i=j;
7186     }
7187   return ret.retn();
7188 }
7189
7190 /*!
7191  * This method makes the hypothesis that \a this is sorted by type. If not an exception will be thrown.
7192  * 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.
7193  * 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.
7194  * This method has 1 input \a profile and 3 outputs \a code \a idsInPflPerType and \a idsPerType.
7195  * 
7196  * \param [in] profile
7197  * \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.
7198  * \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,
7199  *              \a idsInPflPerType[i] stores the tuple ids in \a profile that correspond to the geometric type code[3*i+0]
7200  * \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.
7201  *              This vector can be empty in case of all geometric type cells are fully covered in ascending in the given input \a profile.
7202  * \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
7203  */
7204 void MEDCouplingUMesh::splitProfilePerType(const DataArrayInt *profile, std::vector<int>& code, std::vector<DataArrayInt *>& idsInPflPerType, std::vector<DataArrayInt *>& idsPerType) const
7205 {
7206   if(!profile)
7207     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile is NULL !");
7208   if(profile->getNumberOfComponents()!=1)
7209     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile should have exactly one component !");
7210   checkConnectivityFullyDefined();
7211   const int *conn=_nodal_connec->begin();
7212   const int *connI=_nodal_connec_index->begin();
7213   int nbOfCells=getNumberOfCells();
7214   std::vector<INTERP_KERNEL::NormalizedCellType> types;
7215   std::vector<int> typeRangeVals(1);
7216   for(const int *i=connI;i!=connI+nbOfCells;)
7217     {
7218       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7219       if(std::find(types.begin(),types.end(),curType)!=types.end())
7220         {
7221           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : current mesh is not sorted by type !");
7222         }
7223       types.push_back(curType);
7224       i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7225       typeRangeVals.push_back((int)std::distance(connI,i));
7226     }
7227   //
7228   DataArrayInt *castArr=0,*rankInsideCast=0,*castsPresent=0;
7229   profile->splitByValueRange(&typeRangeVals[0],&typeRangeVals[0]+typeRangeVals.size(),castArr,rankInsideCast,castsPresent);
7230   MCAuto<DataArrayInt> tmp0=castArr;
7231   MCAuto<DataArrayInt> tmp1=rankInsideCast;
7232   MCAuto<DataArrayInt> tmp2=castsPresent;
7233   //
7234   int nbOfCastsFinal=castsPresent->getNumberOfTuples();
7235   code.resize(3*nbOfCastsFinal);
7236   std::vector< MCAuto<DataArrayInt> > idsInPflPerType2;
7237   std::vector< MCAuto<DataArrayInt> > idsPerType2;
7238   for(int i=0;i<nbOfCastsFinal;i++)
7239     {
7240       int castId=castsPresent->getIJ(i,0);
7241       MCAuto<DataArrayInt> tmp3=castArr->findIdsEqual(castId);
7242       idsInPflPerType2.push_back(tmp3);
7243       code[3*i]=(int)types[castId];
7244       code[3*i+1]=tmp3->getNumberOfTuples();
7245       MCAuto<DataArrayInt> tmp4=rankInsideCast->selectByTupleId(tmp3->begin(),tmp3->begin()+tmp3->getNumberOfTuples());
7246       if(!tmp4->isIota(typeRangeVals[castId+1]-typeRangeVals[castId]))
7247         {
7248           tmp4->copyStringInfoFrom(*profile);
7249           idsPerType2.push_back(tmp4);
7250           code[3*i+2]=(int)idsPerType2.size()-1;
7251         }
7252       else
7253         {
7254           code[3*i+2]=-1;
7255         }
7256     }
7257   std::size_t sz2=idsInPflPerType2.size();
7258   idsInPflPerType.resize(sz2);
7259   for(std::size_t i=0;i<sz2;i++)
7260     {
7261       DataArrayInt *locDa=idsInPflPerType2[i];
7262       locDa->incrRef();
7263       idsInPflPerType[i]=locDa;
7264     }
7265   std::size_t sz=idsPerType2.size();
7266   idsPerType.resize(sz);
7267   for(std::size_t i=0;i<sz;i++)
7268     {
7269       DataArrayInt *locDa=idsPerType2[i];
7270       locDa->incrRef();
7271       idsPerType[i]=locDa;
7272     }
7273 }
7274
7275 /*!
7276  * This method is here too emulate the MEDMEM behaviour on BDC (buildDescendingConnectivity). Hoping this method becomes deprecated very soon.
7277  * This method make the assumption that \a this and 'nM1LevMesh' mesh lyies on same coords (same pointer) as MED and MEDMEM does.
7278  * The following equality should be verified 'nM1LevMesh->getMeshDimension()==this->getMeshDimension()-1'
7279  * 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.
7280  */
7281 MEDCouplingUMesh *MEDCouplingUMesh::emulateMEDMEMBDC(const MEDCouplingUMesh *nM1LevMesh, DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *&revDesc, DataArrayInt *&revDescIndx, DataArrayInt *& nM1LevMeshIds, DataArrayInt *&meshnM1Old2New) const
7282 {
7283   checkFullyDefined();
7284   nM1LevMesh->checkFullyDefined();
7285   if(getMeshDimension()-1!=nM1LevMesh->getMeshDimension())
7286     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : The mesh passed as first argument should have a meshDim equal to this->getMeshDimension()-1 !" );
7287   if(_coords!=nM1LevMesh->getCoords())
7288     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : 'this' and mesh in first argument should share the same coords : Use tryToShareSameCoords method !");
7289   MCAuto<DataArrayInt> tmp0=DataArrayInt::New();
7290   MCAuto<DataArrayInt> tmp1=DataArrayInt::New();
7291   MCAuto<MEDCouplingUMesh> ret1=buildDescendingConnectivity(desc,descIndx,tmp0,tmp1);
7292   MCAuto<DataArrayInt> ret0=ret1->sortCellsInMEDFileFrmt();
7293   desc->transformWithIndArr(ret0->begin(),ret0->begin()+ret0->getNbOfElems());
7294   MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
7295   tmp->setConnectivity(tmp0,tmp1);
7296   tmp->renumberCells(ret0->begin(),false);
7297   revDesc=tmp->getNodalConnectivity();
7298   revDescIndx=tmp->getNodalConnectivityIndex();
7299   DataArrayInt *ret=0;
7300   if(!ret1->areCellsIncludedIn(nM1LevMesh,2,ret))
7301     {
7302       int tmp2;
7303       ret->getMaxValue(tmp2);
7304       ret->decrRef();
7305       std::ostringstream oss; oss << "MEDCouplingUMesh::emulateMEDMEMBDC : input N-1 mesh present a cell not in descending mesh ... Id of cell is " << tmp2 << " !";
7306       throw INTERP_KERNEL::Exception(oss.str());
7307     }
7308   nM1LevMeshIds=ret;
7309   //
7310   revDesc->incrRef();
7311   revDescIndx->incrRef();
7312   ret1->incrRef();
7313   ret0->incrRef();
7314   meshnM1Old2New=ret0;
7315   return ret1;
7316 }
7317
7318 /*!
7319  * Permutes the nodal connectivity arrays so that the cells are sorted by type, which is
7320  * necessary for writing the mesh to MED file. Additionally returns a permutation array
7321  * in "Old to New" mode.
7322  *  \return DataArrayInt * - a new instance of DataArrayInt. The caller is to delete
7323  *          this array using decrRef() as it is no more needed.
7324  *  \throw If the nodal connectivity of cells is not defined.
7325  */
7326 DataArrayInt *MEDCouplingUMesh::sortCellsInMEDFileFrmt()
7327 {
7328   checkConnectivityFullyDefined();
7329   MCAuto<DataArrayInt> ret=getRenumArrForMEDFileFrmt();
7330   renumberCells(ret->begin(),false);
7331   return ret.retn();
7332 }
7333
7334 /*!
7335  * This methods checks that cells are sorted by their types.
7336  * This method makes asumption (no check) that connectivity is correctly set before calling.
7337  */
7338 bool MEDCouplingUMesh::checkConsecutiveCellTypes() const
7339 {
7340   checkFullyDefined();
7341   const int *conn=_nodal_connec->begin();
7342   const int *connI=_nodal_connec_index->begin();
7343   int nbOfCells=getNumberOfCells();
7344   std::set<INTERP_KERNEL::NormalizedCellType> types;
7345   for(const int *i=connI;i!=connI+nbOfCells;)
7346     {
7347       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7348       if(types.find(curType)!=types.end())
7349         return false;
7350       types.insert(curType);
7351       i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7352     }
7353   return true;
7354 }
7355
7356 /*!
7357  * This method is a specialization of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method that is called here.
7358  * The geometric type order is specified by MED file.
7359  * 
7360  * \sa  MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder
7361  */
7362 bool MEDCouplingUMesh::checkConsecutiveCellTypesForMEDFileFrmt() const
7363 {
7364   return checkConsecutiveCellTypesAndOrder(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
7365 }
7366
7367 /*!
7368  * This method performs the same job as checkConsecutiveCellTypes except that the order of types sequence is analyzed to check
7369  * that the order is specified in array defined by [ \a orderBg , \a orderEnd ).
7370  * If there is some geo types in \a this \b NOT in [ \a orderBg, \a orderEnd ) it is OK (return true) if contiguous.
7371  * If there is some geo types in [ \a orderBg, \a orderEnd ) \b NOT in \a this it is OK too (return true) if contiguous.
7372  */
7373 bool MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
7374 {
7375   checkFullyDefined();
7376   const int *conn=_nodal_connec->begin();
7377   const int *connI=_nodal_connec_index->begin();
7378   int nbOfCells=getNumberOfCells();
7379   if(nbOfCells==0)
7380     return true;
7381   int lastPos=-1;
7382   std::set<INTERP_KERNEL::NormalizedCellType> sg;
7383   for(const int *i=connI;i!=connI+nbOfCells;)
7384     {
7385       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7386       const INTERP_KERNEL::NormalizedCellType *isTypeExists=std::find(orderBg,orderEnd,curType);
7387       if(isTypeExists!=orderEnd)
7388         {
7389           int pos=(int)std::distance(orderBg,isTypeExists);
7390           if(pos<=lastPos)
7391             return false;
7392           lastPos=pos;
7393           i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7394         }
7395       else
7396         {
7397           if(sg.find(curType)==sg.end())
7398             {
7399               i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7400               sg.insert(curType);
7401             }
7402           else
7403             return false;
7404         }
7405     }
7406   return true;
7407 }
7408
7409 /*!
7410  * This method returns 2 newly allocated DataArrayInt instances. The first is an array of size 'this->getNumberOfCells()' with one component,
7411  * 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
7412  * 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'.
7413  */
7414 DataArrayInt *MEDCouplingUMesh::getLevArrPerCellTypes(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd, DataArrayInt *&nbPerType) const
7415 {
7416   checkConnectivityFullyDefined();
7417   int nbOfCells=getNumberOfCells();
7418   const int *conn=_nodal_connec->begin();
7419   const int *connI=_nodal_connec_index->begin();
7420   MCAuto<DataArrayInt> tmpa=DataArrayInt::New();
7421   MCAuto<DataArrayInt> tmpb=DataArrayInt::New();
7422   tmpa->alloc(nbOfCells,1);
7423   tmpb->alloc((int)std::distance(orderBg,orderEnd),1);
7424   tmpb->fillWithZero();
7425   int *tmp=tmpa->getPointer();
7426   int *tmp2=tmpb->getPointer();
7427   for(const int *i=connI;i!=connI+nbOfCells;i++)
7428     {
7429       const INTERP_KERNEL::NormalizedCellType *where=std::find(orderBg,orderEnd,(INTERP_KERNEL::NormalizedCellType)conn[*i]);
7430       if(where!=orderEnd)
7431         {
7432           int pos=(int)std::distance(orderBg,where);
7433           tmp2[pos]++;
7434           tmp[std::distance(connI,i)]=pos;
7435         }
7436       else
7437         {
7438           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*i]);
7439           std::ostringstream oss; oss << "MEDCouplingUMesh::getLevArrPerCellTypes : Cell #" << std::distance(connI,i);
7440           oss << " has a type " << cm.getRepr() << " not in input array of type !";
7441           throw INTERP_KERNEL::Exception(oss.str());
7442         }
7443     }
7444   nbPerType=tmpb.retn();
7445   return tmpa.retn();
7446 }
7447
7448 /*!
7449  * This method behaves exactly as MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec but the order is those defined in MED file spec.
7450  *
7451  * \return a new object containing the old to new correspondance.
7452  *
7453  * \sa MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec, MEDCouplingUMesh::sortCellsInMEDFileFrmt.
7454  */
7455 DataArrayInt *MEDCouplingUMesh::getRenumArrForMEDFileFrmt() const
7456 {
7457   return getRenumArrForConsecutiveCellTypesSpec(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
7458 }
7459
7460 /*!
7461  * 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.
7462  * This method returns an array of size getNumberOfCells() that gives a renumber array old2New that can be used as input of MEDCouplingMesh::renumberCells.
7463  * The mesh after this call to MEDCouplingMesh::renumberCells will pass the test of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder with the same inputs.
7464  * The returned array minimizes the permutations that is to say the order of cells inside same geometric type remains the same.
7465  */
7466 DataArrayInt *MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
7467 {
7468   DataArrayInt *nbPerType=0;
7469   MCAuto<DataArrayInt> tmpa=getLevArrPerCellTypes(orderBg,orderEnd,nbPerType);
7470   nbPerType->decrRef();
7471   return tmpa->buildPermArrPerLevel();
7472 }
7473
7474 /*!
7475  * This method reorganize the cells of \a this so that the cells with same geometric types are put together.
7476  * The number of cells remains unchanged after the call of this method.
7477  * This method tries to minimizes the number of needed permutations. So, this method behaves not exactly as
7478  * MEDCouplingUMesh::sortCellsInMEDFileFrmt.
7479  *
7480  * \return the array giving the correspondance old to new.
7481  */
7482 DataArrayInt *MEDCouplingUMesh::rearrange2ConsecutiveCellTypes()
7483 {
7484   checkFullyDefined();
7485   computeTypes();
7486   const int *conn=_nodal_connec->begin();
7487   const int *connI=_nodal_connec_index->begin();
7488   int nbOfCells=getNumberOfCells();
7489   std::vector<INTERP_KERNEL::NormalizedCellType> types;
7490   for(const int *i=connI;i!=connI+nbOfCells && (types.size()!=_types.size());)
7491     if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)conn[*i])==types.end())
7492       {
7493         INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7494         types.push_back(curType);
7495         for(i++;i!=connI+nbOfCells && (INTERP_KERNEL::NormalizedCellType)conn[*i]==curType;i++);
7496       }
7497   DataArrayInt *ret=DataArrayInt::New();
7498   ret->alloc(nbOfCells,1);
7499   int *retPtr=ret->getPointer();
7500   std::fill(retPtr,retPtr+nbOfCells,-1);
7501   int newCellId=0;
7502   for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
7503     {
7504       for(const int *i=connI;i!=connI+nbOfCells;i++)
7505         if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
7506           retPtr[std::distance(connI,i)]=newCellId++;
7507     }
7508   renumberCells(retPtr,false);
7509   return ret;
7510 }
7511
7512 /*!
7513  * This method splits \a this into as mush as untructured meshes that consecutive set of same type cells.
7514  * So this method has typically a sense if MEDCouplingUMesh::checkConsecutiveCellTypes has a sense.
7515  * This method makes asumption that connectivity is correctly set before calling.
7516  */
7517 std::vector<MEDCouplingUMesh *> MEDCouplingUMesh::splitByType() const
7518 {
7519   checkConnectivityFullyDefined();
7520   const int *conn=_nodal_connec->begin();
7521   const int *connI=_nodal_connec_index->begin();
7522   int nbOfCells=getNumberOfCells();
7523   std::vector<MEDCouplingUMesh *> ret;
7524   for(const int *i=connI;i!=connI+nbOfCells;)
7525     {
7526       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7527       int beginCellId=(int)std::distance(connI,i);
7528       i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7529       int endCellId=(int)std::distance(connI,i);
7530       int sz=endCellId-beginCellId;
7531       int *cells=new int[sz];
7532       for(int j=0;j<sz;j++)
7533         cells[j]=beginCellId+j;
7534       MEDCouplingUMesh *m=(MEDCouplingUMesh *)buildPartOfMySelf(cells,cells+sz,true);
7535       delete [] cells;
7536       ret.push_back(m);
7537     }
7538   return ret;
7539 }
7540
7541 /*!
7542  * This method performs the opposite operation than those in MEDCoupling1SGTUMesh::buildUnstructured.
7543  * If \a this is a single geometric type unstructured mesh, it will be converted into a more compact data structure,
7544  * MEDCoupling1GTUMesh instance. The returned instance will aggregate the same DataArrayDouble instance of coordinates than \a this.
7545  *
7546  * \return a newly allocated instance, that the caller must manage.
7547  * \throw If \a this contains more than one geometric type.
7548  * \throw If the nodal connectivity of \a this is not fully defined.
7549  * \throw If the internal data is not coherent.
7550  */
7551 MEDCoupling1GTUMesh *MEDCouplingUMesh::convertIntoSingleGeoTypeMesh() const
7552 {
7553   checkConnectivityFullyDefined();
7554   if(_types.size()!=1)
7555     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : current mesh does not contain exactly one geometric type !");
7556   INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
7557   MCAuto<MEDCoupling1GTUMesh> ret=MEDCoupling1GTUMesh::New(getName(),typ);
7558   ret->setCoords(getCoords());
7559   MEDCoupling1SGTUMesh *retC=dynamic_cast<MEDCoupling1SGTUMesh *>((MEDCoupling1GTUMesh*)ret);
7560   if(retC)
7561     {
7562       MCAuto<DataArrayInt> c=convertNodalConnectivityToStaticGeoTypeMesh();
7563       retC->setNodalConnectivity(c);
7564     }
7565   else
7566     {
7567       MEDCoupling1DGTUMesh *retD=dynamic_cast<MEDCoupling1DGTUMesh *>((MEDCoupling1GTUMesh*)ret);
7568       if(!retD)
7569         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : Internal error !");
7570       DataArrayInt *c=0,*ci=0;
7571       convertNodalConnectivityToDynamicGeoTypeMesh(c,ci);
7572       MCAuto<DataArrayInt> cs(c),cis(ci);
7573       retD->setNodalConnectivity(cs,cis);
7574     }
7575   return ret.retn();
7576 }
7577
7578 DataArrayInt *MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh() const
7579 {
7580   checkConnectivityFullyDefined();
7581   if(_types.size()!=1)
7582     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : current mesh does not contain exactly one geometric type !");
7583   INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
7584   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
7585   if(cm.isDynamic())
7586     {
7587       std::ostringstream oss; oss << "MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : this contains a single geo type (" << cm.getRepr() << ") but ";
7588       oss << "this type is dynamic ! Only static geometric type is possible for that type ! call convertNodalConnectivityToDynamicGeoTypeMesh instead !";
7589       throw INTERP_KERNEL::Exception(oss.str());
7590     }
7591   int nbCells=getNumberOfCells();
7592   int typi=(int)typ;
7593   int nbNodesPerCell=(int)cm.getNumberOfNodes();
7594   MCAuto<DataArrayInt> connOut=DataArrayInt::New(); connOut->alloc(nbCells*nbNodesPerCell,1);
7595   int *outPtr=connOut->getPointer();
7596   const int *conn=_nodal_connec->begin();
7597   const int *connI=_nodal_connec_index->begin();
7598   nbNodesPerCell++;
7599   for(int i=0;i<nbCells;i++,connI++)
7600     {
7601       if(conn[connI[0]]==typi && connI[1]-connI[0]==nbNodesPerCell)
7602         outPtr=std::copy(conn+connI[0]+1,conn+connI[1],outPtr);
7603       else
7604         {
7605           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 << ") !";
7606           throw INTERP_KERNEL::Exception(oss.str());
7607         }
7608     }
7609   return connOut.retn();
7610 }
7611
7612 /*!
7613  * Convert the nodal connectivity of the mesh so that all the cells are of dynamic types (polygon or quadratic
7614  * polygon). This returns the corresponding new nodal connectivity in \ref numbering-indirect format.
7615  * \param nodalConn
7616  * \param nodalConnI
7617  */
7618 void MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh(DataArrayInt *&nodalConn, DataArrayInt *&nodalConnIndex) const
7619 {
7620   static const char msg0[]="MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : nodal connectivity in this are invalid ! Call checkConsistency !";
7621   checkConnectivityFullyDefined();
7622   if(_types.size()!=1)
7623     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : current mesh does not contain exactly one geometric type !");
7624   int nbCells=getNumberOfCells(),lgth=_nodal_connec->getNumberOfTuples();
7625   if(lgth<nbCells)
7626     throw INTERP_KERNEL::Exception(msg0);
7627   MCAuto<DataArrayInt> c(DataArrayInt::New()),ci(DataArrayInt::New());
7628   c->alloc(lgth-nbCells,1); ci->alloc(nbCells+1,1);
7629   int *cp(c->getPointer()),*cip(ci->getPointer());
7630   const int *incp(_nodal_connec->begin()),*incip(_nodal_connec_index->begin());
7631   cip[0]=0;
7632   for(int i=0;i<nbCells;i++,cip++,incip++)
7633     {
7634       int strt(incip[0]+1),stop(incip[1]);//+1 to skip geo type
7635       int delta(stop-strt);
7636       if(delta>=1)
7637         {
7638           if((strt>=0 && strt<lgth) && (stop>=0 && stop<=lgth))
7639             cp=std::copy(incp+strt,incp+stop,cp);
7640           else
7641             throw INTERP_KERNEL::Exception(msg0);
7642         }
7643       else
7644         throw INTERP_KERNEL::Exception(msg0);
7645       cip[1]=cip[0]+delta;
7646     }
7647   nodalConn=c.retn(); nodalConnIndex=ci.retn();
7648 }
7649
7650 /*!
7651  * This method takes in input a vector of MEDCouplingUMesh instances lying on the same coordinates with same mesh dimensions.
7652  * Each mesh in \b ms must be sorted by type with the same order (typically using MEDCouplingUMesh::sortCellsInMEDFileFrmt).
7653  * This method is particulary useful for MED file interaction. It allows to aggregate several meshes and keeping the type sorting
7654  * and the track of the permutation by chunk of same geotype cells to retrieve it. The traditional formats old2new and new2old
7655  * are not used here to avoid the build of big permutation array.
7656  *
7657  * \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
7658  *                those specified in MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
7659  * \param [out] szOfCellGrpOfSameType is a newly allocated DataArrayInt instance whose number of tuples is equal to the number of chunks of same geotype
7660  *              in all meshes in \b ms. The accumulation of all values of this array is equal to the number of cells of returned mesh.
7661  * \param [out] idInMsOfCellGrpOfSameType is a newly allocated DataArrayInt instance having the same size than \b szOfCellGrpOfSameType. This
7662  *              output array gives for each chunck of same type the corresponding mesh id in \b ms.
7663  * \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
7664  *         is sorted by type following the geo cell types order of MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
7665  */
7666 MEDCouplingUMesh *MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& ms,
7667                                                                             DataArrayInt *&szOfCellGrpOfSameType,
7668                                                                             DataArrayInt *&idInMsOfCellGrpOfSameType)
7669 {
7670   std::vector<const MEDCouplingUMesh *> ms2;
7671   for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms.begin();it!=ms.end();it++)
7672     if(*it)
7673       {
7674         (*it)->checkConnectivityFullyDefined();
7675         ms2.push_back(*it);
7676       }
7677   if(ms2.empty())
7678     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : input vector is empty !");
7679   const DataArrayDouble *refCoo=ms2[0]->getCoords();
7680   int meshDim=ms2[0]->getMeshDimension();
7681   std::vector<const MEDCouplingUMesh *> m1ssm;
7682   std::vector< MCAuto<MEDCouplingUMesh> > m1ssmAuto;
7683   //
7684   std::vector<const MEDCouplingUMesh *> m1ssmSingle;
7685   std::vector< MCAuto<MEDCouplingUMesh> > m1ssmSingleAuto;
7686   int fake=0,rk=0;
7687   MCAuto<DataArrayInt> ret1(DataArrayInt::New()),ret2(DataArrayInt::New());
7688   ret1->alloc(0,1); ret2->alloc(0,1);
7689   for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms2.begin();it!=ms2.end();it++,rk++)
7690     {
7691       if(meshDim!=(*it)->getMeshDimension())
7692         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshdims mismatch !");
7693       if(refCoo!=(*it)->getCoords())
7694         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshes are not shared by a single coordinates coords !");
7695       std::vector<MEDCouplingUMesh *> sp=(*it)->splitByType();
7696       std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<const MEDCouplingUMesh *> >(m1ssm));
7697       std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<MCAuto<MEDCouplingUMesh> > >(m1ssmAuto));
7698       for(std::vector<MEDCouplingUMesh *>::const_iterator it2=sp.begin();it2!=sp.end();it2++)
7699         {
7700           MEDCouplingUMesh *singleCell=static_cast<MEDCouplingUMesh *>((*it2)->buildPartOfMySelf(&fake,&fake+1,true));
7701           m1ssmSingleAuto.push_back(singleCell);
7702           m1ssmSingle.push_back(singleCell);
7703           ret1->pushBackSilent((*it2)->getNumberOfCells()); ret2->pushBackSilent(rk);
7704         }
7705     }
7706   MCAuto<MEDCouplingUMesh> m1ssmSingle2=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmSingle);
7707   MCAuto<DataArrayInt> renum=m1ssmSingle2->sortCellsInMEDFileFrmt();
7708   std::vector<const MEDCouplingUMesh *> m1ssmfinal(m1ssm.size());
7709   for(std::size_t i=0;i<m1ssm.size();i++)
7710     m1ssmfinal[renum->getIJ(i,0)]=m1ssm[i];
7711   MCAuto<MEDCouplingUMesh> ret0=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmfinal);
7712   szOfCellGrpOfSameType=ret1->renumber(renum->begin());
7713   idInMsOfCellGrpOfSameType=ret2->renumber(renum->begin());
7714   return ret0.retn();
7715 }
7716
7717 /*!
7718  * This method returns a newly created DataArrayInt instance.
7719  * This method retrieves cell ids in [ \a begin, \a end ) that have the type \a type.
7720  */
7721 DataArrayInt *MEDCouplingUMesh::keepCellIdsByType(INTERP_KERNEL::NormalizedCellType type, const int *begin, const int *end) const
7722 {
7723   checkFullyDefined();
7724   const int *conn=_nodal_connec->begin();
7725   const int *connIndex=_nodal_connec_index->begin();
7726   MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(0,1);
7727   for(const int *w=begin;w!=end;w++)
7728     if((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]==type)
7729       ret->pushBackSilent(*w);
7730   return ret.retn();
7731 }
7732
7733 /*!
7734  * This method makes the assumption that da->getNumberOfTuples()<this->getNumberOfCells(). This method makes the assumption that ids contained in 'da'
7735  * are in [0:getNumberOfCells())
7736  */
7737 DataArrayInt *MEDCouplingUMesh::convertCellArrayPerGeoType(const DataArrayInt *da) const
7738 {
7739   checkFullyDefined();
7740   const int *conn=_nodal_connec->begin();
7741   const int *connI=_nodal_connec_index->begin();
7742   int nbOfCells=getNumberOfCells();
7743   std::set<INTERP_KERNEL::NormalizedCellType> types(getAllGeoTypes());
7744   int *tmp=new int[nbOfCells];
7745   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
7746     {
7747       int j=0;
7748       for(const int *i=connI;i!=connI+nbOfCells;i++)
7749         if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
7750           tmp[std::distance(connI,i)]=j++;
7751     }
7752   DataArrayInt *ret=DataArrayInt::New();
7753   ret->alloc(da->getNumberOfTuples(),da->getNumberOfComponents());
7754   ret->copyStringInfoFrom(*da);
7755   int *retPtr=ret->getPointer();
7756   const int *daPtr=da->begin();
7757   int nbOfElems=da->getNbOfElems();
7758   for(int k=0;k<nbOfElems;k++)
7759     retPtr[k]=tmp[daPtr[k]];
7760   delete [] tmp;
7761   return ret;
7762 }
7763
7764 /*!
7765  * This method reduced number of cells of this by keeping cells whose type is different from 'type' and if type=='type'
7766  * This method \b works \b for mesh sorted by type.
7767  * cells whose ids is in 'idsPerGeoType' array.
7768  * This method conserves coords and name of mesh.
7769  */
7770 MEDCouplingUMesh *MEDCouplingUMesh::keepSpecifiedCells(INTERP_KERNEL::NormalizedCellType type, const int *idsPerGeoTypeBg, const int *idsPerGeoTypeEnd) const
7771 {
7772   std::vector<int> code=getDistributionOfTypes();
7773   std::size_t nOfTypesInThis=code.size()/3;
7774   int sz=0,szOfType=0;
7775   for(std::size_t i=0;i<nOfTypesInThis;i++)
7776     {
7777       if(code[3*i]!=type)
7778         sz+=code[3*i+1];
7779       else
7780         szOfType=code[3*i+1];
7781     }
7782   for(const int *work=idsPerGeoTypeBg;work!=idsPerGeoTypeEnd;work++)
7783     if(*work<0 || *work>=szOfType)
7784       {
7785         std::ostringstream oss; oss << "MEDCouplingUMesh::keepSpecifiedCells : Request on type " << type << " at place #" << std::distance(idsPerGeoTypeBg,work) << " value " << *work;
7786         oss << ". It should be in [0," << szOfType << ") !";
7787         throw INTERP_KERNEL::Exception(oss.str());
7788       }
7789   MCAuto<DataArrayInt> idsTokeep=DataArrayInt::New(); idsTokeep->alloc(sz+(int)std::distance(idsPerGeoTypeBg,idsPerGeoTypeEnd),1);
7790   int *idsPtr=idsTokeep->getPointer();
7791   int offset=0;
7792   for(std::size_t i=0;i<nOfTypesInThis;i++)
7793     {
7794       if(code[3*i]!=type)
7795         for(int j=0;j<code[3*i+1];j++)
7796           *idsPtr++=offset+j;
7797       else
7798         idsPtr=std::transform(idsPerGeoTypeBg,idsPerGeoTypeEnd,idsPtr,std::bind2nd(std::plus<int>(),offset));
7799       offset+=code[3*i+1];
7800     }
7801   MCAuto<MEDCouplingUMesh> ret=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(idsTokeep->begin(),idsTokeep->end(),true));
7802   ret->copyTinyInfoFrom(this);
7803   return ret.retn();
7804 }
7805
7806 /*!
7807  * This method returns a vector of size 'this->getNumberOfCells()'.
7808  * This method retrieves for each cell in \a this if it is linear (false) or quadratic(true).
7809  */
7810 std::vector<bool> MEDCouplingUMesh::getQuadraticStatus() const
7811 {
7812   int ncell=getNumberOfCells();
7813   std::vector<bool> ret(ncell);
7814   const int *cI=getNodalConnectivityIndex()->begin();
7815   const int *c=getNodalConnectivity()->begin();
7816   for(int i=0;i<ncell;i++)
7817     {
7818       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[i]];
7819       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
7820       ret[i]=cm.isQuadratic();
7821     }
7822   return ret;
7823 }
7824
7825 /*!
7826  * Returns a newly created mesh (with ref count ==1) that contains merge of \a this and \a other.
7827  */
7828 MEDCouplingMesh *MEDCouplingUMesh::mergeMyselfWith(const MEDCouplingMesh *other) const
7829 {
7830   if(other->getType()!=UNSTRUCTURED)
7831     throw INTERP_KERNEL::Exception("Merge of umesh only available with umesh each other !");
7832   const MEDCouplingUMesh *otherC=static_cast<const MEDCouplingUMesh *>(other);
7833   return MergeUMeshes(this,otherC);
7834 }
7835
7836 /*!
7837  * Returns a new DataArrayDouble holding barycenters of all cells. The barycenter is
7838  * computed by averaging coordinates of cell nodes, so this method is not a right
7839  * choice for degnerated meshes (not well oriented, cells with measure close to zero).
7840  *  \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
7841  *          this->getNumberOfCells() tuples per \a this->getSpaceDimension()
7842  *          components. The caller is to delete this array using decrRef() as it is
7843  *          no more needed.
7844  *  \throw If the coordinates array is not set.
7845  *  \throw If the nodal connectivity of cells is not defined.
7846  *  \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
7847  */
7848 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMass() const
7849 {
7850   MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
7851   int spaceDim=getSpaceDimension();
7852   int nbOfCells=getNumberOfCells();
7853   ret->alloc(nbOfCells,spaceDim);
7854   ret->copyStringInfoFrom(*getCoords());
7855   double *ptToFill=ret->getPointer();
7856   const int *nodal=_nodal_connec->begin();
7857   const int *nodalI=_nodal_connec_index->begin();
7858   const double *coor=_coords->begin();
7859   for(int i=0;i<nbOfCells;i++)
7860     {
7861       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
7862       INTERP_KERNEL::computeBarycenter2<int,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[i]+1,nodalI[i+1]-nodalI[i]-1,coor,spaceDim,ptToFill);
7863       ptToFill+=spaceDim;
7864     }
7865   return ret.retn();
7866 }
7867
7868 /*!
7869  * This method computes for each cell in \a this, the location of the iso barycenter of nodes constituting
7870  * the cell. Contrary to badly named MEDCouplingUMesh::computeCellCenterOfMass method that returns the center of inertia of the 
7871  * 
7872  * \return a newly allocated DataArrayDouble instance that the caller has to deal with. The returned 
7873  *          DataArrayDouble instance will have \c this->getNumberOfCells() tuples and \c this->getSpaceDimension() components.
7874  * 
7875  * \sa MEDCouplingUMesh::computeCellCenterOfMass
7876  * \throw If \a this is not fully defined (coordinates and connectivity)
7877  * \throw If there is presence in nodal connectivity in \a this of node ids not in [0, \c this->getNumberOfNodes() )
7878  */
7879 DataArrayDouble *MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell() const
7880 {
7881   checkFullyDefined();
7882   MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
7883   int spaceDim=getSpaceDimension();
7884   int nbOfCells=getNumberOfCells();
7885   int nbOfNodes=getNumberOfNodes();
7886   ret->alloc(nbOfCells,spaceDim);
7887   double *ptToFill=ret->getPointer();
7888   const int *nodal=_nodal_connec->begin();
7889   const int *nodalI=_nodal_connec_index->begin();
7890   const double *coor=_coords->begin();
7891   for(int i=0;i<nbOfCells;i++,ptToFill+=spaceDim)
7892     {
7893       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
7894       std::fill(ptToFill,ptToFill+spaceDim,0.);
7895       if(type!=INTERP_KERNEL::NORM_POLYHED)
7896         {
7897           for(const int *conn=nodal+nodalI[i]+1;conn!=nodal+nodalI[i+1];conn++)
7898             {
7899               if(*conn>=0 && *conn<nbOfNodes)
7900                 std::transform(coor+spaceDim*conn[0],coor+spaceDim*(conn[0]+1),ptToFill,ptToFill,std::plus<double>());
7901               else
7902                 {
7903                   std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of nodeId #" << *conn << " should be in [0," <<   nbOfNodes << ") !";
7904                   throw INTERP_KERNEL::Exception(oss.str());
7905                 }
7906             }
7907           int nbOfNodesInCell=nodalI[i+1]-nodalI[i]-1;
7908           if(nbOfNodesInCell>0)
7909             std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies<double>(),1./(double)nbOfNodesInCell));
7910           else
7911             {
7912               std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of cell with no nodes !";
7913               throw INTERP_KERNEL::Exception(oss.str());
7914             }
7915         }
7916       else
7917         {
7918           std::set<int> s(nodal+nodalI[i]+1,nodal+nodalI[i+1]);
7919           s.erase(-1);
7920           for(std::set<int>::const_iterator it=s.begin();it!=s.end();it++)
7921             {
7922               if(*it>=0 && *it<nbOfNodes)
7923                 std::transform(coor+spaceDim*(*it),coor+spaceDim*((*it)+1),ptToFill,ptToFill,std::plus<double>());
7924               else
7925                 {
7926                   std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell polyhedron cell #" << i << " presence of nodeId #" << *it << " should be in [0," <<   nbOfNodes << ") !";
7927                   throw INTERP_KERNEL::Exception(oss.str());
7928                 }
7929             }
7930           if(!s.empty())
7931             std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies<double>(),1./(double)s.size()));
7932           else
7933             {
7934               std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on polyhedron cell #" << i << " there are no nodes !";
7935               throw INTERP_KERNEL::Exception(oss.str());
7936             }
7937         }
7938     }
7939   return ret.retn();
7940 }
7941
7942 /*!
7943  * Returns a new DataArrayDouble holding barycenters of specified cells. The
7944  * barycenter is computed by averaging coordinates of cell nodes. The cells to treat
7945  * are specified via an array of cell ids. 
7946  *  \warning Validity of the specified cell ids is not checked! 
7947  *           Valid range is [ 0, \a this->getNumberOfCells() ).
7948  *  \param [in] begin - an array of cell ids of interest.
7949  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
7950  *  \return DataArrayDouble * - a new instance of DataArrayDouble, of size ( \a
7951  *          end - \a begin ) tuples per \a this->getSpaceDimension() components. The
7952  *          caller is to delete this array using decrRef() as it is no more needed. 
7953  *  \throw If the coordinates array is not set.
7954  *  \throw If the nodal connectivity of cells is not defined.
7955  *
7956  *  \if ENABLE_EXAMPLES
7957  *  \ref cpp_mcumesh_getPartBarycenterAndOwner "Here is a C++ example".<br>
7958  *  \ref  py_mcumesh_getPartBarycenterAndOwner "Here is a Python example".
7959  *  \endif
7960  */
7961 DataArrayDouble *MEDCouplingUMesh::getPartBarycenterAndOwner(const int *begin, const int *end) const
7962 {
7963   DataArrayDouble *ret=DataArrayDouble::New();
7964   int spaceDim=getSpaceDimension();
7965   int nbOfTuple=(int)std::distance(begin,end);
7966   ret->alloc(nbOfTuple,spaceDim);
7967   double *ptToFill=ret->getPointer();
7968   double *tmp=new double[spaceDim];
7969   const int *nodal=_nodal_connec->begin();
7970   const int *nodalI=_nodal_connec_index->begin();
7971   const double *coor=_coords->begin();
7972   for(const int *w=begin;w!=end;w++)
7973     {
7974       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[*w]];
7975       INTERP_KERNEL::computeBarycenter2<int,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[*w]+1,nodalI[*w+1]-nodalI[*w]-1,coor,spaceDim,ptToFill);
7976       ptToFill+=spaceDim;
7977     }
7978   delete [] tmp;
7979   return ret;
7980 }
7981
7982 /*!
7983  * 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".
7984  * So the returned instance will have 4 components and \c this->getNumberOfCells() tuples.
7985  * So this method expects that \a this has a spaceDimension equal to 3 and meshDimension equal to 2.
7986  * The computation of the plane equation is done using each time the 3 first nodes of 2D cells.
7987  * This method is useful to detect 2D cells in 3D space that are not coplanar.
7988  * 
7989  * \return DataArrayDouble * - a new instance of DataArrayDouble having 4 components and a number of tuples equal to number of cells in \a this.
7990  * \throw If spaceDim!=3 or meshDim!=2.
7991  * \throw If connectivity of \a this is invalid.
7992  * \throw If connectivity of a cell in \a this points to an invalid node.
7993  */
7994 DataArrayDouble *MEDCouplingUMesh::computePlaneEquationOf3DFaces() const
7995 {
7996   MCAuto<DataArrayDouble> ret(DataArrayDouble::New());
7997   int nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
7998   if(getSpaceDimension()!=3 || getMeshDimension()!=2)
7999     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computePlaneEquationOf3DFaces : This method must be applied on a mesh having meshDimension equal 2 and a spaceDimension equal to 3 !");
8000   ret->alloc(nbOfCells,4);
8001   double *retPtr(ret->getPointer());
8002   const int *nodal(_nodal_connec->begin()),*nodalI(_nodal_connec_index->begin());
8003   const double *coor(_coords->begin());
8004   for(int i=0;i<nbOfCells;i++,nodalI++,retPtr+=4)
8005     {
8006       double matrix[16]={0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,0},matrix2[16];
8007       if(nodalI[1]-nodalI[0]>=3)
8008         {
8009           for(int j=0;j<3;j++)
8010             {
8011               int nodeId(nodal[nodalI[0]+1+j]);
8012               if(nodeId>=0 && nodeId<nbOfNodes)
8013                 std::copy(coor+nodeId*3,coor+(nodeId+1)*3,matrix+4*j);
8014               else
8015                 {
8016                   std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! This cell points to an invalid nodeId : " << nodeId << " !";
8017                   throw INTERP_KERNEL::Exception(oss.str());
8018                 }
8019             }
8020         }
8021       else
8022         {
8023           std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! Must be constitued by more than 3 nodes !";
8024           throw INTERP_KERNEL::Exception(oss.str());
8025         }
8026       INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
8027       retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
8028     }
8029   return ret.retn();
8030 }
8031
8032 /*!
8033  * This method expects as input a DataArrayDouble non nul instance 'da' that should be allocated. If not an exception is thrown.
8034  * 
8035  */
8036 MEDCouplingUMesh *MEDCouplingUMesh::Build0DMeshFromCoords(DataArrayDouble *da)
8037 {
8038   if(!da)
8039     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build0DMeshFromCoords : instance of DataArrayDouble must be not null !");
8040   da->checkAllocated();
8041   std::string name(da->getName());
8042   MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New(name,0));
8043   if(name.empty())
8044     ret->setName("Mesh");
8045   ret->setCoords(da);
8046   int nbOfTuples(da->getNumberOfTuples());
8047   MCAuto<DataArrayInt> c(DataArrayInt::New()),cI(DataArrayInt::New());
8048   c->alloc(2*nbOfTuples,1);
8049   cI->alloc(nbOfTuples+1,1);
8050   int *cp(c->getPointer()),*cip(cI->getPointer());
8051   *cip++=0;
8052   for(int i=0;i<nbOfTuples;i++)
8053     {
8054       *cp++=INTERP_KERNEL::NORM_POINT1;
8055       *cp++=i;
8056       *cip++=2*(i+1);
8057     }
8058   ret->setConnectivity(c,cI,true);
8059   return ret.retn();
8060 }
8061
8062 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::Build1DMeshFromCoords(DataArrayDouble *da)
8063 {
8064   if(!da)
8065     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build01MeshFromCoords : instance of DataArrayDouble must be not null !");
8066   da->checkAllocated();
8067   std::string name(da->getName());
8068   MCAuto<MEDCouplingUMesh> ret;
8069   {
8070     MCAuto<MEDCouplingCMesh> tmp(MEDCouplingCMesh::New());
8071     MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
8072     arr->alloc(da->getNumberOfTuples());
8073     tmp->setCoordsAt(0,arr);
8074     ret=tmp->buildUnstructured();
8075   }
8076   ret->setCoords(da);
8077   if(name.empty())
8078     ret->setName("Mesh");
8079   else
8080     ret->setName(name);
8081   return ret;
8082 }
8083
8084 /*!
8085  * Creates a new MEDCouplingUMesh by concatenating two given meshes of the same dimension.
8086  * Cells and nodes of
8087  * the first mesh precede cells and nodes of the second mesh within the result mesh.
8088  *  \param [in] mesh1 - the first mesh.
8089  *  \param [in] mesh2 - the second mesh.
8090  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
8091  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
8092  *          is no more needed.
8093  *  \throw If \a mesh1 == NULL or \a mesh2 == NULL.
8094  *  \throw If the coordinates array is not set in none of the meshes.
8095  *  \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
8096  *  \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
8097  */
8098 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
8099 {
8100   std::vector<const MEDCouplingUMesh *> tmp(2);
8101   tmp[0]=const_cast<MEDCouplingUMesh *>(mesh1); tmp[1]=const_cast<MEDCouplingUMesh *>(mesh2);
8102   return MergeUMeshes(tmp);
8103 }
8104
8105 /*!
8106  * Creates a new MEDCouplingUMesh by concatenating all given meshes of the same dimension.
8107  * Cells and nodes of
8108  * the *i*-th mesh precede cells and nodes of the (*i*+1)-th mesh within the result mesh.
8109  *  \param [in] a - a vector of meshes (MEDCouplingUMesh) to concatenate.
8110  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
8111  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
8112  *          is no more needed.
8113  *  \throw If \a a.size() == 0.
8114  *  \throw If \a a[ *i* ] == NULL.
8115  *  \throw If the coordinates array is not set in none of the meshes.
8116  *  \throw If \a a[ *i* ]->getMeshDimension() < 0.
8117  *  \throw If the meshes in \a a are of different dimension (getMeshDimension()).
8118  */
8119 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const std::vector<const MEDCouplingUMesh *>& a)
8120 {
8121   std::size_t sz=a.size();
8122   if(sz==0)
8123     return MergeUMeshesLL(a);
8124   for(std::size_t ii=0;ii<sz;ii++)
8125     if(!a[ii])
8126       {
8127         std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshes : item #" << ii << " in input array of size "<< sz << " is empty !";
8128         throw INTERP_KERNEL::Exception(oss.str());
8129       }
8130   std::vector< MCAuto<MEDCouplingUMesh> > bb(sz);
8131   std::vector< const MEDCouplingUMesh * > aa(sz);
8132   int spaceDim=-3;
8133   for(std::size_t i=0;i<sz && spaceDim==-3;i++)
8134     {
8135       const MEDCouplingUMesh *cur=a[i];
8136       const DataArrayDouble *coo=cur->getCoords();
8137       if(coo)
8138         spaceDim=coo->getNumberOfComponents();
8139     }
8140   if(spaceDim==-3)
8141     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : no spaceDim specified ! unable to perform merge !");
8142   for(std::size_t i=0;i<sz;i++)
8143     {
8144       bb[i]=a[i]->buildSetInstanceFromThis(spaceDim);
8145       aa[i]=bb[i];
8146     }
8147   return MergeUMeshesLL(aa);
8148 }
8149
8150 /// @cond INTERNAL
8151
8152 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesLL(const std::vector<const MEDCouplingUMesh *>& a)
8153 {
8154   if(a.empty())
8155     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : input array must be NON EMPTY !");
8156   std::vector<const MEDCouplingUMesh *>::const_iterator it=a.begin();
8157   int meshDim=(*it)->getMeshDimension();
8158   int nbOfCells=(*it)->getNumberOfCells();
8159   int meshLgth=(*it++)->getNodalConnectivityArrayLen();
8160   for(;it!=a.end();it++)
8161     {
8162       if(meshDim!=(*it)->getMeshDimension())
8163         throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, MergeUMeshes impossible !");
8164       nbOfCells+=(*it)->getNumberOfCells();
8165       meshLgth+=(*it)->getNodalConnectivityArrayLen();
8166     }
8167   std::vector<const MEDCouplingPointSet *> aps(a.size());
8168   std::copy(a.begin(),a.end(),aps.begin());
8169   MCAuto<DataArrayDouble> pts=MergeNodesArray(aps);
8170   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("merge",meshDim);
8171   ret->setCoords(pts);
8172   MCAuto<DataArrayInt> c=DataArrayInt::New();
8173   c->alloc(meshLgth,1);
8174   int *cPtr=c->getPointer();
8175   MCAuto<DataArrayInt> cI=DataArrayInt::New();
8176   cI->alloc(nbOfCells+1,1);
8177   int *cIPtr=cI->getPointer();
8178   *cIPtr++=0;
8179   int offset=0;
8180   int offset2=0;
8181   for(it=a.begin();it!=a.end();it++)
8182     {
8183       int curNbOfCell=(*it)->getNumberOfCells();
8184       const int *curCI=(*it)->_nodal_connec_index->begin();
8185       const int *curC=(*it)->_nodal_connec->begin();
8186       cIPtr=std::transform(curCI+1,curCI+curNbOfCell+1,cIPtr,std::bind2nd(std::plus<int>(),offset));
8187       for(int j=0;j<curNbOfCell;j++)
8188         {
8189           const int *src=curC+curCI[j];
8190           *cPtr++=*src++;
8191           for(;src!=curC+curCI[j+1];src++,cPtr++)
8192             {
8193               if(*src!=-1)
8194                 *cPtr=*src+offset2;
8195               else
8196                 *cPtr=-1;
8197             }
8198         }
8199       offset+=curCI[curNbOfCell];
8200       offset2+=(*it)->getNumberOfNodes();
8201     }
8202   //
8203   ret->setConnectivity(c,cI,true);
8204   return ret.retn();
8205 }
8206
8207 /// @endcond
8208
8209 /*!
8210  * Creates a new MEDCouplingUMesh by concatenating cells of two given meshes of same
8211  * dimension and sharing the node coordinates array.
8212  * All cells of the first mesh precede all cells of the second mesh
8213  * within the result mesh. 
8214  *  \param [in] mesh1 - the first mesh.
8215  *  \param [in] mesh2 - the second mesh.
8216  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
8217  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
8218  *          is no more needed.
8219  *  \throw If \a mesh1 == NULL or \a mesh2 == NULL.
8220  *  \throw If the meshes do not share the node coordinates array.
8221  *  \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
8222  *  \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
8223  */
8224 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
8225 {
8226   std::vector<const MEDCouplingUMesh *> tmp(2);
8227   tmp[0]=mesh1; tmp[1]=mesh2;
8228   return MergeUMeshesOnSameCoords(tmp);
8229 }
8230
8231 /*!
8232  * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
8233  * dimension and sharing the node coordinates array.
8234  * All cells of the *i*-th mesh precede all cells of the
8235  * (*i*+1)-th mesh within the result mesh.
8236  *  \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
8237  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
8238  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
8239  *          is no more needed.
8240  *  \throw If \a a.size() == 0.
8241  *  \throw If \a a[ *i* ] == NULL.
8242  *  \throw If the meshes do not share the node coordinates array.
8243  *  \throw If \a a[ *i* ]->getMeshDimension() < 0.
8244  *  \throw If the meshes in \a a are of different dimension (getMeshDimension()).
8245  */
8246 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes)
8247 {
8248   if(meshes.empty())
8249     throw INTERP_KERNEL::Exception("meshes input parameter is expected to be non empty.");
8250   for(std::size_t ii=0;ii<meshes.size();ii++)
8251     if(!meshes[ii])
8252       {
8253         std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshesOnSameCoords : item #" << ii << " in input array of size "<< meshes.size() << " is empty !";
8254         throw INTERP_KERNEL::Exception(oss.str());
8255       }
8256   const DataArrayDouble *coords=meshes.front()->getCoords();
8257   int meshDim=meshes.front()->getMeshDimension();
8258   std::vector<const MEDCouplingUMesh *>::const_iterator iter=meshes.begin();
8259   int meshLgth=0;
8260   int meshIndexLgth=0;
8261   for(;iter!=meshes.end();iter++)
8262     {
8263       if(coords!=(*iter)->getCoords())
8264         throw INTERP_KERNEL::Exception("meshes does not share the same coords ! Try using tryToShareSameCoords method !");
8265       if(meshDim!=(*iter)->getMeshDimension())
8266         throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, FuseUMeshesOnSameCoords impossible !");
8267       meshLgth+=(*iter)->getNodalConnectivityArrayLen();
8268       meshIndexLgth+=(*iter)->getNumberOfCells();
8269     }
8270   MCAuto<DataArrayInt> nodal=DataArrayInt::New();
8271   nodal->alloc(meshLgth,1);
8272   int *nodalPtr=nodal->getPointer();
8273   MCAuto<DataArrayInt> nodalIndex=DataArrayInt::New();
8274   nodalIndex->alloc(meshIndexLgth+1,1);
8275   int *nodalIndexPtr=nodalIndex->getPointer();
8276   int offset=0;
8277   for(iter=meshes.begin();iter!=meshes.end();iter++)
8278     {
8279       const int *nod=(*iter)->getNodalConnectivity()->begin();
8280       const int *index=(*iter)->getNodalConnectivityIndex()->begin();
8281       int nbOfCells=(*iter)->getNumberOfCells();
8282       int meshLgth2=(*iter)->getNodalConnectivityArrayLen();
8283       nodalPtr=std::copy(nod,nod+meshLgth2,nodalPtr);
8284       if(iter!=meshes.begin())
8285         nodalIndexPtr=std::transform(index+1,index+nbOfCells+1,nodalIndexPtr,std::bind2nd(std::plus<int>(),offset));
8286       else
8287         nodalIndexPtr=std::copy(index,index+nbOfCells+1,nodalIndexPtr);
8288       offset+=meshLgth2;
8289     }
8290   MEDCouplingUMesh *ret=MEDCouplingUMesh::New();
8291   ret->setName("merge");
8292   ret->setMeshDimension(meshDim);
8293   ret->setConnectivity(nodal,nodalIndex,true);
8294   ret->setCoords(coords);
8295   return ret;
8296 }
8297
8298 /*!
8299  * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
8300  * dimension and sharing the node coordinates array. Cells of the *i*-th mesh precede
8301  * cells of the (*i*+1)-th mesh within the result mesh. Duplicates of cells are
8302  * removed from \a this mesh and arrays mapping between new and old cell ids in "Old to
8303  * New" mode are returned for each input mesh.
8304  *  \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
8305  *  \param [in] compType - specifies a cell comparison technique. For meaning of its
8306  *          valid values [0,1,2], see zipConnectivityTraducer().
8307  *  \param [in,out] corr - an array of DataArrayInt, of the same size as \a
8308  *          meshes. The *i*-th array describes cell ids mapping for \a meshes[ *i* ]
8309  *          mesh. The caller is to delete each of the arrays using decrRef() as it is
8310  *          no more needed.
8311  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
8312  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
8313  *          is no more needed.
8314  *  \throw If \a meshes.size() == 0.
8315  *  \throw If \a meshes[ *i* ] == NULL.
8316  *  \throw If the meshes do not share the node coordinates array.
8317  *  \throw If \a meshes[ *i* ]->getMeshDimension() < 0.
8318  *  \throw If the \a meshes are of different dimension (getMeshDimension()).
8319  *  \throw If the nodal connectivity of cells of any of \a meshes is not defined.
8320  *  \throw If the nodal connectivity any of \a meshes includes an invalid id.
8321  */
8322 MEDCouplingUMesh *MEDCouplingUMesh::FuseUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes, int compType, std::vector<DataArrayInt *>& corr)
8323 {
8324   //All checks are delegated to MergeUMeshesOnSameCoords
8325   MCAuto<MEDCouplingUMesh> ret=MergeUMeshesOnSameCoords(meshes);
8326   MCAuto<DataArrayInt> o2n=ret->zipConnectivityTraducer(compType);
8327   corr.resize(meshes.size());
8328   std::size_t nbOfMeshes=meshes.size();
8329   int offset=0;
8330   const int *o2nPtr=o2n->begin();
8331   for(std::size_t i=0;i<nbOfMeshes;i++)
8332     {
8333       DataArrayInt *tmp=DataArrayInt::New();
8334       int curNbOfCells=meshes[i]->getNumberOfCells();
8335       tmp->alloc(curNbOfCells,1);
8336       std::copy(o2nPtr+offset,o2nPtr+offset+curNbOfCells,tmp->getPointer());
8337       offset+=curNbOfCells;
8338       tmp->setName(meshes[i]->getName());
8339       corr[i]=tmp;
8340     }
8341   return ret.retn();
8342 }
8343
8344 /*!
8345  * Makes all given meshes share the nodal connectivity array. The common connectivity
8346  * array is created by concatenating the connectivity arrays of all given meshes. All
8347  * the given meshes must be of the same space dimension but dimension of cells **can
8348  * differ**. This method is particulary useful in MEDLoader context to build a \ref
8349  * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
8350  * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
8351  *  \param [in,out] meshes - a vector of meshes to update.
8352  *  \throw If any of \a meshes is NULL.
8353  *  \throw If the coordinates array is not set in any of \a meshes.
8354  *  \throw If the nodal connectivity of cells is not defined in any of \a meshes.
8355  *  \throw If \a meshes are of different space dimension.
8356  */
8357 void MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords(const std::vector<MEDCouplingUMesh *>& meshes)
8358 {
8359   std::size_t sz=meshes.size();
8360   if(sz==0 || sz==1)
8361     return;
8362   std::vector< const DataArrayDouble * > coords(meshes.size());
8363   std::vector< const DataArrayDouble * >::iterator it2=coords.begin();
8364   for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++,it2++)
8365     {
8366       if((*it))
8367         {
8368           (*it)->checkConnectivityFullyDefined();
8369           const DataArrayDouble *coo=(*it)->getCoords();
8370           if(coo)
8371             *it2=coo;
8372           else
8373             {
8374               std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
8375               oss << " has no coordinate array defined !";
8376               throw INTERP_KERNEL::Exception(oss.str());
8377             }
8378         }
8379       else
8380         {
8381           std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
8382           oss << " is null !";
8383           throw INTERP_KERNEL::Exception(oss.str());
8384         }
8385     }
8386   MCAuto<DataArrayDouble> res=DataArrayDouble::Aggregate(coords);
8387   std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();
8388   int offset=(*it)->getNumberOfNodes();
8389   (*it++)->setCoords(res);
8390   for(;it!=meshes.end();it++)
8391     {
8392       int oldNumberOfNodes=(*it)->getNumberOfNodes();
8393       (*it)->setCoords(res);
8394       (*it)->shiftNodeNumbersInConn(offset);
8395       offset+=oldNumberOfNodes;
8396     }
8397 }
8398
8399 /*!
8400  * Merges nodes coincident with a given precision within all given meshes that share
8401  * the nodal connectivity array. The given meshes **can be of different** mesh
8402  * dimension. This method is particulary useful in MEDLoader context to build a \ref
8403  * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
8404  * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array. 
8405  *  \param [in,out] meshes - a vector of meshes to update.
8406  *  \param [in] eps - the precision used to detect coincident nodes (infinite norm).
8407  *  \throw If any of \a meshes is NULL.
8408  *  \throw If the \a meshes do not share the same node coordinates array.
8409  *  \throw If the nodal connectivity of cells is not defined in any of \a meshes.
8410  */
8411 void MEDCouplingUMesh::MergeNodesOnUMeshesSharingSameCoords(const std::vector<MEDCouplingUMesh *>& meshes, double eps)
8412 {
8413   if(meshes.empty())
8414     return ;
8415   std::set<const DataArrayDouble *> s;
8416   for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
8417     {
8418       if(*it)
8419         s.insert((*it)->getCoords());
8420       else
8421         {
8422           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 !";
8423           throw INTERP_KERNEL::Exception(oss.str());
8424         }
8425     }
8426   if(s.size()!=1)
8427     {
8428       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 !";
8429       throw INTERP_KERNEL::Exception(oss.str());
8430     }
8431   const DataArrayDouble *coo=*(s.begin());
8432   if(!coo)
8433     return;
8434   //
8435   DataArrayInt *comm,*commI;
8436   coo->findCommonTuples(eps,-1,comm,commI);
8437   MCAuto<DataArrayInt> tmp1(comm),tmp2(commI);
8438   int oldNbOfNodes=coo->getNumberOfTuples();
8439   int newNbOfNodes;
8440   MCAuto<DataArrayInt> o2n=DataArrayInt::ConvertIndexArrayToO2N(oldNbOfNodes,comm->begin(),commI->begin(),commI->end(),newNbOfNodes);
8441   if(oldNbOfNodes==newNbOfNodes)
8442     return ;
8443   MCAuto<DataArrayDouble> newCoords=coo->renumberAndReduce(o2n->begin(),newNbOfNodes);
8444   for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
8445     {
8446       (*it)->renumberNodesInConn(o2n->begin());
8447       (*it)->setCoords(newCoords);
8448     } 
8449 }
8450
8451 /*!
8452  * 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.
8453  * \param nbOfNodesPerLev in parameter that specifies the number of nodes of one slice of global dataset
8454  * \param isQuad specifies the policy of connectivity.
8455  * @ret in/out parameter in which the result will be append
8456  */
8457 void MEDCouplingUMesh::AppendExtrudedCell(const int *connBg, const int *connEnd, int nbOfNodesPerLev, bool isQuad, std::vector<int>& ret)
8458 {
8459   INTERP_KERNEL::NormalizedCellType flatType=(INTERP_KERNEL::NormalizedCellType)connBg[0];
8460   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(flatType);
8461   ret.push_back(cm.getExtrudedType());
8462   int deltaz=isQuad?2*nbOfNodesPerLev:nbOfNodesPerLev;
8463   switch(flatType)
8464   {
8465     case INTERP_KERNEL::NORM_POINT1:
8466       {
8467         ret.push_back(connBg[1]);
8468         ret.push_back(connBg[1]+nbOfNodesPerLev);
8469         break;
8470       }
8471     case INTERP_KERNEL::NORM_SEG2:
8472       {
8473         int conn[4]={connBg[1],connBg[2],connBg[2]+deltaz,connBg[1]+deltaz};
8474         ret.insert(ret.end(),conn,conn+4);
8475         break;
8476       }
8477     case INTERP_KERNEL::NORM_SEG3:
8478       {
8479         int conn[8]={connBg[1],connBg[3],connBg[3]+deltaz,connBg[1]+deltaz,connBg[2],connBg[3]+nbOfNodesPerLev,connBg[2]+deltaz,connBg[1]+nbOfNodesPerLev};
8480         ret.insert(ret.end(),conn,conn+8);
8481         break;
8482       }
8483     case INTERP_KERNEL::NORM_QUAD4:
8484       {
8485         int conn[8]={connBg[1],connBg[2],connBg[3],connBg[4],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz,connBg[4]+deltaz};
8486         ret.insert(ret.end(),conn,conn+8);
8487         break;
8488       }
8489     case INTERP_KERNEL::NORM_TRI3:
8490       {
8491         int conn[6]={connBg[1],connBg[2],connBg[3],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz};
8492         ret.insert(ret.end(),conn,conn+6);
8493         break;
8494       }
8495     case INTERP_KERNEL::NORM_TRI6:
8496       {
8497         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,
8498           connBg[1]+nbOfNodesPerLev,connBg[2]+nbOfNodesPerLev,connBg[3]+nbOfNodesPerLev};
8499         ret.insert(ret.end(),conn,conn+15);
8500         break;
8501       }
8502     case INTERP_KERNEL::NORM_QUAD8:
8503       {
8504         int conn[20]={
8505           connBg[1],connBg[2],connBg[3],connBg[4],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz,connBg[4]+deltaz,
8506           connBg[5],connBg[6],connBg[7],connBg[8],connBg[5]+deltaz,connBg[6]+deltaz,connBg[7]+deltaz,connBg[8]+deltaz,
8507           connBg[1]+nbOfNodesPerLev,connBg[2]+nbOfNodesPerLev,connBg[3]+nbOfNodesPerLev,connBg[4]+nbOfNodesPerLev
8508         };
8509         ret.insert(ret.end(),conn,conn+20);
8510         break;
8511       }
8512     case INTERP_KERNEL::NORM_POLYGON:
8513       {
8514         std::back_insert_iterator< std::vector<int> > ii(ret);
8515         std::copy(connBg+1,connEnd,ii);
8516         *ii++=-1;
8517         std::reverse_iterator<const int *> rConnBg(connEnd);
8518         std::reverse_iterator<const int *> rConnEnd(connBg+1);
8519         std::transform(rConnBg,rConnEnd,ii,std::bind2nd(std::plus<int>(),deltaz));
8520         std::size_t nbOfRadFaces=std::distance(connBg+1,connEnd);
8521         for(std::size_t i=0;i<nbOfRadFaces;i++)
8522           {
8523             *ii++=-1;
8524             int conn[4]={connBg[(i+1)%nbOfRadFaces+1],connBg[i+1],connBg[i+1]+deltaz,connBg[(i+1)%nbOfRadFaces+1]+deltaz};
8525             std::copy(conn,conn+4,ii);
8526           }
8527         break;
8528       }
8529     default:
8530       throw INTERP_KERNEL::Exception("A flat type has been detected that has not its extruded representation !");
8531   }
8532 }
8533
8534 /*!
8535  * This static operates only for coords in 3D. The polygon is specfied by its connectivity nodes in [ \a begin , \a end ).
8536  */
8537 bool MEDCouplingUMesh::IsPolygonWellOriented(bool isQuadratic, const double *vec, const int *begin, const int *end, const double *coords)
8538 {
8539   std::size_t i, ip1;
8540   double v[3]={0.,0.,0.};
8541   std::size_t sz=std::distance(begin,end);
8542   if(isQuadratic)
8543     sz/=2;
8544   for(i=0;i<sz;i++)
8545     {
8546       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];
8547       v[1]+=coords[3*begin[i]+2]*coords[3*begin[(i+1)%sz]]-coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+2];
8548       v[2]+=coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+1]-coords[3*begin[i]+1]*coords[3*begin[(i+1)%sz]];
8549     }
8550   double ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
8551
8552   // Try using quadratic points if standard points are degenerated (for example a QPOLYG with two
8553   // SEG3 forming a circle):
8554   if (fabs(ret) < INTERP_KERNEL::DEFAULT_ABS_TOL && isQuadratic)
8555     {
8556       v[0] = 0.0; v[1] = 0.0; v[2] = 0.0;
8557       for(std::size_t j=0;j<sz;j++)
8558         {
8559           if (j%2)  // current point i is quadratic, next point i+1 is standard
8560             {
8561               i = sz+j;
8562               ip1 = (j+1)%sz; // ip1 = "i+1"
8563             }
8564           else      // current point i is standard, next point i+1 is quadratic
8565             {
8566               i = j;
8567               ip1 = j+sz;
8568             }
8569           v[0]+=coords[3*begin[i]+1]*coords[3*begin[ip1]+2]-coords[3*begin[i]+2]*coords[3*begin[ip1]+1];
8570           v[1]+=coords[3*begin[i]+2]*coords[3*begin[ip1]]-coords[3*begin[i]]*coords[3*begin[ip1]+2];
8571           v[2]+=coords[3*begin[i]]*coords[3*begin[ip1]+1]-coords[3*begin[i]+1]*coords[3*begin[ip1]];
8572         }
8573       ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
8574     }
8575   return (ret>0.);
8576 }
8577
8578 /*!
8579  * The polyhedron is specfied by its connectivity nodes in [ \a begin , \a end ).
8580  */
8581 bool MEDCouplingUMesh::IsPolyhedronWellOriented(const int *begin, const int *end, const double *coords)
8582 {
8583   std::vector<std::pair<int,int> > edges;
8584   std::size_t nbOfFaces=std::count(begin,end,-1)+1;
8585   const int *bgFace=begin;
8586   for(std::size_t i=0;i<nbOfFaces;i++)
8587     {
8588       const int *endFace=std::find(bgFace+1,end,-1);
8589       std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
8590       for(std::size_t j=0;j<nbOfEdgesInFace;j++)
8591         {
8592           std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
8593           if(std::find(edges.begin(),edges.end(),p1)!=edges.end())
8594             return false;
8595           edges.push_back(p1);
8596         }
8597       bgFace=endFace+1;
8598     }
8599   return INTERP_KERNEL::calculateVolumeForPolyh2<int,INTERP_KERNEL::ALL_C_MODE>(begin,(int)std::distance(begin,end),coords)>-EPS_FOR_POLYH_ORIENTATION;
8600 }
8601
8602 /*!
8603  * The 3D extruded static cell (PENTA6,HEXA8,HEXAGP12...) its connectivity nodes in [ \a begin , \a end ).
8604  */
8605 bool MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented(const int *begin, const int *end, const double *coords)
8606 {
8607   double vec0[3],vec1[3];
8608   std::size_t sz=std::distance(begin,end);
8609   if(sz%2!=0)
8610     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented : the length of nodal connectivity of extruded cell is not even !");
8611   int nbOfNodes=(int)sz/2;
8612   INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(begin,nbOfNodes,coords,vec0);
8613   const double *pt0=coords+3*begin[0];
8614   const double *pt1=coords+3*begin[nbOfNodes];
8615   vec1[0]=pt1[0]-pt0[0]; vec1[1]=pt1[1]-pt0[1]; vec1[2]=pt1[2]-pt0[2];
8616   return (vec0[0]*vec1[0]+vec0[1]*vec1[1]+vec0[2]*vec1[2])<0.;
8617 }
8618
8619 void MEDCouplingUMesh::CorrectExtrudedStaticCell(int *begin, int *end)
8620 {
8621   std::size_t sz=std::distance(begin,end);
8622   INTERP_KERNEL::AutoPtr<int> tmp=new int[sz];
8623   std::size_t nbOfNodes(sz/2);
8624   std::copy(begin,end,(int *)tmp);
8625   for(std::size_t j=1;j<nbOfNodes;j++)
8626     {
8627       begin[j]=tmp[nbOfNodes-j];
8628       begin[j+nbOfNodes]=tmp[nbOfNodes+nbOfNodes-j];
8629     }
8630 }
8631
8632 bool MEDCouplingUMesh::IsTetra4WellOriented(const int *begin, const int *end, const double *coords)
8633 {
8634   std::size_t sz=std::distance(begin,end);
8635   if(sz!=4)
8636     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsTetra4WellOriented : Tetra4 cell with not 4 nodes ! Call checkConsistency !");
8637   double vec0[3],vec1[3];
8638   const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[1],*pt2=coords+3*begin[2],*pt3=coords+3*begin[3];
8639   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]; 
8640   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;
8641 }
8642
8643 bool MEDCouplingUMesh::IsPyra5WellOriented(const int *begin, const int *end, const double *coords)
8644 {
8645   std::size_t sz=std::distance(begin,end);
8646   if(sz!=5)
8647     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsPyra5WellOriented : Pyra5 cell with not 5 nodes ! Call checkConsistency !");
8648   double vec0[3];
8649   INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(begin,4,coords,vec0);
8650   const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[4];
8651   return (vec0[0]*(pt1[0]-pt0[0])+vec0[1]*(pt1[1]-pt0[1])+vec0[2]*(pt1[2]-pt0[2]))<0.;
8652 }
8653
8654 /*!
8655  * 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 ) 
8656  * 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
8657  * a 2D space.
8658  *
8659  * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not.
8660  * \param [in] coords the coordinates with nb of components exactly equal to 3
8661  * \param [in] begin begin of the nodal connectivity (geometric type included) of a single polyhedron cell
8662  * \param [in] end end of nodal connectivity of a single polyhedron cell (excluded)
8663  * \param [out] res the result is put at the end of the vector without any alteration of the data.
8664  */
8665 void MEDCouplingUMesh::SimplifyPolyhedronCell(double eps, const DataArrayDouble *coords, const int *begin, const int *end, DataArrayInt *res)
8666 {
8667   int nbFaces=std::count(begin+1,end,-1)+1;
8668   MCAuto<DataArrayDouble> v=DataArrayDouble::New(); v->alloc(nbFaces,3);
8669   double *vPtr=v->getPointer();
8670   MCAuto<DataArrayDouble> p=DataArrayDouble::New(); p->alloc(nbFaces,1);
8671   double *pPtr=p->getPointer();
8672   const int *stFaceConn=begin+1;
8673   for(int i=0;i<nbFaces;i++,vPtr+=3,pPtr++)
8674     {
8675       const int *endFaceConn=std::find(stFaceConn,end,-1);
8676       ComputeVecAndPtOfFace(eps,coords->begin(),stFaceConn,endFaceConn,vPtr,pPtr);
8677       stFaceConn=endFaceConn+1;
8678     }
8679   pPtr=p->getPointer(); vPtr=v->getPointer();
8680   DataArrayInt *comm1=0,*commI1=0;
8681   v->findCommonTuples(eps,-1,comm1,commI1);
8682   MCAuto<DataArrayInt> comm1Auto(comm1),commI1Auto(commI1);
8683   const int *comm1Ptr=comm1->begin();
8684   const int *commI1Ptr=commI1->begin();
8685   int nbOfGrps1=commI1Auto->getNumberOfTuples()-1;
8686   res->pushBackSilent((int)INTERP_KERNEL::NORM_POLYHED);
8687   //
8688   MCAuto<MEDCouplingUMesh> mm=MEDCouplingUMesh::New("",3);
8689   mm->setCoords(const_cast<DataArrayDouble *>(coords)); mm->allocateCells(1); mm->insertNextCell(INTERP_KERNEL::NORM_POLYHED,(int)std::distance(begin+1,end),begin+1);
8690   mm->finishInsertingCells();
8691   //
8692   for(int i=0;i<nbOfGrps1;i++)
8693     {
8694       int vecId=comm1Ptr[commI1Ptr[i]];
8695       MCAuto<DataArrayDouble> tmpgrp2=p->selectByTupleId(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
8696       DataArrayInt *comm2=0,*commI2=0;
8697       tmpgrp2->findCommonTuples(eps,-1,comm2,commI2);
8698       MCAuto<DataArrayInt> comm2Auto(comm2),commI2Auto(commI2);
8699       const int *comm2Ptr=comm2->begin();
8700       const int *commI2Ptr=commI2->begin();
8701       int nbOfGrps2=commI2Auto->getNumberOfTuples()-1;
8702       for(int j=0;j<nbOfGrps2;j++)
8703         {
8704           if(commI2Ptr[j+1]-commI2Ptr[j]<=1)
8705             {
8706               res->insertAtTheEnd(begin,end);
8707               res->pushBackSilent(-1);
8708             }
8709           else
8710             {
8711               int pointId=comm1Ptr[commI1Ptr[i]+comm2Ptr[commI2Ptr[j]]];
8712               MCAuto<DataArrayInt> ids2=comm2->selectByTupleIdSafeSlice(commI2Ptr[j],commI2Ptr[j+1],1);
8713               ids2->transformWithIndArr(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
8714               DataArrayInt *tmp0=DataArrayInt::New(),*tmp1=DataArrayInt::New(),*tmp2=DataArrayInt::New(),*tmp3=DataArrayInt::New();
8715               MCAuto<MEDCouplingUMesh> mm2=mm->buildDescendingConnectivity(tmp0,tmp1,tmp2,tmp3); tmp0->decrRef(); tmp1->decrRef(); tmp2->decrRef(); tmp3->decrRef();
8716               MCAuto<MEDCouplingUMesh> mm3=static_cast<MEDCouplingUMesh *>(mm2->buildPartOfMySelf(ids2->begin(),ids2->end(),true));
8717               MCAuto<DataArrayInt> idsNodeTmp=mm3->zipCoordsTraducer();
8718               MCAuto<DataArrayInt> idsNode=idsNodeTmp->invertArrayO2N2N2O(mm3->getNumberOfNodes());
8719               const int *idsNodePtr=idsNode->begin();
8720               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];
8721               double vec[3]; vec[0]=vPtr[3*vecId+1]; vec[1]=-vPtr[3*vecId]; vec[2]=0.;
8722               double norm=vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2];
8723               if(std::abs(norm)>eps)
8724                 {
8725                   double angle=INTERP_KERNEL::EdgeArcCircle::SafeAsin(norm);
8726                   mm3->rotate(center,vec,angle);
8727                 }
8728               mm3->changeSpaceDimension(2);
8729               MCAuto<MEDCouplingUMesh> mm4=mm3->buildSpreadZonesWithPoly();
8730               const int *conn4=mm4->getNodalConnectivity()->begin();
8731               const int *connI4=mm4->getNodalConnectivityIndex()->begin();
8732               int nbOfCells=mm4->getNumberOfCells();
8733               for(int k=0;k<nbOfCells;k++)
8734                 {
8735                   int l=0;
8736                   for(const int *work=conn4+connI4[k]+1;work!=conn4+connI4[k+1];work++,l++)
8737                     res->pushBackSilent(idsNodePtr[*work]);
8738                   res->pushBackSilent(-1);
8739                 }
8740             }
8741         }
8742     }
8743   res->popBackSilent();
8744 }
8745
8746 /*!
8747  * 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
8748  * through origin. The plane is defined by its nodal connectivity [ \b begin, \b end ).
8749  * 
8750  * \param [in] eps below that value the dot product of 2 vectors is considered as colinears
8751  * \param [in] coords coordinates expected to have 3 components.
8752  * \param [in] begin start of the nodal connectivity of the face.
8753  * \param [in] end end of the nodal connectivity (excluded) of the face.
8754  * \param [out] v the normalized vector of size 3
8755  * \param [out] p the pos of plane
8756  */
8757 void MEDCouplingUMesh::ComputeVecAndPtOfFace(double eps, const double *coords, const int *begin, const int *end, double *v, double *p)
8758 {
8759   std::size_t nbPoints=std::distance(begin,end);
8760   if(nbPoints<3)
8761     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeVecAndPtOfFace : < of 3 points in face ! not able to find a plane on that face !");
8762   double vec[3]={0.,0.,0.};
8763   std::size_t j=0;
8764   bool refFound=false;
8765   for(;j<nbPoints-1 && !refFound;j++)
8766     {
8767       vec[0]=coords[3*begin[j+1]]-coords[3*begin[j]];
8768       vec[1]=coords[3*begin[j+1]+1]-coords[3*begin[j]+1];
8769       vec[2]=coords[3*begin[j+1]+2]-coords[3*begin[j]+2];
8770       double norm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
8771       if(norm>eps)
8772         {
8773           refFound=true;
8774           vec[0]/=norm; vec[1]/=norm; vec[2]/=norm;
8775         }
8776     }
8777   for(std::size_t i=j;i<nbPoints-1;i++)
8778     {
8779       double curVec[3];
8780       curVec[0]=coords[3*begin[i+1]]-coords[3*begin[i]];
8781       curVec[1]=coords[3*begin[i+1]+1]-coords[3*begin[i]+1];
8782       curVec[2]=coords[3*begin[i+1]+2]-coords[3*begin[i]+2];
8783       double norm=sqrt(curVec[0]*curVec[0]+curVec[1]*curVec[1]+curVec[2]*curVec[2]);
8784       if(norm<eps)
8785         continue;
8786       curVec[0]/=norm; curVec[1]/=norm; curVec[2]/=norm;
8787       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];
8788       norm=sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
8789       if(norm>eps)
8790         {
8791           v[0]/=norm; v[1]/=norm; v[2]/=norm;
8792           *p=v[0]*coords[3*begin[i]]+v[1]*coords[3*begin[i]+1]+v[2]*coords[3*begin[i]+2];
8793           return ;
8794         }
8795     }
8796   throw INTERP_KERNEL::Exception("Not able to find a normal vector of that 3D face !");
8797 }
8798
8799 /*!
8800  * This method tries to obtain a well oriented polyhedron.
8801  * If the algorithm fails, an exception will be thrown.
8802  */
8803 void MEDCouplingUMesh::TryToCorrectPolyhedronOrientation(int *begin, int *end, const double *coords)
8804 {
8805   std::list< std::pair<int,int> > edgesOK,edgesFinished;
8806   std::size_t nbOfFaces=std::count(begin,end,-1)+1;
8807   std::vector<bool> isPerm(nbOfFaces,false);//field on faces False: I don't know, True : oriented
8808   isPerm[0]=true;
8809   int *bgFace=begin,*endFace=std::find(begin+1,end,-1);
8810   std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
8811   for(std::size_t l=0;l<nbOfEdgesInFace;l++) { std::pair<int,int> p1(bgFace[l],bgFace[(l+1)%nbOfEdgesInFace]); edgesOK.push_back(p1); }
8812   //
8813   while(std::find(isPerm.begin(),isPerm.end(),false)!=isPerm.end())
8814     {
8815       bgFace=begin;
8816       std::size_t smthChanged=0;
8817       for(std::size_t i=0;i<nbOfFaces;i++)
8818         {
8819           endFace=std::find(bgFace+1,end,-1);
8820           nbOfEdgesInFace=std::distance(bgFace,endFace);
8821           if(!isPerm[i])
8822             {
8823               bool b;
8824               for(std::size_t j=0;j<nbOfEdgesInFace;j++)
8825                 {
8826                   std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
8827                   std::pair<int,int> p2(p1.second,p1.first);
8828                   bool b1=std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end();
8829                   bool b2=std::find(edgesOK.begin(),edgesOK.end(),p2)!=edgesOK.end();
8830                   if(b1 || b2) { b=b2; isPerm[i]=true; smthChanged++; break; }
8831                 }
8832               if(isPerm[i])
8833                 { 
8834                   if(!b)
8835                     std::reverse(bgFace+1,endFace);
8836                   for(std::size_t j=0;j<nbOfEdgesInFace;j++)
8837                     {
8838                       std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
8839                       std::pair<int,int> p2(p1.second,p1.first);
8840                       if(std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end())
8841                         { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
8842                       if(std::find(edgesFinished.begin(),edgesFinished.end(),p1)!=edgesFinished.end() || std::find(edgesFinished.begin(),edgesFinished.end(),p2)!=edgesFinished.end())
8843                         { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
8844                       std::list< std::pair<int,int> >::iterator it=std::find(edgesOK.begin(),edgesOK.end(),p2);
8845                       if(it!=edgesOK.end())
8846                         {
8847                           edgesOK.erase(it);
8848                           edgesFinished.push_back(p1);
8849                         }
8850                       else
8851                         edgesOK.push_back(p1);
8852                     }
8853                 }
8854             }
8855           bgFace=endFace+1;
8856         }
8857       if(smthChanged==0)
8858         { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired !"); }
8859     }
8860   if(!edgesOK.empty())
8861     { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired : Some edges are shared only once !"); }
8862   if(INTERP_KERNEL::calculateVolumeForPolyh2<int,INTERP_KERNEL::ALL_C_MODE>(begin,(int)std::distance(begin,end),coords)<-EPS_FOR_POLYH_ORIENTATION)
8863     {//not lucky ! The first face was not correctly oriented : reorient all faces...
8864       bgFace=begin;
8865       for(std::size_t i=0;i<nbOfFaces;i++)
8866         {
8867           endFace=std::find(bgFace+1,end,-1);
8868           std::reverse(bgFace+1,endFace);
8869           bgFace=endFace+1;
8870         }
8871     }
8872 }
8873
8874 DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMeshLinear(const MEDCouplingUMesh *skin, const DataArrayInt *n2o) const
8875 {
8876   int nbOfNodesExpected(skin->getNumberOfNodes());
8877   const int *n2oPtr(n2o->begin());
8878   MCAuto<DataArrayInt> revNodal(DataArrayInt::New()),revNodalI(DataArrayInt::New());
8879   skin->getReverseNodalConnectivity(revNodal,revNodalI);
8880   const int *revNodalPtr(revNodal->begin()),*revNodalIPtr(revNodalI->begin());
8881   const int *nodalPtr(skin->getNodalConnectivity()->begin());
8882   const int *nodalIPtr(skin->getNodalConnectivityIndex()->begin());
8883   MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(nbOfNodesExpected+1,1);
8884   int *work(ret->getPointer());  *work++=INTERP_KERNEL::NORM_POLYGON;
8885   if(nbOfNodesExpected<1)
8886     return ret.retn();
8887   int prevCell(0),prevNode(nodalPtr[nodalIPtr[0]+1]);
8888   *work++=n2oPtr[prevNode];
8889   for(int i=1;i<nbOfNodesExpected;i++)
8890     {
8891       if(nodalIPtr[prevCell+1]-nodalIPtr[prevCell]==3)
8892         {
8893           std::set<int> conn(nodalPtr+nodalIPtr[prevCell]+1,nodalPtr+nodalIPtr[prevCell]+3);
8894           conn.erase(prevNode);
8895           if(conn.size()==1)
8896             {
8897               int curNode(*(conn.begin()));
8898               *work++=n2oPtr[curNode];
8899               std::set<int> shar(revNodalPtr+revNodalIPtr[curNode],revNodalPtr+revNodalIPtr[curNode+1]);
8900               shar.erase(prevCell);
8901               if(shar.size()==1)
8902                 {
8903                   prevCell=*(shar.begin());
8904                   prevNode=curNode;
8905                 }
8906               else
8907                 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshLinear : presence of unexpected 2 !");
8908             }
8909           else
8910             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshLinear : presence of unexpected 1 !");
8911         }
8912       else
8913         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshLinear : presence of unexpected cell !");
8914     }
8915   return ret.retn();
8916 }
8917
8918 DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMeshQuadratic(const MEDCouplingUMesh *skin, const DataArrayInt *n2o) const
8919 {
8920   int nbOfNodesExpected(skin->getNumberOfNodes());
8921   int nbOfTurn(nbOfNodesExpected/2);
8922   const int *n2oPtr(n2o->begin());
8923   MCAuto<DataArrayInt> revNodal(DataArrayInt::New()),revNodalI(DataArrayInt::New());
8924   skin->getReverseNodalConnectivity(revNodal,revNodalI);
8925   const int *revNodalPtr(revNodal->begin()),*revNodalIPtr(revNodalI->begin());
8926   const int *nodalPtr(skin->getNodalConnectivity()->begin());
8927   const int *nodalIPtr(skin->getNodalConnectivityIndex()->begin());
8928   MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(nbOfNodesExpected+1,1);
8929   int *work(ret->getPointer());  *work++=INTERP_KERNEL::NORM_QPOLYG;
8930   if(nbOfNodesExpected<1)
8931     return ret.retn();
8932   int prevCell(0),prevNode(nodalPtr[nodalIPtr[0]+1]);
8933   *work=n2oPtr[prevNode]; work[nbOfTurn]=n2oPtr[nodalPtr[nodalIPtr[0]+3]]; work++;
8934   for(int i=1;i<nbOfTurn;i++)
8935     {
8936       if(nodalIPtr[prevCell+1]-nodalIPtr[prevCell]==4)
8937         {
8938           std::set<int> conn(nodalPtr+nodalIPtr[prevCell]+1,nodalPtr+nodalIPtr[prevCell]+3);
8939           conn.erase(prevNode);
8940           if(conn.size()==1)
8941             {
8942               int curNode(*(conn.begin()));
8943               *work=n2oPtr[curNode];
8944               std::set<int> shar(revNodalPtr+revNodalIPtr[curNode],revNodalPtr+revNodalIPtr[curNode+1]);
8945               shar.erase(prevCell);
8946               if(shar.size()==1)
8947                 {
8948                   int curCell(*(shar.begin()));
8949                   work[nbOfTurn]=n2oPtr[nodalPtr[nodalIPtr[curCell]+3]];
8950                   prevCell=curCell;
8951                   prevNode=curNode;
8952                   work++;
8953                 }
8954               else
8955                 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshQuadratic : presence of unexpected 2 !");
8956             }
8957           else
8958             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshQuadratic : presence of unexpected 1 !");
8959         }
8960       else
8961         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshQuadratic : presence of unexpected cell !");
8962     }
8963   return ret.retn();
8964 }
8965
8966 /*!
8967  * This method makes the assumption spacedimension == meshdimension == 2.
8968  * This method works only for linear cells.
8969  * 
8970  * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYGON in pos#0)
8971  */
8972 DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMesh() const
8973 {
8974   if(getMeshDimension()!=2 || getSpaceDimension()!=2)
8975     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : meshdimension, spacedimension must be equal to 2 !");
8976   MCAuto<MEDCouplingUMesh> skin(computeSkin());
8977   int oldNbOfNodes(skin->getNumberOfNodes());
8978   MCAuto<DataArrayInt> o2n(skin->zipCoordsTraducer());
8979   int nbOfNodesExpected(skin->getNumberOfNodes());
8980   MCAuto<DataArrayInt> n2o(o2n->invertArrayO2N2N2O(oldNbOfNodes));
8981   int nbCells(skin->getNumberOfCells());
8982   if(nbCells==nbOfNodesExpected)
8983     return buildUnionOf2DMeshLinear(skin,n2o);
8984   else if(2*nbCells==nbOfNodesExpected)
8985     return buildUnionOf2DMeshQuadratic(skin,n2o);
8986   else
8987     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : the mesh 2D in input appears to be not in a single part of a 2D mesh !");
8988 }
8989
8990 /*!
8991  * This method makes the assumption spacedimension == meshdimension == 3.
8992  * This method works only for linear cells.
8993  * 
8994  * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYHED in pos#0)
8995  */
8996 DataArrayInt *MEDCouplingUMesh::buildUnionOf3DMesh() const
8997 {
8998   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
8999     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf3DMesh : meshdimension, spacedimension must be equal to 2 !");
9000   MCAuto<MEDCouplingUMesh> m=computeSkin();
9001   const int *conn=m->getNodalConnectivity()->begin();
9002   const int *connI=m->getNodalConnectivityIndex()->begin();
9003   int nbOfCells=m->getNumberOfCells();
9004   MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(m->getNodalConnectivity()->getNumberOfTuples(),1);
9005   int *work=ret->getPointer();  *work++=INTERP_KERNEL::NORM_POLYHED;
9006   if(nbOfCells<1)
9007     return ret.retn();
9008   work=std::copy(conn+connI[0]+1,conn+connI[1],work);
9009   for(int i=1;i<nbOfCells;i++)
9010     {
9011       *work++=-1;
9012       work=std::copy(conn+connI[i]+1,conn+connI[i+1],work);
9013     }
9014   return ret.retn();
9015 }
9016
9017 /*!
9018  * \brief Creates a graph of cell neighbors
9019  *  \return MEDCouplingSkyLineArray * - an sky line array the user should delete.
9020  *  In the sky line array, graph arcs are stored in terms of (index,value) notation.
9021  *  For example
9022  *  - index:  0 3 5 6 6
9023  *  - value:  1 2 3 2 3 3
9024  *  means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
9025  *  Arcs are not doubled but reflexive (1,1) arcs are present for each cell
9026  */
9027 MEDCouplingSkyLineArray *MEDCouplingUMesh::generateGraph() const
9028 {
9029   checkConnectivityFullyDefined();
9030
9031   int meshDim = this->getMeshDimension();
9032   MEDCoupling::DataArrayInt* indexr=MEDCoupling::DataArrayInt::New();
9033   MEDCoupling::DataArrayInt* revConn=MEDCoupling::DataArrayInt::New();
9034   this->getReverseNodalConnectivity(revConn,indexr);
9035   const int* indexr_ptr=indexr->begin();
9036   const int* revConn_ptr=revConn->begin();
9037
9038   const MEDCoupling::DataArrayInt* index;
9039   const MEDCoupling::DataArrayInt* conn;
9040   conn=this->getNodalConnectivity(); // it includes a type as the 1st element!!!
9041   index=this->getNodalConnectivityIndex();
9042   int nbCells=this->getNumberOfCells();
9043   const int* index_ptr=index->begin();
9044   const int* conn_ptr=conn->begin();
9045
9046   //creating graph arcs (cell to cell relations)
9047   //arcs are stored in terms of (index,value) notation
9048   // 0 3 5 6 6
9049   // 1 2 3 2 3 3
9050   // means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
9051   // in present version arcs are not doubled but reflexive (1,1) arcs are present for each cell
9052
9053   //warning here one node have less than or equal effective number of cell with it
9054   //but cell could have more than effective nodes
9055   //because other equals nodes in other domain (with other global inode)
9056   std::vector <int> cell2cell_index(nbCells+1,0);
9057   std::vector <int> cell2cell;
9058   cell2cell.reserve(3*nbCells);
9059
9060   for (int icell=0; icell<nbCells;icell++)
9061     {
9062       std::map<int,int > counter;
9063       for (int iconn=index_ptr[icell]+1; iconn<index_ptr[icell+1];iconn++)
9064         {
9065           int inode=conn_ptr[iconn];
9066           for (int iconnr=indexr_ptr[inode]; iconnr<indexr_ptr[inode+1];iconnr++)
9067             {
9068               int icell2=revConn_ptr[iconnr];
9069               std::map<int,int>::iterator iter=counter.find(icell2);
9070               if (iter!=counter.end()) (iter->second)++;
9071               else counter.insert(std::make_pair(icell2,1));
9072             }
9073         }
9074       for (std::map<int,int>::const_iterator iter=counter.begin();
9075            iter!=counter.end(); iter++)
9076         if (iter->second >= meshDim)
9077           {
9078             cell2cell_index[icell+1]++;
9079             cell2cell.push_back(iter->first);
9080           }
9081     }
9082   indexr->decrRef();
9083   revConn->decrRef();
9084   cell2cell_index[0]=0;
9085   for (int icell=0; icell<nbCells;icell++)
9086     cell2cell_index[icell+1]=cell2cell_index[icell]+cell2cell_index[icell+1];
9087
9088   //filling up index and value to create skylinearray structure
9089   MEDCouplingSkyLineArray* array=new MEDCouplingSkyLineArray(cell2cell_index,cell2cell);
9090   return array;
9091 }
9092
9093 /*!
9094  * This method put in zip format into parameter 'zipFrmt' in full interlace mode.
9095  * This format is often asked by INTERP_KERNEL algorithms to avoid many indirections into coordinates array.
9096  */
9097 void MEDCouplingUMesh::FillInCompact3DMode(int spaceDim, int nbOfNodesInCell, const int *conn, const double *coo, double *zipFrmt)
9098 {
9099   double *w=zipFrmt;
9100   if(spaceDim==3)
9101     for(int i=0;i<nbOfNodesInCell;i++)
9102       w=std::copy(coo+3*conn[i],coo+3*conn[i]+3,w);
9103   else if(spaceDim==2)
9104     {
9105       for(int i=0;i<nbOfNodesInCell;i++)
9106         {
9107           w=std::copy(coo+2*conn[i],coo+2*conn[i]+2,w);
9108           *w++=0.;
9109         }
9110     }
9111   else
9112     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::FillInCompact3DMode : Invalid spaceDim specified : must be 2 or 3 !");
9113 }
9114
9115 void MEDCouplingUMesh::writeVTKLL(std::ostream& ofs, const std::string& cellData, const std::string& pointData, DataArrayByte *byteData) const
9116 {
9117   int nbOfCells=getNumberOfCells();
9118   if(nbOfCells<=0)
9119     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::writeVTK : the unstructured mesh has no cells !");
9120   ofs << "  <" << getVTKDataSetType() << ">\n";
9121   ofs << "    <Piece NumberOfPoints=\"" << getNumberOfNodes() << "\" NumberOfCells=\"" << nbOfCells << "\">\n";
9122   ofs << "      <PointData>\n" << pointData << std::endl;
9123   ofs << "      </PointData>\n";
9124   ofs << "      <CellData>\n" << cellData << std::endl;
9125   ofs << "      </CellData>\n";
9126   ofs << "      <Points>\n";
9127   if(getSpaceDimension()==3)
9128     _coords->writeVTK(ofs,8,"Points",byteData);
9129   else
9130     {
9131       MCAuto<DataArrayDouble> coo=_coords->changeNbOfComponents(3,0.);
9132       coo->writeVTK(ofs,8,"Points",byteData);
9133     }
9134   ofs << "      </Points>\n";
9135   ofs << "      <Cells>\n";
9136   const int *cPtr=_nodal_connec->begin();
9137   const int *cIPtr=_nodal_connec_index->begin();
9138   MCAuto<DataArrayInt> faceoffsets=DataArrayInt::New(); faceoffsets->alloc(nbOfCells,1);
9139   MCAuto<DataArrayInt> types=DataArrayInt::New(); types->alloc(nbOfCells,1);
9140   MCAuto<DataArrayInt> offsets=DataArrayInt::New(); offsets->alloc(nbOfCells,1);
9141   MCAuto<DataArrayInt> connectivity=DataArrayInt::New(); connectivity->alloc(_nodal_connec->getNumberOfTuples()-nbOfCells,1);
9142   int *w1=faceoffsets->getPointer(),*w2=types->getPointer(),*w3=offsets->getPointer(),*w4=connectivity->getPointer();
9143   int szFaceOffsets=0,szConn=0;
9144   for(int i=0;i<nbOfCells;i++,w1++,w2++,w3++)
9145     {
9146       *w2=cPtr[cIPtr[i]];
9147       if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]!=INTERP_KERNEL::NORM_POLYHED)
9148         {
9149           *w1=-1;
9150           *w3=szConn+cIPtr[i+1]-cIPtr[i]-1; szConn+=cIPtr[i+1]-cIPtr[i]-1;
9151           w4=std::copy(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],w4);
9152         }
9153       else
9154         {
9155           int deltaFaceOffset=cIPtr[i+1]-cIPtr[i]+1;
9156           *w1=szFaceOffsets+deltaFaceOffset; szFaceOffsets+=deltaFaceOffset;
9157           std::set<int> c(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1]); c.erase(-1);
9158           *w3=szConn+(int)c.size(); szConn+=(int)c.size();
9159           w4=std::copy(c.begin(),c.end(),w4);
9160         }
9161     }
9162   types->transformWithIndArr(MEDCOUPLING2VTKTYPETRADUCER,MEDCOUPLING2VTKTYPETRADUCER+INTERP_KERNEL::NORM_MAXTYPE+1);
9163   types->writeVTK(ofs,8,"UInt8","types",byteData);
9164   offsets->writeVTK(ofs,8,"Int32","offsets",byteData);
9165   if(szFaceOffsets!=0)
9166     {//presence of Polyhedra
9167       connectivity->reAlloc(szConn);
9168       faceoffsets->writeVTK(ofs,8,"Int32","faceoffsets",byteData);
9169       MCAuto<DataArrayInt> faces=DataArrayInt::New(); faces->alloc(szFaceOffsets,1);
9170       w1=faces->getPointer();
9171       for(int i=0;i<nbOfCells;i++)
9172         if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]==INTERP_KERNEL::NORM_POLYHED)
9173           {
9174             int nbFaces=std::count(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],-1)+1;
9175             *w1++=nbFaces;
9176             const int *w6=cPtr+cIPtr[i]+1,*w5=0;
9177             for(int j=0;j<nbFaces;j++)
9178               {
9179                 w5=std::find(w6,cPtr+cIPtr[i+1],-1);
9180                 *w1++=(int)std::distance(w6,w5);
9181                 w1=std::copy(w6,w5,w1);
9182                 w6=w5+1;
9183               }
9184           }
9185       faces->writeVTK(ofs,8,"Int32","faces",byteData);
9186     }
9187   connectivity->writeVTK(ofs,8,"Int32","connectivity",byteData);
9188   ofs << "      </Cells>\n";
9189   ofs << "    </Piece>\n";
9190   ofs << "  </" << getVTKDataSetType() << ">\n";
9191 }
9192
9193 void MEDCouplingUMesh::reprQuickOverview(std::ostream& stream) const
9194 {
9195   stream << "MEDCouplingUMesh C++ instance at " << this << ". Name : \"" << getName() << "\".";
9196   if(_mesh_dim==-2)
9197     { stream << " Not set !"; return ; }
9198   stream << " Mesh dimension : " << _mesh_dim << ".";
9199   if(_mesh_dim==-1)
9200     return ;
9201   if(!_coords)
9202     { stream << " No coordinates set !"; return ; }
9203   if(!_coords->isAllocated())
9204     { stream << " Coordinates set but not allocated !"; return ; }
9205   stream << " Space dimension : " << _coords->getNumberOfComponents() << "." << std::endl;
9206   stream << "Number of nodes : " << _coords->getNumberOfTuples() << ".";
9207   if(!_nodal_connec_index)
9208     { stream << std::endl << "Nodal connectivity NOT set !"; return ; }
9209   if(!_nodal_connec_index->isAllocated())
9210     { stream << std::endl << "Nodal connectivity set but not allocated !"; return ; }
9211   int lgth=_nodal_connec_index->getNumberOfTuples();
9212   int cpt=_nodal_connec_index->getNumberOfComponents();
9213   if(cpt!=1 || lgth<1)
9214     return ;
9215   stream << std::endl << "Number of cells : " << lgth-1 << ".";
9216 }
9217
9218 std::string MEDCouplingUMesh::getVTKDataSetType() const
9219 {
9220   return std::string("UnstructuredGrid");
9221 }
9222
9223 std::string MEDCouplingUMesh::getVTKFileExtension() const
9224 {
9225   return std::string("vtu");
9226 }
9227
9228 /*!
9229  * Partitions the first given 2D mesh using the second given 2D mesh as a tool, and
9230  * returns a result mesh constituted by polygons.
9231  * Thus the final result contains all nodes from m1 plus new nodes. However it doesn't necessarily contains
9232  * all nodes from m2.
9233  * The meshes should be in 2D space. In
9234  * addition, returns two arrays mapping cells of the result mesh to cells of the input
9235  * meshes.
9236  *  \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
9237  *                      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)
9238  *  \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
9239  *                      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)
9240  *  \param [in] eps - precision used to detect coincident mesh entities.
9241  *  \param [out] cellNb1 - a new instance of DataArrayInt holding for each result
9242  *         cell an id of the cell of \a m1 it comes from. The caller is to delete
9243  *         this array using decrRef() as it is no more needed.
9244  *  \param [out] cellNb2 - a new instance of DataArrayInt holding for each result
9245  *         cell an id of the cell of \a m2 it comes from. -1 value means that a
9246  *         result cell comes from a cell (or part of cell) of \a m1 not overlapped by
9247  *         any cell of \a m2. The caller is to delete this array using decrRef() as
9248  *         it is no more needed.  
9249  *  \return MEDCouplingUMesh * - the result 2D mesh which is a new instance of
9250  *         MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
9251  *         is no more needed.  
9252  *  \throw If the coordinates array is not set in any of the meshes.
9253  *  \throw If the nodal connectivity of cells is not defined in any of the meshes.
9254  *  \throw If any of the meshes is not a 2D mesh in 2D space.
9255  *
9256  *  \sa conformize2D, mergeNodes
9257  */
9258 MEDCouplingUMesh *MEDCouplingUMesh::Intersect2DMeshes(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2,
9259                                                       double eps, DataArrayInt *&cellNb1, DataArrayInt *&cellNb2)
9260 {
9261   if(!m1 || !m2)
9262     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshes : input meshes must be not NULL !");
9263   m1->checkFullyDefined();
9264   m2->checkFullyDefined();
9265   if(m1->getMeshDimension()!=2 || m1->getSpaceDimension()!=2 || m2->getMeshDimension()!=2 || m2->getSpaceDimension()!=2)
9266     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshes works on umeshes m1 AND m2  with meshdim equal to 2 and spaceDim equal to 2 too!");
9267
9268   // Step 1: compute all edge intersections (new nodes)
9269   std::vector< std::vector<int> > intersectEdge1, colinear2, subDiv2;
9270   MEDCouplingUMesh *m1Desc=0,*m2Desc=0; // descending connec. meshes
9271   DataArrayInt *desc1=0,*descIndx1=0,*revDesc1=0,*revDescIndx1=0,*desc2=0,*descIndx2=0,*revDesc2=0,*revDescIndx2=0;
9272   std::vector<double> addCoo,addCoordsQuadratic;  // coordinates of newly created nodes
9273   IntersectDescending2DMeshes(m1,m2,eps,intersectEdge1,colinear2, subDiv2,
9274                               m1Desc,desc1,descIndx1,revDesc1,revDescIndx1,
9275                               addCoo, m2Desc,desc2,descIndx2,revDesc2,revDescIndx2);
9276   revDesc1->decrRef(); revDescIndx1->decrRef(); revDesc2->decrRef(); revDescIndx2->decrRef();
9277   MCAuto<DataArrayInt> dd1(desc1),dd2(descIndx1),dd3(desc2),dd4(descIndx2);
9278   MCAuto<MEDCouplingUMesh> dd5(m1Desc),dd6(m2Desc);
9279
9280   // Step 2: re-order newly created nodes according to the ordering found in m2
9281   std::vector< std::vector<int> > intersectEdge2;
9282   BuildIntersectEdges(m1Desc,m2Desc,addCoo,subDiv2,intersectEdge2);
9283   subDiv2.clear(); dd5=0; dd6=0;
9284
9285   // Step 3:
9286   std::vector<int> cr,crI; //no DataArrayInt because interface with Geometric2D
9287   std::vector<int> cNb1,cNb2; //no DataArrayInt because interface with Geometric2D
9288   BuildIntersecting2DCellsFromEdges(eps,m1,desc1->begin(),descIndx1->begin(),intersectEdge1,colinear2,m2,desc2->begin(),descIndx2->begin(),intersectEdge2,addCoo,
9289                                     /* outputs -> */addCoordsQuadratic,cr,crI,cNb1,cNb2);
9290
9291   // Step 4: Prepare final result:
9292   MCAuto<DataArrayDouble> addCooDa(DataArrayDouble::New());
9293   addCooDa->alloc((int)(addCoo.size())/2,2);
9294   std::copy(addCoo.begin(),addCoo.end(),addCooDa->getPointer());
9295   MCAuto<DataArrayDouble> addCoordsQuadraticDa(DataArrayDouble::New());
9296   addCoordsQuadraticDa->alloc((int)(addCoordsQuadratic.size())/2,2);
9297   std::copy(addCoordsQuadratic.begin(),addCoordsQuadratic.end(),addCoordsQuadraticDa->getPointer());
9298   std::vector<const DataArrayDouble *> coordss(4);
9299   coordss[0]=m1->getCoords(); coordss[1]=m2->getCoords(); coordss[2]=addCooDa; coordss[3]=addCoordsQuadraticDa;
9300   MCAuto<DataArrayDouble> coo(DataArrayDouble::Aggregate(coordss));
9301   MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("Intersect2D",2));
9302   MCAuto<DataArrayInt> conn(DataArrayInt::New()); conn->alloc((int)cr.size(),1); std::copy(cr.begin(),cr.end(),conn->getPointer());
9303   MCAuto<DataArrayInt> connI(DataArrayInt::New()); connI->alloc((int)crI.size(),1); std::copy(crI.begin(),crI.end(),connI->getPointer());
9304   MCAuto<DataArrayInt> c1(DataArrayInt::New()); c1->alloc((int)cNb1.size(),1); std::copy(cNb1.begin(),cNb1.end(),c1->getPointer());
9305   MCAuto<DataArrayInt> c2(DataArrayInt::New()); c2->alloc((int)cNb2.size(),1); std::copy(cNb2.begin(),cNb2.end(),c2->getPointer());
9306   ret->setConnectivity(conn,connI,true);
9307   ret->setCoords(coo);
9308   cellNb1=c1.retn(); cellNb2=c2.retn();
9309   return ret.retn();
9310 }
9311
9312 /// @cond INTERNAL
9313
9314 bool IsColinearOfACellOf(const std::vector< std::vector<int> >& intersectEdge1, const std::vector<int>& candidates, int start, int stop, int& retVal)
9315 {
9316   if(candidates.empty())
9317     return false;
9318   for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
9319     {
9320       const std::vector<int>& pool(intersectEdge1[*it]);
9321       int tmp[2]; tmp[0]=start; tmp[1]=stop;
9322       if(std::search(pool.begin(),pool.end(),tmp,tmp+2)!=pool.end())
9323         {
9324           retVal=*it+1;
9325           return true;
9326         }
9327       tmp[0]=stop; tmp[1]=start;
9328       if(std::search(pool.begin(),pool.end(),tmp,tmp+2)!=pool.end())
9329         {
9330           retVal=-*it-1;
9331           return true;
9332         }
9333     }
9334   return false;
9335 }
9336
9337 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,
9338                                      MCAuto<DataArrayInt>& idsInRetColinear, MCAuto<DataArrayInt>& idsInMesh1DForIdsInRetColinear)
9339 {
9340   idsInRetColinear=DataArrayInt::New(); idsInRetColinear->alloc(0,1);
9341   idsInMesh1DForIdsInRetColinear=DataArrayInt::New(); idsInMesh1DForIdsInRetColinear->alloc(0,1);
9342   int nCells(mesh1D->getNumberOfCells());
9343   if(nCells!=(int)intersectEdge2.size())
9344     throw INTERP_KERNEL::Exception("BuildMesh1DCutFrom : internal error # 1 !");
9345   const DataArrayDouble *coo2(mesh1D->getCoords());
9346   const int *c(mesh1D->getNodalConnectivity()->begin()),*ci(mesh1D->getNodalConnectivityIndex()->begin());
9347   const double *coo2Ptr(coo2->begin());
9348   int offset1(coords1->getNumberOfTuples());
9349   int offset2(offset1+coo2->getNumberOfTuples());
9350   int offset3(offset2+addCoo.size()/2);
9351   std::vector<double> addCooQuad;
9352   MCAuto<DataArrayInt> cOut(DataArrayInt::New()),ciOut(DataArrayInt::New()); cOut->alloc(0,1); ciOut->alloc(1,1); ciOut->setIJ(0,0,0);
9353   int tmp[4],cicnt(0),kk(0);
9354   for(int i=0;i<nCells;i++)
9355     {
9356       std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
9357       INTERP_KERNEL::Edge *e(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[i]],c+ci[i]+1,coo2Ptr,m));
9358       const std::vector<int>& subEdges(intersectEdge2[i]);
9359       int nbSubEdge(subEdges.size()/2);
9360       for(int j=0;j<nbSubEdge;j++,kk++)
9361         {
9362           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));
9363           MCAuto<INTERP_KERNEL::Edge> e2(e->buildEdgeLyingOnMe(n1,n2));
9364           INTERP_KERNEL::Edge *e2Ptr(e2);
9365           std::map<int,int>::const_iterator itm;
9366           if(dynamic_cast<INTERP_KERNEL::EdgeArcCircle *>(e2Ptr))
9367             {
9368               tmp[0]=INTERP_KERNEL::NORM_SEG3;
9369               itm=mergedNodes.find(subEdges[2*j]);
9370               tmp[1]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j];
9371               itm=mergedNodes.find(subEdges[2*j+1]);
9372               tmp[2]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j+1];
9373               tmp[3]=offset3+(int)addCooQuad.size()/2;
9374               double tmp2[2];
9375               e2->getBarycenter(tmp2); addCooQuad.insert(addCooQuad.end(),tmp2,tmp2+2);
9376               cicnt+=4;
9377               cOut->insertAtTheEnd(tmp,tmp+4);
9378               ciOut->pushBackSilent(cicnt);
9379             }
9380           else
9381             {
9382               tmp[0]=INTERP_KERNEL::NORM_SEG2;
9383               itm=mergedNodes.find(subEdges[2*j]);
9384               tmp[1]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j];
9385               itm=mergedNodes.find(subEdges[2*j+1]);
9386               tmp[2]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j+1];
9387               cicnt+=3;
9388               cOut->insertAtTheEnd(tmp,tmp+3);
9389               ciOut->pushBackSilent(cicnt);
9390             }
9391           int tmp00;
9392           if(IsColinearOfACellOf(intersectEdge1,colinear2[i],tmp[1],tmp[2],tmp00))
9393             {
9394               idsInRetColinear->pushBackSilent(kk);
9395               idsInMesh1DForIdsInRetColinear->pushBackSilent(tmp00);
9396             }
9397         }
9398       e->decrRef();
9399     }
9400   MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New(mesh1D->getName(),1));
9401   ret->setConnectivity(cOut,ciOut,true);
9402   MCAuto<DataArrayDouble> arr3(DataArrayDouble::New());
9403   arr3->useArray(&addCoo[0],false,C_DEALLOC,(int)addCoo.size()/2,2);
9404   MCAuto<DataArrayDouble> arr4(DataArrayDouble::New()); arr4->useArray(&addCooQuad[0],false,C_DEALLOC,(int)addCooQuad.size()/2,2);
9405   std::vector<const DataArrayDouble *> coordss(4);
9406   coordss[0]=coords1; coordss[1]=mesh1D->getCoords(); coordss[2]=arr3; coordss[3]=arr4;
9407   MCAuto<DataArrayDouble> arr(DataArrayDouble::Aggregate(coordss));
9408   ret->setCoords(arr);
9409   return ret.retn();
9410 }
9411
9412 MEDCouplingUMesh *BuildRefined2DCellLinear(const DataArrayDouble *coords, const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1)
9413 {
9414   std::vector<int> allEdges;
9415   for(const int *it2(descBg);it2!=descEnd;it2++)
9416     {
9417       const std::vector<int>& edge1(intersectEdge1[std::abs(*it2)-1]);
9418       if(*it2>0)
9419         allEdges.insert(allEdges.end(),edge1.begin(),edge1.end());
9420       else
9421         allEdges.insert(allEdges.end(),edge1.rbegin(),edge1.rend());
9422     }
9423   std::size_t nb(allEdges.size());
9424   if(nb%2!=0)
9425     throw INTERP_KERNEL::Exception("BuildRefined2DCellLinear : internal error 1 !");
9426   std::size_t nbOfEdgesOf2DCellSplit(nb/2);
9427   MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
9428   ret->setCoords(coords);
9429   ret->allocateCells(1);
9430   std::vector<int> connOut(nbOfEdgesOf2DCellSplit);
9431   for(std::size_t kk=0;kk<nbOfEdgesOf2DCellSplit;kk++)
9432     connOut[kk]=allEdges[2*kk];
9433   ret->insertNextCell(INTERP_KERNEL::NORM_POLYGON,connOut.size(),&connOut[0]);
9434   return ret.retn();
9435 }
9436
9437 MEDCouplingUMesh *BuildRefined2DCellQuadratic(const DataArrayDouble *coords, const MEDCouplingUMesh *mesh2D, int cellIdInMesh2D, const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1)
9438 {
9439   const int *c(mesh2D->getNodalConnectivity()->begin()),*ci(mesh2D->getNodalConnectivityIndex()->begin());
9440   const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c[ci[cellIdInMesh2D]]));
9441   std::size_t ii(0);
9442   unsigned sz(cm.getNumberOfSons2(c+ci[cellIdInMesh2D]+1,ci[cellIdInMesh2D+1]-ci[cellIdInMesh2D]-1));
9443   if(sz!=std::distance(descBg,descEnd))
9444     throw INTERP_KERNEL::Exception("BuildRefined2DCellQuadratic : internal error 1 !");
9445   INTERP_KERNEL::AutoPtr<int> tmpPtr(new int[ci[cellIdInMesh2D+1]-ci[cellIdInMesh2D]]);
9446   std::vector<int> allEdges,centers;
9447   const double *coordsPtr(coords->begin());
9448   MCAuto<DataArrayDouble> addCoo(DataArrayDouble::New()); addCoo->alloc(0,1);
9449   int offset(coords->getNumberOfTuples());
9450   for(const int *it2(descBg);it2!=descEnd;it2++,ii++)
9451     {
9452       INTERP_KERNEL::NormalizedCellType typeOfSon;
9453       cm.fillSonCellNodalConnectivity2(ii,c+ci[cellIdInMesh2D]+1,ci[cellIdInMesh2D+1]-ci[cellIdInMesh2D]-1,tmpPtr,typeOfSon);
9454       const std::vector<int>& edge1(intersectEdge1[std::abs(*it2)-1]);
9455       if(*it2>0)
9456         allEdges.insert(allEdges.end(),edge1.begin(),edge1.end());
9457       else
9458         allEdges.insert(allEdges.end(),edge1.rbegin(),edge1.rend());
9459       if(edge1.size()==2)
9460         centers.push_back(tmpPtr[2]);//special case where no subsplit of edge -> reuse the original center.
9461       else
9462         {//the current edge has been subsplit -> create corresponding centers.
9463           std::size_t nbOfCentersToAppend(edge1.size()/2);
9464           std::map< MCAuto<INTERP_KERNEL::Node>,int> m;
9465           MCAuto<INTERP_KERNEL::Edge> ee(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpPtr,coordsPtr,m));
9466           std::vector<int>::const_iterator it3(allEdges.end()-edge1.size());
9467           for(std::size_t k=0;k<nbOfCentersToAppend;k++)
9468             {
9469               double tmpp[2];
9470               const double *aa(coordsPtr+2*(*it3++));
9471               const double *bb(coordsPtr+2*(*it3++));
9472               ee->getMiddleOfPoints(aa,bb,tmpp);
9473               addCoo->insertAtTheEnd(tmpp,tmpp+2);
9474               centers.push_back(offset+k);
9475             }
9476         }
9477     }
9478   std::size_t nb(allEdges.size());
9479   if(nb%2!=0)
9480     throw INTERP_KERNEL::Exception("BuildRefined2DCellQuadratic : internal error 2 !");
9481   std::size_t nbOfEdgesOf2DCellSplit(nb/2);
9482   MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
9483   if(addCoo->empty())
9484     ret->setCoords(coords);
9485   else
9486     {
9487       addCoo->rearrange(2);
9488       addCoo=DataArrayDouble::Aggregate(coords,addCoo);
9489       ret->setCoords(addCoo);
9490     }
9491   ret->allocateCells(1);
9492   std::vector<int> connOut(nbOfEdgesOf2DCellSplit);
9493   for(std::size_t kk=0;kk<nbOfEdgesOf2DCellSplit;kk++)
9494     connOut[kk]=allEdges[2*kk];
9495   connOut.insert(connOut.end(),centers.begin(),centers.end());
9496   ret->insertNextCell(INTERP_KERNEL::NORM_QPOLYG,connOut.size(),&connOut[0]);
9497   return ret.retn();
9498 }
9499
9500 /*!
9501  * This method creates a refinement of a cell in \a mesh2D. Those cell is defined by descending connectivity and the sorted subdivided nodal connectivity
9502  * of those edges.
9503  *
9504  * \param [in] mesh2D - The origin 2D mesh. \b Warning \b coords are not those of \a mesh2D. But mesh2D->getCoords()==coords[:mesh2D->getNumberOfNodes()]
9505  */
9506 MEDCouplingUMesh *BuildRefined2DCell(const DataArrayDouble *coords, const MEDCouplingUMesh *mesh2D, int cellIdInMesh2D, const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1)
9507 {
9508   const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(mesh2D->getTypeOfCell(cellIdInMesh2D)));
9509   if(!cm.isQuadratic())
9510     return BuildRefined2DCellLinear(coords,descBg,descEnd,intersectEdge1);
9511   else
9512     return BuildRefined2DCellQuadratic(coords,mesh2D,cellIdInMesh2D,descBg,descEnd,intersectEdge1);
9513 }
9514
9515 void AddCellInMesh2D(MEDCouplingUMesh *mesh2D, const std::vector<int>& conn, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edges)
9516 {
9517   bool isQuad(false);
9518   for(std::vector< MCAuto<INTERP_KERNEL::Edge> >::const_iterator it=edges.begin();it!=edges.end();it++)
9519     {
9520       const INTERP_KERNEL::Edge *ee(*it);
9521       if(dynamic_cast<const INTERP_KERNEL::EdgeArcCircle *>(ee))
9522         isQuad=true;
9523     }
9524   if(!isQuad)
9525     mesh2D->insertNextCell(INTERP_KERNEL::NORM_POLYGON,conn.size(),&conn[0]);
9526   else
9527     {
9528       const double *coo(mesh2D->getCoords()->begin());
9529       std::size_t sz(conn.size());
9530       std::vector<double> addCoo;
9531       std::vector<int> conn2(conn);
9532       int offset(mesh2D->getNumberOfNodes());
9533       for(std::size_t i=0;i<sz;i++)
9534         {
9535           double tmp[2];
9536           edges[(i+1)%sz]->getMiddleOfPoints(coo+2*conn[i],coo+2*conn[(i+1)%sz],tmp);// tony a chier i+1 -> i
9537           addCoo.insert(addCoo.end(),tmp,tmp+2);
9538           conn2.push_back(offset+(int)i);
9539         }
9540       mesh2D->getCoords()->rearrange(1);
9541       mesh2D->getCoords()->pushBackValsSilent(&addCoo[0],&addCoo[0]+addCoo.size());
9542       mesh2D->getCoords()->rearrange(2);
9543       mesh2D->insertNextCell(INTERP_KERNEL::NORM_QPOLYG,conn2.size(),&conn2[0]);
9544     }
9545 }
9546
9547 /*!
9548  * \b WARNING edges in out1 coming from \a splitMesh1D are \b NOT oriented because only used for equation of curve.
9549  *
9550  * This method cuts in 2 parts the input 2D cell given using boundaries description (\a edge1Bis and \a edge1BisPtr) using
9551  * a set of edges defined in \a splitMesh1D.
9552  */
9553 void BuildMesh2DCutInternal2(const MEDCouplingUMesh *splitMesh1D, const std::vector<int>& edge1Bis, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edge1BisPtr,
9554                              std::vector< std::vector<int> >& out0, std::vector< std::vector< MCAuto<INTERP_KERNEL::Edge> > >& out1)
9555 {
9556   std::size_t nb(edge1Bis.size()/2);
9557   std::size_t nbOfEdgesOf2DCellSplit(nb/2);
9558   int iEnd(splitMesh1D->getNumberOfCells());
9559   if(iEnd==0)
9560     throw INTERP_KERNEL::Exception("BuildMesh2DCutInternal2 : internal error ! input 1D mesh must have at least one cell !");
9561   std::size_t ii,jj;
9562   const int *cSplitPtr(splitMesh1D->getNodalConnectivity()->begin()),*ciSplitPtr(splitMesh1D->getNodalConnectivityIndex()->begin());
9563   for(ii=0;ii<nb && edge1Bis[2*ii]!=cSplitPtr[ciSplitPtr[0]+1];ii++);
9564   for(jj=ii;jj<nb && edge1Bis[2*jj+1]!=cSplitPtr[ciSplitPtr[iEnd-1]+2];jj++);
9565   //
9566   if(jj==nb)
9567     {//the edges splitMesh1D[iStart:iEnd] does not fully cut the current 2D cell -> single output cell
9568       out0.resize(1); out1.resize(1);
9569       std::vector<int>& connOut(out0[0]);
9570       connOut.resize(nbOfEdgesOf2DCellSplit);
9571       std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr(out1[0]);
9572       edgesPtr.resize(nbOfEdgesOf2DCellSplit);
9573       for(std::size_t kk=0;kk<nbOfEdgesOf2DCellSplit;kk++)
9574         {
9575           connOut[kk]=edge1Bis[2*kk];
9576           edgesPtr[kk]=edge1BisPtr[2*kk];
9577         }
9578     }
9579   else
9580     {
9581       // [i,iEnd[ contains the
9582       out0.resize(2); out1.resize(2);
9583       std::vector<int>& connOutLeft(out0[0]);
9584       std::vector<int>& connOutRight(out0[1]);//connOutLeft should end with edge1Bis[2*ii] and connOutRight should end with edge1Bis[2*jj+1]
9585       std::vector< MCAuto<INTERP_KERNEL::Edge> >& eleft(out1[0]);
9586       std::vector< MCAuto<INTERP_KERNEL::Edge> >& eright(out1[1]);
9587       for(std::size_t k=ii;k<jj+1;k++)
9588         { connOutLeft.push_back(edge1Bis[2*k+1]); eleft.push_back(edge1BisPtr[2*k+1]); }
9589       std::vector< MCAuto<INTERP_KERNEL::Edge> > ees(iEnd);
9590       for(int ik=0;ik<iEnd;ik++)
9591         {
9592           std::map< MCAuto<INTERP_KERNEL::Node>,int> m;
9593           MCAuto<INTERP_KERNEL::Edge> ee(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)cSplitPtr[ciSplitPtr[ik]],cSplitPtr+ciSplitPtr[ik]+1,splitMesh1D->getCoords()->begin(),m));
9594           ees[ik]=ee;
9595         }
9596       for(int ik=iEnd-1;ik>=0;ik--)
9597         connOutLeft.push_back(cSplitPtr[ciSplitPtr[ik]+1]);
9598       for(std::size_t k=jj+1;k<nbOfEdgesOf2DCellSplit+ii;k++)
9599         { connOutRight.push_back(edge1Bis[2*k+1]); eright.push_back(edge1BisPtr[2*k+1]); }
9600       eleft.insert(eleft.end(),ees.rbegin(),ees.rend());
9601       for(int ik=0;ik<iEnd;ik++)
9602         connOutRight.push_back(cSplitPtr[ciSplitPtr[ik]+2]);
9603       eright.insert(eright.end(),ees.begin(),ees.end());
9604     }
9605 }
9606
9607 /// @endcond
9608
9609 /// @cond INTERNAL
9610
9611 struct CellInfo
9612 {
9613 public:
9614   CellInfo() { }
9615   CellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr);
9616 public:
9617   std::vector<int> _edges;
9618   std::vector< MCAuto<INTERP_KERNEL::Edge> > _edges_ptr;
9619 };
9620
9621 CellInfo::CellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr)
9622 {
9623   std::size_t nbe(edges.size());
9624   std::vector<int> edges2(2*nbe); std::vector< MCAuto<INTERP_KERNEL::Edge> > edgesPtr2(2*nbe);
9625   for(std::size_t i=0;i<nbe;i++)
9626     {
9627       edges2[2*i]=edges[i]; edges2[2*i+1]=edges[(i+1)%nbe];
9628       edgesPtr2[2*i]=edgesPtr[(i+1)%nbe]; edgesPtr2[2*i+1]=edgesPtr[(i+1)%nbe];//tony a chier
9629     }
9630   _edges.resize(4*nbe); _edges_ptr.resize(4*nbe);
9631   std::copy(edges2.begin(),edges2.end(),_edges.begin()); std::copy(edges2.begin(),edges2.end(),_edges.begin()+2*nbe);
9632   std::copy(edgesPtr2.begin(),edgesPtr2.end(),_edges_ptr.begin()); std::copy(edgesPtr2.begin(),edgesPtr2.end(),_edges_ptr.begin()+2*nbe);
9633 }
9634
9635 class EdgeInfo
9636 {
9637 public:
9638   EdgeInfo(int istart, int iend, const MCAuto<MEDCouplingUMesh>& mesh):_istart(istart),_iend(iend),_mesh(mesh),_left(-7),_right(-7) { }
9639   EdgeInfo(int istart, int iend, int pos, const MCAuto<INTERP_KERNEL::Edge>& edge):_istart(istart),_iend(iend),_edge(edge),_left(pos),_right(pos+1) { }
9640   bool isInMyRange(int pos) const { return pos>=_istart && pos<_iend; }
9641   void somethingHappendAt(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight);
9642   void feedEdgeInfoAt(double eps, const MEDCouplingUMesh *mesh2D, int offset, int neighbors[2]) const;
9643 private:
9644   int _istart;
9645   int _iend;
9646   MCAuto<MEDCouplingUMesh> _mesh;
9647   MCAuto<INTERP_KERNEL::Edge> _edge;
9648   int _left;
9649   int _right;
9650 };
9651
9652 void EdgeInfo::somethingHappendAt(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight)
9653 {
9654   const MEDCouplingUMesh *mesh(_mesh);
9655   if(mesh)
9656     return ;
9657   if(_right<pos)
9658     return ;
9659   if(_left>pos)
9660     { _left++; _right++; return ; }
9661   if(_right==pos)
9662     {
9663       bool isLeft(std::find(newLeft.begin(),newLeft.end(),_edge)!=newLeft.end()),isRight(std::find(newRight.begin(),newRight.end(),_edge)!=newRight.end());
9664       if((isLeft && isRight) || (!isLeft && !isRight))
9665         throw INTERP_KERNEL::Exception("EdgeInfo::somethingHappendAt : internal error # 1 !");
9666       if(isLeft)
9667         return ;
9668       if(isRight)
9669         {
9670           _right++;
9671           return ;
9672         }
9673     }
9674   if(_left==pos)
9675     {
9676       bool isLeft(std::find(newLeft.begin(),newLeft.end(),_edge)!=newLeft.end()),isRight(std::find(newRight.begin(),newRight.end(),_edge)!=newRight.end());
9677       if((isLeft && isRight) || (!isLeft && !isRight))
9678         throw INTERP_KERNEL::Exception("EdgeInfo::somethingHappendAt : internal error # 2 !");
9679       if(isLeft)
9680         {
9681           _right++;
9682           return ;
9683         }
9684       if(isRight)
9685         {
9686           _left++;
9687           _right++;
9688           return ;
9689         }
9690     }
9691 }
9692
9693 void EdgeInfo::feedEdgeInfoAt(double eps, const MEDCouplingUMesh *mesh2D, int offset, int neighbors[2]) const
9694 {
9695   const MEDCouplingUMesh *mesh(_mesh);
9696   if(!mesh)
9697     {
9698       neighbors[0]=offset+_left; neighbors[1]=offset+_right;
9699     }
9700   else
9701     {// not fully splitting cell case
9702       if(mesh2D->getNumberOfCells()==1)
9703         {//little optimization. 1 cell no need to find in which cell mesh is !
9704           neighbors[0]=offset; neighbors[1]=offset;
9705           return;
9706         }
9707       else
9708         {
9709           MCAuto<DataArrayDouble> barys(mesh->computeCellCenterOfMass());
9710           int cellId(mesh2D->getCellContainingPoint(barys->begin(),eps));
9711           if(cellId==-1)
9712             throw INTERP_KERNEL::Exception("EdgeInfo::feedEdgeInfoAt : internal error !");
9713           neighbors[0]=offset+cellId; neighbors[1]=offset+cellId;
9714         }
9715     }
9716 }
9717
9718 class VectorOfCellInfo
9719 {
9720 public:
9721   VectorOfCellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr);
9722   std::size_t size() const { return _pool.size(); }
9723   int getPositionOf(double eps, const MEDCouplingUMesh *mesh) const;
9724   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);
9725   const std::vector<int>& getConnOf(int pos) const { return get(pos)._edges; }
9726   const std::vector< MCAuto<INTERP_KERNEL::Edge> >& getEdgePtrOf(int pos) const { return get(pos)._edges_ptr; }
9727   MCAuto<MEDCouplingUMesh> getZeMesh() const { return _ze_mesh; }
9728   void feedEdgeInfoAt(double eps, int pos, int offset, int neighbors[2]) const;
9729 private:
9730   int getZePosOfEdgeGivenItsGlobalId(int pos) const;
9731   void updateEdgeInfo(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight);
9732   const CellInfo& get(int pos) const;
9733   CellInfo& get(int pos);
9734 private:
9735   std::vector<CellInfo> _pool;
9736   MCAuto<MEDCouplingUMesh> _ze_mesh;
9737   std::vector<EdgeInfo> _edge_info;
9738 };
9739
9740 VectorOfCellInfo::VectorOfCellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr):_pool(1)
9741 {
9742   _pool[0]._edges=edges;
9743   _pool[0]._edges_ptr=edgesPtr;
9744 }
9745
9746 int VectorOfCellInfo::getPositionOf(double eps, const MEDCouplingUMesh *mesh) const
9747 {
9748   if(_pool.empty())
9749     throw INTERP_KERNEL::Exception("VectorOfCellSplitter::getPositionOf : empty !");
9750   if(_pool.size()==1)
9751     return 0;
9752   const MEDCouplingUMesh *zeMesh(_ze_mesh);
9753   if(!zeMesh)
9754     throw INTERP_KERNEL::Exception("VectorOfCellSplitter::getPositionOf : null aggregated mesh !");
9755   MCAuto<DataArrayDouble> barys(mesh->computeCellCenterOfMass());
9756   return zeMesh->getCellContainingPoint(barys->begin(),eps);
9757 }
9758
9759 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)
9760 {
9761   get(pos);//to check pos
9762   bool isFast(pos==0 && _pool.size()==1);
9763   std::size_t sz(edges.size());
9764   // dealing with edges
9765   if(sz==1)
9766     _edge_info.push_back(EdgeInfo(istart,iend,mesh1DInCase));
9767   else
9768     _edge_info.push_back(EdgeInfo(istart,iend,pos,edgePtrs[0].back()));
9769   //
9770   std::vector<CellInfo> pool(_pool.size()-1+sz);
9771   for(int i=0;i<pos;i++)
9772     pool[i]=_pool[i];
9773   for(std::size_t j=0;j<sz;j++)
9774     pool[pos+j]=CellInfo(edges[j],edgePtrs[j]);
9775   for(int i=pos+1;i<(int)_pool.size();i++)
9776     pool[i+sz-1]=_pool[i];
9777   _pool=pool;
9778   //
9779   if(sz==2)
9780     updateEdgeInfo(pos,edgePtrs[0],edgePtrs[1]);
9781   //
9782   if(isFast)
9783     {
9784       _ze_mesh=mesh;
9785       return ;
9786     }
9787   //
9788   std::vector< MCAuto<MEDCouplingUMesh> > ms;
9789   if(pos>0)
9790     {
9791       MCAuto<MEDCouplingUMesh> elt(static_cast<MEDCouplingUMesh *>(_ze_mesh->buildPartOfMySelfSlice(0,pos,true)));
9792       ms.push_back(elt);
9793     }
9794   ms.push_back(mesh);
9795   if(pos<_ze_mesh->getNumberOfCells()-1)
9796   {
9797     MCAuto<MEDCouplingUMesh> elt(static_cast<MEDCouplingUMesh *>(_ze_mesh->buildPartOfMySelfSlice(pos+1,_ze_mesh->getNumberOfCells(),true)));
9798     ms.push_back(elt);
9799   }
9800   std::vector< const MEDCouplingUMesh *> ms2(ms.size());
9801   for(std::size_t j=0;j<ms2.size();j++)
9802     ms2[j]=ms[j];
9803   _ze_mesh=MEDCouplingUMesh::MergeUMeshesOnSameCoords(ms2);
9804 }
9805
9806 void VectorOfCellInfo::feedEdgeInfoAt(double eps, int pos, int offset, int neighbors[2]) const
9807 {
9808   _edge_info[getZePosOfEdgeGivenItsGlobalId(pos)].feedEdgeInfoAt(eps,_ze_mesh,offset,neighbors);
9809 }
9810
9811 int VectorOfCellInfo::getZePosOfEdgeGivenItsGlobalId(int pos) const
9812 {
9813   if(pos<0)
9814     throw INTERP_KERNEL::Exception("VectorOfCellInfo::getZePosOfEdgeGivenItsGlobalId : invalid id ! Must be >=0 !");
9815   int ret(0);
9816   for(std::vector<EdgeInfo>::const_iterator it=_edge_info.begin();it!=_edge_info.end();it++,ret++)
9817     {
9818       if((*it).isInMyRange(pos))
9819         return ret;
9820     }
9821   throw INTERP_KERNEL::Exception("VectorOfCellInfo::getZePosOfEdgeGivenItsGlobalId : invalid id !");
9822 }
9823
9824 void VectorOfCellInfo::updateEdgeInfo(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight)
9825 {
9826   get(pos);//to check;
9827   if(_edge_info.empty())
9828     return ;
9829   std::size_t sz(_edge_info.size()-1);
9830   for(std::size_t i=0;i<sz;i++)
9831     _edge_info[i].somethingHappendAt(pos,newLeft,newRight);
9832 }
9833
9834 const CellInfo& VectorOfCellInfo::get(int pos) const
9835 {
9836   if(pos<0 || pos>=(int)_pool.size())
9837     throw INTERP_KERNEL::Exception("VectorOfCellSplitter::get const : invalid pos !");
9838   return _pool[pos];
9839 }
9840
9841 CellInfo& VectorOfCellInfo::get(int pos)
9842 {
9843   if(pos<0 || pos>=(int)_pool.size())
9844     throw INTERP_KERNEL::Exception("VectorOfCellSplitter::get : invalid pos !");
9845   return _pool[pos];
9846 }
9847
9848 /*!
9849  * Given :
9850  * - a \b closed set of edges ( \a allEdges and \a allEdgesPtr ) that defines the split descending 2D cell.
9851  * - \a splitMesh1D a split 2D curve mesh contained into 2D cell defined above.
9852  *
9853  * This method returns the 2D mesh and feeds \a idsLeftRight using offset.
9854  *
9855  * Algorithm : \a splitMesh1D is cut into contiguous parts. Each contiguous parts will build incrementally the output 2D cells.
9856  *
9857  * \param [in] allEdges a list of pairs (beginNode, endNode). Linked with \a allEdgesPtr to get the equation of edge.
9858  */
9859 MEDCouplingUMesh *BuildMesh2DCutInternal(double eps, const MEDCouplingUMesh *splitMesh1D, const std::vector<int>& allEdges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& allEdgesPtr, int offset,
9860                                          MCAuto<DataArrayInt>& idsLeftRight)
9861 {
9862   int nbCellsInSplitMesh1D(splitMesh1D->getNumberOfCells());
9863   if(nbCellsInSplitMesh1D==0)
9864     throw INTERP_KERNEL::Exception("BuildMesh2DCutInternal : internal error ! input 1D mesh must have at least one cell !");
9865   const int *cSplitPtr(splitMesh1D->getNodalConnectivity()->begin()),*ciSplitPtr(splitMesh1D->getNodalConnectivityIndex()->begin());
9866   std::size_t nb(allEdges.size()),jj;
9867   if(nb%2!=0)
9868     throw INTERP_KERNEL::Exception("BuildMesh2DCutFrom : internal error 2 !");
9869   std::vector<int> edge1Bis(nb*2);
9870   std::vector< MCAuto<INTERP_KERNEL::Edge> > edge1BisPtr(nb*2);
9871   std::copy(allEdges.begin(),allEdges.end(),edge1Bis.begin());
9872   std::copy(allEdges.begin(),allEdges.end(),edge1Bis.begin()+nb);
9873   std::copy(allEdgesPtr.begin(),allEdgesPtr.end(),edge1BisPtr.begin());
9874   std::copy(allEdgesPtr.begin(),allEdgesPtr.end(),edge1BisPtr.begin()+nb);
9875   //
9876   idsLeftRight=DataArrayInt::New(); idsLeftRight->alloc(nbCellsInSplitMesh1D*2); idsLeftRight->fillWithValue(-2); idsLeftRight->rearrange(2);
9877   int *idsLeftRightPtr(idsLeftRight->getPointer());
9878   VectorOfCellInfo pool(edge1Bis,edge1BisPtr);
9879   for(int iStart=0;iStart<nbCellsInSplitMesh1D;)
9880     {// split [0:nbCellsInSplitMesh1D) in contiguous parts [iStart:iEnd)
9881       int iEnd(iStart);
9882       for(;iEnd<nbCellsInSplitMesh1D;)
9883         {
9884           for(jj=0;jj<nb && edge1Bis[2*jj+1]!=cSplitPtr[ciSplitPtr[iEnd]+2];jj++);
9885           if(jj!=nb)
9886             break;
9887           else
9888             iEnd++;
9889         }
9890       if(iEnd<nbCellsInSplitMesh1D)
9891         iEnd++;
9892       //
9893       MCAuto<MEDCouplingUMesh> partOfSplitMesh1D(static_cast<MEDCouplingUMesh *>(splitMesh1D->buildPartOfMySelfSlice(iStart,iEnd,1,true)));
9894       int pos(pool.getPositionOf(eps,partOfSplitMesh1D));
9895       //
9896       MCAuto<MEDCouplingUMesh>retTmp(MEDCouplingUMesh::New("",2));
9897       retTmp->setCoords(splitMesh1D->getCoords());
9898       retTmp->allocateCells();
9899
9900       std::vector< std::vector<int> > out0;
9901       std::vector< std::vector< MCAuto<INTERP_KERNEL::Edge> > > out1;
9902
9903       BuildMesh2DCutInternal2(partOfSplitMesh1D,pool.getConnOf(pos),pool.getEdgePtrOf(pos),out0,out1);
9904       for(std::size_t cnt=0;cnt<out0.size();cnt++)
9905         AddCellInMesh2D(retTmp,out0[cnt],out1[cnt]);
9906       pool.setMeshAt(pos,retTmp,iStart,iEnd,partOfSplitMesh1D,out0,out1);
9907       //
9908       iStart=iEnd;
9909     }
9910   for(int mm=0;mm<nbCellsInSplitMesh1D;mm++)
9911     pool.feedEdgeInfoAt(eps,mm,offset,idsLeftRightPtr+2*mm);
9912   return pool.getZeMesh().retn();
9913 }
9914
9915 MEDCouplingUMesh *BuildMesh2DCutFrom(double eps, int cellIdInMesh2D, const MEDCouplingUMesh *mesh2DDesc, const MEDCouplingUMesh *splitMesh1D,
9916                                      const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1, int offset,
9917                                      MCAuto<DataArrayInt>& idsLeftRight)
9918 {
9919   const int *cdescPtr(mesh2DDesc->getNodalConnectivity()->begin()),*cidescPtr(mesh2DDesc->getNodalConnectivityIndex()->begin());
9920   //
9921   std::vector<int> allEdges;
9922   std::vector< MCAuto<INTERP_KERNEL::Edge> > allEdgesPtr; // for each sub edge in splitMesh2D the uncut Edge object of the original mesh2D
9923   for(const int *it(descBg);it!=descEnd;it++) // for all edges in the descending connectivity of the 2D mesh in relative Fortran mode
9924     {
9925       int edgeId(std::abs(*it)-1);
9926       std::map< MCAuto<INTERP_KERNEL::Node>,int> m;
9927       MCAuto<INTERP_KERNEL::Edge> ee(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)cdescPtr[cidescPtr[edgeId]],cdescPtr+cidescPtr[edgeId]+1,mesh2DDesc->getCoords()->begin(),m));
9928       const std::vector<int>& edge1(intersectEdge1[edgeId]);
9929       if(*it>0)
9930         allEdges.insert(allEdges.end(),edge1.begin(),edge1.end());
9931       else
9932         allEdges.insert(allEdges.end(),edge1.rbegin(),edge1.rend());
9933       std::size_t sz(edge1.size());
9934       for(std::size_t cnt=0;cnt<sz;cnt++)
9935         allEdgesPtr.push_back(ee);
9936     }
9937   //
9938   return BuildMesh2DCutInternal(eps,splitMesh1D,allEdges,allEdgesPtr,offset,idsLeftRight);
9939 }
9940
9941 bool AreEdgeEqual(const double *coo2D, const INTERP_KERNEL::CellModel& typ1, const int *conn1, const INTERP_KERNEL::CellModel& typ2, const int *conn2, double eps)
9942 {
9943   if(!typ1.isQuadratic() && !typ2.isQuadratic())
9944     {//easy case comparison not
9945       return conn1[0]==conn2[0] && conn1[1]==conn2[1];
9946     }
9947   else if(typ1.isQuadratic() && typ2.isQuadratic())
9948     {
9949       bool status0(conn1[0]==conn2[0] && conn1[1]==conn2[1]);
9950       if(!status0)
9951         return false;
9952       if(conn1[2]==conn2[2])
9953         return true;
9954       const double *a(coo2D+2*conn1[2]),*b(coo2D+2*conn2[2]);
9955       double dist(sqrt((a[0]-b[0])*(a[0]-b[0])+(a[1]-b[1])*(a[1]-b[1])));
9956       return dist<eps;
9957     }
9958   else
9959     {//only one is quadratic
9960       bool status0(conn1[0]==conn2[0] && conn1[1]==conn2[1]);
9961       if(!status0)
9962         return false;
9963       const double *a(0),*bb(0),*be(0);
9964       if(typ1.isQuadratic())
9965         {
9966           a=coo2D+2*conn1[2]; bb=coo2D+2*conn2[0]; be=coo2D+2*conn2[1];
9967         }
9968       else
9969         {
9970           a=coo2D+2*conn2[2]; bb=coo2D+2*conn1[0]; be=coo2D+2*conn1[1];
9971         }
9972       double b[2]; b[0]=(be[0]+bb[0])/2.; b[1]=(be[1]+bb[1])/2.;
9973       double dist(sqrt((a[0]-b[0])*(a[0]-b[0])+(a[1]-b[1])*(a[1]-b[1])));
9974       return dist<eps;
9975     }
9976 }
9977
9978 /*!
9979  * This method returns among the cellIds [ \a candidatesIn2DBg , \a candidatesIn2DEnd ) in \a mesh2DSplit those exactly sharing \a cellIdInMesh1DSplitRelative in \a mesh1DSplit.
9980  * \a mesh2DSplit and \a mesh1DSplit are expected to share the coordinates array.
9981  *
9982  * \param [in] cellIdInMesh1DSplitRelative is in Fortran mode using sign to specify direction.
9983  */
9984 int FindRightCandidateAmong(const MEDCouplingUMesh *mesh2DSplit, const int *candidatesIn2DBg, const int *candidatesIn2DEnd, const MEDCouplingUMesh *mesh1DSplit, int cellIdInMesh1DSplitRelative, double eps)
9985 {
9986   if(candidatesIn2DEnd==candidatesIn2DBg)
9987     throw INTERP_KERNEL::Exception("FindRightCandidateAmong : internal error 1 !");
9988   const double *coo(mesh2DSplit->getCoords()->begin());
9989   if(std::distance(candidatesIn2DBg,candidatesIn2DEnd)==1)
9990     return *candidatesIn2DBg;
9991   int edgeId(std::abs(cellIdInMesh1DSplitRelative)-1);
9992   MCAuto<MEDCouplingUMesh> cur1D(static_cast<MEDCouplingUMesh *>(mesh1DSplit->buildPartOfMySelf(&edgeId,&edgeId+1,true)));
9993   if(cellIdInMesh1DSplitRelative<0)
9994     cur1D->changeOrientationOfCells();
9995   const int *c1D(cur1D->getNodalConnectivity()->begin());
9996   const INTERP_KERNEL::CellModel& ref1DType(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c1D[0]));
9997   for(const int *it=candidatesIn2DBg;it!=candidatesIn2DEnd;it++)
9998     {
9999       MCAuto<MEDCouplingUMesh> cur2D(static_cast<MEDCouplingUMesh *>(mesh2DSplit->buildPartOfMySelf(it,it+1,true)));
10000       const int *c(cur2D->getNodalConnectivity()->begin()),*ci(cur2D->getNodalConnectivityIndex()->begin());
10001       const INTERP_KERNEL::CellModel &cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c[ci[0]]));
10002       unsigned sz(cm.getNumberOfSons2(c+ci[0]+1,ci[1]-ci[0]-1));
10003       INTERP_KERNEL::AutoPtr<int> tmpPtr(new int[ci[1]-ci[0]]);
10004       for(unsigned it2=0;it2<sz;it2++)
10005         {
10006           INTERP_KERNEL::NormalizedCellType typeOfSon;
10007           cm.fillSonCellNodalConnectivity2(it2,c+ci[0]+1,ci[1]-ci[0]-1,tmpPtr,typeOfSon);
10008           const INTERP_KERNEL::CellModel &curCM(INTERP_KERNEL::CellModel::GetCellModel(typeOfSon));
10009           if(AreEdgeEqual(coo,ref1DType,c1D+1,curCM,tmpPtr,eps))
10010             return *it;
10011         }
10012     }
10013   throw INTERP_KERNEL::Exception("FindRightCandidateAmong : internal error 2 ! Unable to find the edge among split cell !");
10014 }
10015
10016 /// @endcond
10017
10018 /*!
10019  * Partitions the first given 2D mesh using the second given 1D mesh as a tool.
10020  * 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
10021  * and finaly, in case of quadratic polygon the centers of edges new nodes.
10022  * The meshes should be in 2D space. In addition, returns two arrays mapping cells of the resulting mesh to cells of the input.
10023  *
10024  * \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
10025  *                      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)
10026  * \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
10027  *                      you can invoke orderConsecutiveCells1D on \a mesh1D.
10028  * \param [in] eps - precision used to perform intersections and localization operations.
10029  * \param [out] splitMesh2D - the result of the split of \a mesh2D mesh.
10030  * \param [out] splitMesh1D - the result of the split of \a mesh1D mesh.
10031  * \param [out] cellIdInMesh2D - the array that gives for each cell id \a i in \a splitMesh2D the id in \a mesh2D it comes from.
10032  *                               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.
10033  * \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
10034  *                               and the cell in \a splitMesh2D on the right for the 2nt component. -1 means no cell.
10035  *                               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.
10036  *
10037  * \sa Intersect2DMeshes, orderConsecutiveCells1D, conformize2D, mergeNodes
10038  */
10039 void MEDCouplingUMesh::Intersect2DMeshWith1DLine(const MEDCouplingUMesh *mesh2D, const MEDCouplingUMesh *mesh1D, double eps, MEDCouplingUMesh *&splitMesh2D, MEDCouplingUMesh *&splitMesh1D, DataArrayInt *&cellIdInMesh2D, DataArrayInt *&cellIdInMesh1D)
10040 {
10041   if(!mesh2D || !mesh1D)
10042     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshWith1DLine : input meshes must be not NULL !");
10043   mesh2D->checkFullyDefined();
10044   mesh1D->checkFullyDefined();
10045   const std::vector<std::string>& compNames(mesh2D->getCoords()->getInfoOnComponents());
10046   if(mesh2D->getMeshDimension()!=2 || mesh2D->getSpaceDimension()!=2 || mesh1D->getMeshDimension()!=1 || mesh1D->getSpaceDimension()!=2)
10047     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshWith1DLine works with mesh2D with spacedim=meshdim=2 and mesh1D with meshdim=1 spaceDim=2 !");
10048   // Step 1: compute all edge intersections (new nodes)
10049   std::vector< std::vector<int> > intersectEdge1, colinear2, subDiv2;
10050   std::vector<double> addCoo,addCoordsQuadratic;  // coordinates of newly created nodes
10051   INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
10052   INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
10053   //
10054   // Build desc connectivity
10055   DataArrayInt *desc1(DataArrayInt::New()),*descIndx1(DataArrayInt::New()),*revDesc1(DataArrayInt::New()),*revDescIndx1(DataArrayInt::New());
10056   MCAuto<DataArrayInt> dd1(desc1),dd2(descIndx1),dd3(revDesc1),dd4(revDescIndx1);
10057   MCAuto<MEDCouplingUMesh> m1Desc(mesh2D->buildDescendingConnectivity2(desc1,descIndx1,revDesc1,revDescIndx1));
10058   std::map<int,int> mergedNodes;
10059   Intersect1DMeshes(m1Desc,mesh1D,eps,intersectEdge1,colinear2,subDiv2,addCoo,mergedNodes);
10060   // use mergeNodes to fix intersectEdge1
10061   for(std::vector< std::vector<int> >::iterator it0=intersectEdge1.begin();it0!=intersectEdge1.end();it0++)
10062     {
10063       std::size_t n((*it0).size()/2);
10064       int eltStart((*it0)[0]),eltEnd((*it0)[2*n-1]);
10065       std::map<int,int>::const_iterator it1;
10066       it1=mergedNodes.find(eltStart);
10067       if(it1!=mergedNodes.end())
10068         (*it0)[0]=(*it1).second;
10069       it1=mergedNodes.find(eltEnd);
10070       if(it1!=mergedNodes.end())
10071         (*it0)[2*n-1]=(*it1).second;
10072     }
10073   //
10074   MCAuto<DataArrayDouble> addCooDa(DataArrayDouble::New());
10075   addCooDa->useArray(&addCoo[0],false,C_DEALLOC,(int)addCoo.size()/2,2);
10076   // Step 2: re-order newly created nodes according to the ordering found in m2
10077   std::vector< std::vector<int> > intersectEdge2;
10078   BuildIntersectEdges(m1Desc,mesh1D,addCoo,subDiv2,intersectEdge2);
10079   subDiv2.clear();
10080   // Step 3: compute splitMesh1D
10081   MCAuto<DataArrayInt> idsInRet1Colinear,idsInDescMesh2DForIdsInRetColinear;
10082   MCAuto<DataArrayInt> ret2(DataArrayInt::New()); ret2->alloc(0,1);
10083   MCAuto<MEDCouplingUMesh> ret1(BuildMesh1DCutFrom(mesh1D,intersectEdge2,mesh2D->getCoords(),addCoo,mergedNodes,colinear2,intersectEdge1,
10084       idsInRet1Colinear,idsInDescMesh2DForIdsInRetColinear));
10085   MCAuto<DataArrayInt> ret3(DataArrayInt::New()); ret3->alloc(ret1->getNumberOfCells()*2,1); ret3->fillWithValue(std::numeric_limits<int>::max()); ret3->rearrange(2);
10086   MCAuto<DataArrayInt> idsInRet1NotColinear(idsInRet1Colinear->buildComplement(ret1->getNumberOfCells()));
10087   // deal with cells in mesh2D that are not cut but only some of their edges are
10088   MCAuto<DataArrayInt> idsInDesc2DToBeRefined(idsInDescMesh2DForIdsInRetColinear->deepCopy());
10089   idsInDesc2DToBeRefined->abs(); idsInDesc2DToBeRefined->applyLin(1,-1);
10090   idsInDesc2DToBeRefined=idsInDesc2DToBeRefined->buildUnique();
10091   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
10092   if(!idsInDesc2DToBeRefined->empty())
10093     {
10094       DataArrayInt *out0(0),*outi0(0);
10095       MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
10096       MCAuto<DataArrayInt> outi0s(outi0);
10097       out0s=out0;
10098       out0s=out0s->buildUnique();
10099       out0s->sort(true);
10100     }
10101   //
10102   MCAuto<MEDCouplingUMesh> ret1NonCol(static_cast<MEDCouplingUMesh *>(ret1->buildPartOfMySelf(idsInRet1NotColinear->begin(),idsInRet1NotColinear->end())));
10103   MCAuto<DataArrayDouble> baryRet1(ret1NonCol->computeCellCenterOfMass());
10104   MCAuto<DataArrayInt> elts,eltsIndex;
10105   mesh2D->getCellsContainingPoints(baryRet1->begin(),baryRet1->getNumberOfTuples(),eps,elts,eltsIndex);
10106   MCAuto<DataArrayInt> eltsIndex2(eltsIndex->deltaShiftIndex());
10107   MCAuto<DataArrayInt> eltsIndex3(eltsIndex2->findIdsEqual(1));
10108   if(eltsIndex2->count(0)+eltsIndex3->getNumberOfTuples()!=ret1NonCol->getNumberOfCells())
10109     throw INTERP_KERNEL::Exception("Intersect2DMeshWith1DLine : internal error 1 !");
10110   MCAuto<DataArrayInt> cellsToBeModified(elts->buildUnique());
10111   MCAuto<DataArrayInt> untouchedCells(cellsToBeModified->buildComplement(mesh2D->getNumberOfCells()));
10112   if((DataArrayInt *)out0s)
10113     untouchedCells=untouchedCells->buildSubstraction(out0s);//if some edges in ret1 are colinear to descending mesh of mesh2D remove cells from untouched one
10114   std::vector< MCAuto<MEDCouplingUMesh> > outMesh2DSplit;
10115   // OK all is ready to insert in ret2 mesh
10116   if(!untouchedCells->empty())
10117     {// the most easy part, cells in mesh2D not impacted at all
10118       outMesh2DSplit.push_back(static_cast<MEDCouplingUMesh *>(mesh2D->buildPartOfMySelf(untouchedCells->begin(),untouchedCells->end())));
10119       outMesh2DSplit.back()->setCoords(ret1->getCoords());
10120       ret2->pushBackValsSilent(untouchedCells->begin(),untouchedCells->end());
10121     }
10122   if((DataArrayInt *)out0s)
10123     {// here dealing with cells in out0s but not in cellsToBeModified
10124       MCAuto<DataArrayInt> fewModifiedCells(out0s->buildSubstraction(cellsToBeModified));
10125       const int *rdptr(dd3->begin()),*rdiptr(dd4->begin()),*dptr(dd1->begin()),*diptr(dd2->begin());
10126       for(const int *it=fewModifiedCells->begin();it!=fewModifiedCells->end();it++)
10127         {
10128           outMesh2DSplit.push_back(BuildRefined2DCell(ret1->getCoords(),mesh2D,*it,dptr+diptr[*it],dptr+diptr[*it+1],intersectEdge1));
10129           ret1->setCoords(outMesh2DSplit.back()->getCoords());
10130         }
10131       int offset(ret2->getNumberOfTuples());
10132       ret2->pushBackValsSilent(fewModifiedCells->begin(),fewModifiedCells->end());
10133       MCAuto<DataArrayInt> partOfRet3(DataArrayInt::New()); partOfRet3->alloc(2*idsInRet1Colinear->getNumberOfTuples(),1);
10134       partOfRet3->fillWithValue(std::numeric_limits<int>::max()); partOfRet3->rearrange(2);
10135       int kk(0),*ret3ptr(partOfRet3->getPointer());
10136       for(const int *it=idsInDescMesh2DForIdsInRetColinear->begin();it!=idsInDescMesh2DForIdsInRetColinear->end();it++,kk++)
10137         {
10138           int faceId(std::abs(*it)-1);
10139           for(const int *it2=rdptr+rdiptr[faceId];it2!=rdptr+rdiptr[faceId+1];it2++)
10140             {
10141               int tmp(fewModifiedCells->findIdFirstEqual(*it2));
10142               if(tmp!=-1)
10143                 {
10144                   if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],-(*it))!=dptr+diptr[*it2+1])
10145                     ret3ptr[2*kk]=tmp+offset;
10146                   if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],(*it))!=dptr+diptr[*it2+1])
10147                     ret3ptr[2*kk+1]=tmp+offset;
10148                 }
10149               else
10150                 {//the current edge is shared by a 2D cell that will be split just after
10151                   if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],-(*it))!=dptr+diptr[*it2+1])
10152                     ret3ptr[2*kk]=-(*it2+1);
10153                   if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],(*it))!=dptr+diptr[*it2+1])
10154                     ret3ptr[2*kk+1]=-(*it2+1);
10155                 }
10156             }
10157         }
10158       m1Desc->setCoords(ret1->getCoords());
10159       ret1NonCol->setCoords(ret1->getCoords());
10160       ret3->setPartOfValues3(partOfRet3,idsInRet1Colinear->begin(),idsInRet1Colinear->end(),0,2,1,true);
10161       if(!outMesh2DSplit.empty())
10162         {
10163           DataArrayDouble *da(outMesh2DSplit.back()->getCoords());
10164           for(std::vector< MCAuto<MEDCouplingUMesh> >::iterator itt=outMesh2DSplit.begin();itt!=outMesh2DSplit.end();itt++)
10165             (*itt)->setCoords(da);
10166         }
10167     }
10168   cellsToBeModified=cellsToBeModified->buildUniqueNotSorted();
10169   for(const int *it=cellsToBeModified->begin();it!=cellsToBeModified->end();it++)
10170     {
10171       MCAuto<DataArrayInt> idsNonColPerCell(elts->findIdsEqual(*it));
10172       idsNonColPerCell->transformWithIndArr(eltsIndex3->begin(),eltsIndex3->end());
10173       MCAuto<DataArrayInt> idsNonColPerCell2(idsInRet1NotColinear->selectByTupleId(idsNonColPerCell->begin(),idsNonColPerCell->end()));
10174       MCAuto<MEDCouplingUMesh> partOfMesh1CuttingCur2DCell(static_cast<MEDCouplingUMesh *>(ret1NonCol->buildPartOfMySelf(idsNonColPerCell->begin(),idsNonColPerCell->end())));
10175       MCAuto<DataArrayInt> partOfRet3;
10176       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));
10177       ret3->setPartOfValues3(partOfRet3,idsNonColPerCell2->begin(),idsNonColPerCell2->end(),0,2,1,true);
10178       outMesh2DSplit.push_back(splitOfOneCell);
10179       for(int i=0;i<splitOfOneCell->getNumberOfCells();i++)
10180         ret2->pushBackSilent(*it);
10181     }
10182   //
10183   std::size_t nbOfMeshes(outMesh2DSplit.size());
10184   std::vector<const MEDCouplingUMesh *> tmp(nbOfMeshes);
10185   for(std::size_t i=0;i<nbOfMeshes;i++)
10186     tmp[i]=outMesh2DSplit[i];
10187   //
10188   ret1->getCoords()->setInfoOnComponents(compNames);
10189   MCAuto<MEDCouplingUMesh> ret2D(MEDCouplingUMesh::MergeUMeshesOnSameCoords(tmp));
10190   // To finish - filter ret3 - std::numeric_limits<int>::max() -> -1 - negate values must be resolved.
10191   ret3->rearrange(1);
10192   MCAuto<DataArrayInt> edgesToDealWith(ret3->findIdsStricltyNegative());
10193   for(const int *it=edgesToDealWith->begin();it!=edgesToDealWith->end();it++)
10194     {
10195       int old2DCellId(-ret3->getIJ(*it,0)-1);
10196       MCAuto<DataArrayInt> candidates(ret2->findIdsEqual(old2DCellId));
10197       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
10198     }
10199   ret3->changeValue(std::numeric_limits<int>::max(),-1);
10200   ret3->rearrange(2);
10201   //
10202   splitMesh1D=ret1.retn();
10203   splitMesh2D=ret2D.retn();
10204   cellIdInMesh2D=ret2.retn();
10205   cellIdInMesh1D=ret3.retn();
10206 }
10207
10208 /**
10209  * Private. Third step of the partitioning algorithm (Intersect2DMeshes): reconstruct full 2D cells from the
10210  * (newly created) nodes corresponding to the edge intersections.
10211  * Output params:
10212  * @param[out] cr, crI connectivity of the resulting mesh
10213  * @param[out] cNb1, cNb2 correspondance arrays giving for the merged mesh the initial cells IDs in m1 / m2
10214  * TODO: describe input parameters
10215  */
10216 void MEDCouplingUMesh::BuildIntersecting2DCellsFromEdges(double eps, const MEDCouplingUMesh *m1, const int *desc1, const int *descIndx1,
10217                                                          const std::vector<std::vector<int> >& intesctEdges1, const std::vector< std::vector<int> >& colinear2,
10218                                                          const MEDCouplingUMesh *m2, const int *desc2, const int *descIndx2, const std::vector<std::vector<int> >& intesctEdges2,
10219                                                          const std::vector<double>& addCoords,
10220                                                          std::vector<double>& addCoordsQuadratic, std::vector<int>& cr, std::vector<int>& crI, std::vector<int>& cNb1, std::vector<int>& cNb2)
10221 {
10222   static const int SPACEDIM=2;
10223   const double *coo1(m1->getCoords()->begin());
10224   const int *conn1(m1->getNodalConnectivity()->begin()),*connI1(m1->getNodalConnectivityIndex()->begin());
10225   int offset1(m1->getNumberOfNodes());
10226   const double *coo2(m2->getCoords()->begin());
10227   const int *conn2(m2->getNodalConnectivity()->begin()),*connI2(m2->getNodalConnectivityIndex()->begin());
10228   int offset2(offset1+m2->getNumberOfNodes());
10229   int offset3(offset2+((int)addCoords.size())/2);
10230   MCAuto<DataArrayDouble> bbox1Arr(m1->getBoundingBoxForBBTree()),bbox2Arr(m2->getBoundingBoxForBBTree());
10231   const double *bbox1(bbox1Arr->begin()),*bbox2(bbox2Arr->begin());
10232   // Here a BBTree on 2D-cells, not on segments:
10233   BBTree<SPACEDIM,int> myTree(bbox2,0,0,m2->getNumberOfCells(),eps);
10234   int ncell1(m1->getNumberOfCells());
10235   crI.push_back(0);
10236   for(int i=0;i<ncell1;i++)
10237     {
10238       std::vector<int> candidates2;
10239       myTree.getIntersectingElems(bbox1+i*2*SPACEDIM,candidates2);
10240       std::map<INTERP_KERNEL::Node *,int> mapp;
10241       std::map<int,INTERP_KERNEL::Node *> mappRev;
10242       INTERP_KERNEL::QuadraticPolygon pol1;
10243       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn1[connI1[i]];
10244       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
10245       // Populate mapp and mappRev with nodes from the current cell (i) from mesh1 - this also builds the Node* objects:
10246       MEDCouplingUMeshBuildQPFromMesh3(coo1,offset1,coo2,offset2,addCoords,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,/* output */mapp,mappRev);
10247       // pol1 is the full cell from mesh2, in QP format, with all the additional intersecting nodes.
10248       pol1.buildFromCrudeDataArray(mappRev,cm.isQuadratic(),conn1+connI1[i]+1,coo1,
10249           desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1);
10250       //
10251       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
10252       std::set<INTERP_KERNEL::Edge *> edgesBoundary2;// store all edges that are on boundary of (pol2 intersect pol1) minus edges on pol1.
10253       INTERP_KERNEL::IteratorOnComposedEdge it1(&pol1);
10254       for(it1.first();!it1.finished();it1.next())
10255         edges1.insert(it1.current()->getPtr());
10256       //
10257       std::map<int,std::vector<INTERP_KERNEL::ElementaryEdge *> > edgesIn2ForShare; // common edges
10258       std::vector<INTERP_KERNEL::QuadraticPolygon> pol2s(candidates2.size());
10259       int ii=0;
10260       for(std::vector<int>::const_iterator it2=candidates2.begin();it2!=candidates2.end();it2++,ii++)
10261         {
10262           INTERP_KERNEL::NormalizedCellType typ2=(INTERP_KERNEL::NormalizedCellType)conn2[connI2[*it2]];
10263           const INTERP_KERNEL::CellModel& cm2=INTERP_KERNEL::CellModel::GetCellModel(typ2);
10264           // Complete mapping with elements coming from the current cell it2 in mesh2:
10265           MEDCouplingUMeshBuildQPFromMesh3(coo1,offset1,coo2,offset2,addCoords,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,/* output */mapp,mappRev);
10266           // pol2 is the new QP in the final merged result.
10267           pol2s[ii].buildFromCrudeDataArray2(mappRev,cm2.isQuadratic(),conn2+connI2[*it2]+1,coo2,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,
10268               pol1,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,colinear2, /* output */ edgesIn2ForShare);
10269         }
10270       ii=0;
10271       for(std::vector<int>::const_iterator it2=candidates2.begin();it2!=candidates2.end();it2++,ii++)
10272         {
10273           INTERP_KERNEL::ComposedEdge::InitLocationsWithOther(pol1,pol2s[ii]);
10274           pol2s[ii].updateLocOfEdgeFromCrudeDataArray2(desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,pol1,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,colinear2);
10275           //MEDCouplingUMeshAssignOnLoc(pol1,pol2,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,colinear2);
10276           pol1.buildPartitionsAbs(pol2s[ii],edges1,edgesBoundary2,mapp,i,*it2,offset3,addCoordsQuadratic,cr,crI,cNb1,cNb2);
10277         }
10278       // Deals with remaining (non-consumed) edges from m1: these are the edges that were never touched
10279       // by m2 but that we still want to keep in the final result.
10280       if(!edges1.empty())
10281         {
10282           try
10283           {
10284               INTERP_KERNEL::QuadraticPolygon::ComputeResidual(pol1,edges1,edgesBoundary2,mapp,offset3,i,addCoordsQuadratic,cr,crI,cNb1,cNb2);
10285           }
10286           catch(INTERP_KERNEL::Exception& e)
10287           {
10288               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();
10289               throw INTERP_KERNEL::Exception(oss.str());
10290           }
10291         }
10292       for(std::map<int,INTERP_KERNEL::Node *>::const_iterator it=mappRev.begin();it!=mappRev.end();it++)
10293         (*it).second->decrRef();
10294     }
10295 }
10296
10297 /**
10298  * Provides a renumbering of the cells of this (which has to be a piecewise connected 1D line), so that
10299  * the segments of the line are indexed in consecutive order (i.e. cells \a i and \a i+1 are neighbors).
10300  * This doesn't modify the mesh. This method only works using nodal connectivity consideration. Coordinates of nodes are ignored here.
10301  * The caller is to deal with the resulting DataArrayInt.
10302  *  \throw If the coordinate array is not set.
10303  *  \throw If the nodal connectivity of the cells is not defined.
10304  *  \throw If m1 is not a mesh of dimension 2, or m1 is not a mesh of dimension 1
10305  *  \throw If m2 is not a (piecewise) line (i.e. if a point has more than 2 adjacent segments)
10306  *
10307  * \sa DataArrayInt::sortEachPairToMakeALinkedList
10308  */
10309 DataArrayInt *MEDCouplingUMesh::orderConsecutiveCells1D() const
10310 {
10311   checkFullyDefined();
10312   if(getMeshDimension()!=1)
10313     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D works on unstructured mesh with meshdim = 1 !");
10314
10315   // Check that this is a line (and not a more complex 1D mesh) - each point is used at most by 2 segments:
10316   MCAuto<DataArrayInt> _d(DataArrayInt::New()),_dI(DataArrayInt::New());
10317   MCAuto<DataArrayInt> _rD(DataArrayInt::New()),_rDI(DataArrayInt::New());
10318   MCAuto<MEDCouplingUMesh> m_points(buildDescendingConnectivity(_d, _dI, _rD, _rDI));
10319   const int *d(_d->begin()), *dI(_dI->begin());
10320   const int *rD(_rD->begin()), *rDI(_rDI->begin());
10321   MCAuto<DataArrayInt> _dsi(_rDI->deltaShiftIndex());
10322   const int * dsi(_dsi->begin());
10323   MCAuto<DataArrayInt> dsii = _dsi->findIdsNotInRange(0,3);
10324   m_points=0;
10325   if (dsii->getNumberOfTuples())
10326     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D only work with a mesh being a (piecewise) connected line!");
10327
10328   int nc(getNumberOfCells());
10329   MCAuto<DataArrayInt> result(DataArrayInt::New());
10330   result->alloc(nc,1);
10331
10332   // set of edges not used so far
10333   std::set<int> edgeSet;
10334   for (int i=0; i<nc; edgeSet.insert(i), i++);
10335
10336   int startSeg=0;
10337   int newIdx=0;
10338   // while we have points with only one neighbor segments
10339   do
10340     {
10341       std::list<int> linePiece;
10342       // fills a list of consecutive segment linked to startSeg. This can go forward or backward.
10343       for (int direction=0;direction<2;direction++) // direction=0 --> forward, direction=1 --> backward
10344         {
10345           // Fill the list forward (resp. backward) from the start segment:
10346           int activeSeg = startSeg;
10347           int prevPointId = -20;
10348           int ptId;
10349           while (!edgeSet.empty())
10350             {
10351               if (!(direction == 1 && prevPointId==-20)) // prevent adding twice startSeg
10352                 {
10353                   if (direction==0)
10354                     linePiece.push_back(activeSeg);
10355                   else
10356                     linePiece.push_front(activeSeg);
10357                   edgeSet.erase(activeSeg);
10358                 }
10359
10360               int ptId1 = d[dI[activeSeg]], ptId2 = d[dI[activeSeg]+1];
10361               ptId = direction ? (ptId1 == prevPointId ? ptId2 : ptId1) : (ptId2 == prevPointId ? ptId1 : ptId2);
10362               if (dsi[ptId] == 1) // hitting the end of the line
10363                 break;
10364               prevPointId = ptId;
10365               int seg1 = rD[rDI[ptId]], seg2 = rD[rDI[ptId]+1];
10366               activeSeg = (seg1 == activeSeg) ? seg2 : seg1;
10367             }
10368         }
10369       // Done, save final piece into DA:
10370       std::copy(linePiece.begin(), linePiece.end(), result->getPointer()+newIdx);
10371       newIdx += linePiece.size();
10372
10373       // identify next valid start segment (one which is not consumed)
10374       if(!edgeSet.empty())
10375         startSeg = *(edgeSet.begin());
10376     }
10377   while (!edgeSet.empty());
10378   return result.retn();
10379 }
10380
10381 /// @cond INTERNAL
10382
10383 void IKGeo2DInternalMapper2(INTERP_KERNEL::Node *n, const std::map<MCAuto<INTERP_KERNEL::Node>,int>& m, int forbVal0, int forbVal1, std::vector<int>& isect)
10384 {
10385   MCAuto<INTERP_KERNEL::Node> nTmp(n); nTmp->incrRef();
10386   std::map<MCAuto<INTERP_KERNEL::Node>,int>::const_iterator it(m.find(nTmp));
10387   if(it==m.end())
10388     throw INTERP_KERNEL::Exception("Internal error in remapping !");
10389   int v((*it).second);
10390   if(v==forbVal0 || v==forbVal1)
10391     return ;
10392   if(std::find(isect.begin(),isect.end(),v)==isect.end())
10393     isect.push_back(v);
10394 }
10395
10396 bool IKGeo2DInternalMapper(const INTERP_KERNEL::ComposedEdge& c, const std::map<MCAuto<INTERP_KERNEL::Node>,int>& m, int forbVal0, int forbVal1, std::vector<int>& isect)
10397 {
10398   int sz(c.size());
10399   if(sz<=1)
10400     return false;
10401   bool presenceOfOn(false);
10402   for(int i=0;i<sz;i++)
10403     {
10404       INTERP_KERNEL::ElementaryEdge *e(c[i]);
10405       if(e->getLoc()!=INTERP_KERNEL::FULL_ON_1)
10406         continue ;
10407       IKGeo2DInternalMapper2(e->getStartNode(),m,forbVal0,forbVal1,isect);
10408       IKGeo2DInternalMapper2(e->getEndNode(),m,forbVal0,forbVal1,isect);
10409     }
10410   return presenceOfOn;
10411 }
10412
10413 /// @endcond
10414
10415 /**
10416  * This method split some of edges of 2D cells in \a this. The edges to be split are specified in \a subNodesInSeg
10417  * and in \a subNodesInSegI using \ref numbering-indirect storage mode.
10418  * To do the work this method can optionally needs information about middle of subedges for quadratic cases if
10419  * a minimal creation of new nodes is wanted.
10420  * So this method try to reduce at most the number of new nodes. The only case that can lead this method to add
10421  * nodes if a SEG3 is split without information of middle.
10422  * \b WARNING : is returned value is different from 0 a call to MEDCouplingUMesh::mergeNodes is necessary to
10423  * avoid to have a non conform mesh.
10424  *
10425  * \return int - the number of new nodes created (in most of cases 0).
10426  * 
10427  * \throw If \a this is not coherent.
10428  * \throw If \a this has not spaceDim equal to 2.
10429  * \throw If \a this has not meshDim equal to 2.
10430  * \throw If some subcells needed to be split are orphan.
10431  * \sa MEDCouplingUMesh::conformize2D
10432  */
10433 int MEDCouplingUMesh::split2DCells(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI, const DataArrayInt *midOpt, const DataArrayInt *midOptI)
10434 {
10435   if(!desc || !descI || !subNodesInSeg || !subNodesInSegI)
10436     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : the 4 first arrays must be not null !");
10437   desc->checkAllocated(); descI->checkAllocated(); subNodesInSeg->checkAllocated(); subNodesInSegI->checkAllocated();
10438   if(getSpaceDimension()!=2 || getMeshDimension()!=2)
10439     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : This method only works for meshes with spaceDim=2 and meshDim=2 !");
10440   if(midOpt==0 && midOptI==0)
10441     {
10442       split2DCellsLinear(desc,descI,subNodesInSeg,subNodesInSegI);
10443       return 0;
10444     }
10445   else if(midOpt!=0 && midOptI!=0)
10446     return split2DCellsQuadratic(desc,descI,subNodesInSeg,subNodesInSegI,midOpt,midOptI);
10447   else
10448     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : middle parameters must be set to null for all or not null for all.");
10449 }
10450
10451 /*!
10452  * \b WARNING this method is \b potentially \b non \b const (if returned array is empty).
10453  * \b WARNING this method lead to have a non geometric type sorted mesh (for MED file users) !
10454  * 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
10455  * 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).
10456  * 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.
10457  * 
10458  * Whatever the returned value, this method does not alter the order of cells in \a this neither the orientation of cells.
10459  * The modified cells, if any, are systematically declared as NORM_POLYGON or NORM_QPOLYG depending on the initial quadraticness of geometric type.
10460  *
10461  * This method expects that \b this has a meshDim equal 2 and spaceDim equal to 2 too.
10462  * This method expects that all nodes in \a this are not closer than \a eps.
10463  * If it is not the case you can invoke MEDCouplingUMesh::mergeNodes before calling this method.
10464  * 
10465  * \param [in] eps the relative error to detect merged edges.
10466  * \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
10467  *                           that the user is expected to deal with.
10468  *
10469  * \throw If \a this is not coherent.
10470  * \throw If \a this has not spaceDim equal to 2.
10471  * \throw If \a this has not meshDim equal to 2.
10472  * \sa MEDCouplingUMesh::mergeNodes, MEDCouplingUMesh::split2DCells
10473  */
10474 DataArrayInt *MEDCouplingUMesh::conformize2D(double eps)
10475 {
10476   static const int SPACEDIM=2;
10477   checkConsistencyLight();
10478   if(getSpaceDimension()!=2 || getMeshDimension()!=2)
10479     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::conformize2D : This method only works for meshes with spaceDim=2 and meshDim=2 !");
10480   MCAuto<DataArrayInt> desc1(DataArrayInt::New()),descIndx1(DataArrayInt::New()),revDesc1(DataArrayInt::New()),revDescIndx1(DataArrayInt::New());
10481   MCAuto<MEDCouplingUMesh> mDesc(buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));
10482   const int *c(mDesc->getNodalConnectivity()->begin()),*ci(mDesc->getNodalConnectivityIndex()->begin()),*rd(revDesc1->begin()),*rdi(revDescIndx1->begin());
10483   MCAuto<DataArrayDouble> bboxArr(mDesc->getBoundingBoxForBBTree());
10484   const double *bbox(bboxArr->begin()),*coords(getCoords()->begin());
10485   int nCell(getNumberOfCells()),nDescCell(mDesc->getNumberOfCells());
10486   std::vector< std::vector<int> > intersectEdge(nDescCell),overlapEdge(nDescCell);
10487   std::vector<double> addCoo;
10488   BBTree<SPACEDIM,int> myTree(bbox,0,0,nDescCell,-eps);
10489   INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
10490   INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
10491   for(int i=0;i<nDescCell;i++)
10492     {
10493       std::vector<int> candidates;
10494       myTree.getIntersectingElems(bbox+i*2*SPACEDIM,candidates);
10495       for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
10496         if(*it>i)
10497           {
10498             std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
10499             INTERP_KERNEL::Edge *e1(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[i]],c+ci[i]+1,coords,m)),
10500                 *e2(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[*it]],c+ci[*it]+1,coords,m));
10501             INTERP_KERNEL::MergePoints merge;
10502             INTERP_KERNEL::QuadraticPolygon c1,c2;
10503             e1->intersectWith(e2,merge,c1,c2);
10504             e1->decrRef(); e2->decrRef();
10505             if(IKGeo2DInternalMapper(c1,m,c[ci[i]+1],c[ci[i]+2],intersectEdge[i]))
10506               overlapEdge[i].push_back(*it);
10507             if(IKGeo2DInternalMapper(c2,m,c[ci[*it]+1],c[ci[*it]+2],intersectEdge[*it]))
10508               overlapEdge[*it].push_back(i);
10509           }
10510     }
10511   // splitting done. sort intersect point in intersectEdge.
10512   std::vector< std::vector<int> > middle(nDescCell);
10513   int nbOf2DCellsToBeSplit(0);
10514   bool middleNeedsToBeUsed(false);
10515   std::vector<bool> cells2DToTreat(nDescCell,false);
10516   for(int i=0;i<nDescCell;i++)
10517     {
10518       std::vector<int>& isect(intersectEdge[i]);
10519       int sz((int)isect.size());
10520       if(sz>1)
10521         {
10522           std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
10523           INTERP_KERNEL::Edge *e(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[i]],c+ci[i]+1,coords,m));
10524           e->sortSubNodesAbs(coords,isect);
10525           e->decrRef();
10526         }
10527       if(sz!=0)
10528         {
10529           int idx0(rdi[i]),idx1(rdi[i+1]);
10530           if(idx1-idx0!=1)
10531             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::conformize2D : internal error #0 !");
10532           if(!cells2DToTreat[rd[idx0]])
10533             {
10534               cells2DToTreat[rd[idx0]]=true;
10535               nbOf2DCellsToBeSplit++;
10536             }
10537           // try to reuse at most eventual 'middle' of SEG3
10538           std::vector<int>& mid(middle[i]);
10539           mid.resize(sz+1,-1);
10540           if((INTERP_KERNEL::NormalizedCellType)c[ci[i]]==INTERP_KERNEL::NORM_SEG3)
10541             {
10542               middleNeedsToBeUsed=true;
10543               const std::vector<int>& candidates(overlapEdge[i]);
10544               std::vector<int> trueCandidates;
10545               for(std::vector<int>::const_iterator itc=candidates.begin();itc!=candidates.end();itc++)
10546                 if((INTERP_KERNEL::NormalizedCellType)c[ci[*itc]]==INTERP_KERNEL::NORM_SEG3)
10547                   trueCandidates.push_back(*itc);
10548               int stNode(c[ci[i]+1]),endNode(isect[0]);
10549               for(int j=0;j<sz+1;j++)
10550                 {
10551                   for(std::vector<int>::const_iterator itc=trueCandidates.begin();itc!=trueCandidates.end();itc++)
10552                     {
10553                       int tmpSt(c[ci[*itc]+1]),tmpEnd(c[ci[*itc]+2]);
10554                       if((tmpSt==stNode && tmpEnd==endNode) || (tmpSt==endNode && tmpEnd==stNode))
10555                         { mid[j]=*itc; break; }
10556                     }
10557                   stNode=endNode;
10558                   endNode=j<sz-1?isect[j+1]:c[ci[i]+2];
10559                 }
10560             }
10561         }
10562     }
10563   MCAuto<DataArrayInt> ret(DataArrayInt::New()),notRet(DataArrayInt::New()); ret->alloc(nbOf2DCellsToBeSplit,1);
10564   if(nbOf2DCellsToBeSplit==0)
10565     return ret.retn();
10566   //
10567   int *retPtr(ret->getPointer());
10568   for(int i=0;i<nCell;i++)
10569     if(cells2DToTreat[i])
10570       *retPtr++=i;
10571   //
10572   MCAuto<DataArrayInt> mSafe,nSafe,oSafe,pSafe,qSafe,rSafe;
10573   DataArrayInt *m(0),*n(0),*o(0),*p(0),*q(0),*r(0);
10574   MEDCouplingUMesh::ExtractFromIndexedArrays(ret->begin(),ret->end(),desc1,descIndx1,m,n); mSafe=m; nSafe=n;
10575   DataArrayInt::PutIntoToSkylineFrmt(intersectEdge,o,p); oSafe=o; pSafe=p;
10576   if(middleNeedsToBeUsed)
10577     { DataArrayInt::PutIntoToSkylineFrmt(middle,q,r); qSafe=q; rSafe=r; }
10578   MCAuto<MEDCouplingUMesh> modif(static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(ret->begin(),ret->end(),true)));
10579   int nbOfNodesCreated(modif->split2DCells(mSafe,nSafe,oSafe,pSafe,qSafe,rSafe));
10580   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.
10581   setPartOfMySelf(ret->begin(),ret->end(),*modif);
10582   {
10583     bool areNodesMerged; int newNbOfNodes;
10584     if(nbOfNodesCreated!=0)
10585       MCAuto<DataArrayInt> tmp(mergeNodes(eps,areNodesMerged,newNbOfNodes));
10586   }
10587   return ret.retn();
10588 }
10589
10590 /*!
10591  * 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.
10592  * 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).
10593  * 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
10594  * to invoke MEDCouplingUMesh::mergeNodes and MEDCouplingUMesh::conformize2D right after this call.
10595  * 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
10596  * new nodes for center of merged edges is are systematically created and appended at the end of the previously existing nodes.
10597  *
10598  * 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
10599  * using new instance, idem for coordinates.
10600  *
10601  * 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.
10602  * 
10603  * \return DataArrayInt  * - The list of cellIds in \a this that have at least one edge colinearized.
10604  *
10605  * \throw If \a this is not coherent.
10606  * \throw If \a this has not spaceDim equal to 2.
10607  * \throw If \a this has not meshDim equal to 2.
10608  * 
10609  * \sa MEDCouplingUMesh::conformize2D, MEDCouplingUMesh::mergeNodes, MEDCouplingUMesh::convexEnvelop2D.
10610  */
10611 DataArrayInt *MEDCouplingUMesh::colinearize2D(double eps)
10612 {
10613   MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(0,1);
10614   checkConsistencyLight();
10615   if(getSpaceDimension()!=2 || getMeshDimension()!=2)
10616     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::colinearize2D : This method only works for meshes with spaceDim=2 and meshDim=2 !");
10617   INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
10618   INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
10619   int nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
10620   const int *cptr(_nodal_connec->begin()),*ciptr(_nodal_connec_index->begin());
10621   MCAuto<DataArrayInt> newc(DataArrayInt::New()),newci(DataArrayInt::New()); newci->alloc(nbOfCells+1,1); newc->alloc(0,1); newci->setIJ(0,0,0);
10622   MCAuto<DataArrayDouble> appendedCoords(DataArrayDouble::New()); appendedCoords->alloc(0,1);//1 not 2 it is not a bug.
10623   const double *coords(_coords->begin());
10624   int *newciptr(newci->getPointer());
10625   for(int i=0;i<nbOfCells;i++,newciptr++,ciptr++)
10626     {
10627       if(Colinearize2DCell(coords,cptr+ciptr[0],cptr+ciptr[1],nbOfNodes,newc,appendedCoords))
10628         ret->pushBackSilent(i);
10629       newciptr[1]=newc->getNumberOfTuples();
10630     }
10631   //
10632   if(ret->empty())
10633     return ret.retn();
10634   if(!appendedCoords->empty())
10635     {
10636       appendedCoords->rearrange(2);
10637       MCAuto<DataArrayDouble> newCoords(DataArrayDouble::Aggregate(getCoords(),appendedCoords));//treat info on components
10638       //non const part
10639       setCoords(newCoords);
10640     }
10641   //non const part
10642   setConnectivity(newc,newci,true);
10643   return ret.retn();
10644 }
10645
10646 /*!
10647  * \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.
10648  *                               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.
10649  *                               And for each j in [1,n) intersect[i][2*(j-1)+1]==intersect[i][2*j].
10650  * \param [out] subDiv2 - for each cell in \a m2Desc returns nodes that split it using convention \a m1Desc first, then \a m2Desc, then addCoo
10651  * \param [out] colinear2 - for each cell in \a m2Desc returns the edges in \a m1Desc that are colinear to it.
10652  * \param [out] addCoo - nodes to be append at the end
10653  * \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.
10654  */
10655 void MEDCouplingUMesh::Intersect1DMeshes(const MEDCouplingUMesh *m1Desc, const MEDCouplingUMesh *m2Desc, double eps,
10656                                          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)
10657 {
10658   static const int SPACEDIM=2;
10659   INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
10660   INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
10661   const int *c1(m1Desc->getNodalConnectivity()->begin()),*ci1(m1Desc->getNodalConnectivityIndex()->begin());
10662   // Build BB tree of all edges in the tool mesh (second mesh)
10663   MCAuto<DataArrayDouble> bbox1Arr(m1Desc->getBoundingBoxForBBTree()),bbox2Arr(m2Desc->getBoundingBoxForBBTree());
10664   const double *bbox1(bbox1Arr->begin()),*bbox2(bbox2Arr->begin());
10665   int nDescCell1(m1Desc->getNumberOfCells()),nDescCell2(m2Desc->getNumberOfCells());
10666   intersectEdge1.resize(nDescCell1);
10667   colinear2.resize(nDescCell2);
10668   subDiv2.resize(nDescCell2);
10669   BBTree<SPACEDIM,int> myTree(bbox2,0,0,m2Desc->getNumberOfCells(),-eps);
10670
10671   std::vector<int> candidates1(1);
10672   int offset1(m1Desc->getNumberOfNodes());
10673   int offset2(offset1+m2Desc->getNumberOfNodes());
10674   for(int i=0;i<nDescCell1;i++)  // for all edges in the first mesh
10675     {
10676       std::vector<int> candidates2; // edges of mesh2 candidate for intersection
10677       myTree.getIntersectingElems(bbox1+i*2*SPACEDIM,candidates2);
10678       if(!candidates2.empty()) // candidates2 holds edges from the second mesh potentially intersecting current edge i in mesh1
10679         {
10680           std::map<INTERP_KERNEL::Node *,int> map1,map2;
10681           // pol2 is not necessarily a closed polygon: just a set of (quadratic) edges (same as candidates2) in the Geometric DS format
10682           INTERP_KERNEL::QuadraticPolygon *pol2=MEDCouplingUMeshBuildQPFromMesh(m2Desc,candidates2,map2);
10683           candidates1[0]=i;
10684           INTERP_KERNEL::QuadraticPolygon *pol1=MEDCouplingUMeshBuildQPFromMesh(m1Desc,candidates1,map1);
10685           // 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
10686           // This trick guarantees that Node * are discriminant (i.e. form a unique identifier)
10687           std::set<INTERP_KERNEL::Node *> nodes;
10688           pol1->getAllNodes(nodes); pol2->getAllNodes(nodes);
10689           std::size_t szz(nodes.size());
10690           std::vector< MCAuto<INTERP_KERNEL::Node> > nodesSafe(szz);
10691           std::set<INTERP_KERNEL::Node *>::const_iterator itt(nodes.begin());
10692           for(std::size_t iii=0;iii<szz;iii++,itt++)
10693             { (*itt)->incrRef(); nodesSafe[iii]=*itt; }
10694           // end of protection
10695           // Performs egde cutting:
10696           pol1->splitAbs(*pol2,map1,map2,offset1,offset2,candidates2,intersectEdge1[i],i,colinear2,subDiv2,addCoo,mergedNodes);
10697           delete pol2;
10698           delete pol1;
10699         }
10700       else
10701         // Copy the edge (take only the two first points, ie discard quadratic point at this stage)
10702         intersectEdge1[i].insert(intersectEdge1[i].end(),c1+ci1[i]+1,c1+ci1[i]+3);
10703     }
10704 }
10705
10706 /*!
10707  * This method is private and is the first step of Partition of 2D mesh (spaceDim==2 and meshDim==2).
10708  * It builds the descending connectivity of the two meshes, and then using a binary tree
10709  * it computes the edge intersections. This results in new points being created : they're stored in addCoo.
10710  * Documentation about parameters  colinear2 and subDiv2 can be found in method QuadraticPolygon::splitAbs().
10711  */
10712 void MEDCouplingUMesh::IntersectDescending2DMeshes(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2, double eps,
10713                                                    std::vector< std::vector<int> >& intersectEdge1, std::vector< std::vector<int> >& colinear2, std::vector< std::vector<int> >& subDiv2,
10714                                                    MEDCouplingUMesh *& m1Desc, DataArrayInt *&desc1, DataArrayInt *&descIndx1, DataArrayInt *&revDesc1, DataArrayInt *&revDescIndx1,
10715                                                    std::vector<double>& addCoo,
10716                                                    MEDCouplingUMesh *& m2Desc, DataArrayInt *&desc2, DataArrayInt *&descIndx2, DataArrayInt *&revDesc2, DataArrayInt *&revDescIndx2)
10717 {
10718   // Build desc connectivity
10719   desc1=DataArrayInt::New(); descIndx1=DataArrayInt::New(); revDesc1=DataArrayInt::New(); revDescIndx1=DataArrayInt::New();
10720   desc2=DataArrayInt::New();
10721   descIndx2=DataArrayInt::New();
10722   revDesc2=DataArrayInt::New();
10723   revDescIndx2=DataArrayInt::New();
10724   MCAuto<DataArrayInt> dd1(desc1),dd2(descIndx1),dd3(revDesc1),dd4(revDescIndx1);
10725   MCAuto<DataArrayInt> dd5(desc2),dd6(descIndx2),dd7(revDesc2),dd8(revDescIndx2);
10726   m1Desc=m1->buildDescendingConnectivity2(desc1,descIndx1,revDesc1,revDescIndx1);
10727   m2Desc=m2->buildDescendingConnectivity2(desc2,descIndx2,revDesc2,revDescIndx2);
10728   MCAuto<MEDCouplingUMesh> dd9(m1Desc),dd10(m2Desc);
10729   std::map<int,int> notUsedMap;
10730   Intersect1DMeshes(m1Desc,m2Desc,eps,intersectEdge1,colinear2,subDiv2,addCoo,notUsedMap);
10731   m1Desc->incrRef(); desc1->incrRef(); descIndx1->incrRef(); revDesc1->incrRef(); revDescIndx1->incrRef();
10732   m2Desc->incrRef(); desc2->incrRef(); descIndx2->incrRef(); revDesc2->incrRef(); revDescIndx2->incrRef();
10733 }
10734
10735 /*!
10736  * This method performs the 2nd step of Partition of 2D mesh.
10737  * This method has 4 inputs :
10738  *  - a mesh 'm1' with meshDim==1 and a SpaceDim==2
10739  *  - a mesh 'm2' with meshDim==1 and a SpaceDim==2
10740  *  - subDiv of size 'm2->getNumberOfCells()' that lists for each seg cell in 'm' the splitting node ids randomly sorted.
10741  * 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'
10742  * Nodes end up lying consecutively on a cutted edge.
10743  * \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.
10744  * (Only present for its coords in case of 'subDiv' shares some nodes of 'm1')
10745  * \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.
10746  * \param addCoo input parameter with additional nodes linked to intersection of the 2 meshes.
10747  * \param[out] intersectEdge the same content as subDiv, but correclty oriented.
10748  */
10749 void MEDCouplingUMesh::BuildIntersectEdges(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2,
10750                                            const std::vector<double>& addCoo,
10751                                            const std::vector< std::vector<int> >& subDiv, std::vector< std::vector<int> >& intersectEdge)
10752 {
10753   int offset1=m1->getNumberOfNodes();
10754   int ncell=m2->getNumberOfCells();
10755   const int *c=m2->getNodalConnectivity()->begin();
10756   const int *cI=m2->getNodalConnectivityIndex()->begin();
10757   const double *coo=m2->getCoords()->begin();
10758   const double *cooBis=m1->getCoords()->begin();
10759   int offset2=offset1+m2->getNumberOfNodes();
10760   intersectEdge.resize(ncell);
10761   for(int i=0;i<ncell;i++,cI++)
10762     {
10763       const std::vector<int>& divs=subDiv[i];
10764       int nnode=cI[1]-cI[0]-1;
10765       std::map<int, std::pair<INTERP_KERNEL::Node *,bool> > mapp2;
10766       std::map<INTERP_KERNEL::Node *, int> mapp22;
10767       for(int j=0;j<nnode;j++)
10768         {
10769           INTERP_KERNEL::Node *nn=new INTERP_KERNEL::Node(coo[2*c[(*cI)+j+1]],coo[2*c[(*cI)+j+1]+1]);
10770           int nnid=c[(*cI)+j+1];
10771           mapp2[nnid]=std::pair<INTERP_KERNEL::Node *,bool>(nn,true);
10772           mapp22[nn]=nnid+offset1;
10773         }
10774       INTERP_KERNEL::Edge *e=MEDCouplingUMeshBuildQPFromEdge((INTERP_KERNEL::NormalizedCellType)c[*cI],mapp2,c+(*cI)+1);
10775       for(std::map<int, std::pair<INTERP_KERNEL::Node *,bool> >::const_iterator it=mapp2.begin();it!=mapp2.end();it++)
10776         ((*it).second.first)->decrRef();
10777       std::vector<INTERP_KERNEL::Node *> addNodes(divs.size());
10778       std::map<INTERP_KERNEL::Node *,int> mapp3;
10779       for(std::size_t j=0;j<divs.size();j++)
10780         {
10781           int id=divs[j];
10782           INTERP_KERNEL::Node *tmp=0;
10783           if(id<offset1)
10784             tmp=new INTERP_KERNEL::Node(cooBis[2*id],cooBis[2*id+1]);
10785           else if(id<offset2)
10786             tmp=new INTERP_KERNEL::Node(coo[2*(id-offset1)],coo[2*(id-offset1)+1]);//if it happens, bad news mesh 'm2' is non conform.
10787           else
10788             tmp=new INTERP_KERNEL::Node(addCoo[2*(id-offset2)],addCoo[2*(id-offset2)+1]);
10789           addNodes[j]=tmp;
10790           mapp3[tmp]=id;
10791         }
10792       e->sortIdsAbs(addNodes,mapp22,mapp3,intersectEdge[i]);
10793       for(std::vector<INTERP_KERNEL::Node *>::const_iterator it=addNodes.begin();it!=addNodes.end();it++)
10794         (*it)->decrRef();
10795       e->decrRef();
10796     }
10797 }
10798
10799 /*!
10800  * 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).
10801  * 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
10802  * with a plane. The result will be put in 'cut3DSuf' out parameter.
10803  * \param [in] cut3DCurve  input paramter that gives for each 3DCurve cell if it owns fully to the plane or partially.
10804  * \param [out] nodesOnPlane, returns all the nodes that are on the plane.
10805  * \param [in] nodal3DSurf is the nodal connectivity of 3D surf mesh.
10806  * \param [in] nodalIndx3DSurf is the nodal connectivity index of 3D surf mesh.
10807  * \param [in] nodal3DCurve is the nodal connectivity of 3D curve mesh.
10808  * \param [in] nodal3DIndxCurve is the nodal connectivity index of 3D curve mesh.
10809  * \param [in] desc is the descending connectivity 3DSurf->3DCurve
10810  * \param [in] descIndx is the descending connectivity index 3DSurf->3DCurve
10811  * \param [out] cut3DSuf input/output param.
10812  */
10813 void MEDCouplingUMesh::AssemblyForSplitFrom3DCurve(const std::vector<int>& cut3DCurve, std::vector<int>& nodesOnPlane, const int *nodal3DSurf, const int *nodalIndx3DSurf,
10814                                                    const int *nodal3DCurve, const int *nodalIndx3DCurve,
10815                                                    const int *desc, const int *descIndx, 
10816                                                    std::vector< std::pair<int,int> >& cut3DSurf)
10817 {
10818   std::set<int> nodesOnP(nodesOnPlane.begin(),nodesOnPlane.end());
10819   int nbOf3DSurfCell=(int)cut3DSurf.size();
10820   for(int i=0;i<nbOf3DSurfCell;i++)
10821     {
10822       std::vector<int> res;
10823       int offset=descIndx[i];
10824       int nbOfSeg=descIndx[i+1]-offset;
10825       for(int j=0;j<nbOfSeg;j++)
10826         {
10827           int edgeId=desc[offset+j];
10828           int status=cut3DCurve[edgeId];
10829           if(status!=-2)
10830             {
10831               if(status>-1)
10832                 res.push_back(status);
10833               else
10834                 {
10835                   res.push_back(nodal3DCurve[nodalIndx3DCurve[edgeId]+1]);
10836                   res.push_back(nodal3DCurve[nodalIndx3DCurve[edgeId]+2]);
10837                 }
10838             }
10839         }
10840       switch(res.size())
10841       {
10842         case 2:
10843           {
10844             cut3DSurf[i].first=res[0]; cut3DSurf[i].second=res[1];
10845             break;
10846           }
10847         case 1:
10848         case 0:
10849           {
10850             std::set<int> s1(nodal3DSurf+nodalIndx3DSurf[i]+1,nodal3DSurf+nodalIndx3DSurf[i+1]);
10851             std::set_intersection(nodesOnP.begin(),nodesOnP.end(),s1.begin(),s1.end(),std::back_insert_iterator< std::vector<int> >(res));
10852             if(res.size()==2)
10853               {
10854                 cut3DSurf[i].first=res[0]; cut3DSurf[i].second=res[1];
10855               }
10856             else
10857               {
10858                 cut3DSurf[i].first=-1; cut3DSurf[i].second=-1;
10859               }
10860             break;
10861           }
10862         default:
10863           {// case when plane is on a multi colinear edge of a polyhedron
10864             if((int)res.size()==2*nbOfSeg)
10865               {
10866                 cut3DSurf[i].first=-2; cut3DSurf[i].second=i;
10867               }
10868             else
10869               throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AssemblyPointsFrom3DCurve : unexpected situation !");
10870           }
10871       }
10872     }
10873 }
10874
10875 /*!
10876  * \a this is expected to be a mesh with spaceDim==3 and meshDim==3. If not an exception will be thrown.
10877  * 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).
10878  * 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
10879  * with a plane. The result will be put in 'nodalRes' 'nodalResIndx' and 'cellIds' out parameters.
10880  * \param cut3DSurf  input paramter that gives for each 3DSurf its intersection with plane (result of MEDCouplingUMesh::AssemblyForSplitFrom3DCurve).
10881  * \param desc is the descending connectivity 3D->3DSurf
10882  * \param descIndx is the descending connectivity index 3D->3DSurf
10883  */
10884 void MEDCouplingUMesh::assemblyForSplitFrom3DSurf(const std::vector< std::pair<int,int> >& cut3DSurf,
10885                                                   const int *desc, const int *descIndx,
10886                                                   DataArrayInt *nodalRes, DataArrayInt *nodalResIndx, DataArrayInt *cellIds) const
10887 {
10888   checkFullyDefined();
10889   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
10890     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::assemblyForSplitFrom3DSurf works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
10891   const int *nodal3D(_nodal_connec->begin()),*nodalIndx3D(_nodal_connec_index->begin());
10892   int nbOfCells(getNumberOfCells());
10893   for(int i=0;i<nbOfCells;i++)
10894     {
10895       std::map<int, std::set<int> > m;
10896       int offset=descIndx[i];
10897       int nbOfFaces=descIndx[i+1]-offset;
10898       int start=-1;
10899       int end=-1;
10900       for(int j=0;j<nbOfFaces;j++)
10901         {
10902           const std::pair<int,int>& p=cut3DSurf[desc[offset+j]];
10903           if(p.first!=-1 && p.second!=-1)
10904             {
10905               if(p.first!=-2)
10906                 {
10907                   start=p.first; end=p.second;
10908                   m[p.first].insert(p.second);
10909                   m[p.second].insert(p.first);
10910                 }
10911               else
10912                 {
10913                   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)nodal3D[nodalIndx3D[i]]);
10914                   int sz=nodalIndx3D[i+1]-nodalIndx3D[i]-1;
10915                   INTERP_KERNEL::AutoPtr<int> tmp=new int[sz];
10916                   INTERP_KERNEL::NormalizedCellType cmsId;
10917                   unsigned nbOfNodesSon=cm.fillSonCellNodalConnectivity2(j,nodal3D+nodalIndx3D[i]+1,sz,tmp,cmsId);
10918                   start=tmp[0]; end=tmp[nbOfNodesSon-1];
10919                   for(unsigned k=0;k<nbOfNodesSon;k++)
10920                     {
10921                       m[tmp[k]].insert(tmp[(k+1)%nbOfNodesSon]);
10922                       m[tmp[(k+1)%nbOfNodesSon]].insert(tmp[k]);
10923                     }
10924                 }
10925             }
10926         }
10927       if(m.empty())
10928         continue;
10929       std::vector<int> conn(1,(int)INTERP_KERNEL::NORM_POLYGON);
10930       int prev=end;
10931       while(end!=start)
10932         {
10933           std::map<int, std::set<int> >::const_iterator it=m.find(start);
10934           const std::set<int>& s=(*it).second;
10935           std::set<int> s2; s2.insert(prev);
10936           std::set<int> s3;
10937           std::set_difference(s.begin(),s.end(),s2.begin(),s2.end(),inserter(s3,s3.begin()));
10938           if(s3.size()==1)
10939             {
10940               int val=*s3.begin();
10941               conn.push_back(start);
10942               prev=start;
10943               start=val;
10944             }
10945           else
10946             start=end;
10947         }
10948       conn.push_back(end);
10949       if(conn.size()>3)
10950         {
10951           nodalRes->insertAtTheEnd(conn.begin(),conn.end());
10952           nodalResIndx->pushBackSilent(nodalRes->getNumberOfTuples());
10953           cellIds->pushBackSilent(i);
10954         }
10955     }
10956 }
10957
10958 void InsertNodeInConnIfNecessary(int nodeIdToInsert, std::vector<int>& conn, const double *coords, double eps)
10959 {
10960   std::vector<int>::iterator it(std::find(conn.begin(),conn.end(),nodeIdToInsert));
10961   if(it!=conn.end())
10962     return ;
10963   std::size_t sz(conn.size());
10964   std::size_t found(std::numeric_limits<std::size_t>::max());
10965   for(std::size_t i=0;i<sz;i++)
10966     {
10967       int pt0(conn[i]),pt1(conn[(i+1)%sz]);
10968       double v1[3]={coords[3*pt1+0]-coords[3*pt0+0],coords[3*pt1+1]-coords[3*pt0+1],coords[3*pt1+2]-coords[3*pt0+2]},v2[3]={coords[3*nodeIdToInsert+0]-coords[3*pt0+0],coords[3*nodeIdToInsert+1]-coords[3*pt0+1],coords[3*nodeIdToInsert+2]-coords[3*pt0+2]};
10969       double normm(sqrt(v1[0]*v1[0]+v1[1]*v1[1]+v1[2]*v1[2]));
10970       std::transform(v1,v1+3,v1,std::bind2nd(std::multiplies<double>(),1./normm));
10971       std::transform(v2,v2+3,v2,std::bind2nd(std::multiplies<double>(),1./normm));
10972       double v3[3];
10973       v3[0]=v1[1]*v2[2]-v1[2]*v2[1]; v3[1]=v1[2]*v2[0]-v1[0]*v2[2]; v3[2]=v1[0]*v2[1]-v1[1]*v2[0];
10974       double normm2(sqrt(v3[0]*v3[0]+v3[1]*v3[1]+v3[2]*v3[2])),dotTest(v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2]);
10975       if(normm2<eps)
10976         if(dotTest>eps && dotTest<1.-eps)
10977           {
10978             found=i;
10979             break;
10980           }
10981     }
10982   if(found==std::numeric_limits<std::size_t>::max())
10983     throw INTERP_KERNEL::Exception("InsertNodeInConnIfNecessary : not found point !");
10984   conn.insert(conn.begin()+(found+1)%sz,nodeIdToInsert);
10985 }
10986
10987 void SplitIntoToPart(const std::vector<int>& conn, int pt0, int pt1, std::vector<int>& part0, std::vector<int>& part1)
10988 {
10989   std::size_t sz(conn.size());
10990   std::vector<int> *curPart(&part0);
10991   for(std::size_t i=0;i<sz;i++)
10992     {
10993       int nextt(conn[(i+1)%sz]);
10994       (*curPart).push_back(nextt);
10995       if(nextt==pt0 || nextt==pt1)
10996         {
10997           if(curPart==&part0)
10998             curPart=&part1;
10999           else
11000             curPart=&part0;
11001           (*curPart).push_back(nextt);
11002         }
11003     }
11004 }
11005
11006 /*!
11007  * this method method splits cur cells 3D Surf in sub cells 3DSurf using the previous subsplit. This method is the last one used to clip.
11008  */
11009 void MEDCouplingUMesh::buildSubCellsFromCut(const std::vector< std::pair<int,int> >& cut3DSurf,
11010                                             const int *desc, const int *descIndx, const double *coords, double eps,
11011                                             std::vector<std::vector<int> >& res) const
11012 {
11013   checkFullyDefined();
11014   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
11015     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSubCellsFromCut works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
11016   const int *nodal3D(_nodal_connec->begin()),*nodalIndx3D(_nodal_connec_index->begin());
11017   int nbOfCells(getNumberOfCells());
11018   if(nbOfCells!=1)
11019     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSubCellsFromCut works only with single cell presently !");
11020   for(int i=0;i<nbOfCells;i++)
11021     {
11022       int offset(descIndx[i]),nbOfFaces(descIndx[i+1]-offset),start(-1),end(-1);
11023       for(int j=0;j<nbOfFaces;j++)
11024         {
11025           const std::pair<int,int>& p=cut3DSurf[desc[offset+j]];
11026           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)nodal3D[nodalIndx3D[i]]));
11027           int sz=nodalIndx3D[i+1]-nodalIndx3D[i]-1;
11028           INTERP_KERNEL::AutoPtr<int> tmp(new int[sz]);
11029           INTERP_KERNEL::NormalizedCellType cmsId;
11030           unsigned nbOfNodesSon(cm.fillSonCellNodalConnectivity2(j,nodal3D+nodalIndx3D[i]+1,sz,tmp,cmsId));
11031           std::vector<int> elt((int *)tmp,(int *)tmp+nbOfNodesSon);
11032           if(p.first!=-1 && p.second!=-1)
11033             {
11034               if(p.first!=-2)
11035                 {
11036                   InsertNodeInConnIfNecessary(p.first,elt,coords,eps);
11037                   InsertNodeInConnIfNecessary(p.second,elt,coords,eps);
11038                   std::vector<int> elt1,elt2;
11039                   SplitIntoToPart(elt,p.first,p.second,elt1,elt2);
11040                   res.push_back(elt1);
11041                   res.push_back(elt2);
11042                 }
11043               else
11044                 res.push_back(elt);
11045             }
11046           else
11047             res.push_back(elt);
11048         }
11049     }
11050 }
11051
11052 /*!
11053  * 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
11054  * 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
11055  * the geometric cell type set to INTERP_KERNEL::NORM_POLYGON.
11056  * 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
11057  * 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.
11058  * 
11059  * \return false if the input connectivity represents already the convex hull, true if the input cell needs to be reordered.
11060  */
11061 bool MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis(const double *coords, const int *nodalConnBg, const int *nodalConnEnd, DataArrayInt *nodalConnecOut)
11062 {
11063   std::size_t sz=std::distance(nodalConnBg,nodalConnEnd);
11064   if(sz>=4)
11065     {
11066       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)*nodalConnBg);
11067       if(cm.getDimension()==2)
11068         {
11069           const int *node=nodalConnBg+1;
11070           int startNode=*node++;
11071           double refX=coords[2*startNode];
11072           for(;node!=nodalConnEnd;node++)
11073             {
11074               if(coords[2*(*node)]<refX)
11075                 {
11076                   startNode=*node;
11077                   refX=coords[2*startNode];
11078                 }
11079             }
11080           std::vector<int> tmpOut; tmpOut.reserve(sz); tmpOut.push_back(startNode);
11081           refX=1e300;
11082           double tmp1;
11083           double tmp2[2];
11084           double angle0=-M_PI/2;
11085           //
11086           int nextNode=-1;
11087           int prevNode=-1;
11088           double resRef;
11089           double angleNext=0.;
11090           while(nextNode!=startNode)
11091             {
11092               nextNode=-1;
11093               resRef=1e300;
11094               for(node=nodalConnBg+1;node!=nodalConnEnd;node++)
11095                 {
11096                   if(*node!=tmpOut.back() && *node!=prevNode)
11097                     {
11098                       tmp2[0]=coords[2*(*node)]-coords[2*tmpOut.back()]; tmp2[1]=coords[2*(*node)+1]-coords[2*tmpOut.back()+1];
11099                       double angleM=INTERP_KERNEL::EdgeArcCircle::GetAbsoluteAngle(tmp2,tmp1);
11100                       double res;
11101                       if(angleM<=angle0)
11102                         res=angle0-angleM;
11103                       else
11104                         res=angle0-angleM+2.*M_PI;
11105                       if(res<resRef)
11106                         {
11107                           nextNode=*node;
11108                           resRef=res;
11109                           angleNext=angleM;
11110                         }
11111                     }
11112                 }
11113               if(nextNode!=startNode)
11114                 {
11115                   angle0=angleNext-M_PI;
11116                   if(angle0<-M_PI)
11117                     angle0+=2*M_PI;
11118                   prevNode=tmpOut.back();
11119                   tmpOut.push_back(nextNode);
11120                 }
11121             }
11122           std::vector<int> tmp3(2*(sz-1));
11123           std::vector<int>::iterator it=std::copy(nodalConnBg+1,nodalConnEnd,tmp3.begin());
11124           std::copy(nodalConnBg+1,nodalConnEnd,it);
11125           if(std::search(tmp3.begin(),tmp3.end(),tmpOut.begin(),tmpOut.end())!=tmp3.end())
11126             {
11127               nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
11128               return false;
11129             }
11130           if(std::search(tmp3.rbegin(),tmp3.rend(),tmpOut.begin(),tmpOut.end())!=tmp3.rend())
11131             {
11132               nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
11133               return false;
11134             }
11135           else
11136             {
11137               nodalConnecOut->pushBackSilent((int)INTERP_KERNEL::NORM_POLYGON);
11138               nodalConnecOut->insertAtTheEnd(tmpOut.begin(),tmpOut.end());
11139               return true;
11140             }
11141         }
11142       else
11143         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
11144     }
11145   else
11146     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
11147 }
11148
11149 /*!
11150  * This method works on an input pair (\b arr, \b arrIndx) where \b arr indexes is in \b arrIndx.
11151  * 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.
11152  * 
11153  * \param [in] idsToRemoveBg begin of set of ids to remove in \b arr (included)
11154  * \param [in] idsToRemoveEnd end of set of ids to remove in \b arr (excluded)
11155  * \param [in,out] arr array in which the remove operation will be done.
11156  * \param [in,out] arrIndx array in the remove operation will modify
11157  * \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])
11158  * \return true if \b arr and \b arrIndx have been modified, false if not.
11159  */
11160 bool MEDCouplingUMesh::RemoveIdsFromIndexedArrays(const int *idsToRemoveBg, const int *idsToRemoveEnd, DataArrayInt *arr, DataArrayInt *arrIndx, int offsetForRemoval)
11161 {
11162   if(!arrIndx || !arr)
11163     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::RemoveIdsFromIndexedArrays : some input arrays are empty !");
11164   if(offsetForRemoval<0)
11165     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::RemoveIdsFromIndexedArrays : offsetForRemoval should be >=0 !");
11166   std::set<int> s(idsToRemoveBg,idsToRemoveEnd);
11167   int nbOfGrps=arrIndx->getNumberOfTuples()-1;
11168   int *arrIPtr=arrIndx->getPointer();
11169   *arrIPtr++=0;
11170   int previousArrI=0;
11171   const int *arrPtr=arr->begin();
11172   std::vector<int> arrOut;//no utility to switch to DataArrayInt because copy always needed
11173   for(int i=0;i<nbOfGrps;i++,arrIPtr++)
11174     {
11175       if(*arrIPtr-previousArrI>offsetForRemoval)
11176         {
11177           for(const int *work=arrPtr+previousArrI+offsetForRemoval;work!=arrPtr+*arrIPtr;work++)
11178             {
11179               if(s.find(*work)==s.end())
11180                 arrOut.push_back(*work);
11181             }
11182         }
11183       previousArrI=*arrIPtr;
11184       *arrIPtr=(int)arrOut.size();
11185     }
11186   if(arr->getNumberOfTuples()==(int)arrOut.size())
11187     return false;
11188   arr->alloc((int)arrOut.size(),1);
11189   std::copy(arrOut.begin(),arrOut.end(),arr->getPointer());
11190   return true;
11191 }
11192
11193 /*!
11194  * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn
11195  * (\ref numbering-indirect).
11196  * This method returns the result of the extraction ( specified by a set of ids in [\b idsOfSelectBg , \b idsOfSelectEnd ) ).
11197  * The selection of extraction is done standardly in new2old format.
11198  * This method returns indexed arrays (\ref numbering-indirect) using 2 arrays (arrOut,arrIndexOut).
11199  *
11200  * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
11201  * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
11202  * \param [in] arrIn arr origin array from which the extraction will be done.
11203  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11204  * \param [out] arrOut the resulting array
11205  * \param [out] arrIndexOut the index array of the resulting array \b arrOut
11206  * \sa MEDCouplingUMesh::ExtractFromIndexedArraysSlice
11207  */
11208 void MEDCouplingUMesh::ExtractFromIndexedArrays(const int *idsOfSelectBg, const int *idsOfSelectEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
11209                                                 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
11210 {
11211   if(!arrIn || !arrIndxIn)
11212     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : input pointer is NULL !");
11213   arrIn->checkAllocated(); arrIndxIn->checkAllocated();
11214   if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1)
11215     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : input arrays must have exactly one component !");
11216   std::size_t sz=std::distance(idsOfSelectBg,idsOfSelectEnd);
11217   const int *arrInPtr=arrIn->begin();
11218   const int *arrIndxPtr=arrIndxIn->begin();
11219   int nbOfGrps=arrIndxIn->getNumberOfTuples()-1;
11220   if(nbOfGrps<0)
11221     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : The format of \"arrIndxIn\" is invalid ! Its nb of tuples should be >=1 !");
11222   int maxSizeOfArr=arrIn->getNumberOfTuples();
11223   MCAuto<DataArrayInt> arro=DataArrayInt::New();
11224   MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
11225   arrIo->alloc((int)(sz+1),1);
11226   const int *idsIt=idsOfSelectBg;
11227   int *work=arrIo->getPointer();
11228   *work++=0;
11229   int lgth=0;
11230   for(std::size_t i=0;i<sz;i++,work++,idsIt++)
11231     {
11232       if(*idsIt>=0 && *idsIt<nbOfGrps)
11233         lgth+=arrIndxPtr[*idsIt+1]-arrIndxPtr[*idsIt];
11234       else
11235         {
11236           std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " ! Must be in [0," << nbOfGrps << ") !";
11237           throw INTERP_KERNEL::Exception(oss.str());
11238         }
11239       if(lgth>=work[-1])
11240         *work=lgth;
11241       else
11242         {
11243           std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " and at this pos arrIndxIn[" << *idsIt;
11244           oss << "+1]-arrIndxIn[" << *idsIt << "] < 0 ! The input index array is bugged !";
11245           throw INTERP_KERNEL::Exception(oss.str());
11246         }
11247     }
11248   arro->alloc(lgth,1);
11249   work=arro->getPointer();
11250   idsIt=idsOfSelectBg;
11251   for(std::size_t i=0;i<sz;i++,idsIt++)
11252     {
11253       if(arrIndxPtr[*idsIt]>=0 && arrIndxPtr[*idsIt+1]<=maxSizeOfArr)
11254         work=std::copy(arrInPtr+arrIndxPtr[*idsIt],arrInPtr+arrIndxPtr[*idsIt+1],work);
11255       else
11256         {
11257           std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " arrIndx[" << *idsIt << "] must be >= 0 and arrIndx[";
11258           oss << *idsIt << "+1] <= " << maxSizeOfArr << " (the size of arrIn)!";
11259           throw INTERP_KERNEL::Exception(oss.str());
11260         }
11261     }
11262   arrOut=arro.retn();
11263   arrIndexOut=arrIo.retn();
11264 }
11265
11266 /*!
11267  * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn
11268  * (\ref numbering-indirect).
11269  * 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 ).
11270  * The selection of extraction is done standardly in new2old format.
11271  * This method returns indexed arrays (\ref numbering-indirect) using 2 arrays (arrOut,arrIndexOut).
11272  *
11273  * \param [in] idsOfSelectStart begin of set of ids of the input extraction (included)
11274  * \param [in] idsOfSelectStop end of set of ids of the input extraction (excluded)
11275  * \param [in] idsOfSelectStep
11276  * \param [in] arrIn arr origin array from which the extraction will be done.
11277  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11278  * \param [out] arrOut the resulting array
11279  * \param [out] arrIndexOut the index array of the resulting array \b arrOut
11280  * \sa MEDCouplingUMesh::ExtractFromIndexedArrays
11281  */
11282 void MEDCouplingUMesh::ExtractFromIndexedArraysSlice(int idsOfSelectStart, int idsOfSelectStop, int idsOfSelectStep, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
11283                                                  DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
11284 {
11285   if(!arrIn || !arrIndxIn)
11286     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : input pointer is NULL !");
11287   arrIn->checkAllocated(); arrIndxIn->checkAllocated();
11288   if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1)
11289     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : input arrays must have exactly one component !");
11290   int sz=DataArrayInt::GetNumberOfItemGivenBESRelative(idsOfSelectStart,idsOfSelectStop,idsOfSelectStep,"MEDCouplingUMesh::ExtractFromIndexedArraysSlice : Input slice ");
11291   const int *arrInPtr=arrIn->begin();
11292   const int *arrIndxPtr=arrIndxIn->begin();
11293   int nbOfGrps=arrIndxIn->getNumberOfTuples()-1;
11294   if(nbOfGrps<0)
11295     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : The format of \"arrIndxIn\" is invalid ! Its nb of tuples should be >=1 !");
11296   int maxSizeOfArr=arrIn->getNumberOfTuples();
11297   MCAuto<DataArrayInt> arro=DataArrayInt::New();
11298   MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
11299   arrIo->alloc((int)(sz+1),1);
11300   int idsIt=idsOfSelectStart;
11301   int *work=arrIo->getPointer();
11302   *work++=0;
11303   int lgth=0;
11304   for(int i=0;i<sz;i++,work++,idsIt+=idsOfSelectStep)
11305     {
11306       if(idsIt>=0 && idsIt<nbOfGrps)
11307         lgth+=arrIndxPtr[idsIt+1]-arrIndxPtr[idsIt];
11308       else
11309         {
11310           std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " ! Must be in [0," << nbOfGrps << ") !";
11311           throw INTERP_KERNEL::Exception(oss.str());
11312         }
11313       if(lgth>=work[-1])
11314         *work=lgth;
11315       else
11316         {
11317           std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " and at this pos arrIndxIn[" << idsIt;
11318           oss << "+1]-arrIndxIn[" << idsIt << "] < 0 ! The input index array is bugged !";
11319           throw INTERP_KERNEL::Exception(oss.str());
11320         }
11321     }
11322   arro->alloc(lgth,1);
11323   work=arro->getPointer();
11324   idsIt=idsOfSelectStart;
11325   for(int i=0;i<sz;i++,idsIt+=idsOfSelectStep)
11326     {
11327       if(arrIndxPtr[idsIt]>=0 && arrIndxPtr[idsIt+1]<=maxSizeOfArr)
11328         work=std::copy(arrInPtr+arrIndxPtr[idsIt],arrInPtr+arrIndxPtr[idsIt+1],work);
11329       else
11330         {
11331           std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " arrIndx[" << idsIt << "] must be >= 0 and arrIndx[";
11332           oss << idsIt << "+1] <= " << maxSizeOfArr << " (the size of arrIn)!";
11333           throw INTERP_KERNEL::Exception(oss.str());
11334         }
11335     }
11336   arrOut=arro.retn();
11337   arrIndexOut=arrIo.retn();
11338 }
11339
11340 /*!
11341  * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11342  * 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
11343  * cellIds \b in [ \b idsOfSelectBg , \b idsOfSelectEnd ) a copy coming from the corresponding values in input pair (\b srcArr, \b srcArrIndex).
11344  * This method is an generalization of MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx that performs the same thing but by without building explicitely a result output arrays.
11345  *
11346  * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
11347  * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
11348  * \param [in] arrIn arr origin array from which the extraction will be done.
11349  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11350  * \param [in] srcArr input array that will be used as source of copy for ids in [ \b idsOfSelectBg, \b idsOfSelectEnd )
11351  * \param [in] srcArrIndex index array of \b srcArr
11352  * \param [out] arrOut the resulting array
11353  * \param [out] arrIndexOut the index array of the resulting array \b arrOut
11354  * 
11355  * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx
11356  */
11357 void MEDCouplingUMesh::SetPartOfIndexedArrays(const int *idsOfSelectBg, const int *idsOfSelectEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
11358                                               const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex,
11359                                               DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
11360 {
11361   if(arrIn==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11362     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArrays : presence of null pointer in input parameter !");
11363   MCAuto<DataArrayInt> arro=DataArrayInt::New();
11364   MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
11365   int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11366   std::vector<bool> v(nbOfTuples,true);
11367   int offset=0;
11368   const int *arrIndxInPtr=arrIndxIn->begin();
11369   const int *srcArrIndexPtr=srcArrIndex->begin();
11370   for(const int *it=idsOfSelectBg;it!=idsOfSelectEnd;it++,srcArrIndexPtr++)
11371     {
11372       if(*it>=0 && *it<nbOfTuples)
11373         {
11374           v[*it]=false;
11375           offset+=(srcArrIndexPtr[1]-srcArrIndexPtr[0])-(arrIndxInPtr[*it+1]-arrIndxInPtr[*it]);
11376         }
11377       else
11378         {
11379           std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArrays : On pos #" << std::distance(idsOfSelectBg,it) << " value is " << *it << " not in [0," << nbOfTuples << ") !";
11380           throw INTERP_KERNEL::Exception(oss.str());
11381         }
11382     }
11383   srcArrIndexPtr=srcArrIndex->begin();
11384   arrIo->alloc(nbOfTuples+1,1);
11385   arro->alloc(arrIn->getNumberOfTuples()+offset,1);
11386   const int *arrInPtr=arrIn->begin();
11387   const int *srcArrPtr=srcArr->begin();
11388   int *arrIoPtr=arrIo->getPointer(); *arrIoPtr++=0;
11389   int *arroPtr=arro->getPointer();
11390   for(int ii=0;ii<nbOfTuples;ii++,arrIoPtr++)
11391     {
11392       if(v[ii])
11393         {
11394           arroPtr=std::copy(arrInPtr+arrIndxInPtr[ii],arrInPtr+arrIndxInPtr[ii+1],arroPtr);
11395           *arrIoPtr=arrIoPtr[-1]+(arrIndxInPtr[ii+1]-arrIndxInPtr[ii]);
11396         }
11397       else
11398         {
11399           std::size_t pos=std::distance(idsOfSelectBg,std::find(idsOfSelectBg,idsOfSelectEnd,ii));
11400           arroPtr=std::copy(srcArrPtr+srcArrIndexPtr[pos],srcArrPtr+srcArrIndexPtr[pos+1],arroPtr);
11401           *arrIoPtr=arrIoPtr[-1]+(srcArrIndexPtr[pos+1]-srcArrIndexPtr[pos]);
11402         }
11403     }
11404   arrOut=arro.retn();
11405   arrIndexOut=arrIo.retn();
11406 }
11407
11408 /*!
11409  * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11410  * This method is an specialization of MEDCouplingUMesh::SetPartOfIndexedArrays in the case of assignement do not modify the index in \b arrIndxIn.
11411  *
11412  * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
11413  * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
11414  * \param [in,out] arrInOut arr origin array from which the extraction will be done.
11415  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11416  * \param [in] srcArr input array that will be used as source of copy for ids in [ \b idsOfSelectBg , \b idsOfSelectEnd )
11417  * \param [in] srcArrIndex index array of \b srcArr
11418  * 
11419  * \sa MEDCouplingUMesh::SetPartOfIndexedArrays
11420  */
11421 void MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx(const int *idsOfSelectBg, const int *idsOfSelectEnd, DataArrayInt *arrInOut, const DataArrayInt *arrIndxIn,
11422                                                      const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex)
11423 {
11424   if(arrInOut==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11425     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx : presence of null pointer in input parameter !");
11426   int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11427   const int *arrIndxInPtr=arrIndxIn->begin();
11428   const int *srcArrIndexPtr=srcArrIndex->begin();
11429   int *arrInOutPtr=arrInOut->getPointer();
11430   const int *srcArrPtr=srcArr->begin();
11431   for(const int *it=idsOfSelectBg;it!=idsOfSelectEnd;it++,srcArrIndexPtr++)
11432     {
11433       if(*it>=0 && *it<nbOfTuples)
11434         {
11435           if(srcArrIndexPtr[1]-srcArrIndexPtr[0]==arrIndxInPtr[*it+1]-arrIndxInPtr[*it])
11436             std::copy(srcArrPtr+srcArrIndexPtr[0],srcArrPtr+srcArrIndexPtr[1],arrInOutPtr+arrIndxInPtr[*it]);
11437           else
11438             {
11439               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] !";
11440               throw INTERP_KERNEL::Exception(oss.str());
11441             }
11442         }
11443       else
11444         {
11445           std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx : On pos #" << std::distance(idsOfSelectBg,it) << " value is " << *it << " not in [0," << nbOfTuples << ") !";
11446           throw INTERP_KERNEL::Exception(oss.str());
11447         }
11448     }
11449 }
11450
11451 /*!
11452  * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
11453  * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
11454  * 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]].
11455  * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
11456  * A negative value in \b arrIn means that it is ignored.
11457  * 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.
11458  * 
11459  * \param [in] arrIn arr origin array from which the extraction will be done.
11460  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11461  * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
11462  * \sa MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed, MEDCouplingUMesh::partitionBySpreadZone
11463  */
11464 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGradually(const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn)
11465 {
11466   int seed=0,nbOfDepthPeelingPerformed=0;
11467   return ComputeSpreadZoneGraduallyFromSeed(&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfDepthPeelingPerformed);
11468 }
11469
11470 /*!
11471  * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
11472  * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
11473  * 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]].
11474  * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
11475  * A negative value in \b arrIn means that it is ignored.
11476  * 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.
11477  * \param [in] seedBg the begin pointer (included) of an array containing the seed of the search zone
11478  * \param [in] seedEnd the end pointer (not included) of an array containing the seed of the search zone
11479  * \param [in] arrIn arr origin array from which the extraction will be done.
11480  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11481  * \param [in] nbOfDepthPeeling the max number of peels requested in search. By default -1, that is to say, no limit.
11482  * \param [out] nbOfDepthPeelingPerformed the number of peels effectively performed. May be different from \a nbOfDepthPeeling
11483  * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
11484  * \sa MEDCouplingUMesh::partitionBySpreadZone
11485  */
11486 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(const int *seedBg, const int *seedEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn, int nbOfDepthPeeling, int& nbOfDepthPeelingPerformed)
11487 {
11488   nbOfDepthPeelingPerformed=0;
11489   if(!arrIndxIn)
11490     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed : arrIndxIn input pointer is NULL !");
11491   int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11492   if(nbOfTuples<=0)
11493     {
11494       DataArrayInt *ret=DataArrayInt::New(); ret->alloc(0,1);
11495       return ret;
11496     }
11497   //
11498   std::vector<bool> fetched(nbOfTuples,false);
11499   return ComputeSpreadZoneGraduallyFromSeedAlg(fetched,seedBg,seedEnd,arrIn,arrIndxIn,nbOfDepthPeeling,nbOfDepthPeelingPerformed);
11500 }
11501
11502 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeedAlg(std::vector<bool>& fetched, const int *seedBg, const int *seedEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn, int nbOfDepthPeeling, int& nbOfDepthPeelingPerformed)
11503 {
11504   nbOfDepthPeelingPerformed=0;
11505   if(!seedBg || !seedEnd || !arrIn || !arrIndxIn)
11506     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeedAlg : some input pointer is NULL !");
11507   int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11508   std::vector<bool> fetched2(nbOfTuples,false);
11509   int i=0;
11510   for(const int *seedElt=seedBg;seedElt!=seedEnd;seedElt++,i++)
11511     {
11512       if(*seedElt>=0 && *seedElt<nbOfTuples)
11513         { fetched[*seedElt]=true; fetched2[*seedElt]=true; }
11514       else
11515         { 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()); }
11516     }
11517   const int *arrInPtr=arrIn->begin();
11518   const int *arrIndxPtr=arrIndxIn->begin();
11519   int targetNbOfDepthPeeling=nbOfDepthPeeling!=-1?nbOfDepthPeeling:std::numeric_limits<int>::max();
11520   std::vector<int> idsToFetch1(seedBg,seedEnd);
11521   std::vector<int> idsToFetch2;
11522   std::vector<int> *idsToFetch=&idsToFetch1;
11523   std::vector<int> *idsToFetchOther=&idsToFetch2;
11524   while(!idsToFetch->empty() && nbOfDepthPeelingPerformed<targetNbOfDepthPeeling)
11525     {
11526       for(std::vector<int>::const_iterator it=idsToFetch->begin();it!=idsToFetch->end();it++)
11527         for(const int *it2=arrInPtr+arrIndxPtr[*it];it2!=arrInPtr+arrIndxPtr[*it+1];it2++)
11528           if(!fetched[*it2])
11529             { fetched[*it2]=true; fetched2[*it2]=true; idsToFetchOther->push_back(*it2); }
11530       std::swap(idsToFetch,idsToFetchOther);
11531       idsToFetchOther->clear();
11532       nbOfDepthPeelingPerformed++;
11533     }
11534   int lgth=(int)std::count(fetched2.begin(),fetched2.end(),true);
11535   i=0;
11536   MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(lgth,1);
11537   int *retPtr=ret->getPointer();
11538   for(std::vector<bool>::const_iterator it=fetched2.begin();it!=fetched2.end();it++,i++)
11539     if(*it)
11540       *retPtr++=i;
11541   return ret.retn();
11542 }
11543
11544 /*!
11545  * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11546  * 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
11547  * cellIds \b in [\b idsOfSelectBg, \b idsOfSelectEnd) a copy coming from the corresponding values in input pair (\b srcArr, \b srcArrIndex).
11548  * This method is an generalization of MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx that performs the same thing but by without building explicitely a result output arrays.
11549  *
11550  * \param [in] start begin of set of ids of the input extraction (included)
11551  * \param [in] end end of set of ids of the input extraction (excluded)
11552  * \param [in] step step of the set of ids in range mode.
11553  * \param [in] arrIn arr origin array from which the extraction will be done.
11554  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11555  * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd)
11556  * \param [in] srcArrIndex index array of \b srcArr
11557  * \param [out] arrOut the resulting array
11558  * \param [out] arrIndexOut the index array of the resulting array \b arrOut
11559  * 
11560  * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx MEDCouplingUMesh::SetPartOfIndexedArrays
11561  */
11562 void MEDCouplingUMesh::SetPartOfIndexedArraysSlice(int start, int end, int step, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
11563                                                const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex,
11564                                                DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
11565 {
11566   if(arrIn==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11567     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSlice : presence of null pointer in input parameter !");
11568   MCAuto<DataArrayInt> arro=DataArrayInt::New();
11569   MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
11570   int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11571   int offset=0;
11572   const int *arrIndxInPtr=arrIndxIn->begin();
11573   const int *srcArrIndexPtr=srcArrIndex->begin();
11574   int nbOfElemsToSet=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::SetPartOfIndexedArraysSlice : ");
11575   int it=start;
11576   for(int i=0;i<nbOfElemsToSet;i++,srcArrIndexPtr++,it+=step)
11577     {
11578       if(it>=0 && it<nbOfTuples)
11579         offset+=(srcArrIndexPtr[1]-srcArrIndexPtr[0])-(arrIndxInPtr[it+1]-arrIndxInPtr[it]);
11580       else
11581         {
11582           std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSlice : On pos #" << i << " value is " << it << " not in [0," << nbOfTuples << ") !";
11583           throw INTERP_KERNEL::Exception(oss.str());
11584         }
11585     }
11586   srcArrIndexPtr=srcArrIndex->begin();
11587   arrIo->alloc(nbOfTuples+1,1);
11588   arro->alloc(arrIn->getNumberOfTuples()+offset,1);
11589   const int *arrInPtr=arrIn->begin();
11590   const int *srcArrPtr=srcArr->begin();
11591   int *arrIoPtr=arrIo->getPointer(); *arrIoPtr++=0;
11592   int *arroPtr=arro->getPointer();
11593   for(int ii=0;ii<nbOfTuples;ii++,arrIoPtr++)
11594     {
11595       int pos=DataArray::GetPosOfItemGivenBESRelativeNoThrow(ii,start,end,step);
11596       if(pos<0)
11597         {
11598           arroPtr=std::copy(arrInPtr+arrIndxInPtr[ii],arrInPtr+arrIndxInPtr[ii+1],arroPtr);
11599           *arrIoPtr=arrIoPtr[-1]+(arrIndxInPtr[ii+1]-arrIndxInPtr[ii]);
11600         }
11601       else
11602         {
11603           arroPtr=std::copy(srcArrPtr+srcArrIndexPtr[pos],srcArrPtr+srcArrIndexPtr[pos+1],arroPtr);
11604           *arrIoPtr=arrIoPtr[-1]+(srcArrIndexPtr[pos+1]-srcArrIndexPtr[pos]);
11605         }
11606     }
11607   arrOut=arro.retn();
11608   arrIndexOut=arrIo.retn();
11609 }
11610
11611 /*!
11612  * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11613  * This method is an specialization of MEDCouplingUMesh::SetPartOfIndexedArrays in the case of assignement do not modify the index in \b arrIndxIn.
11614  *
11615  * \param [in] start begin of set of ids of the input extraction (included)
11616  * \param [in] end end of set of ids of the input extraction (excluded)
11617  * \param [in] step step of the set of ids in range mode.
11618  * \param [in,out] arrInOut arr origin array from which the extraction will be done.
11619  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11620  * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd)
11621  * \param [in] srcArrIndex index array of \b srcArr
11622  * 
11623  * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSlice MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx
11624  */
11625 void MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice(int start, int end, int step, DataArrayInt *arrInOut, const DataArrayInt *arrIndxIn,
11626                                                       const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex)
11627 {
11628   if(arrInOut==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11629     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : presence of null pointer in input parameter !");
11630   int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11631   const int *arrIndxInPtr=arrIndxIn->begin();
11632   const int *srcArrIndexPtr=srcArrIndex->begin();
11633   int *arrInOutPtr=arrInOut->getPointer();
11634   const int *srcArrPtr=srcArr->begin();
11635   int nbOfElemsToSet=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : ");
11636   int it=start;
11637   for(int i=0;i<nbOfElemsToSet;i++,srcArrIndexPtr++,it+=step)
11638     {
11639       if(it>=0 && it<nbOfTuples)
11640         {
11641           if(srcArrIndexPtr[1]-srcArrIndexPtr[0]==arrIndxInPtr[it+1]-arrIndxInPtr[it])
11642             std::copy(srcArrPtr+srcArrIndexPtr[0],srcArrPtr+srcArrIndexPtr[1],arrInOutPtr+arrIndxInPtr[it]);
11643           else
11644             {
11645               std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : On pos #" << i << " id (idsOfSelectBg[" << i << "]) is " << it << " arrIndxIn[id+1]-arrIndxIn[id]!=srcArrIndex[pos+1]-srcArrIndex[pos] !";
11646               throw INTERP_KERNEL::Exception(oss.str());
11647             }
11648         }
11649       else
11650         {
11651           std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : On pos #" << i << " value is " << it << " not in [0," << nbOfTuples << ") !";
11652           throw INTERP_KERNEL::Exception(oss.str());
11653         }
11654     }
11655 }
11656
11657 /*!
11658  * \b this is expected to be a mesh fully defined whose spaceDim==meshDim.
11659  * It returns a new allocated mesh having the same mesh dimension and lying on same coordinates.
11660  * The returned mesh contains as poly cells as number of contiguous zone (regarding connectivity).
11661  * A spread contiguous zone is built using poly cells (polyhedra in 3D, polygons in 2D and polyline in 1D).
11662  * The sum of measure field of returned mesh is equal to the sum of measure field of this.
11663  * 
11664  * \return a newly allocated mesh lying on the same coords than \b this with same meshdimension than \b this.
11665  */
11666 MEDCouplingUMesh *MEDCouplingUMesh::buildSpreadZonesWithPoly() const
11667 {
11668   checkFullyDefined();
11669   int mdim=getMeshDimension();
11670   int spaceDim=getSpaceDimension();
11671   if(mdim!=spaceDim)
11672     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension and spacedimension do not match !");
11673   std::vector<DataArrayInt *> partition=partitionBySpreadZone();
11674   std::vector< MCAuto<DataArrayInt> > partitionAuto; partitionAuto.reserve(partition.size());
11675   std::copy(partition.begin(),partition.end(),std::back_insert_iterator<std::vector< MCAuto<DataArrayInt> > >(partitionAuto));
11676   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
11677   ret->setCoords(getCoords());
11678   ret->allocateCells((int)partition.size());
11679   //
11680   for(std::vector<DataArrayInt *>::const_iterator it=partition.begin();it!=partition.end();it++)
11681     {
11682       MCAuto<MEDCouplingUMesh> tmp=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf((*it)->begin(),(*it)->end(),true));
11683       MCAuto<DataArrayInt> cell;
11684       switch(mdim)
11685       {
11686         case 2:
11687           cell=tmp->buildUnionOf2DMesh();
11688           break;
11689         case 3:
11690           cell=tmp->buildUnionOf3DMesh();
11691           break;
11692         default:
11693           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension supported are [2,3] ! Not implemented yet for others !");
11694       }
11695
11696       ret->insertNextCell((INTERP_KERNEL::NormalizedCellType)cell->getIJSafe(0,0),cell->getNumberOfTuples()-1,cell->begin()+1);
11697     }
11698   //
11699   ret->finishInsertingCells();
11700   return ret.retn();
11701 }
11702
11703 /*!
11704  * This method partitions \b this into contiguous zone.
11705  * This method only needs a well defined connectivity. Coordinates are not considered here.
11706  * This method returns a vector of \b newly allocated arrays that the caller has to deal with.
11707  */
11708 std::vector<DataArrayInt *> MEDCouplingUMesh::partitionBySpreadZone() const
11709 {
11710   DataArrayInt *neigh=0,*neighI=0;
11711   computeNeighborsOfCells(neigh,neighI);
11712   MCAuto<DataArrayInt> neighAuto(neigh),neighIAuto(neighI);
11713   return PartitionBySpreadZone(neighAuto,neighIAuto);
11714 }
11715
11716 std::vector<DataArrayInt *> MEDCouplingUMesh::PartitionBySpreadZone(const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn)
11717 {
11718   if(!arrIn || !arrIndxIn)
11719     throw INTERP_KERNEL::Exception("PartitionBySpreadZone : null input pointers !");
11720   arrIn->checkAllocated(); arrIndxIn->checkAllocated();
11721   int nbOfTuples(arrIndxIn->getNumberOfTuples());
11722   if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1 || nbOfTuples<1)
11723     throw INTERP_KERNEL::Exception("PartitionBySpreadZone : invalid arrays in input !");
11724   int nbOfCellsCur(nbOfTuples-1);
11725   std::vector<DataArrayInt *> ret;
11726   if(nbOfCellsCur<=0)
11727     return ret;
11728   std::vector<bool> fetchedCells(nbOfCellsCur,false);
11729   std::vector< MCAuto<DataArrayInt> > ret2;
11730   int seed=0;
11731   while(seed<nbOfCellsCur)
11732     {
11733       int nbOfPeelPerformed=0;
11734       ret2.push_back(ComputeSpreadZoneGraduallyFromSeedAlg(fetchedCells,&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfPeelPerformed));
11735       seed=(int)std::distance(fetchedCells.begin(),std::find(fetchedCells.begin()+seed,fetchedCells.end(),false));
11736     }
11737   for(std::vector< MCAuto<DataArrayInt> >::iterator it=ret2.begin();it!=ret2.end();it++)
11738     ret.push_back((*it).retn());
11739   return ret;
11740 }
11741
11742 /*!
11743  * This method returns given a distribution of cell type (returned for example by MEDCouplingUMesh::getDistributionOfTypes method and customized after) a
11744  * newly allocated DataArrayInt instance with 2 components ready to be interpreted as input of DataArrayInt::findRangeIdForEachTuple method.
11745  *
11746  * \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.
11747  * \return a newly allocated DataArrayInt to be managed by the caller.
11748  * \throw In case of \a code has not the right format (typically of size 3*n)
11749  */
11750 DataArrayInt *MEDCouplingUMesh::ComputeRangesFromTypeDistribution(const std::vector<int>& code)
11751 {
11752   MCAuto<DataArrayInt> ret=DataArrayInt::New();
11753   std::size_t nb=code.size()/3;
11754   if(code.size()%3!=0)
11755     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeRangesFromTypeDistribution : invalid input code !");
11756   ret->alloc((int)nb,2);
11757   int *retPtr=ret->getPointer();
11758   for(std::size_t i=0;i<nb;i++,retPtr+=2)
11759     {
11760       retPtr[0]=code[3*i+2];
11761       retPtr[1]=code[3*i+2]+code[3*i+1];
11762     }
11763   return ret.retn();
11764 }
11765
11766 /*!
11767  * This method expects that \a this a 3D mesh (spaceDim=3 and meshDim=3) with all coordinates and connectivities set.
11768  * All cells in \a this are expected to be linear 3D cells.
11769  * This method will split **all** 3D cells in \a this into INTERP_KERNEL::NORM_TETRA4 cells and put them in the returned mesh.
11770  * It leads to an increase to number of cells.
11771  * This method contrary to MEDCouplingUMesh::simplexize can append coordinates in \a this to perform its work.
11772  * The \a nbOfAdditionalPoints returned value informs about it. If > 0, the coordinates array in returned mesh will have \a nbOfAdditionalPoints 
11773  * more tuples (nodes) than in \a this. Anyway, all the nodes in \a this (with the same order) will be in the returned mesh.
11774  *
11775  * \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.
11776  *                      For all other cells, the splitting policy will be ignored. See INTERP_KERNEL::SplittingPolicy for the images.
11777  * \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. 
11778  * \param [out] n2oCells - A new instance of DataArrayInt holding, for each new cell,
11779  *          an id of old cell producing it. The caller is to delete this array using
11780  *         decrRef() as it is no more needed.
11781  * \return MEDCoupling1SGTUMesh * - the mesh containing only INTERP_KERNEL::NORM_TETRA4 cells.
11782  *
11783  * \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
11784  * the policy PLANAR_FACE_6 should be used on a mesh sorted with MEDCoupling1SGTUMesh::sortHexa8EachOther.
11785  * 
11786  * \throw If \a this is not a 3D mesh (spaceDim==3 and meshDim==3).
11787  * \throw If \a this is not fully constituted with linear 3D cells.
11788  * \sa MEDCouplingUMesh::simplexize, MEDCoupling1SGTUMesh::sortHexa8EachOther
11789  */
11790 MEDCoupling1SGTUMesh *MEDCouplingUMesh::tetrahedrize(int policy, DataArrayInt *& n2oCells, int& nbOfAdditionalPoints) const
11791 {
11792   INTERP_KERNEL::SplittingPolicy pol((INTERP_KERNEL::SplittingPolicy)policy);
11793   checkConnectivityFullyDefined();
11794   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
11795     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tetrahedrize : only available for mesh with meshdim == 3 and spacedim == 3 !");
11796   int nbOfCells(getNumberOfCells()),nbNodes(getNumberOfNodes());
11797   MCAuto<MEDCoupling1SGTUMesh> ret0(MEDCoupling1SGTUMesh::New(getName(),INTERP_KERNEL::NORM_TETRA4));
11798   MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(nbOfCells,1);
11799   int *retPt(ret->getPointer());
11800   MCAuto<DataArrayInt> newConn(DataArrayInt::New()); newConn->alloc(0,1);
11801   MCAuto<DataArrayDouble> addPts(DataArrayDouble::New()); addPts->alloc(0,1);
11802   const int *oldc(_nodal_connec->begin());
11803   const int *oldci(_nodal_connec_index->begin());
11804   const double *coords(_coords->begin());
11805   for(int i=0;i<nbOfCells;i++,oldci++,retPt++)
11806     {
11807       std::vector<int> a; std::vector<double> b;
11808       INTERP_KERNEL::SplitIntoTetras(pol,(INTERP_KERNEL::NormalizedCellType)oldc[oldci[0]],oldc+oldci[0]+1,oldc+oldci[1],coords,a,b);
11809       std::size_t nbOfTet(a.size()/4); *retPt=(int)nbOfTet;
11810       const int *aa(&a[0]);
11811       if(!b.empty())
11812         {
11813           for(std::vector<int>::iterator it=a.begin();it!=a.end();it++)
11814             if(*it<0)
11815               *it=(-(*(it))-1+nbNodes);
11816           addPts->insertAtTheEnd(b.begin(),b.end());
11817           nbNodes+=(int)b.size()/3;
11818         }
11819       for(std::size_t j=0;j<nbOfTet;j++,aa+=4)
11820         newConn->insertAtTheEnd(aa,aa+4);
11821     }
11822   if(!addPts->empty())
11823     {
11824       addPts->rearrange(3);
11825       nbOfAdditionalPoints=addPts->getNumberOfTuples();
11826       addPts=DataArrayDouble::Aggregate(getCoords(),addPts);
11827       ret0->setCoords(addPts);
11828     }
11829   else
11830     {
11831       nbOfAdditionalPoints=0;
11832       ret0->setCoords(getCoords());
11833     }
11834   ret0->setNodalConnectivity(newConn);
11835   //
11836   ret->computeOffsetsFull();
11837   n2oCells=ret->buildExplicitArrOfSliceOnScaledArr(0,nbOfCells,1);
11838   return ret0.retn();
11839 }
11840
11841 /*!
11842  * 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). 
11843  *
11844  * \sa MEDCouplingUMesh::split2DCells
11845  */
11846 void MEDCouplingUMesh::split2DCellsLinear(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI)
11847 {
11848   checkConnectivityFullyDefined();
11849   int ncells(getNumberOfCells()),lgthToReach(getNodalConnectivityArrayLen()+subNodesInSeg->getNumberOfTuples());
11850   MCAuto<DataArrayInt> c(DataArrayInt::New()); c->alloc((std::size_t)lgthToReach);
11851   const int *subPtr(subNodesInSeg->begin()),*subIPtr(subNodesInSegI->begin()),*descPtr(desc->begin()),*descIPtr(descI->begin()),*oldConn(getNodalConnectivity()->begin());
11852   int *cPtr(c->getPointer()),*ciPtr(getNodalConnectivityIndex()->getPointer());
11853   int prevPosOfCi(ciPtr[0]);
11854   for(int i=0;i<ncells;i++,ciPtr++,descIPtr++)
11855     {
11856       int offset(descIPtr[0]),sz(descIPtr[1]-descIPtr[0]),deltaSz(0);
11857       *cPtr++=(int)INTERP_KERNEL::NORM_POLYGON; *cPtr++=oldConn[prevPosOfCi+1];
11858       for(int j=0;j<sz;j++)
11859         {
11860           int offset2(subIPtr[descPtr[offset+j]]),sz2(subIPtr[descPtr[offset+j]+1]-subIPtr[descPtr[offset+j]]);
11861           for(int k=0;k<sz2;k++)
11862             *cPtr++=subPtr[offset2+k];
11863           if(j!=sz-1)
11864             *cPtr++=oldConn[prevPosOfCi+j+2];
11865           deltaSz+=sz2;
11866         }
11867       prevPosOfCi=ciPtr[1];
11868       ciPtr[1]=ciPtr[0]+1+sz+deltaSz;//sz==old nb of nodes because (nb of subedges=nb of nodes for polygons)
11869     }
11870   if(c->end()!=cPtr)
11871     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCellsLinear : Some of edges to be split are orphan !");
11872   _nodal_connec->decrRef();
11873   _nodal_connec=c.retn(); _types.clear(); _types.insert(INTERP_KERNEL::NORM_POLYGON);
11874 }
11875
11876 int InternalAddPoint(const INTERP_KERNEL::Edge *e, int id, const double *coo, int startId, int endId, DataArrayDouble& addCoo, int& nodesCnter)
11877 {
11878   if(id!=-1)
11879     return id;
11880   else
11881     {
11882       int ret(nodesCnter++);
11883       double newPt[2];
11884       e->getMiddleOfPoints(coo+2*startId,coo+2*endId,newPt);
11885       addCoo.insertAtTheEnd(newPt,newPt+2);
11886       return ret;
11887     }
11888 }
11889
11890 int InternalAddPointOriented(const INTERP_KERNEL::Edge *e, int id, const double *coo, int startId, int endId, DataArrayDouble& addCoo, int& nodesCnter)
11891 {
11892   if(id!=-1)
11893     return id;
11894   else
11895     {
11896       int ret(nodesCnter++);
11897       double newPt[2];
11898       e->getMiddleOfPointsOriented(coo+2*startId,coo+2*endId,newPt);
11899       addCoo.insertAtTheEnd(newPt,newPt+2);
11900       return ret;
11901     }
11902 }
11903
11904
11905 /// @cond INTERNAL
11906
11907 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)
11908 {
11909   int tmp[3];
11910   int trueStart(start>=0?start:nbOfEdges+start);
11911   tmp[0]=linOrArc?(int)INTERP_KERNEL::NORM_QPOLYG:(int)INTERP_KERNEL::NORM_POLYGON; tmp[1]=connBg[trueStart]; tmp[2]=connBg[stp];
11912   newConnOfCell->insertAtTheEnd(tmp,tmp+3);
11913   if(linOrArc)
11914     {
11915       if(stp-start>1)
11916         {
11917           int tmp2(0),tmp3(appendedCoords->getNumberOfTuples()/2);
11918           InternalAddPointOriented(e,-1,coords,tmp[1],tmp[2],*appendedCoords,tmp2);
11919           middles.push_back(tmp3+offset);
11920         }
11921       else
11922         middles.push_back(connBg[trueStart+nbOfEdges]);
11923     }
11924 }
11925
11926 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)
11927 {
11928   int tmpSrt(newConnOfCell->back()),tmpEnd(connBg[stp]);
11929   newConnOfCell->pushBackSilent(tmpEnd);
11930   if(linOrArc)
11931     {
11932       if(stp-start>1)
11933         {
11934           int tmp2(0),tmp3(appendedCoords->getNumberOfTuples()/2);
11935           InternalAddPointOriented(e,-1,coords,tmpSrt,tmpEnd,*appendedCoords,tmp2);
11936           middles.push_back(tmp3+offset);
11937         }
11938       else
11939         middles.push_back(connBg[start+nbOfEdges]);
11940     }
11941 }
11942
11943 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)
11944 {
11945   // only the quadratic point to deal with:
11946   if(linOrArc)
11947     {
11948       if(stp-start>1)
11949         {
11950           int tmpSrt(connBg[start]),tmpEnd(connBg[stp]);
11951           int tmp2(0),tmp3(appendedCoords->getNumberOfTuples()/2);
11952           InternalAddPointOriented(e,-1,coords,tmpSrt,tmpEnd,*appendedCoords,tmp2);
11953           middles.push_back(tmp3+offset);
11954         }
11955       else
11956         middles.push_back(connBg[start+nbOfEdges]);
11957     }
11958 }
11959
11960 /// @endcond
11961
11962 /*!
11963  * 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 ) .
11964  * \a appendedCoords is a DataArrayDouble instance with number of components equal to one (even if the items are pushed by pair).
11965  */
11966 bool MEDCouplingUMesh::Colinearize2DCell(const double *coords, const int *connBg, const int *connEnd, int offset, DataArrayInt *newConnOfCell, DataArrayDouble *appendedCoords)
11967 {
11968   std::size_t sz(std::distance(connBg,connEnd));
11969   if(sz<3)//3 because 2+1(for the cell type) and 2 is the minimal number of edges of 2D cell.
11970     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Colinearize2DCell : the input cell has invalid format !");
11971   sz--;
11972   INTERP_KERNEL::AutoPtr<int> tmpConn(new int[sz]);
11973   const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connBg[0]));
11974   unsigned nbs(cm.getNumberOfSons2(connBg+1,sz));
11975   unsigned nbOfHit(0); // number of fusions operated
11976   int posBaseElt(0),posEndElt(0),nbOfTurn(0);
11977   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
11978   INTERP_KERNEL::NormalizedCellType typeOfSon;
11979   std::vector<int> middles;
11980   bool ret(false);
11981   for(;(nbOfTurn+nbOfHit)<nbs;nbOfTurn++)
11982     {
11983       cm.fillSonCellNodalConnectivity2(posBaseElt,connBg+1,sz,tmpConn,typeOfSon);
11984       std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
11985       INTERP_KERNEL::Edge *e(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpConn,coords,m));
11986       posEndElt = posBaseElt+1;
11987
11988       // Look backward first: are the final edges of the cells colinear with the first ones?
11989       // This initializes posBaseElt.
11990       if(nbOfTurn==0)
11991         {
11992           for(unsigned i=1;i<nbs && nbOfHit<maxNbOfHit;i++) // 2nd condition is to avoid ending with a cell wih one single edge
11993             {
11994               cm.fillSonCellNodalConnectivity2(nbs-i,connBg+1,sz,tmpConn,typeOfSon);
11995               INTERP_KERNEL::Edge *eCand(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpConn,coords,m));
11996               INTERP_KERNEL::EdgeIntersector *eint(INTERP_KERNEL::Edge::BuildIntersectorWith(e,eCand));
11997               bool isColinear=eint->areColinears();
11998               if(isColinear)
11999                 {
12000                   nbOfHit++;
12001                   posBaseElt--;
12002                   ret=true;
12003                 }
12004               delete eint;
12005               eCand->decrRef();
12006               if(!isColinear)
12007                 break;
12008             }
12009         }
12010       // Now move forward:
12011       const unsigned fwdStart = (nbOfTurn == 0 ? 0 : posBaseElt);  // the first element to be inspected going forward
12012       for(unsigned j=fwdStart+1;j<nbs && nbOfHit<maxNbOfHit;j++)  // 2nd condition is to avoid ending with a cell wih one single edge
12013         {
12014           cm.fillSonCellNodalConnectivity2((int)j,connBg+1,sz,tmpConn,typeOfSon); // get edge #j's connectivity
12015           INTERP_KERNEL::Edge *eCand(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpConn,coords,m));
12016           INTERP_KERNEL::EdgeIntersector *eint(INTERP_KERNEL::Edge::BuildIntersectorWith(e,eCand));
12017           bool isColinear(eint->areColinears());
12018           if(isColinear)
12019             {
12020               nbOfHit++;
12021               posEndElt++;
12022               ret=true;
12023             }
12024           delete eint;
12025           eCand->decrRef();
12026           if(!isColinear)
12027               break;
12028         }
12029       //push [posBaseElt,posEndElt) in newConnOfCell using e
12030       // 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!
12031       if(nbOfTurn==0)
12032         // at the begining of the connectivity (insert type)
12033         EnterTheResultOf2DCellFirst(e,posBaseElt,posEndElt,(int)nbs,cm.isQuadratic(),coords,connBg+1,offset,newConnOfCell,appendedCoords,middles);
12034       else if((nbOfHit+nbOfTurn) != (nbs-1))
12035         // in the middle
12036         EnterTheResultOf2DCellMiddle(e,posBaseElt,posEndElt,(int)nbs,cm.isQuadratic(),coords,connBg+1,offset,newConnOfCell,appendedCoords,middles);
12037       if ((nbOfHit+nbOfTurn) == (nbs-1))
12038         // at the end (only quad points to deal with)
12039         EnterTheResultOf2DCellEnd(e,posBaseElt,posEndElt,(int)nbs,cm.isQuadratic(),coords,connBg+1,offset,newConnOfCell,appendedCoords,middles);
12040       posBaseElt=posEndElt;
12041       e->decrRef();
12042     }
12043   if(!middles.empty())
12044     newConnOfCell->insertAtTheEnd(middles.begin(),middles.end());
12045   return ret;
12046 }
12047
12048 /*!
12049  * It is the quadratic part of MEDCouplingUMesh::split2DCells. Here some additionnal nodes can be added at the end of coordinates array object.
12050  *
12051  * \return  int - the number of new nodes created.
12052  * \sa MEDCouplingUMesh::split2DCells
12053  */
12054 int MEDCouplingUMesh::split2DCellsQuadratic(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI, const DataArrayInt *mid, const DataArrayInt *midI)
12055 {
12056   checkConsistencyLight();
12057   int ncells(getNumberOfCells()),lgthToReach(getNodalConnectivityArrayLen()+2*subNodesInSeg->getNumberOfTuples()),nodesCnt(getNumberOfNodes());
12058   MCAuto<DataArrayInt> c(DataArrayInt::New()); c->alloc((std::size_t)lgthToReach);
12059   MCAuto<DataArrayDouble> addCoo(DataArrayDouble::New()); addCoo->alloc(0,1);
12060   const int *subPtr(subNodesInSeg->begin()),*subIPtr(subNodesInSegI->begin()),*descPtr(desc->begin()),*descIPtr(descI->begin()),*oldConn(getNodalConnectivity()->begin());
12061   const int *midPtr(mid->begin()),*midIPtr(midI->begin());
12062   const double *oldCoordsPtr(getCoords()->begin());
12063   int *cPtr(c->getPointer()),*ciPtr(getNodalConnectivityIndex()->getPointer());
12064   int prevPosOfCi(ciPtr[0]);
12065   for(int i=0;i<ncells;i++,ciPtr++,descIPtr++)
12066     {
12067       int offset(descIPtr[0]),sz(descIPtr[1]-descIPtr[0]),deltaSz(sz);
12068       for(int j=0;j<sz;j++)
12069         { int sz2(subIPtr[descPtr[offset+j]+1]-subIPtr[descPtr[offset+j]]); deltaSz+=sz2; }
12070       *cPtr++=(int)INTERP_KERNEL::NORM_QPOLYG; cPtr[0]=oldConn[prevPosOfCi+1];
12071       for(int j=0;j<sz;j++)//loop over subedges of oldConn
12072         {
12073           int offset2(subIPtr[descPtr[offset+j]]),sz2(subIPtr[descPtr[offset+j]+1]-subIPtr[descPtr[offset+j]]),offset3(midIPtr[descPtr[offset+j]]);
12074           if(sz2==0)
12075             {
12076               if(j<sz-1)
12077                 cPtr[1]=oldConn[prevPosOfCi+2+j];
12078               cPtr[deltaSz]=oldConn[prevPosOfCi+1+j+sz]; cPtr++;
12079               continue;
12080             }
12081           std::vector<INTERP_KERNEL::Node *> ns(3);
12082           ns[0]=new INTERP_KERNEL::Node(oldCoordsPtr[2*oldConn[prevPosOfCi+1+j]],oldCoordsPtr[2*oldConn[prevPosOfCi+1+j]+1]);
12083           ns[1]=new INTERP_KERNEL::Node(oldCoordsPtr[2*oldConn[prevPosOfCi+1+(1+j)%sz]],oldCoordsPtr[2*oldConn[prevPosOfCi+1+(1+j)%sz]+1]);
12084           ns[2]=new INTERP_KERNEL::Node(oldCoordsPtr[2*oldConn[prevPosOfCi+1+sz+j]],oldCoordsPtr[2*oldConn[prevPosOfCi+1+sz+j]+1]);
12085           MCAuto<INTERP_KERNEL::Edge> e(INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(ns));
12086           for(int k=0;k<sz2;k++)//loop over subsplit of current subedge
12087             {
12088               cPtr[1]=subPtr[offset2+k];
12089               cPtr[deltaSz]=InternalAddPoint(e,midPtr[offset3+k],oldCoordsPtr,cPtr[0],cPtr[1],*addCoo,nodesCnt); cPtr++;
12090             }
12091           int tmpEnd(oldConn[prevPosOfCi+1+(j+1)%sz]);
12092           if(j!=sz-1)
12093             { cPtr[1]=tmpEnd; }
12094           cPtr[deltaSz]=InternalAddPoint(e,midPtr[offset3+sz2],oldCoordsPtr,cPtr[0],tmpEnd,*addCoo,nodesCnt); cPtr++;
12095         }
12096       prevPosOfCi=ciPtr[1]; cPtr+=deltaSz;
12097       ciPtr[1]=ciPtr[0]+1+2*deltaSz;//sz==old nb of nodes because (nb of subedges=nb of nodes for polygons)
12098     }
12099   if(c->end()!=cPtr)
12100     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCellsQuadratic : Some of edges to be split are orphan !");
12101   _nodal_connec->decrRef();
12102   _nodal_connec=c.retn(); _types.clear(); _types.insert(INTERP_KERNEL::NORM_QPOLYG);
12103   addCoo->rearrange(2);
12104   MCAuto<DataArrayDouble> coo(DataArrayDouble::Aggregate(getCoords(),addCoo));//info are copied from getCoords() by using Aggregate
12105   setCoords(coo);
12106   return addCoo->getNumberOfTuples();
12107 }
12108
12109 void MEDCouplingUMesh::ComputeAllTypesInternal(std::set<INTERP_KERNEL::NormalizedCellType>& types, const DataArrayInt *nodalConnec, const DataArrayInt *nodalConnecIndex)
12110 {
12111   if(nodalConnec && nodalConnecIndex)
12112     {
12113       types.clear();
12114       const int *conn(nodalConnec->begin()),*connIndex(nodalConnecIndex->begin());
12115       int nbOfElem(nodalConnecIndex->getNbOfElems()-1);
12116       if(nbOfElem>0)
12117         for(const int *pt=connIndex;pt!=connIndex+nbOfElem;pt++)
12118           types.insert((INTERP_KERNEL::NormalizedCellType)conn[*pt]);
12119     }
12120 }
12121
12122 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),
12123     _own_cell(true),_cell_id(-1),_nb_cell(0)
12124 {
12125   if(mesh)
12126     {
12127       mesh->incrRef();
12128       _nb_cell=mesh->getNumberOfCells();
12129     }
12130 }
12131
12132 MEDCouplingUMeshCellIterator::~MEDCouplingUMeshCellIterator()
12133 {
12134   if(_mesh)
12135     _mesh->decrRef();
12136   if(_own_cell)
12137     delete _cell;
12138 }
12139
12140 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh, MEDCouplingUMeshCell *itc, int bg, int end):_mesh(mesh),_cell(itc),
12141     _own_cell(false),_cell_id(bg-1),
12142     _nb_cell(end)
12143 {
12144   if(mesh)
12145     mesh->incrRef();
12146 }
12147
12148 MEDCouplingUMeshCell *MEDCouplingUMeshCellIterator::nextt()
12149 {
12150   _cell_id++;
12151   if(_cell_id<_nb_cell)
12152     {
12153       _cell->next();
12154       return _cell;
12155     }
12156   else
12157     return 0;
12158 }
12159
12160 MEDCouplingUMeshCellByTypeEntry::MEDCouplingUMeshCellByTypeEntry(MEDCouplingUMesh *mesh):_mesh(mesh)
12161 {
12162   if(_mesh)
12163     _mesh->incrRef();
12164 }
12165
12166 MEDCouplingUMeshCellByTypeIterator *MEDCouplingUMeshCellByTypeEntry::iterator()
12167 {
12168   return new MEDCouplingUMeshCellByTypeIterator(_mesh);
12169 }
12170
12171 MEDCouplingUMeshCellByTypeEntry::~MEDCouplingUMeshCellByTypeEntry()
12172 {
12173   if(_mesh)
12174     _mesh->decrRef();
12175 }
12176
12177 MEDCouplingUMeshCellEntry::MEDCouplingUMeshCellEntry(MEDCouplingUMesh *mesh,  INTERP_KERNEL::NormalizedCellType type, MEDCouplingUMeshCell *itc, int bg, int end):_mesh(mesh),_type(type),
12178     _itc(itc),
12179     _bg(bg),_end(end)
12180 {
12181   if(_mesh)
12182     _mesh->incrRef();
12183 }
12184
12185 MEDCouplingUMeshCellEntry::~MEDCouplingUMeshCellEntry()
12186 {
12187   if(_mesh)
12188     _mesh->decrRef();
12189 }
12190
12191 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCellEntry::getType() const
12192 {
12193   return _type;
12194 }
12195
12196 int MEDCouplingUMeshCellEntry::getNumberOfElems() const
12197 {
12198   return _end-_bg;
12199 }
12200
12201 MEDCouplingUMeshCellIterator *MEDCouplingUMeshCellEntry::iterator()
12202 {
12203   return new MEDCouplingUMeshCellIterator(_mesh,_itc,_bg,_end);
12204 }
12205
12206 MEDCouplingUMeshCellByTypeIterator::MEDCouplingUMeshCellByTypeIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),_cell_id(0),_nb_cell(0)
12207 {
12208   if(mesh)
12209     {
12210       mesh->incrRef();
12211       _nb_cell=mesh->getNumberOfCells();
12212     }
12213 }
12214
12215 MEDCouplingUMeshCellByTypeIterator::~MEDCouplingUMeshCellByTypeIterator()
12216 {
12217   if(_mesh)
12218     _mesh->decrRef();
12219   delete _cell;
12220 }
12221
12222 MEDCouplingUMeshCellEntry *MEDCouplingUMeshCellByTypeIterator::nextt()
12223 {
12224   const int *c=_mesh->getNodalConnectivity()->begin();
12225   const int *ci=_mesh->getNodalConnectivityIndex()->begin();
12226   if(_cell_id<_nb_cell)
12227     {
12228       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[_cell_id]];
12229       int nbOfElems=(int)std::distance(ci+_cell_id,std::find_if(ci+_cell_id,ci+_nb_cell,MEDCouplingImpl::ConnReader(c,type)));
12230       int startId=_cell_id;
12231       _cell_id+=nbOfElems;
12232       return new MEDCouplingUMeshCellEntry(_mesh,type,_cell,startId,_cell_id);
12233     }
12234   else
12235     return 0;
12236 }
12237
12238 MEDCouplingUMeshCell::MEDCouplingUMeshCell(MEDCouplingUMesh *mesh):_conn(0),_conn_indx(0),_conn_lgth(NOTICABLE_FIRST_VAL)
12239 {
12240   if(mesh)
12241     {
12242       _conn=mesh->getNodalConnectivity()->getPointer();
12243       _conn_indx=mesh->getNodalConnectivityIndex()->getPointer();
12244     }
12245 }
12246
12247 void MEDCouplingUMeshCell::next()
12248 {
12249   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
12250     {
12251       _conn+=_conn_lgth;
12252       _conn_indx++;
12253     }
12254   _conn_lgth=_conn_indx[1]-_conn_indx[0];
12255 }
12256
12257 std::string MEDCouplingUMeshCell::repr() const
12258 {
12259   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
12260     {
12261       std::ostringstream oss; oss << "Cell Type " << INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)_conn[0]).getRepr();
12262       oss << " : ";
12263       std::copy(_conn+1,_conn+_conn_lgth,std::ostream_iterator<int>(oss," "));
12264       return oss.str();
12265     }
12266   else
12267     return std::string("MEDCouplingUMeshCell::repr : Invalid pos");
12268 }
12269
12270 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCell::getType() const
12271 {
12272   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
12273     return (INTERP_KERNEL::NormalizedCellType)_conn[0];
12274   else
12275     return INTERP_KERNEL::NORM_ERROR;
12276 }
12277
12278 const int *MEDCouplingUMeshCell::getAllConn(int& lgth) const
12279 {
12280   lgth=_conn_lgth;
12281   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
12282     return _conn;
12283   else
12284     return 0;
12285 }