Salome HOME
new functionality MEDCouplingUMesh.explodeMeshIntoMicroEdges
[tools/medcoupling.git] / src / MEDCoupling / MEDCouplingUMesh.cxx
1 // Copyright (C) 2007-2016  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19 // Author : Anthony Geay (CEA/DEN)
20
21 #include "MEDCouplingUMesh.hxx"
22 #include "MEDCoupling1GTUMesh.hxx"
23 #include "MEDCouplingMemArray.txx"
24 #include "MEDCouplingFieldDouble.hxx"
25 #include "MEDCouplingSkyLineArray.hxx"
26 #include "CellModel.hxx"
27 #include "VolSurfUser.txx"
28 #include "InterpolationUtils.hxx"
29 #include "PointLocatorAlgos.txx"
30 #include "BBTree.txx"
31 #include "BBTreeDst.txx"
32 #include "SplitterTetra.hxx"
33 #include "DiameterCalculator.hxx"
34 #include "DirectedBoundingBox.hxx"
35 #include "InterpKernelMatrixTools.hxx"
36 #include "InterpKernelMeshQuality.hxx"
37 #include "InterpKernelCellSimplify.hxx"
38 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
39 #include "InterpKernelAutoPtr.hxx"
40 #include "InterpKernelGeo2DNode.hxx"
41 #include "InterpKernelGeo2DEdgeLin.hxx"
42 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
43 #include "InterpKernelGeo2DQuadraticPolygon.hxx"
44
45 #include <sstream>
46 #include <fstream>
47 #include <numeric>
48 #include <cstring>
49 #include <limits>
50 #include <list>
51
52 using namespace MEDCoupling;
53
54 double MEDCouplingUMesh::EPS_FOR_POLYH_ORIENTATION=1.e-14;
55
56 /// @cond INTERNAL
57 const INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::MEDMEM_ORDER[N_MEDMEM_ORDER] = { INTERP_KERNEL::NORM_POINT1, INTERP_KERNEL::NORM_SEG2, INTERP_KERNEL::NORM_SEG3, INTERP_KERNEL::NORM_SEG4, INTERP_KERNEL::NORM_POLYL, INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4, INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_TRI7, INTERP_KERNEL::NORM_QUAD8, INTERP_KERNEL::NORM_QUAD9, INTERP_KERNEL::NORM_POLYGON, INTERP_KERNEL::NORM_QPOLYG, INTERP_KERNEL::NORM_TETRA4, INTERP_KERNEL::NORM_PYRA5, INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXA8, INTERP_KERNEL::NORM_HEXGP12, INTERP_KERNEL::NORM_TETRA10, INTERP_KERNEL::NORM_PYRA13, INTERP_KERNEL::NORM_PENTA15, INTERP_KERNEL::NORM_HEXA20, INTERP_KERNEL::NORM_HEXA27, INTERP_KERNEL::NORM_POLYHED };
58 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().c_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().c_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().c_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().c_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().c_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().c_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().c_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().c_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 /*!
869  * This method is called by MEDCouplingUMesh::computeNeighborsOfCells. This methods performs the algorithm
870  * of MEDCouplingUMesh::computeNeighborsOfCells.
871  * This method is useful for users that want to reduce along a criterion the set of neighbours cell. This is
872  * typically the case to extract a set a neighbours,
873  * excluding a set of meshdim-1 cells in input descending connectivity.
874  * Typically \b desc, \b descIndx, \b revDesc and \b revDescIndx (\ref numbering-indirect) input params are
875  * the result of MEDCouplingUMesh::buildDescendingConnectivity.
876  * This method lists cell by cell in \b this which are its neighbors. To compute the result only connectivities
877  * are considered.
878  * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
879  *
880  * \param [in] desc descending connectivity array.
881  * \param [in] descIndx descending connectivity index array used to walk through \b desc (\ref numbering-indirect).
882  * \param [in] revDesc reverse descending connectivity array.
883  * \param [in] revDescIndx reverse descending connectivity index array used to walk through \b revDesc (\ref numbering-indirect).
884  * \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
885  *                        parameter allows to select the right part in this array. The number of tuples is equal to the last values in \b neighborsIndx.
886  * \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.
887  */
888 void MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(const DataArrayInt *desc, const DataArrayInt *descIndx, const DataArrayInt *revDesc, const DataArrayInt *revDescIndx,
889                                                   DataArrayInt *&neighbors, DataArrayInt *&neighborsIndx)
890 {
891   if(!desc || !descIndx || !revDesc || !revDescIndx)
892     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeNeighborsOfCellsAdv some input array is empty !");
893   const int *descPtr=desc->getConstPointer();
894   const int *descIPtr=descIndx->getConstPointer();
895   const int *revDescPtr=revDesc->getConstPointer();
896   const int *revDescIPtr=revDescIndx->getConstPointer();
897   //
898   int nbCells=descIndx->getNumberOfTuples()-1;
899   MCAuto<DataArrayInt> out0=DataArrayInt::New();
900   MCAuto<DataArrayInt> out1=DataArrayInt::New(); out1->alloc(nbCells+1,1);
901   int *out1Ptr=out1->getPointer();
902   *out1Ptr++=0;
903   out0->reserve(desc->getNumberOfTuples());
904   for(int i=0;i<nbCells;i++,descIPtr++,out1Ptr++)
905     {
906       for(const int *w1=descPtr+descIPtr[0];w1!=descPtr+descIPtr[1];w1++)
907         {
908           std::set<int> s(revDescPtr+revDescIPtr[*w1],revDescPtr+revDescIPtr[(*w1)+1]);
909           s.erase(i);
910           out0->insertAtTheEnd(s.begin(),s.end());
911         }
912       *out1Ptr=out0->getNumberOfTuples();
913     }
914   neighbors=out0.retn();
915   neighborsIndx=out1.retn();
916 }
917
918 /*!
919  * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
920  * For speed reasons no check of this will be done. This method calls
921  * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
922  * This method lists node by node in \b this which are its neighbors. To compute the result
923  * only connectivities are considered.
924  * The neighbor nodes of node having id 'nodeId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
925  *
926  * \param [out] neighbors is an array storing all the neighbors of all nodes in \b this. This array
927  * is newly allocated and should be dealt by the caller. \b neighborsIndx 2nd output
928  * parameter allows to select the right part in this array (\ref numbering-indirect).
929  * The number of tuples is equal to the last values in \b neighborsIndx.
930  * \param [out] neighborsIdx is an array of size this->getNumberOfCells()+1 newly allocated and should
931  * be dealt by the caller. This arrays allow to use the first output parameter \b neighbors.
932  */
933 void MEDCouplingUMesh::computeNeighborsOfNodes(DataArrayInt *&neighbors, DataArrayInt *&neighborsIdx) const
934 {
935   checkFullyDefined();
936   int mdim(getMeshDimension()),nbNodes(getNumberOfNodes());
937   MCAuto<DataArrayInt> desc(DataArrayInt::New()),descIndx(DataArrayInt::New()),revDesc(DataArrayInt::New()),revDescIndx(DataArrayInt::New());
938   MCAuto<MEDCouplingUMesh> mesh1D;
939   switch(mdim)
940   {
941     case 3:
942       {
943         mesh1D=explode3DMeshTo1D(desc,descIndx,revDesc,revDescIndx);
944         break;
945       }
946     case 2:
947       {
948         mesh1D=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
949         break;
950       }
951     case 1:
952       {
953         mesh1D=const_cast<MEDCouplingUMesh *>(this);
954         mesh1D->incrRef();
955         break;
956       }
957     default:
958       {
959         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2,1] !");
960       }
961   }
962   desc=DataArrayInt::New(); descIndx=DataArrayInt::New(); revDesc=0; revDescIndx=0;
963   mesh1D->getReverseNodalConnectivity(desc,descIndx);
964   MCAuto<DataArrayInt> ret0(DataArrayInt::New());
965   ret0->alloc(desc->getNumberOfTuples(),1);
966   int *r0Pt(ret0->getPointer());
967   const int *c1DPtr(mesh1D->getNodalConnectivity()->begin()),*rn(desc->begin()),*rni(descIndx->begin());
968   for(int i=0;i<nbNodes;i++,rni++)
969     {
970       for(const int *oneDCellIt=rn+rni[0];oneDCellIt!=rn+rni[1];oneDCellIt++)
971         *r0Pt++=c1DPtr[3*(*oneDCellIt)+1]==i?c1DPtr[3*(*oneDCellIt)+2]:c1DPtr[3*(*oneDCellIt)+1];
972     }
973   neighbors=ret0.retn();
974   neighborsIdx=descIndx.retn();
975 }
976
977 /// @cond INTERNAL
978
979 /*!
980  * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
981  * For speed reasons no check of this will be done.
982  */
983 template<class SonsGenerator>
984 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivityGen(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx, DimM1DescNbrer nbrer) const
985 {
986   if(!desc || !descIndx || !revDesc || !revDescIndx)
987     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildDescendingConnectivityGen : present of a null pointer in input !");
988   checkConnectivityFullyDefined();
989   int nbOfCells=getNumberOfCells();
990   int nbOfNodes=getNumberOfNodes();
991   MCAuto<DataArrayInt> revNodalIndx=DataArrayInt::New(); revNodalIndx->alloc(nbOfNodes+1,1); revNodalIndx->fillWithZero();
992   int *revNodalIndxPtr=revNodalIndx->getPointer();
993   const int *conn=_nodal_connec->getConstPointer();
994   const int *connIndex=_nodal_connec_index->getConstPointer();
995   std::string name="Mesh constituent of "; name+=getName();
996   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(name,getMeshDimension()-SonsGenerator::DELTA);
997   ret->setCoords(getCoords());
998   ret->allocateCells(2*nbOfCells);
999   descIndx->alloc(nbOfCells+1,1);
1000   MCAuto<DataArrayInt> revDesc2(DataArrayInt::New()); revDesc2->reserve(2*nbOfCells);
1001   int *descIndxPtr=descIndx->getPointer(); *descIndxPtr++=0;
1002   for(int eltId=0;eltId<nbOfCells;eltId++,descIndxPtr++)
1003     {
1004       int pos=connIndex[eltId];
1005       int posP1=connIndex[eltId+1];
1006       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[pos]);
1007       SonsGenerator sg(cm);
1008       unsigned nbOfSons=sg.getNumberOfSons2(conn+pos+1,posP1-pos-1);
1009       INTERP_KERNEL::AutoPtr<int> tmp=new int[posP1-pos];
1010       for(unsigned i=0;i<nbOfSons;i++)
1011         {
1012           INTERP_KERNEL::NormalizedCellType cmsId;
1013           unsigned nbOfNodesSon=sg.fillSonCellNodalConnectivity2(i,conn+pos+1,posP1-pos-1,tmp,cmsId);
1014           for(unsigned k=0;k<nbOfNodesSon;k++)
1015             if(tmp[k]>=0)
1016               revNodalIndxPtr[tmp[k]+1]++;
1017           ret->insertNextCell(cmsId,nbOfNodesSon,tmp);
1018           revDesc2->pushBackSilent(eltId);
1019         }
1020       descIndxPtr[0]=descIndxPtr[-1]+(int)nbOfSons;
1021     }
1022   int nbOfCellsM1=ret->getNumberOfCells();
1023   std::transform(revNodalIndxPtr+1,revNodalIndxPtr+nbOfNodes+1,revNodalIndxPtr,revNodalIndxPtr+1,std::plus<int>());
1024   MCAuto<DataArrayInt> revNodal=DataArrayInt::New(); revNodal->alloc(revNodalIndx->back(),1);
1025   std::fill(revNodal->getPointer(),revNodal->getPointer()+revNodalIndx->back(),-1);
1026   int *revNodalPtr=revNodal->getPointer();
1027   const int *connM1=ret->getNodalConnectivity()->getConstPointer();
1028   const int *connIndexM1=ret->getNodalConnectivityIndex()->getConstPointer();
1029   for(int eltId=0;eltId<nbOfCellsM1;eltId++)
1030     {
1031       const int *strtNdlConnOfCurCell=connM1+connIndexM1[eltId]+1;
1032       const int *endNdlConnOfCurCell=connM1+connIndexM1[eltId+1];
1033       for(const int *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
1034         if(*iter>=0)//for polyhedrons
1035           *std::find_if(revNodalPtr+revNodalIndxPtr[*iter],revNodalPtr+revNodalIndxPtr[*iter+1],std::bind2nd(std::equal_to<int>(),-1))=eltId;
1036     }
1037   //
1038   DataArrayInt *commonCells=0,*commonCellsI=0;
1039   FindCommonCellsAlg(3,0,ret->getNodalConnectivity(),ret->getNodalConnectivityIndex(),revNodal,revNodalIndx,commonCells,commonCellsI);
1040   MCAuto<DataArrayInt> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1041   const int *commonCellsPtr(commonCells->getConstPointer()),*commonCellsIPtr(commonCellsI->getConstPointer());
1042   int newNbOfCellsM1=-1;
1043   MCAuto<DataArrayInt> o2nM1=DataArrayInt::ConvertIndexArrayToO2N(nbOfCellsM1,commonCells->begin(),
1044                                                                                                             commonCellsI->begin(),commonCellsI->end(),newNbOfCellsM1);
1045   std::vector<bool> isImpacted(nbOfCellsM1,false);
1046   for(const int *work=commonCellsI->begin();work!=commonCellsI->end()-1;work++)
1047     for(int work2=work[0];work2!=work[1];work2++)
1048       isImpacted[commonCellsPtr[work2]]=true;
1049   const int *o2nM1Ptr=o2nM1->getConstPointer();
1050   MCAuto<DataArrayInt> n2oM1=o2nM1->invertArrayO2N2N2OBis(newNbOfCellsM1);
1051   const int *n2oM1Ptr=n2oM1->getConstPointer();
1052   MCAuto<MEDCouplingUMesh> ret2=static_cast<MEDCouplingUMesh *>(ret->buildPartOfMySelf(n2oM1->begin(),n2oM1->end(),true));
1053   ret2->copyTinyInfoFrom(this);
1054   desc->alloc(descIndx->back(),1);
1055   int *descPtr=desc->getPointer();
1056   const INTERP_KERNEL::CellModel& cmsDft=INTERP_KERNEL::CellModel::GetCellModel(INTERP_KERNEL::NORM_POINT1);
1057   for(int i=0;i<nbOfCellsM1;i++,descPtr++)
1058     {
1059       if(!isImpacted[i])
1060         *descPtr=nbrer(o2nM1Ptr[i],0,cmsDft,false,0,0);
1061       else
1062         {
1063           if(i!=n2oM1Ptr[o2nM1Ptr[i]])
1064             {
1065               const INTERP_KERNEL::CellModel& cms=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connM1[connIndexM1[i]]);
1066               *descPtr=nbrer(o2nM1Ptr[i],connIndexM1[i+1]-connIndexM1[i]-1,cms,true,connM1+connIndexM1[n2oM1Ptr[o2nM1Ptr[i]]]+1,connM1+connIndexM1[i]+1);
1067             }
1068           else
1069             *descPtr=nbrer(o2nM1Ptr[i],0,cmsDft,false,0,0);
1070         }
1071     }
1072   revDesc->reserve(newNbOfCellsM1);
1073   revDescIndx->alloc(newNbOfCellsM1+1,1);
1074   int *revDescIndxPtr=revDescIndx->getPointer(); *revDescIndxPtr++=0;
1075   const int *revDesc2Ptr=revDesc2->getConstPointer();
1076   for(int i=0;i<newNbOfCellsM1;i++,revDescIndxPtr++)
1077     {
1078       int oldCellIdM1=n2oM1Ptr[i];
1079       if(!isImpacted[oldCellIdM1])
1080         {
1081           revDesc->pushBackSilent(revDesc2Ptr[oldCellIdM1]);
1082           revDescIndxPtr[0]=revDescIndxPtr[-1]+1;
1083         }
1084       else
1085         {
1086           for(int j=commonCellsIPtr[0];j<commonCellsIPtr[1];j++)
1087             revDesc->pushBackSilent(revDesc2Ptr[commonCellsPtr[j]]);
1088           revDescIndxPtr[0]=revDescIndxPtr[-1]+commonCellsIPtr[1]-commonCellsIPtr[0];
1089           commonCellsIPtr++;
1090         }
1091     }
1092   //
1093   return ret2.retn();
1094 }
1095
1096 struct MEDCouplingAccVisit
1097 {
1098   MEDCouplingAccVisit():_new_nb_of_nodes(0) { }
1099   int operator()(int val) { if(val!=-1) return _new_nb_of_nodes++; else return -1; }
1100   int _new_nb_of_nodes;
1101 };
1102
1103 /// @endcond
1104
1105 /*!
1106  * Converts specified cells to either polygons (if \a this is a 2D mesh) or
1107  * polyhedrons (if \a this is a 3D mesh). The cells to convert are specified by an
1108  * array of cell ids. Pay attention that after conversion all algorithms work slower
1109  * with \a this mesh than before conversion. <br> If an exception is thrown during the
1110  * conversion due presence of invalid ids in the array of cells to convert, as a
1111  * result \a this mesh contains some already converted elements. In this case the 2D
1112  * mesh remains valid but 3D mesh becomes \b inconsistent!
1113  *  \warning This method can significantly modify the order of geometric types in \a this,
1114  *          hence, to write this mesh to the MED file, its cells must be sorted using
1115  *          sortCellsInMEDFileFrmt().
1116  *  \param [in] cellIdsToConvertBg - the array holding ids of cells to convert.
1117  *  \param [in] cellIdsToConvertEnd - a pointer to the last-plus-one-th element of \a
1118  *         cellIdsToConvertBg.
1119  *  \throw If the coordinates array is not set.
1120  *  \throw If the nodal connectivity of cells is node defined.
1121  *  \throw If dimension of \a this mesh is not either 2 or 3.
1122  *
1123  *  \if ENABLE_EXAMPLES
1124  *  \ref cpp_mcumesh_convertToPolyTypes "Here is a C++ example".<br>
1125  *  \ref  py_mcumesh_convertToPolyTypes "Here is a Python example".
1126  *  \endif
1127  */
1128 void MEDCouplingUMesh::convertToPolyTypes(const int *cellIdsToConvertBg, const int *cellIdsToConvertEnd)
1129 {
1130   checkFullyDefined();
1131   int dim=getMeshDimension();
1132   if(dim<2 || dim>3)
1133     throw INTERP_KERNEL::Exception("Invalid mesh dimension : must be 2 or 3 !");
1134   int nbOfCells(getNumberOfCells());
1135   if(dim==2)
1136     {
1137       const int *connIndex=_nodal_connec_index->getConstPointer();
1138       int *conn=_nodal_connec->getPointer();
1139       for(const int *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1140         {
1141           if(*iter>=0 && *iter<nbOfCells)
1142             {
1143               const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*iter]]);
1144               if(!cm.isQuadratic())
1145                 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_POLYGON;
1146               else
1147                 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_QPOLYG;
1148             }
1149           else
1150             {
1151               std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1152               oss << " in range [0," << nbOfCells << ") !";
1153               throw INTERP_KERNEL::Exception(oss.str().c_str());
1154             }
1155         }
1156     }
1157   else
1158     {
1159       int *connIndex(_nodal_connec_index->getPointer());
1160       const int *connOld(_nodal_connec->getConstPointer());
1161       MCAuto<DataArrayInt> connNew(DataArrayInt::New()),connNewI(DataArrayInt::New()); connNew->alloc(0,1); connNewI->alloc(1,1); connNewI->setIJ(0,0,0);
1162       std::vector<bool> toBeDone(nbOfCells,false);
1163       for(const int *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1164         {
1165           if(*iter>=0 && *iter<nbOfCells)
1166             toBeDone[*iter]=true;
1167           else
1168             {
1169               std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1170               oss << " in range [0," << nbOfCells << ") !";
1171               throw INTERP_KERNEL::Exception(oss.str().c_str());
1172             }
1173         }
1174       for(int cellId=0;cellId<nbOfCells;cellId++)
1175         {
1176           int pos(connIndex[cellId]),posP1(connIndex[cellId+1]);
1177           int lgthOld(posP1-pos-1);
1178           if(toBeDone[cellId])
1179             {
1180               const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connOld[pos]);
1181               unsigned nbOfFaces(cm.getNumberOfSons2(connOld+pos+1,lgthOld));
1182               int *tmp(new int[nbOfFaces*lgthOld+1]);
1183               int *work=tmp; *work++=INTERP_KERNEL::NORM_POLYHED;
1184               for(unsigned j=0;j<nbOfFaces;j++)
1185                 {
1186                   INTERP_KERNEL::NormalizedCellType type;
1187                   unsigned offset=cm.fillSonCellNodalConnectivity2(j,connOld+pos+1,lgthOld,work,type);
1188                   work+=offset;
1189                   *work++=-1;
1190                 }
1191               std::size_t newLgth(std::distance(tmp,work)-1);//-1 for last -1
1192               connNew->pushBackValsSilent(tmp,tmp+newLgth);
1193               connNewI->pushBackSilent(connNewI->back()+(int)newLgth);
1194               delete [] tmp;
1195             }
1196           else
1197             {
1198               connNew->pushBackValsSilent(connOld+pos,connOld+posP1);
1199               connNewI->pushBackSilent(connNewI->back()+posP1-pos);
1200             }
1201         }
1202       setConnectivity(connNew,connNewI,false);//false because computeTypes called just behind.
1203     }
1204   computeTypes();
1205 }
1206
1207 /*!
1208  * Converts all cells to either polygons (if \a this is a 2D mesh) or
1209  * polyhedrons (if \a this is a 3D mesh).
1210  *  \warning As this method is purely for user-friendliness and no optimization is
1211  *          done to avoid construction of a useless vector, this method can be costly
1212  *          in memory.
1213  *  \throw If the coordinates array is not set.
1214  *  \throw If the nodal connectivity of cells is node defined.
1215  *  \throw If dimension of \a this mesh is not either 2 or 3.
1216  */
1217 void MEDCouplingUMesh::convertAllToPoly()
1218 {
1219   int nbOfCells=getNumberOfCells();
1220   std::vector<int> cellIds(nbOfCells);
1221   for(int i=0;i<nbOfCells;i++)
1222     cellIds[i]=i;
1223   convertToPolyTypes(&cellIds[0],&cellIds[0]+cellIds.size());
1224 }
1225
1226 /*!
1227  * Fixes nodal connectivity of invalid cells of type NORM_POLYHED. This method
1228  * expects that all NORM_POLYHED cells have connectivity similar to that of prismatic
1229  * volumes like NORM_HEXA8, NORM_PENTA6 etc., i.e. the first half of nodes describes a
1230  * base facet of the volume and the second half of nodes describes an opposite facet
1231  * having the same number of nodes as the base one. This method converts such
1232  * connectivity to a valid polyhedral format where connectivity of each facet is
1233  * explicitly described and connectivity of facets are separated by -1. If \a this mesh
1234  * contains a NORM_POLYHED cell with a valid connectivity, or an invalid connectivity is
1235  * not as expected, an exception is thrown and the mesh remains unchanged. Care of
1236  * a correct orientation of the first facet of a polyhedron, else orientation of a
1237  * corrected cell is reverse.<br>
1238  * This method is useful to build an extruded unstructured mesh with polyhedrons as
1239  * it releases the user from boring description of polyhedra connectivity in the valid
1240  * format.
1241  *  \throw If \a this->getMeshDimension() != 3.
1242  *  \throw If \a this->getSpaceDimension() != 3.
1243  *  \throw If the nodal connectivity of cells is not defined.
1244  *  \throw If the coordinates array is not set.
1245  *  \throw If \a this mesh contains polyhedrons with the valid connectivity.
1246  *  \throw If \a this mesh contains polyhedrons with odd number of nodes.
1247  *
1248  *  \if ENABLE_EXAMPLES
1249  *  \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
1250  *  \ref  py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
1251  *  \endif
1252  */
1253 void MEDCouplingUMesh::convertExtrudedPolyhedra()
1254 {
1255   checkFullyDefined();
1256   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1257     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertExtrudedPolyhedra works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
1258   int nbOfCells=getNumberOfCells();
1259   MCAuto<DataArrayInt> newCi=DataArrayInt::New();
1260   newCi->alloc(nbOfCells+1,1);
1261   int *newci=newCi->getPointer();
1262   const int *ci=_nodal_connec_index->getConstPointer();
1263   const int *c=_nodal_connec->getConstPointer();
1264   newci[0]=0;
1265   for(int i=0;i<nbOfCells;i++)
1266     {
1267       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1268       if(type==INTERP_KERNEL::NORM_POLYHED)
1269         {
1270           if(std::count(c+ci[i]+1,c+ci[i+1],-1)!=0)
1271             {
1272               std::ostringstream oss; oss << "MEDCouplingUMesh::convertExtrudedPolyhedra : cell # " << i << " is a polhedron BUT it has NOT exactly 1 face !";
1273               throw INTERP_KERNEL::Exception(oss.str().c_str());
1274             }
1275           std::size_t n2=std::distance(c+ci[i]+1,c+ci[i+1]);
1276           if(n2%2!=0)
1277             {
1278               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 !";
1279               throw INTERP_KERNEL::Exception(oss.str().c_str());
1280             }
1281           int n1=(int)(n2/2);
1282           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)
1283         }
1284       else
1285         newci[i+1]=(ci[i+1]-ci[i])+newci[i];
1286     }
1287   MCAuto<DataArrayInt> newC=DataArrayInt::New();
1288   newC->alloc(newci[nbOfCells],1);
1289   int *newc=newC->getPointer();
1290   for(int i=0;i<nbOfCells;i++)
1291     {
1292       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1293       if(type==INTERP_KERNEL::NORM_POLYHED)
1294         {
1295           std::size_t n1=std::distance(c+ci[i]+1,c+ci[i+1])/2;
1296           newc=std::copy(c+ci[i],c+ci[i]+n1+1,newc);
1297           *newc++=-1;
1298           for(std::size_t j=0;j<n1;j++)
1299             {
1300               newc[j]=c[ci[i]+1+n1+(n1-j)%n1];
1301               newc[n1+5*j]=-1;
1302               newc[n1+5*j+1]=c[ci[i]+1+j];
1303               newc[n1+5*j+2]=c[ci[i]+1+j+n1];
1304               newc[n1+5*j+3]=c[ci[i]+1+(j+1)%n1+n1];
1305               newc[n1+5*j+4]=c[ci[i]+1+(j+1)%n1];
1306             }
1307           newc+=n1*6;
1308         }
1309       else
1310         newc=std::copy(c+ci[i],c+ci[i+1],newc);
1311     }
1312   _nodal_connec_index->decrRef(); _nodal_connec_index=newCi.retn();
1313   _nodal_connec->decrRef(); _nodal_connec=newC.retn();
1314 }
1315
1316
1317 /*!
1318  * Converts all polygons (if \a this is a 2D mesh) or polyhedrons (if \a this is a 3D
1319  * mesh) to cells of classical types. This method is opposite to convertToPolyTypes().
1320  * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
1321  *          to write this mesh to the MED file, its cells must be sorted using
1322  *          sortCellsInMEDFileFrmt().
1323  * \warning Cells (and most notably polyhedrons) must be correctly oriented for this to work
1324  *          properly. See orientCorrectlyPolyhedrons() and arePolyhedronsNotCorrectlyOriented().
1325  * \return \c true if at least one cell has been converted, \c false else. In the
1326  *         last case the nodal connectivity remains unchanged.
1327  * \throw If the coordinates array is not set.
1328  * \throw If the nodal connectivity of cells is not defined.
1329  * \throw If \a this->getMeshDimension() < 0.
1330  */
1331 bool MEDCouplingUMesh::unPolyze()
1332 {
1333   checkFullyDefined();
1334   int mdim=getMeshDimension();
1335   if(mdim<0)
1336     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::unPolyze works on umeshes with meshdim equals to 0, 1 2 or 3 !");
1337   if(mdim<=1)
1338     return false;
1339   int nbOfCells=getNumberOfCells();
1340   if(nbOfCells<1)
1341     return false;
1342   int initMeshLgth=getNodalConnectivityArrayLen();
1343   int *conn=_nodal_connec->getPointer();
1344   int *index=_nodal_connec_index->getPointer();
1345   int posOfCurCell=0;
1346   int newPos=0;
1347   int lgthOfCurCell;
1348   bool ret=false;
1349   for(int i=0;i<nbOfCells;i++)
1350     {
1351       lgthOfCurCell=index[i+1]-posOfCurCell;
1352       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
1353       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
1354       INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::NORM_ERROR;
1355       int newLgth;
1356       if(cm.isDynamic())
1357         {
1358           switch(cm.getDimension())
1359           {
1360             case 2:
1361               {
1362                 INTERP_KERNEL::AutoPtr<int> tmp=new int[lgthOfCurCell-1];
1363                 std::copy(conn+posOfCurCell+1,conn+posOfCurCell+lgthOfCurCell,(int *)tmp);
1364                 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly2D(cm.isQuadratic(),tmp,lgthOfCurCell-1,conn+newPos+1,newLgth);
1365                 break;
1366               }
1367             case 3:
1368               {
1369                 int nbOfFaces,lgthOfPolyhConn;
1370                 INTERP_KERNEL::AutoPtr<int> zipFullReprOfPolyh=INTERP_KERNEL::CellSimplify::getFullPolyh3DCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,nbOfFaces,lgthOfPolyhConn);
1371                 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly3D(zipFullReprOfPolyh,nbOfFaces,lgthOfPolyhConn,conn+newPos+1,newLgth);
1372                 break;
1373               }
1374             case 1:
1375               {
1376                 newType=(lgthOfCurCell==3)?INTERP_KERNEL::NORM_SEG2:INTERP_KERNEL::NORM_POLYL;
1377                 break;
1378               }
1379           }
1380           ret=ret || (newType!=type);
1381           conn[newPos]=newType;
1382           newPos+=newLgth+1;
1383           posOfCurCell=index[i+1];
1384           index[i+1]=newPos;
1385         }
1386       else
1387         {
1388           std::copy(conn+posOfCurCell,conn+posOfCurCell+lgthOfCurCell,conn+newPos);
1389           newPos+=lgthOfCurCell;
1390           posOfCurCell+=lgthOfCurCell;
1391           index[i+1]=newPos;
1392         }
1393     }
1394   if(newPos!=initMeshLgth)
1395     _nodal_connec->reAlloc(newPos);
1396   if(ret)
1397     computeTypes();
1398   return ret;
1399 }
1400
1401 /*!
1402  * This method expects that spaceDimension is equal to 3 and meshDimension equal to 3.
1403  * This method performs operation only on polyhedrons in \b this. If no polyhedrons exists in \b this, \b this remains unchanged.
1404  * This method allows to merge if any coplanar 3DSurf cells that may appear in some polyhedrons cells. 
1405  *
1406  * \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 
1407  *             precision.
1408  */
1409 void MEDCouplingUMesh::simplifyPolyhedra(double eps)
1410 {
1411   checkFullyDefined();
1412   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1413     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplifyPolyhedra : works on meshdimension 3 and spaceDimension 3 !");
1414   MCAuto<DataArrayDouble> coords=getCoords()->deepCopy();
1415   coords->recenterForMaxPrecision(eps);
1416   //
1417   int nbOfCells=getNumberOfCells();
1418   const int *conn=_nodal_connec->getConstPointer();
1419   const int *index=_nodal_connec_index->getConstPointer();
1420   MCAuto<DataArrayInt> connINew=DataArrayInt::New();
1421   connINew->alloc(nbOfCells+1,1);
1422   int *connINewPtr=connINew->getPointer(); *connINewPtr++=0;
1423   MCAuto<DataArrayInt> connNew=DataArrayInt::New(); connNew->alloc(0,1);
1424   bool changed=false;
1425   for(int i=0;i<nbOfCells;i++,connINewPtr++)
1426     {
1427       if(conn[index[i]]==(int)INTERP_KERNEL::NORM_POLYHED)
1428         {
1429           SimplifyPolyhedronCell(eps,coords,conn+index[i],conn+index[i+1],connNew);
1430           changed=true;
1431         }
1432       else
1433         connNew->insertAtTheEnd(conn+index[i],conn+index[i+1]);
1434       *connINewPtr=connNew->getNumberOfTuples();
1435     }
1436   if(changed)
1437     setConnectivity(connNew,connINew,false);
1438 }
1439
1440 /*!
1441  * This method returns all node ids used in the connectivity of \b this. The data array returned has to be dealt by the caller.
1442  * The returned node ids are sorted ascendingly. This method is close to MEDCouplingUMesh::getNodeIdsInUse except
1443  * the format of the returned DataArrayInt instance.
1444  * 
1445  * \return a newly allocated DataArrayInt sorted ascendingly of fetched node ids.
1446  * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1447  */
1448 DataArrayInt *MEDCouplingUMesh::computeFetchedNodeIds() const
1449 {
1450   checkConnectivityFullyDefined();
1451   int nbOfCells=getNumberOfCells();
1452   const int *connIndex=_nodal_connec_index->getConstPointer();
1453   const int *conn=_nodal_connec->getConstPointer();
1454   const int *maxEltPt=std::max_element(_nodal_connec->begin(),_nodal_connec->end());
1455   int maxElt=maxEltPt==_nodal_connec->end()?0:std::abs(*maxEltPt)+1;
1456   std::vector<bool> retS(maxElt,false);
1457   for(int i=0;i<nbOfCells;i++)
1458     for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1459       if(conn[j]>=0)
1460         retS[conn[j]]=true;
1461   int sz=0;
1462   for(int i=0;i<maxElt;i++)
1463     if(retS[i])
1464       sz++;
1465   DataArrayInt *ret=DataArrayInt::New();
1466   ret->alloc(sz,1);
1467   int *retPtr=ret->getPointer();
1468   for(int i=0;i<maxElt;i++)
1469     if(retS[i])
1470       *retPtr++=i;
1471   return ret;
1472 }
1473
1474 /*!
1475  * \param [in,out] nodeIdsInUse an array of size typically equal to nbOfNodes.
1476  * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1477  */
1478 void MEDCouplingUMesh::computeNodeIdsAlg(std::vector<bool>& nodeIdsInUse) const
1479 {
1480   int nbOfNodes((int)nodeIdsInUse.size()),nbOfCells(getNumberOfCells());
1481   const int *connIndex(_nodal_connec_index->getConstPointer()),*conn(_nodal_connec->getConstPointer());
1482   for(int i=0;i<nbOfCells;i++)
1483     for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1484       if(conn[j]>=0)
1485         {
1486           if(conn[j]<nbOfNodes)
1487             nodeIdsInUse[conn[j]]=true;
1488           else
1489             {
1490               std::ostringstream oss; oss << "MEDCouplingUMesh::computeNodeIdsAlg : In cell #" << i  << " presence of node id " <<  conn[j] << " not in [0," << nbOfNodes << ") !";
1491               throw INTERP_KERNEL::Exception(oss.str().c_str());
1492             }
1493         }
1494 }
1495
1496 /*!
1497  * Finds nodes not used in any cell and returns an array giving a new id to every node
1498  * by excluding the unused nodes, for which the array holds -1. The result array is
1499  * a mapping in "Old to New" mode. 
1500  *  \param [out] nbrOfNodesInUse - number of node ids present in the nodal connectivity.
1501  *  \return DataArrayInt * - a new instance of DataArrayInt. Its length is \a
1502  *          this->getNumberOfNodes(). It holds for each node of \a this mesh either -1
1503  *          if the node is unused or a new id else. The caller is to delete this
1504  *          array using decrRef() as it is no more needed.  
1505  *  \throw If the coordinates array is not set.
1506  *  \throw If the nodal connectivity of cells is not defined.
1507  *  \throw If the nodal connectivity includes an invalid id.
1508  *
1509  *  \if ENABLE_EXAMPLES
1510  *  \ref cpp_mcumesh_getNodeIdsInUse "Here is a C++ example".<br>
1511  *  \ref  py_mcumesh_getNodeIdsInUse "Here is a Python example".
1512  *  \endif
1513  * \sa computeFetchedNodeIds, computeNodeIdsAlg()
1514  */
1515 DataArrayInt *MEDCouplingUMesh::getNodeIdsInUse(int& nbrOfNodesInUse) const
1516 {
1517   nbrOfNodesInUse=-1;
1518   int nbOfNodes(getNumberOfNodes());
1519   MCAuto<DataArrayInt> ret=DataArrayInt::New();
1520   ret->alloc(nbOfNodes,1);
1521   int *traducer=ret->getPointer();
1522   std::fill(traducer,traducer+nbOfNodes,-1);
1523   int nbOfCells=getNumberOfCells();
1524   const int *connIndex=_nodal_connec_index->getConstPointer();
1525   const int *conn=_nodal_connec->getConstPointer();
1526   for(int i=0;i<nbOfCells;i++)
1527     for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1528       if(conn[j]>=0)
1529         {
1530           if(conn[j]<nbOfNodes)
1531             traducer[conn[j]]=1;
1532           else
1533             {
1534               std::ostringstream oss; oss << "MEDCouplingUMesh::getNodeIdsInUse : In cell #" << i  << " presence of node id " <<  conn[j] << " not in [0," << nbOfNodes << ") !";
1535               throw INTERP_KERNEL::Exception(oss.str().c_str());
1536             }
1537         }
1538   nbrOfNodesInUse=(int)std::count(traducer,traducer+nbOfNodes,1);
1539   std::transform(traducer,traducer+nbOfNodes,traducer,MEDCouplingAccVisit());
1540   return ret.retn();
1541 }
1542
1543 /*!
1544  * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1545  * For each cell in \b this the number of nodes constituting cell is computed.
1546  * For each polyhedron cell, the sum of the number of nodes of each face constituting polyhedron cell is returned.
1547  * So for pohyhedrons some nodes can be counted several times in the returned result.
1548  * 
1549  * \return a newly allocated array
1550  * \sa MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell
1551  */
1552 DataArrayInt *MEDCouplingUMesh::computeNbOfNodesPerCell() const
1553 {
1554   checkConnectivityFullyDefined();
1555   int nbOfCells=getNumberOfCells();
1556   MCAuto<DataArrayInt> ret=DataArrayInt::New();
1557   ret->alloc(nbOfCells,1);
1558   int *retPtr=ret->getPointer();
1559   const int *conn=getNodalConnectivity()->getConstPointer();
1560   const int *connI=getNodalConnectivityIndex()->getConstPointer();
1561   for(int i=0;i<nbOfCells;i++,retPtr++)
1562     {
1563       if(conn[connI[i]]!=(int)INTERP_KERNEL::NORM_POLYHED)
1564         *retPtr=connI[i+1]-connI[i]-1;
1565       else
1566         *retPtr=connI[i+1]-connI[i]-1-std::count(conn+connI[i]+1,conn+connI[i+1],-1);
1567     }
1568   return ret.retn();
1569 }
1570
1571 /*!
1572  * This method computes effective number of nodes per cell. That is to say nodes appearing several times in nodal connectivity of a cell,
1573  * will be counted only once here whereas it will be counted several times in MEDCouplingUMesh::computeNbOfNodesPerCell method.
1574  *
1575  * \return DataArrayInt * - new object to be deallocated by the caller.
1576  * \sa MEDCouplingUMesh::computeNbOfNodesPerCell
1577  */
1578 DataArrayInt *MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell() const
1579 {
1580   checkConnectivityFullyDefined();
1581   int nbOfCells=getNumberOfCells();
1582   MCAuto<DataArrayInt> ret=DataArrayInt::New();
1583   ret->alloc(nbOfCells,1);
1584   int *retPtr=ret->getPointer();
1585   const int *conn=getNodalConnectivity()->getConstPointer();
1586   const int *connI=getNodalConnectivityIndex()->getConstPointer();
1587   for(int i=0;i<nbOfCells;i++,retPtr++)
1588     {
1589       std::set<int> s(conn+connI[i]+1,conn+connI[i+1]);
1590       if(conn[connI[i]]!=(int)INTERP_KERNEL::NORM_POLYHED)
1591         *retPtr=(int)s.size();
1592       else
1593         {
1594           s.erase(-1);
1595           *retPtr=(int)s.size();
1596         }
1597     }
1598   return ret.retn();
1599 }
1600
1601 /*!
1602  * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1603  * For each cell in \b this the number of faces constituting (entity of dimension this->getMeshDimension()-1) cell is computed.
1604  * 
1605  * \return a newly allocated array
1606  */
1607 DataArrayInt *MEDCouplingUMesh::computeNbOfFacesPerCell() const
1608 {
1609   checkConnectivityFullyDefined();
1610   int nbOfCells=getNumberOfCells();
1611   MCAuto<DataArrayInt> ret=DataArrayInt::New();
1612   ret->alloc(nbOfCells,1);
1613   int *retPtr=ret->getPointer();
1614   const int *conn=getNodalConnectivity()->getConstPointer();
1615   const int *connI=getNodalConnectivityIndex()->getConstPointer();
1616   for(int i=0;i<nbOfCells;i++,retPtr++,connI++)
1617     {
1618       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]);
1619       *retPtr=cm.getNumberOfSons2(conn+connI[0]+1,connI[1]-connI[0]-1);
1620     }
1621   return ret.retn();
1622 }
1623
1624 /*!
1625  * Removes unused nodes (the node coordinates array is shorten) and returns an array
1626  * mapping between new and old node ids in "Old to New" mode. -1 values in the returned
1627  * array mean that the corresponding old node is no more used. 
1628  *  \return DataArrayInt * - a new instance of DataArrayInt of length \a
1629  *           this->getNumberOfNodes() before call of this method. The caller is to
1630  *           delete this array using decrRef() as it is no more needed. 
1631  *  \throw If the coordinates array is not set.
1632  *  \throw If the nodal connectivity of cells is not defined.
1633  *  \throw If the nodal connectivity includes an invalid id.
1634  *  \sa areAllNodesFetched
1635  *
1636  *  \if ENABLE_EXAMPLES
1637  *  \ref cpp_mcumesh_zipCoordsTraducer "Here is a C++ example".<br>
1638  *  \ref  py_mcumesh_zipCoordsTraducer "Here is a Python example".
1639  *  \endif
1640  */
1641 DataArrayInt *MEDCouplingUMesh::zipCoordsTraducer()
1642 {
1643   return MEDCouplingPointSet::zipCoordsTraducer();
1644 }
1645
1646 /*!
1647  * This method stands if 'cell1' and 'cell2' are equals regarding 'compType' policy.
1648  * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1649  */
1650 int MEDCouplingUMesh::AreCellsEqual(const int *conn, const int *connI, int cell1, int cell2, int compType)
1651 {
1652   switch(compType)
1653   {
1654     case 0:
1655       return AreCellsEqualPolicy0(conn,connI,cell1,cell2);
1656     case 1:
1657       return AreCellsEqualPolicy1(conn,connI,cell1,cell2);
1658     case 2:
1659       return AreCellsEqualPolicy2(conn,connI,cell1,cell2);
1660     case 3:
1661       return AreCellsEqualPolicy2NoType(conn,connI,cell1,cell2);
1662     case 7:
1663       return AreCellsEqualPolicy7(conn,connI,cell1,cell2);
1664   }
1665   throw INTERP_KERNEL::Exception("Unknown comparison asked ! Must be in 0,1,2,3 or 7.");
1666 }
1667
1668 /*!
1669  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 0.
1670  */
1671 int MEDCouplingUMesh::AreCellsEqualPolicy0(const int *conn, const int *connI, int cell1, int cell2)
1672 {
1673   if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1674     return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;
1675   return 0;
1676 }
1677
1678 /*!
1679  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 1.
1680  */
1681 int MEDCouplingUMesh::AreCellsEqualPolicy1(const int *conn, const int *connI, int cell1, int cell2)
1682 {
1683   int sz=connI[cell1+1]-connI[cell1];
1684   if(sz==connI[cell2+1]-connI[cell2])
1685     {
1686       if(conn[connI[cell1]]==conn[connI[cell2]])
1687         {
1688           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1689           unsigned dim=cm.getDimension();
1690           if(dim!=3)
1691             {
1692               if(dim!=1)
1693                 {
1694                   int sz1=2*(sz-1);
1695                   INTERP_KERNEL::AutoPtr<int> tmp=new int[sz1];
1696                   int *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(int *)tmp);
1697                   std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1698                   work=std::search((int *)tmp,(int *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1699                   return work!=tmp+sz1?1:0;
1700                 }
1701               else
1702                 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;//case of SEG2 and SEG3
1703             }
1704           else
1705             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy1 : not implemented yet for meshdim == 3 !");
1706         }
1707     }
1708   return 0;
1709 }
1710
1711 /*!
1712  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 2.
1713  */
1714 int MEDCouplingUMesh::AreCellsEqualPolicy2(const int *conn, const int *connI, int cell1, int cell2)
1715 {
1716   if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1717     {
1718       if(conn[connI[cell1]]==conn[connI[cell2]])
1719         {
1720           std::set<int> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1721           std::set<int> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1722           return s1==s2?1:0;
1723         }
1724     }
1725   return 0;
1726 }
1727
1728 /*!
1729  * This method is less restrictive than AreCellsEqualPolicy2. Here the geometric type is absolutely not taken into account !
1730  */
1731 int MEDCouplingUMesh::AreCellsEqualPolicy2NoType(const int *conn, const int *connI, int cell1, int cell2)
1732 {
1733   if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1734     {
1735       std::set<int> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1736       std::set<int> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1737       return s1==s2?1:0;
1738     }
1739   return 0;
1740 }
1741
1742 /*!
1743  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 7.
1744  */
1745 int MEDCouplingUMesh::AreCellsEqualPolicy7(const int *conn, const int *connI, int cell1, int cell2)
1746 {
1747   int sz=connI[cell1+1]-connI[cell1];
1748   if(sz==connI[cell2+1]-connI[cell2])
1749     {
1750       if(conn[connI[cell1]]==conn[connI[cell2]])
1751         {
1752           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1753           unsigned dim=cm.getDimension();
1754           if(dim!=3)
1755             {
1756               if(dim!=1)
1757                 {
1758                   int sz1=2*(sz-1);
1759                   INTERP_KERNEL::AutoPtr<int> tmp=new int[sz1];
1760                   int *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(int *)tmp);
1761                   std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1762                   work=std::search((int *)tmp,(int *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1763                   if(work!=tmp+sz1)
1764                     return 1;
1765                   else
1766                     {
1767                       std::reverse_iterator<int *> it1((int *)tmp+sz1);
1768                       std::reverse_iterator<int *> it2((int *)tmp);
1769                       if(std::search(it1,it2,conn+connI[cell2]+1,conn+connI[cell2+1])!=it2)
1770                         return 2;
1771                       else
1772                         return 0;
1773                     }
1774
1775                   return work!=tmp+sz1?1:0;
1776                 }
1777               else
1778                 {//case of SEG2 and SEG3
1779                   if(std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1))
1780                     return 1;
1781                   if(!cm.isQuadratic())
1782                     {
1783                       std::reverse_iterator<const int *> it1(conn+connI[cell1+1]);
1784                       std::reverse_iterator<const int *> it2(conn+connI[cell1]+1);
1785                       if(std::equal(it1,it2,conn+connI[cell2]+1))
1786                         return 2;
1787                       return 0;
1788                     }
1789                   else
1790                     {
1791                       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])
1792                         return 2;
1793                       return 0;
1794                     }
1795                 }
1796             }
1797           else
1798             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy7 : not implemented yet for meshdim == 3 !");
1799         }
1800     }
1801   return 0;
1802 }
1803
1804 /*!
1805  * This method find in candidate pool defined by 'candidates' the cells equal following the polycy 'compType'.
1806  * If any true is returned and the results will be put at the end of 'result' output parameter. If not false is returned
1807  * and result remains unchanged.
1808  * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1809  * If in 'candidates' pool -1 value is considered as an empty value.
1810  * WARNING this method returns only ONE set of result !
1811  */
1812 bool MEDCouplingUMesh::AreCellsEqualInPool(const std::vector<int>& candidates, int compType, const int *conn, const int *connI, DataArrayInt *result)
1813 {
1814   if(candidates.size()<1)
1815     return false;
1816   bool ret=false;
1817   std::vector<int>::const_iterator iter=candidates.begin();
1818   int start=(*iter++);
1819   for(;iter!=candidates.end();iter++)
1820     {
1821       int status=AreCellsEqual(conn,connI,start,*iter,compType);
1822       if(status!=0)
1823         {
1824           if(!ret)
1825             {
1826               result->pushBackSilent(start);
1827               ret=true;
1828             }
1829           if(status==1)
1830             result->pushBackSilent(*iter);
1831           else
1832             result->pushBackSilent(status==2?(*iter+1):-(*iter+1));
1833         }
1834     }
1835   return ret;
1836 }
1837
1838 /*!
1839  * This method find cells that are equal (regarding \a compType) in \a this. The comparison is specified
1840  * by \a compType.
1841  * This method keeps the coordiantes of \a this. This method is time consuming.
1842  *
1843  * \param [in] compType input specifying the technique used to compare cells each other.
1844  *   - 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.
1845  *   - 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)
1846  * and their type equal. For 1D mesh the policy 1 is equivalent to 0.
1847  *   - 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
1848  * can be used for users not sensitive to orientation of cell
1849  * \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.
1850  * \param [out] commonCellsArr common cells ids (\ref numbering-indirect)
1851  * \param [out] commonCellsIArr common cells ids (\ref numbering-indirect)
1852  * \return the correspondance array old to new in a newly allocated array.
1853  * 
1854  */
1855 void MEDCouplingUMesh::findCommonCells(int compType, int startCellId, DataArrayInt *& commonCellsArr, DataArrayInt *& commonCellsIArr) const
1856 {
1857   MCAuto<DataArrayInt> revNodal=DataArrayInt::New(),revNodalI=DataArrayInt::New();
1858   getReverseNodalConnectivity(revNodal,revNodalI);
1859   FindCommonCellsAlg(compType,startCellId,_nodal_connec,_nodal_connec_index,revNodal,revNodalI,commonCellsArr,commonCellsIArr);
1860 }
1861
1862 void MEDCouplingUMesh::FindCommonCellsAlg(int compType, int startCellId, const DataArrayInt *nodal, const DataArrayInt *nodalI, const DataArrayInt *revNodal, const DataArrayInt *revNodalI,
1863                                           DataArrayInt *& commonCellsArr, DataArrayInt *& commonCellsIArr)
1864 {
1865   MCAuto<DataArrayInt> commonCells=DataArrayInt::New(),commonCellsI=DataArrayInt::New(); commonCells->alloc(0,1);
1866   int nbOfCells=nodalI->getNumberOfTuples()-1;
1867   commonCellsI->reserve(1); commonCellsI->pushBackSilent(0);
1868   const int *revNodalPtr=revNodal->getConstPointer(),*revNodalIPtr=revNodalI->getConstPointer();
1869   const int *connPtr=nodal->getConstPointer(),*connIPtr=nodalI->getConstPointer();
1870   std::vector<bool> isFetched(nbOfCells,false);
1871   if(startCellId==0)
1872     {
1873       for(int i=0;i<nbOfCells;i++)
1874         {
1875           if(!isFetched[i])
1876             {
1877               const int *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind2nd(std::not_equal_to<int>(),-1));
1878               std::vector<int> v,v2;
1879               if(connOfNode!=connPtr+connIPtr[i+1])
1880                 {
1881                   const int *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1882                   v2.insert(v2.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1]);
1883                   connOfNode++;
1884                 }
1885               for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1886                 if(*connOfNode>=0)
1887                   {
1888                     v=v2;
1889                     const int *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1890                     std::vector<int>::iterator it=std::set_intersection(v.begin(),v.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1891                     v2.resize(std::distance(v2.begin(),it));
1892                   }
1893               if(v2.size()>1)
1894                 {
1895                   if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1896                     {
1897                       int pos=commonCellsI->back();
1898                       commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1899                       for(const int *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1900                         isFetched[*it]=true;
1901                     }
1902                 }
1903             }
1904         }
1905     }
1906   else
1907     {
1908       for(int i=startCellId;i<nbOfCells;i++)
1909         {
1910           if(!isFetched[i])
1911             {
1912               const int *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind2nd(std::not_equal_to<int>(),-1));
1913               std::vector<int> v,v2;
1914               if(connOfNode!=connPtr+connIPtr[i+1])
1915                 {
1916                   v2.insert(v2.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1]);
1917                   connOfNode++;
1918                 }
1919               for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1920                 if(*connOfNode>=0)
1921                   {
1922                     v=v2;
1923                     std::vector<int>::iterator it=std::set_intersection(v.begin(),v.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1924                     v2.resize(std::distance(v2.begin(),it));
1925                   }
1926               if(v2.size()>1)
1927                 {
1928                   if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1929                     {
1930                       int pos=commonCellsI->back();
1931                       commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1932                       for(const int *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1933                         isFetched[*it]=true;
1934                     }
1935                 }
1936             }
1937         }
1938     }
1939   commonCellsArr=commonCells.retn();
1940   commonCellsIArr=commonCellsI.retn();
1941 }
1942
1943 /*!
1944  * Checks if \a this mesh includes all cells of an \a other mesh, and returns an array
1945  * giving for each cell of the \a other an id of a cell in \a this mesh. A value larger
1946  * than \a this->getNumberOfCells() in the returned array means that there is no
1947  * corresponding cell in \a this mesh.
1948  * It is expected that \a this and \a other meshes share the same node coordinates
1949  * array, if it is not so an exception is thrown. 
1950  *  \param [in] other - the mesh to compare with.
1951  *  \param [in] compType - specifies a cell comparison technique. For meaning of its
1952  *         valid values [0,1,2], see zipConnectivityTraducer().
1953  *  \param [out] arr - a new instance of DataArrayInt returning correspondence
1954  *         between cells of the two meshes. It contains \a other->getNumberOfCells()
1955  *         values. The caller is to delete this array using
1956  *         decrRef() as it is no more needed.
1957  *  \return bool - \c true if all cells of \a other mesh are present in the \a this
1958  *         mesh.
1959  *
1960  *  \if ENABLE_EXAMPLES
1961  *  \ref cpp_mcumesh_areCellsIncludedIn "Here is a C++ example".<br>
1962  *  \ref  py_mcumesh_areCellsIncludedIn "Here is a Python example".
1963  *  \endif
1964  *  \sa checkDeepEquivalOnSameNodesWith()
1965  *  \sa checkGeoEquivalWith()
1966  */
1967 bool MEDCouplingUMesh::areCellsIncludedIn(const MEDCouplingUMesh *other, int compType, DataArrayInt *& arr) const
1968 {
1969   MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1970   int nbOfCells=getNumberOfCells();
1971   static const int possibleCompType[]={0,1,2};
1972   if(std::find(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),compType)==possibleCompType+sizeof(possibleCompType)/sizeof(int))
1973     {
1974       std::ostringstream oss; oss << "MEDCouplingUMesh::areCellsIncludedIn : only following policies are possible : ";
1975       std::copy(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),std::ostream_iterator<int>(oss," "));
1976       oss << " !";
1977       throw INTERP_KERNEL::Exception(oss.str().c_str());
1978     }
1979   MCAuto<DataArrayInt> o2n=mesh->zipConnectivityTraducer(compType,nbOfCells);
1980   arr=o2n->subArray(nbOfCells);
1981   arr->setName(other->getName());
1982   int tmp;
1983   if(other->getNumberOfCells()==0)
1984     return true;
1985   return arr->getMaxValue(tmp)<nbOfCells;
1986 }
1987
1988 /*!
1989  * This method makes the assumption that \a this and \a other share the same coords. If not an exception will be thrown !
1990  * This method tries to determine if \b other is fully included in \b this.
1991  * The main difference is that this method is not expected to throw exception.
1992  * This method has two outputs :
1993  *
1994  * \param other other mesh
1995  * \param arr is an output parameter that returns a \b newly created instance. This array is of size 'other->getNumberOfCells()'.
1996  * \return If \a other is fully included in 'this 'true is returned. If not false is returned.
1997  */
1998 bool MEDCouplingUMesh::areCellsIncludedInPolicy7(const MEDCouplingUMesh *other, DataArrayInt *& arr) const
1999 {
2000   MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
2001   DataArrayInt *commonCells=0,*commonCellsI=0;
2002   int thisNbCells=getNumberOfCells();
2003   mesh->findCommonCells(7,thisNbCells,commonCells,commonCellsI);
2004   MCAuto<DataArrayInt> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
2005   const int *commonCellsPtr=commonCells->getConstPointer(),*commonCellsIPtr=commonCellsI->getConstPointer();
2006   int otherNbCells=other->getNumberOfCells();
2007   MCAuto<DataArrayInt> arr2=DataArrayInt::New();
2008   arr2->alloc(otherNbCells,1);
2009   arr2->fillWithZero();
2010   int *arr2Ptr=arr2->getPointer();
2011   int nbOfCommon=commonCellsI->getNumberOfTuples()-1;
2012   for(int i=0;i<nbOfCommon;i++)
2013     {
2014       int start=commonCellsPtr[commonCellsIPtr[i]];
2015       if(start<thisNbCells)
2016         {
2017           for(int j=commonCellsIPtr[i]+1;j!=commonCellsIPtr[i+1];j++)
2018             {
2019               int sig=commonCellsPtr[j]>0?1:-1;
2020               int val=std::abs(commonCellsPtr[j])-1;
2021               if(val>=thisNbCells)
2022                 arr2Ptr[val-thisNbCells]=sig*(start+1);
2023             }
2024         }
2025     }
2026   arr2->setName(other->getName());
2027   if(arr2->presenceOfValue(0))
2028     return false;
2029   arr=arr2.retn();
2030   return true;
2031 }
2032
2033 MEDCouplingUMesh *MEDCouplingUMesh::mergeMyselfWithOnSameCoords(const MEDCouplingPointSet *other) const
2034 {
2035   if(!other)
2036     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : input other is null !");
2037   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
2038   if(!otherC)
2039     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : the input other mesh is not of type unstructured !");
2040   std::vector<const MEDCouplingUMesh *> ms(2);
2041   ms[0]=this;
2042   ms[1]=otherC;
2043   return MergeUMeshesOnSameCoords(ms);
2044 }
2045
2046 /*!
2047  * Build a sub part of \b this lying or not on the same coordinates than \b this (regarding value of \b keepCoords).
2048  * By default coordinates are kept. This method is close to MEDCouplingUMesh::buildPartOfMySelf except that here input
2049  * cellIds is not given explicitely but by a range python like.
2050  * 
2051  * \param start
2052  * \param end
2053  * \param step
2054  * \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.
2055  * \return a newly allocated
2056  * 
2057  * \warning This method modifies can generate an unstructured mesh whose cells are not sorted by geometric type order.
2058  * In view of the MED file writing, a renumbering of cells of returned unstructured mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
2059  */
2060 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfSlice(int start, int end, int step, bool keepCoords) const
2061 {
2062   if(getMeshDimension()!=-1)
2063     return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelfSlice(start,end,step,keepCoords));
2064   else
2065     {
2066       int newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfSlice for -1 dimension mesh ");
2067       if(newNbOfCells!=1)
2068         throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
2069       if(start!=0)
2070         throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
2071       incrRef();
2072       return const_cast<MEDCouplingUMesh *>(this);
2073     }
2074 }
2075
2076 /*!
2077  * Creates a new MEDCouplingUMesh containing specified cells of \a this mesh.
2078  * The result mesh shares or not the node coordinates array with \a this mesh depending
2079  * on \a keepCoords parameter.
2080  *  \warning Cells of the result mesh can be \b not sorted by geometric type, hence,
2081  *           to write this mesh to the MED file, its cells must be sorted using
2082  *           sortCellsInMEDFileFrmt().
2083  *  \param [in] begin - an array of cell ids to include to the new mesh.
2084  *  \param [in] end - a pointer to last-plus-one-th element of \a begin.
2085  *  \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2086  *         array of \a this mesh, else "free" nodes are removed from the result mesh
2087  *         by calling zipCoords().
2088  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2089  *         to delete this mesh using decrRef() as it is no more needed. 
2090  *  \throw If the coordinates array is not set.
2091  *  \throw If the nodal connectivity of cells is not defined.
2092  *  \throw If any cell id in the array \a begin is not valid.
2093  *
2094  *  \if ENABLE_EXAMPLES
2095  *  \ref cpp_mcumesh_buildPartOfMySelf "Here is a C++ example".<br>
2096  *  \ref  py_mcumesh_buildPartOfMySelf "Here is a Python example".
2097  *  \endif
2098  */
2099 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelf(const int *begin, const int *end, bool keepCoords) const
2100 {
2101   if(getMeshDimension()!=-1)
2102     return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelf(begin,end,keepCoords));
2103   else
2104     {
2105       if(end-begin!=1)
2106         throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
2107       if(begin[0]!=0)
2108         throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
2109       incrRef();
2110       return const_cast<MEDCouplingUMesh *>(this);
2111     }
2112 }
2113
2114 /*!
2115  * This method operates only on nodal connectivity on \b this. Coordinates of \b this is completely ignored here.
2116  *
2117  * 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.
2118  * Size of [ \b cellIdsBg, \b cellIdsEnd ) ) must be equal to the number of cells of otherOnSameCoordsThanThis.
2119  * The number of cells of \b this will remain the same with this method.
2120  *
2121  * \param [in] cellIdsBg begin of cell ids (included) of cells in this to assign
2122  * \param [in] cellIdsEnd end of cell ids (excluded) of cells in this to assign
2123  * \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 ).
2124  *             Coordinate pointer of \b this and those of \b otherOnSameCoordsThanThis must be the same
2125  */
2126 void MEDCouplingUMesh::setPartOfMySelf(const int *cellIdsBg, const int *cellIdsEnd, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2127 {
2128   checkConnectivityFullyDefined();
2129   otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2130   if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2131     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelf : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2132   if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2133     {
2134       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2135       oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2136       throw INTERP_KERNEL::Exception(oss.str().c_str());
2137     }
2138   int nbOfCellsToModify=(int)std::distance(cellIdsBg,cellIdsEnd);
2139   if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2140     {
2141       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : cells ids length (" <<  nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2142       throw INTERP_KERNEL::Exception(oss.str().c_str());
2143     }
2144   int nbOfCells=getNumberOfCells();
2145   bool easyAssign=true;
2146   const int *connI=_nodal_connec_index->getConstPointer();
2147   const int *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2148   for(const int *it=cellIdsBg;it!=cellIdsEnd && easyAssign;it++,connIOther++)
2149     {
2150       if(*it>=0 && *it<nbOfCells)
2151         {
2152           easyAssign=(connIOther[1]-connIOther[0])==(connI[*it+1]-connI[*it]);
2153         }
2154       else
2155         {
2156           std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : On pos #" << std::distance(cellIdsBg,it) << " id is equal to " << *it << " which is not in [0," << nbOfCells << ") !";
2157           throw INTERP_KERNEL::Exception(oss.str().c_str());
2158         }
2159     }
2160   if(easyAssign)
2161     {
2162       MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2163       computeTypes();
2164     }
2165   else
2166     {
2167       DataArrayInt *arrOut=0,*arrIOut=0;
2168       MEDCouplingUMesh::SetPartOfIndexedArrays(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2169                                                arrOut,arrIOut);
2170       MCAuto<DataArrayInt> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2171       setConnectivity(arrOut,arrIOut,true);
2172     }
2173 }
2174
2175 void MEDCouplingUMesh::setPartOfMySelfSlice(int start, int end, int step, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2176 {
2177   checkConnectivityFullyDefined();
2178   otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2179   if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2180     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelfSlice : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2181   if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2182     {
2183       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2184       oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2185       throw INTERP_KERNEL::Exception(oss.str().c_str());
2186     }
2187   int nbOfCellsToModify=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::setPartOfMySelfSlice : ");
2188   if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2189     {
2190       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : cells ids length (" <<  nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2191       throw INTERP_KERNEL::Exception(oss.str().c_str());
2192     }
2193   int nbOfCells=getNumberOfCells();
2194   bool easyAssign=true;
2195   const int *connI=_nodal_connec_index->getConstPointer();
2196   const int *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2197   int it=start;
2198   for(int i=0;i<nbOfCellsToModify && easyAssign;i++,it+=step,connIOther++)
2199     {
2200       if(it>=0 && it<nbOfCells)
2201         {
2202           easyAssign=(connIOther[1]-connIOther[0])==(connI[it+1]-connI[it]);
2203         }
2204       else
2205         {
2206           std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : On pos #" << i << " id is equal to " << it << " which is not in [0," << nbOfCells << ") !";
2207           throw INTERP_KERNEL::Exception(oss.str().c_str());
2208         }
2209     }
2210   if(easyAssign)
2211     {
2212       MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2213       computeTypes();
2214     }
2215   else
2216     {
2217       DataArrayInt *arrOut=0,*arrIOut=0;
2218       MEDCouplingUMesh::SetPartOfIndexedArraysSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2219                                                 arrOut,arrIOut);
2220       MCAuto<DataArrayInt> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2221       setConnectivity(arrOut,arrIOut,true);
2222     }
2223 }                      
2224
2225 /*!
2226  * Keeps from \a this only cells which constituing point id are in the ids specified by [ \a begin,\a end ).
2227  * The resulting cell ids are stored at the end of the 'cellIdsKept' parameter.
2228  * Parameter \a fullyIn specifies if a cell that has part of its nodes in ids array is kept or not.
2229  * If \a fullyIn is true only cells whose ids are \b fully contained in [ \a begin,\a end ) tab will be kept.
2230  *
2231  * \param [in] begin input start of array of node ids.
2232  * \param [in] end input end of array of node ids.
2233  * \param [in] fullyIn input that specifies if all node ids must be in [ \a begin,\a end ) array to consider cell to be in.
2234  * \param [in,out] cellIdsKeptArr array where all candidate cell ids are put at the end.
2235  */
2236 void MEDCouplingUMesh::fillCellIdsToKeepFromNodeIds(const int *begin, const int *end, bool fullyIn, DataArrayInt *&cellIdsKeptArr) const
2237 {
2238   MCAuto<DataArrayInt> cellIdsKept=DataArrayInt::New(); cellIdsKept->alloc(0,1);
2239   checkConnectivityFullyDefined();
2240   int tmp=-1;
2241   int sz=getNodalConnectivity()->getMaxValue(tmp); sz=std::max(sz,0)+1;
2242   std::vector<bool> fastFinder(sz,false);
2243   for(const int *work=begin;work!=end;work++)
2244     if(*work>=0 && *work<sz)
2245       fastFinder[*work]=true;
2246   int nbOfCells=getNumberOfCells();
2247   const int *conn=getNodalConnectivity()->getConstPointer();
2248   const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2249   for(int i=0;i<nbOfCells;i++)
2250     {
2251       int ref=0,nbOfHit=0;
2252       for(const int *work2=conn+connIndex[i]+1;work2!=conn+connIndex[i+1];work2++)
2253         if(*work2>=0)
2254           {
2255             ref++;
2256             if(fastFinder[*work2])
2257               nbOfHit++;
2258           }
2259       if((ref==nbOfHit && fullyIn) || (nbOfHit!=0 && !fullyIn))
2260         cellIdsKept->pushBackSilent(i);
2261     }
2262   cellIdsKeptArr=cellIdsKept.retn();
2263 }
2264
2265 /*!
2266  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2267  * this->getMeshDimension(), that bound some cells of \a this mesh.
2268  * The cells of lower dimension to include to the result mesh are selected basing on
2269  * specified node ids and the value of \a fullyIn parameter. If \a fullyIn ==\c true, a
2270  * cell is copied if its all nodes are in the array \a begin of node ids. If \a fullyIn
2271  * ==\c false, a cell is copied if any its node is in the array of node ids. The
2272  * created mesh shares the node coordinates array with \a this mesh. 
2273  *  \param [in] begin - the array of node ids.
2274  *  \param [in] end - a pointer to the (last+1)-th element of \a begin.
2275  *  \param [in] fullyIn - if \c true, then cells whose all nodes are in the
2276  *         array \a begin are added, else cells whose any node is in the
2277  *         array \a begin are added.
2278  *  \return MEDCouplingUMesh * - new instance of MEDCouplingUMesh. The caller is
2279  *         to delete this mesh using decrRef() as it is no more needed. 
2280  *  \throw If the coordinates array is not set.
2281  *  \throw If the nodal connectivity of cells is not defined.
2282  *  \throw If any node id in \a begin is not valid.
2283  *
2284  *  \if ENABLE_EXAMPLES
2285  *  \ref cpp_mcumesh_buildFacePartOfMySelfNode "Here is a C++ example".<br>
2286  *  \ref  py_mcumesh_buildFacePartOfMySelfNode "Here is a Python example".
2287  *  \endif
2288  */
2289 MEDCouplingUMesh *MEDCouplingUMesh::buildFacePartOfMySelfNode(const int *begin, const int *end, bool fullyIn) const
2290 {
2291   MCAuto<DataArrayInt> desc,descIndx,revDesc,revDescIndx;
2292   desc=DataArrayInt::New(); descIndx=DataArrayInt::New(); revDesc=DataArrayInt::New(); revDescIndx=DataArrayInt::New();
2293   MCAuto<MEDCouplingUMesh> subMesh=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2294   desc=0; descIndx=0; revDesc=0; revDescIndx=0;
2295   return static_cast<MEDCouplingUMesh*>(subMesh->buildPartOfMySelfNode(begin,end,fullyIn));
2296 }
2297
2298 /*!
2299  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2300  * this->getMeshDimension(), which bound only one cell of \a this mesh.
2301  *  \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2302  *         array of \a this mesh, else "free" nodes are removed from the result mesh
2303  *         by calling zipCoords().
2304  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2305  *         to delete this mesh using decrRef() as it is no more needed. 
2306  *  \throw If the coordinates array is not set.
2307  *  \throw If the nodal connectivity of cells is not defined.
2308  *
2309  *  \if ENABLE_EXAMPLES
2310  *  \ref cpp_mcumesh_buildBoundaryMesh "Here is a C++ example".<br>
2311  *  \ref  py_mcumesh_buildBoundaryMesh "Here is a Python example".
2312  *  \endif
2313  */
2314 MEDCouplingUMesh *MEDCouplingUMesh::buildBoundaryMesh(bool keepCoords) const
2315 {
2316   DataArrayInt *desc=DataArrayInt::New();
2317   DataArrayInt *descIndx=DataArrayInt::New();
2318   DataArrayInt *revDesc=DataArrayInt::New();
2319   DataArrayInt *revDescIndx=DataArrayInt::New();
2320   //
2321   MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2322   revDesc->decrRef();
2323   desc->decrRef();
2324   descIndx->decrRef();
2325   int nbOfCells=meshDM1->getNumberOfCells();
2326   const int *revDescIndxC=revDescIndx->getConstPointer();
2327   std::vector<int> boundaryCells;
2328   for(int i=0;i<nbOfCells;i++)
2329     if(revDescIndxC[i+1]-revDescIndxC[i]==1)
2330       boundaryCells.push_back(i);
2331   revDescIndx->decrRef();
2332   MEDCouplingUMesh *ret=meshDM1->buildPartOfMySelf(&boundaryCells[0],&boundaryCells[0]+boundaryCells.size(),keepCoords);
2333   return ret;
2334 }
2335
2336 /*!
2337  * This method returns a newly created DataArrayInt instance containing ids of cells located in boundary.
2338  * A cell is detected to be on boundary if it contains one or more than one face having only one father.
2339  * This method makes the assumption that \a this is fully defined (coords,connectivity). If not an exception will be thrown. 
2340  */
2341 DataArrayInt *MEDCouplingUMesh::findCellIdsOnBoundary() const
2342 {
2343   checkFullyDefined();
2344   MCAuto<DataArrayInt> desc=DataArrayInt::New();
2345   MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
2346   MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
2347   MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
2348   //
2349   buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx)->decrRef();
2350   desc=(DataArrayInt*)0; descIndx=(DataArrayInt*)0;
2351   //
2352   MCAuto<DataArrayInt> tmp=revDescIndx->deltaShiftIndex();
2353   MCAuto<DataArrayInt> faceIds=tmp->findIdsEqual(1); tmp=(DataArrayInt*)0;
2354   const int *revDescPtr=revDesc->getConstPointer();
2355   const int *revDescIndxPtr=revDescIndx->getConstPointer();
2356   int nbOfCells=getNumberOfCells();
2357   std::vector<bool> ret1(nbOfCells,false);
2358   int sz=0;
2359   for(const int *pt=faceIds->begin();pt!=faceIds->end();pt++)
2360     if(!ret1[revDescPtr[revDescIndxPtr[*pt]]])
2361       { ret1[revDescPtr[revDescIndxPtr[*pt]]]=true; sz++; }
2362   //
2363   DataArrayInt *ret2=DataArrayInt::New();
2364   ret2->alloc(sz,1);
2365   int *ret2Ptr=ret2->getPointer();
2366   sz=0;
2367   for(std::vector<bool>::const_iterator it=ret1.begin();it!=ret1.end();it++,sz++)
2368     if(*it)
2369       *ret2Ptr++=sz;
2370   ret2->setName("BoundaryCells");
2371   return ret2;
2372 }
2373
2374 /*!
2375  * This method finds in \b this the cell ids that lie on mesh \b otherDimM1OnSameCoords.
2376  * \b this and \b otherDimM1OnSameCoords have to lie on the same coordinate array pointer. The coherency of that coords array with connectivity
2377  * of \b this and \b otherDimM1OnSameCoords is not important here because this method works only on connectivity.
2378  * this->getMeshDimension() - 1 must be equal to otherDimM1OnSameCoords.getMeshDimension()
2379  *
2380  * s0 is the cell ids set in \b this lying on at least one node in the fetched nodes in \b otherDimM1OnSameCoords.
2381  * 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
2382  * equals a cell in \b otherDimM1OnSameCoords.
2383  *
2384  * \throw if \b otherDimM1OnSameCoords is not part of constituent of \b this, or if coordinate pointer of \b this and \b otherDimM1OnSameCoords
2385  *        are not same, or if this->getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension()
2386  *
2387  * \param [in] otherDimM1OnSameCoords
2388  * \param [out] cellIdsRk0 a newly allocated array containing the cell ids of s0 (which are cell ids of \b this) in the above algorithm.
2389  * \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
2390  *              cellIdsRk1->transformWithIndArr(cellIdsRk0->begin(),cellIdsRk0->end());
2391  */
2392 void MEDCouplingUMesh::findCellIdsLyingOn(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayInt *&cellIdsRk0, DataArrayInt *&cellIdsRk1) const
2393 {
2394   if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2395     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : coordinates pointer are not the same ! Use tryToShareSameCoords method !");
2396   checkConnectivityFullyDefined();
2397   otherDimM1OnSameCoords.checkConnectivityFullyDefined();
2398   if(getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension())
2399     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : invalid mesh dimension of input mesh regarding meshdimesion of this !");
2400   MCAuto<DataArrayInt> fetchedNodeIds1=otherDimM1OnSameCoords.computeFetchedNodeIds();
2401   MCAuto<DataArrayInt> s0arr=getCellIdsLyingOnNodes(fetchedNodeIds1->begin(),fetchedNodeIds1->end(),false);
2402   MCAuto<MEDCouplingUMesh> thisPart=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(s0arr->begin(),s0arr->end(),true));
2403   MCAuto<DataArrayInt> descThisPart=DataArrayInt::New(),descIThisPart=DataArrayInt::New(),revDescThisPart=DataArrayInt::New(),revDescIThisPart=DataArrayInt::New();
2404   MCAuto<MEDCouplingUMesh> thisPartConsti=thisPart->buildDescendingConnectivity(descThisPart,descIThisPart,revDescThisPart,revDescIThisPart);
2405   const int *revDescThisPartPtr=revDescThisPart->getConstPointer(),*revDescIThisPartPtr=revDescIThisPart->getConstPointer();
2406   DataArrayInt *idsOtherInConsti=0;
2407   bool b=thisPartConsti->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsOtherInConsti);
2408   MCAuto<DataArrayInt> idsOtherInConstiAuto(idsOtherInConsti);
2409   if(!b)
2410     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : the given mdim-1 mesh in other is not a constituent of this !");
2411   std::set<int> s1;
2412   for(const int *idOther=idsOtherInConsti->begin();idOther!=idsOtherInConsti->end();idOther++)
2413     s1.insert(revDescThisPartPtr+revDescIThisPartPtr[*idOther],revDescThisPartPtr+revDescIThisPartPtr[*idOther+1]);
2414   MCAuto<DataArrayInt> s1arr_renum1=DataArrayInt::New(); s1arr_renum1->alloc((int)s1.size(),1); std::copy(s1.begin(),s1.end(),s1arr_renum1->getPointer());
2415   s1arr_renum1->sort();
2416   cellIdsRk0=s0arr.retn();
2417   //cellIdsRk1=s_renum1.retn();
2418   cellIdsRk1=s1arr_renum1.retn();
2419 }
2420
2421 /*!
2422  * 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
2423  * returned. This subpart of meshdim-1 mesh is built using meshdim-1 cells in it shared only one cell in \b this.
2424  * 
2425  * \return a newly allocated mesh lying on the same coordinates than \b this. The caller has to deal with returned mesh.
2426  */
2427 MEDCouplingUMesh *MEDCouplingUMesh::computeSkin() const
2428 {
2429   MCAuto<DataArrayInt> desc=DataArrayInt::New();
2430   MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
2431   MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
2432   MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
2433   //
2434   MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2435   revDesc=0; desc=0; descIndx=0;
2436   MCAuto<DataArrayInt> revDescIndx2=revDescIndx->deltaShiftIndex();
2437   MCAuto<DataArrayInt> part=revDescIndx2->findIdsEqual(1);
2438   return static_cast<MEDCouplingUMesh *>(meshDM1->buildPartOfMySelf(part->begin(),part->end(),true));
2439 }
2440
2441 /*!
2442  * Finds nodes lying on the boundary of \a this mesh.
2443  *  \return DataArrayInt * - a new instance of DataArrayInt holding ids of found
2444  *          nodes. The caller is to delete this array using decrRef() as it is no
2445  *          more needed.
2446  *  \throw If the coordinates array is not set.
2447  *  \throw If the nodal connectivity of cells is node defined.
2448  *
2449  *  \if ENABLE_EXAMPLES
2450  *  \ref cpp_mcumesh_findBoundaryNodes "Here is a C++ example".<br>
2451  *  \ref  py_mcumesh_findBoundaryNodes "Here is a Python example".
2452  *  \endif
2453  */
2454 DataArrayInt *MEDCouplingUMesh::findBoundaryNodes() const
2455 {
2456   MCAuto<MEDCouplingUMesh> skin=computeSkin();
2457   return skin->computeFetchedNodeIds();
2458 }
2459
2460 MEDCouplingUMesh *MEDCouplingUMesh::buildUnstructured() const
2461 {
2462   incrRef();
2463   return const_cast<MEDCouplingUMesh *>(this);
2464 }
2465
2466 /*!
2467  * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2468  * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2469  * 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.
2470  * 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.
2471  * 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.
2472  *
2473  * \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
2474  *             parameter is altered during the call.
2475  * \param [out] nodeIdsToDuplicate node ids needed to be duplicated following the algorithm explain above.
2476  * \param [out] cellIdsNeededToBeRenum cell ids in \b this in which the renumber of nodes should be performed.
2477  * \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.
2478  *
2479  * \warning This method modifies param \b otherDimM1OnSameCoords (for speed reasons).
2480  */
2481 void MEDCouplingUMesh::findNodesToDuplicate(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayInt *& nodeIdsToDuplicate,
2482                                             DataArrayInt *& cellIdsNeededToBeRenum, DataArrayInt *& cellIdsNotModified) const
2483 {
2484   typedef MCAuto<DataArrayInt> DAInt;
2485   typedef MCAuto<MEDCouplingUMesh> MCUMesh;
2486
2487   checkFullyDefined();
2488   otherDimM1OnSameCoords.checkFullyDefined();
2489   if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2490     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : meshes do not share the same coords array !");
2491   if(otherDimM1OnSameCoords.getMeshDimension()!=getMeshDimension()-1)
2492     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the mesh given in other parameter must have this->getMeshDimension()-1 !");
2493
2494   // Checking star-shaped M1 group:
2495   DAInt dt0=DataArrayInt::New(),dit0=DataArrayInt::New(),rdt0=DataArrayInt::New(),rdit0=DataArrayInt::New();
2496   MCUMesh meshM2 = otherDimM1OnSameCoords.buildDescendingConnectivity(dt0, dit0, rdt0, rdit0);
2497   DAInt dsi = rdit0->deltaShiftIndex();
2498   DAInt idsTmp0 = dsi->findIdsNotInRange(-1, 3);
2499   if(idsTmp0->getNumberOfTuples())
2500     throw INTERP_KERNEL::Exception("MEDFileUMesh::buildInnerBoundaryAlongM1Group: group is too complex: some points (or edges) have more than two connected segments (or faces)!");
2501   dt0=0; dit0=0; rdt0=0; rdit0=0; idsTmp0=0;
2502
2503   // Get extreme nodes from the group (they won't be duplicated), ie nodes belonging to boundary cells of M1
2504   DAInt xtremIdsM2 = dsi->findIdsEqual(1); dsi = 0;
2505   MCUMesh meshM2Part = static_cast<MEDCouplingUMesh *>(meshM2->buildPartOfMySelf(xtremIdsM2->begin(), xtremIdsM2->end(),true));
2506   DAInt xtrem = meshM2Part->computeFetchedNodeIds();
2507   // Remove from the list points on the boundary of the M0 mesh (those need duplication!)
2508   dt0=DataArrayInt::New(),dit0=DataArrayInt::New(),rdt0=DataArrayInt::New(),rdit0=DataArrayInt::New();
2509   MCUMesh m0desc = buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); dt0=0; dit0=0; rdt0=0;
2510   dsi = rdit0->deltaShiftIndex();
2511   DAInt boundSegs = dsi->findIdsEqual(1);   // boundary segs/faces of the M0 mesh
2512   MCUMesh m0descSkin = static_cast<MEDCouplingUMesh *>(m0desc->buildPartOfMySelf(boundSegs->begin(),boundSegs->end(), true));
2513   DAInt fNodes = m0descSkin->computeFetchedNodeIds();
2514   // In 3D, some points on the boundary of M0 still need duplication:
2515   DAInt notDup = 0;
2516   if (getMeshDimension() == 3)
2517     {
2518       DAInt dnu1=DataArrayInt::New(), dnu2=DataArrayInt::New(), dnu3=DataArrayInt::New(), dnu4=DataArrayInt::New();
2519       MCUMesh m0descSkinDesc = m0descSkin->buildDescendingConnectivity(dnu1, dnu2, dnu3, dnu4);
2520       dnu1=0;dnu2=0;dnu3=0;dnu4=0;
2521       DataArrayInt * corresp=0;
2522       meshM2->areCellsIncludedIn(m0descSkinDesc,2,corresp);
2523       DAInt validIds = corresp->findIdsInRange(0, meshM2->getNumberOfCells());
2524       corresp->decrRef();
2525       if (validIds->getNumberOfTuples())
2526         {
2527           MCUMesh m1IntersecSkin = static_cast<MEDCouplingUMesh *>(m0descSkinDesc->buildPartOfMySelf(validIds->begin(), validIds->end(), true));
2528           DAInt notDuplSkin = m1IntersecSkin->findBoundaryNodes();
2529           DAInt fNodes1 = fNodes->buildSubstraction(notDuplSkin);
2530           notDup = xtrem->buildSubstraction(fNodes1);
2531         }
2532       else
2533         notDup = xtrem->buildSubstraction(fNodes);
2534     }
2535   else
2536     notDup = xtrem->buildSubstraction(fNodes);
2537
2538   // Now compute cells around group (i.e. cells where we will do the propagation to identify the two sub-sets delimited by the group)
2539   DAInt m1Nodes = otherDimM1OnSameCoords.computeFetchedNodeIds();
2540   DAInt dupl = m1Nodes->buildSubstraction(notDup);
2541   DAInt cellsAroundGroup = getCellIdsLyingOnNodes(dupl->begin(), dupl->end(), false);  // false= take cell in, even if not all nodes are in notDup
2542
2543   //
2544   MCUMesh m0Part2=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(cellsAroundGroup->begin(),cellsAroundGroup->end(),true));
2545   int nCells2 = m0Part2->getNumberOfCells();
2546   DAInt desc00=DataArrayInt::New(),descI00=DataArrayInt::New(),revDesc00=DataArrayInt::New(),revDescI00=DataArrayInt::New();
2547   MCUMesh m01=m0Part2->buildDescendingConnectivity(desc00,descI00,revDesc00,revDescI00);
2548
2549   // Neighbor information of the mesh without considering the crack (serves to count how many connex pieces it is made of)
2550   DataArrayInt *tmp00=0,*tmp11=0;
2551   MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00, tmp00, tmp11);
2552   DAInt neighInit00(tmp00);
2553   DAInt neighIInit00(tmp11);
2554   // Neighbor information of the mesh WITH the crack (some neighbors are removed):
2555   DataArrayInt *idsTmp=0;
2556   bool b=m01->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsTmp);
2557   DAInt ids(idsTmp);
2558   // In the neighbor information remove the connection between high dimension cells and its low level constituents which are part
2559   // of the frontier given in parameter (i.e. the cells of low dimension from the group delimiting the crack):
2560   MEDCouplingUMesh::RemoveIdsFromIndexedArrays(ids->begin(),ids->end(),desc00,descI00);
2561   DataArrayInt *tmp0=0,*tmp1=0;
2562   // Compute the neighbor of each cell in m0Part2, taking into account the broken link above. Two
2563   // cells on either side of the crack (defined by the mesh of low dimension) are not neighbor anymore.
2564   ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00,tmp0,tmp1);
2565   DAInt neigh00(tmp0);
2566   DAInt neighI00(tmp1);
2567
2568   // For each initial connex part of the sub-mesh (or said differently for each independent crack):
2569   int seed = 0, nIter = 0;
2570   int nIterMax = nCells2+1; // Safety net for the loop
2571   DAInt hitCells = DataArrayInt::New(); hitCells->alloc(nCells2);
2572   hitCells->fillWithValue(-1);
2573   DAInt cellsToModifyConn0_torenum = DataArrayInt::New();
2574   cellsToModifyConn0_torenum->alloc(0,1);
2575   while (nIter < nIterMax)
2576     {
2577       DAInt t = hitCells->findIdsEqual(-1);
2578       if (!t->getNumberOfTuples())
2579         break;
2580       // Connex zone without the crack (to compute the next seed really)
2581       int dnu;
2582       DAInt connexCheck = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neighInit00,neighIInit00, -1, dnu);
2583       int cnt = 0;
2584       for (int * ptr = connexCheck->getPointer(); cnt < connexCheck->getNumberOfTuples(); ptr++, cnt++)
2585         hitCells->setIJ(*ptr,0,1);
2586       // Connex zone WITH the crack (to identify cells lying on either part of the crack)
2587       DAInt spreadZone = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neigh00,neighI00, -1, dnu);
2588       cellsToModifyConn0_torenum = DataArrayInt::Aggregate(cellsToModifyConn0_torenum, spreadZone, 0);
2589       // Compute next seed, i.e. a cell in another connex part, which was not covered by the previous iterations
2590       DAInt comple = cellsToModifyConn0_torenum->buildComplement(nCells2);
2591       DAInt nonHitCells = hitCells->findIdsEqual(-1);
2592       DAInt intersec = nonHitCells->buildIntersection(comple);
2593       if (intersec->getNumberOfTuples())
2594         { seed = intersec->getIJ(0,0); }
2595       else
2596         { break; }
2597       nIter++;
2598     }
2599   if (nIter >= nIterMax)
2600     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate(): internal error - too many iterations.");
2601
2602   DAInt cellsToModifyConn1_torenum=cellsToModifyConn0_torenum->buildComplement(neighI00->getNumberOfTuples()-1);
2603   cellsToModifyConn0_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2604   cellsToModifyConn1_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2605   //
2606   cellIdsNeededToBeRenum=cellsToModifyConn0_torenum.retn();
2607   cellIdsNotModified=cellsToModifyConn1_torenum.retn();
2608   nodeIdsToDuplicate=dupl.retn();
2609 }
2610
2611 /*!
2612  * This method operates a modification of the connectivity and coords in \b this.
2613  * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this 
2614  * its ids will be modified to id this->getNumberOfNodes()+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2615  * 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
2616  * renumbered. The node id nodeIdsToDuplicateBg[0] will have id this->getNumberOfNodes()+0, node id nodeIdsToDuplicateBg[1] will have id this->getNumberOfNodes()+1,
2617  * node id nodeIdsToDuplicateBg[2] will have id this->getNumberOfNodes()+2...
2618  * 
2619  * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2620  * 
2621  * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2622  * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2623  */
2624 void MEDCouplingUMesh::duplicateNodes(const int *nodeIdsToDuplicateBg, const int *nodeIdsToDuplicateEnd)
2625 {
2626   int nbOfNodes=getNumberOfNodes();
2627   duplicateNodesInCoords(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd);
2628   duplicateNodesInConn(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,nbOfNodes);
2629 }
2630
2631 /*!
2632  * This method renumbers only nodal connectivity in \a this. The renumbering is only an offset applied. So this method is a specialization of
2633  * \a renumberNodesInConn. \b WARNING, this method does not check that the resulting node ids in the nodal connectivity is in a valid range !
2634  *
2635  * \param [in] offset - specifies the offset to be applied on each element of connectivity.
2636  *
2637  * \sa renumberNodesInConn
2638  */
2639 void MEDCouplingUMesh::renumberNodesWithOffsetInConn(int offset)
2640 {
2641   checkConnectivityFullyDefined();
2642   int *conn(getNodalConnectivity()->getPointer());
2643   const int *connIndex(getNodalConnectivityIndex()->getConstPointer());
2644   int nbOfCells(getNumberOfCells());
2645   for(int i=0;i<nbOfCells;i++)
2646     for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2647       {
2648         int& node=conn[iconn];
2649         if(node>=0)//avoid polyhedron separator
2650           {
2651             node+=offset;
2652           }
2653       }
2654   _nodal_connec->declareAsNew();
2655   updateTime();
2656 }
2657
2658 /*!
2659  *  Same than renumberNodesInConn(const int *) except that here the format of old-to-new traducer is using map instead
2660  *  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
2661  *  of a big mesh.
2662  */
2663 void MEDCouplingUMesh::renumberNodesInConn(const INTERP_KERNEL::HashMap<int,int>& newNodeNumbersO2N)
2664 {
2665   checkConnectivityFullyDefined();
2666   int *conn(getNodalConnectivity()->getPointer());
2667   const int *connIndex(getNodalConnectivityIndex()->getConstPointer());
2668   int nbOfCells(getNumberOfCells());
2669   for(int i=0;i<nbOfCells;i++)
2670     for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2671       {
2672         int& node=conn[iconn];
2673         if(node>=0)//avoid polyhedron separator
2674           {
2675             INTERP_KERNEL::HashMap<int,int>::const_iterator it(newNodeNumbersO2N.find(node));
2676             if(it!=newNodeNumbersO2N.end())
2677               {
2678                 node=(*it).second;
2679               }
2680             else
2681               {
2682                 std::ostringstream oss; oss << "MEDCouplingUMesh::renumberNodesInConn(map) : presence in connectivity for cell #" << i << " of node #" << node << " : Not in map !";
2683                 throw INTERP_KERNEL::Exception(oss.str().c_str());
2684               }
2685           }
2686       }
2687   _nodal_connec->declareAsNew();
2688   updateTime();
2689 }
2690
2691 /*!
2692  * Changes ids of nodes within the nodal connectivity arrays according to a permutation
2693  * array in "Old to New" mode. The node coordinates array is \b not changed by this method.
2694  * This method is a generalization of shiftNodeNumbersInConn().
2695  *  \warning This method performs no check of validity of new ids. **Use it with care !**
2696  *  \param [in] newNodeNumbersO2N - a permutation array, of length \a
2697  *         this->getNumberOfNodes(), in "Old to New" mode. 
2698  *         See \ref numbering for more info on renumbering modes.
2699  *  \throw If the nodal connectivity of cells is not defined.
2700  *
2701  *  \if ENABLE_EXAMPLES
2702  *  \ref cpp_mcumesh_renumberNodesInConn "Here is a C++ example".<br>
2703  *  \ref  py_mcumesh_renumberNodesInConn "Here is a Python example".
2704  *  \endif
2705  */
2706 void MEDCouplingUMesh::renumberNodesInConn(const int *newNodeNumbersO2N)
2707 {
2708   checkConnectivityFullyDefined();
2709   int *conn=getNodalConnectivity()->getPointer();
2710   const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2711   int nbOfCells(getNumberOfCells());
2712   for(int i=0;i<nbOfCells;i++)
2713     for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2714       {
2715         int& node=conn[iconn];
2716         if(node>=0)//avoid polyhedron separator
2717           {
2718             node=newNodeNumbersO2N[node];
2719           }
2720       }
2721   _nodal_connec->declareAsNew();
2722   updateTime();
2723 }
2724
2725 /*!
2726  * This method renumbers nodes \b in \b connectivity \b only \b without \b any \b reference \b to \b coords.
2727  * This method performs no check on the fact that new coordinate ids are valid. \b Use \b it \b with \b care !
2728  * This method is an specialization of \ref MEDCoupling::MEDCouplingUMesh::renumberNodesInConn "renumberNodesInConn method".
2729  * 
2730  * \param [in] delta specifies the shift size applied to nodeId in nodal connectivity in \b this.
2731  */
2732 void MEDCouplingUMesh::shiftNodeNumbersInConn(int delta)
2733 {
2734   checkConnectivityFullyDefined();
2735   int *conn=getNodalConnectivity()->getPointer();
2736   const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2737   int nbOfCells=getNumberOfCells();
2738   for(int i=0;i<nbOfCells;i++)
2739     for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2740       {
2741         int& node=conn[iconn];
2742         if(node>=0)//avoid polyhedron separator
2743           {
2744             node+=delta;
2745           }
2746       }
2747   _nodal_connec->declareAsNew();
2748   updateTime();
2749 }
2750
2751 /*!
2752  * This method operates a modification of the connectivity in \b this.
2753  * 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.
2754  * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this 
2755  * its ids will be modified to id offset+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2756  * 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
2757  * renumbered. The node id nodeIdsToDuplicateBg[0] will have id offset+0, node id nodeIdsToDuplicateBg[1] will have id offset+1,
2758  * node id nodeIdsToDuplicateBg[2] will have id offset+2...
2759  * 
2760  * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2761  * As an another consequense after the call of this method \b this can be transiently non cohrent.
2762  * 
2763  * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2764  * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2765  * \param [in] offset the offset applied to all node ids in connectivity that are in [ \a nodeIdsToDuplicateBg, \a nodeIdsToDuplicateEnd ). 
2766  */
2767 void MEDCouplingUMesh::duplicateNodesInConn(const int *nodeIdsToDuplicateBg, const int *nodeIdsToDuplicateEnd, int offset)
2768 {
2769   checkConnectivityFullyDefined();
2770   std::map<int,int> m;
2771   int val=offset;
2772   for(const int *work=nodeIdsToDuplicateBg;work!=nodeIdsToDuplicateEnd;work++,val++)
2773     m[*work]=val;
2774   int *conn=getNodalConnectivity()->getPointer();
2775   const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2776   int nbOfCells=getNumberOfCells();
2777   for(int i=0;i<nbOfCells;i++)
2778     for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2779       {
2780         int& node=conn[iconn];
2781         if(node>=0)//avoid polyhedron separator
2782           {
2783             std::map<int,int>::iterator it=m.find(node);
2784             if(it!=m.end())
2785               node=(*it).second;
2786           }
2787       }
2788   updateTime();
2789 }
2790
2791 /*!
2792  * This method renumbers cells of \a this using the array specified by [old2NewBg;old2NewBg+getNumberOfCells())
2793  *
2794  * Contrary to MEDCouplingPointSet::renumberNodes, this method makes a permutation without any fuse of cell.
2795  * After the call of this method the number of cells remains the same as before.
2796  *
2797  * If 'check' equals true the method will check that any elements in [ \a old2NewBg; \a old2NewEnd ) is unique ; if not
2798  * an INTERP_KERNEL::Exception will be thrown. When 'check' equals true [ \a old2NewBg ; \a old2NewEnd ) is not expected to
2799  * be strictly in [0;this->getNumberOfCells()).
2800  *
2801  * If 'check' equals false the method will not check the content of [ \a old2NewBg ; \a old2NewEnd ).
2802  * To avoid any throw of SIGSEGV when 'check' equals false, the elements in [ \a old2NewBg ; \a old2NewEnd ) should be unique and
2803  * should be contained in[0;this->getNumberOfCells()).
2804  * 
2805  * \param [in] old2NewBg is expected to be a dynamically allocated pointer of size at least equal to this->getNumberOfCells()
2806  * \param check
2807  */
2808 void MEDCouplingUMesh::renumberCells(const int *old2NewBg, bool check)
2809 {
2810   checkConnectivityFullyDefined();
2811   int nbCells=getNumberOfCells();
2812   const int *array=old2NewBg;
2813   if(check)
2814     array=DataArrayInt::CheckAndPreparePermutation(old2NewBg,old2NewBg+nbCells);
2815   //
2816   const int *conn=_nodal_connec->getConstPointer();
2817   const int *connI=_nodal_connec_index->getConstPointer();
2818   MCAuto<DataArrayInt> o2n=DataArrayInt::New(); o2n->useArray(array,false,C_DEALLOC,nbCells,1);
2819   MCAuto<DataArrayInt> n2o=o2n->invertArrayO2N2N2O(nbCells);
2820   const int *n2oPtr=n2o->begin();
2821   MCAuto<DataArrayInt> newConn=DataArrayInt::New();
2822   newConn->alloc(_nodal_connec->getNumberOfTuples(),_nodal_connec->getNumberOfComponents());
2823   newConn->copyStringInfoFrom(*_nodal_connec);
2824   MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
2825   newConnI->alloc(_nodal_connec_index->getNumberOfTuples(),_nodal_connec_index->getNumberOfComponents());
2826   newConnI->copyStringInfoFrom(*_nodal_connec_index);
2827   //
2828   int *newC=newConn->getPointer();
2829   int *newCI=newConnI->getPointer();
2830   int loc=0;
2831   newCI[0]=loc;
2832   for(int i=0;i<nbCells;i++)
2833     {
2834       int pos=n2oPtr[i];
2835       int nbOfElts=connI[pos+1]-connI[pos];
2836       newC=std::copy(conn+connI[pos],conn+connI[pos+1],newC);
2837       loc+=nbOfElts;
2838       newCI[i+1]=loc;
2839     }
2840   //
2841   setConnectivity(newConn,newConnI);
2842   if(check)
2843     free(const_cast<int *>(array));
2844 }
2845
2846 /*!
2847  * Finds cells whose bounding boxes intersect a given bounding box.
2848  *  \param [in] bbox - an array defining the bounding box via coordinates of its
2849  *         extremum points in "no interlace" mode, i.e. xMin, xMax, yMin, yMax, zMin,
2850  *         zMax (if in 3D). 
2851  *  \param [in] eps - a factor used to increase size of the bounding box of cell
2852  *         before comparing it with \a bbox. This factor is multiplied by the maximal
2853  *         extent of the bounding box of cell to produce an addition to this bounding box.
2854  *  \return DataArrayInt * - a new instance of DataArrayInt holding ids for found
2855  *         cells. The caller is to delete this array using decrRef() as it is no more
2856  *         needed. 
2857  *  \throw If the coordinates array is not set.
2858  *  \throw If the nodal connectivity of cells is not defined.
2859  *
2860  *  \if ENABLE_EXAMPLES
2861  *  \ref cpp_mcumesh_getCellsInBoundingBox "Here is a C++ example".<br>
2862  *  \ref  py_mcumesh_getCellsInBoundingBox "Here is a Python example".
2863  *  \endif
2864  */
2865 DataArrayInt *MEDCouplingUMesh::getCellsInBoundingBox(const double *bbox, double eps) const
2866 {
2867   MCAuto<DataArrayInt> elems=DataArrayInt::New(); elems->alloc(0,1);
2868   if(getMeshDimension()==-1)
2869     {
2870       elems->pushBackSilent(0);
2871       return elems.retn();
2872     }
2873   int dim=getSpaceDimension();
2874   INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2875   const int* conn      = getNodalConnectivity()->getConstPointer();
2876   const int* conn_index= getNodalConnectivityIndex()->getConstPointer();
2877   const double* coords = getCoords()->getConstPointer();
2878   int nbOfCells=getNumberOfCells();
2879   for ( int ielem=0; ielem<nbOfCells;ielem++ )
2880     {
2881       for (int i=0; i<dim; i++)
2882         {
2883           elem_bb[i*2]=std::numeric_limits<double>::max();
2884           elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2885         }
2886
2887       for (int inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2888         {
2889           int node= conn[inode];
2890           if(node>=0)//avoid polyhedron separator
2891             {
2892               for (int idim=0; idim<dim; idim++)
2893                 {
2894                   if ( coords[node*dim+idim] < elem_bb[idim*2] )
2895                     {
2896                       elem_bb[idim*2] = coords[node*dim+idim] ;
2897                     }
2898                   if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2899                     {
2900                       elem_bb[idim*2+1] = coords[node*dim+idim] ;
2901                     }
2902                 }
2903             }
2904         }
2905       if (intersectsBoundingBox(elem_bb, bbox, dim, eps))
2906         elems->pushBackSilent(ielem);
2907     }
2908   return elems.retn();
2909 }
2910
2911 /*!
2912  * Given a boundary box 'bbox' returns elements 'elems' contained in this 'bbox' or touching 'bbox' (within 'eps' distance).
2913  * Warning 'elems' is incremented during the call so if elems is not empty before call returned elements will be
2914  * added in 'elems' parameter.
2915  */
2916 DataArrayInt *MEDCouplingUMesh::getCellsInBoundingBox(const INTERP_KERNEL::DirectedBoundingBox& bbox, double eps)
2917 {
2918   MCAuto<DataArrayInt> elems=DataArrayInt::New(); elems->alloc(0,1);
2919   if(getMeshDimension()==-1)
2920     {
2921       elems->pushBackSilent(0);
2922       return elems.retn();
2923     }
2924   int dim=getSpaceDimension();
2925   INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2926   const int* conn      = getNodalConnectivity()->getConstPointer();
2927   const int* conn_index= getNodalConnectivityIndex()->getConstPointer();
2928   const double* coords = getCoords()->getConstPointer();
2929   int nbOfCells=getNumberOfCells();
2930   for ( int ielem=0; ielem<nbOfCells;ielem++ )
2931     {
2932       for (int i=0; i<dim; i++)
2933         {
2934           elem_bb[i*2]=std::numeric_limits<double>::max();
2935           elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2936         }
2937
2938       for (int inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2939         {
2940           int node= conn[inode];
2941           if(node>=0)//avoid polyhedron separator
2942             {
2943               for (int idim=0; idim<dim; idim++)
2944                 {
2945                   if ( coords[node*dim+idim] < elem_bb[idim*2] )
2946                     {
2947                       elem_bb[idim*2] = coords[node*dim+idim] ;
2948                     }
2949                   if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2950                     {
2951                       elem_bb[idim*2+1] = coords[node*dim+idim] ;
2952                     }
2953                 }
2954             }
2955         }
2956       if(intersectsBoundingBox(bbox, elem_bb, dim, eps))
2957         elems->pushBackSilent(ielem);
2958     }
2959   return elems.retn();
2960 }
2961
2962 /*!
2963  * Returns a type of a cell by its id.
2964  *  \param [in] cellId - the id of the cell of interest.
2965  *  \return INTERP_KERNEL::NormalizedCellType - enumeration item describing the cell type.
2966  *  \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2967  */
2968 INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::getTypeOfCell(int cellId) const
2969 {
2970   const int *ptI=_nodal_connec_index->getConstPointer();
2971   const int *pt=_nodal_connec->getConstPointer();
2972   if(cellId>=0 && cellId<(int)_nodal_connec_index->getNbOfElems()-1)
2973     return (INTERP_KERNEL::NormalizedCellType) pt[ptI[cellId]];
2974   else
2975     {
2976       std::ostringstream oss; oss << "MEDCouplingUMesh::getTypeOfCell : Requesting type of cell #" << cellId << " but it should be in [0," << _nodal_connec_index->getNbOfElems()-1 << ") !";
2977       throw INTERP_KERNEL::Exception(oss.str().c_str());
2978     }
2979 }
2980
2981 /*!
2982  * This method returns a newly allocated array containing cell ids (ascendingly sorted) whose geometric type are equal to type.
2983  * This method does not throw exception if geometric type \a type is not in \a this.
2984  * This method throws an INTERP_KERNEL::Exception if meshdimension of \b this is not equal to those of \b type.
2985  * The coordinates array is not considered here.
2986  *
2987  * \param [in] type the geometric type
2988  * \return cell ids in this having geometric type \a type.
2989  */
2990 DataArrayInt *MEDCouplingUMesh::giveCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2991 {
2992
2993   MCAuto<DataArrayInt> ret=DataArrayInt::New();
2994   ret->alloc(0,1);
2995   checkConnectivityFullyDefined();
2996   int nbCells=getNumberOfCells();
2997   int mdim=getMeshDimension();
2998   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
2999   if(mdim!=(int)cm.getDimension())
3000     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::giveCellsWithType : Mismatch between mesh dimension and dimension of the cell !");
3001   const int *ptI=_nodal_connec_index->getConstPointer();
3002   const int *pt=_nodal_connec->getConstPointer();
3003   for(int i=0;i<nbCells;i++)
3004     {
3005       if((INTERP_KERNEL::NormalizedCellType)pt[ptI[i]]==type)
3006         ret->pushBackSilent(i);
3007     }
3008   return ret.retn();
3009 }
3010
3011 /*!
3012  * Returns nb of cells having the geometric type \a type. No throw if no cells in \a this has the geometric type \a type.
3013  */
3014 int MEDCouplingUMesh::getNumberOfCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
3015 {
3016   const int *ptI=_nodal_connec_index->getConstPointer();
3017   const int *pt=_nodal_connec->getConstPointer();
3018   int nbOfCells=getNumberOfCells();
3019   int ret=0;
3020   for(int i=0;i<nbOfCells;i++)
3021     if((INTERP_KERNEL::NormalizedCellType) pt[ptI[i]]==type)
3022       ret++;
3023   return ret;
3024 }
3025
3026 /*!
3027  * Returns the nodal connectivity of a given cell.
3028  * The separator of faces within polyhedron connectivity (-1) is not returned, thus
3029  * all returned node ids can be used in getCoordinatesOfNode().
3030  *  \param [in] cellId - an id of the cell of interest.
3031  *  \param [in,out] conn - a vector where the node ids are appended. It is not
3032  *         cleared before the appending.
3033  *  \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
3034  */
3035 void MEDCouplingUMesh::getNodeIdsOfCell(int cellId, std::vector<int>& conn) const
3036 {
3037   const int *ptI=_nodal_connec_index->getConstPointer();
3038   const int *pt=_nodal_connec->getConstPointer();
3039   for(const int *w=pt+ptI[cellId]+1;w!=pt+ptI[cellId+1];w++)
3040     if(*w>=0)
3041       conn.push_back(*w);
3042 }
3043
3044 std::string MEDCouplingUMesh::simpleRepr() const
3045 {
3046   static const char msg0[]="No coordinates specified !";
3047   std::ostringstream ret;
3048   ret << "Unstructured mesh with name : \"" << getName() << "\"\n";
3049   ret << "Description of mesh : \"" << getDescription() << "\"\n";
3050   int tmpp1,tmpp2;
3051   double tt=getTime(tmpp1,tmpp2);
3052   ret << "Time attached to the mesh [unit] : " << tt << " [" << getTimeUnit() << "]\n";
3053   ret << "Iteration : " << tmpp1  << " Order : " << tmpp2 << "\n";
3054   if(_mesh_dim>=-1)
3055     { ret << "Mesh dimension : " << _mesh_dim << "\nSpace dimension : "; }
3056   else
3057     { ret << " Mesh dimension has not been set or is invalid !"; }
3058   if(_coords!=0)
3059     {
3060       const int spaceDim=getSpaceDimension();
3061       ret << spaceDim << "\nInfo attached on space dimension : ";
3062       for(int i=0;i<spaceDim;i++)
3063         ret << "\"" << _coords->getInfoOnComponent(i) << "\" ";
3064       ret << "\n";
3065     }
3066   else
3067     ret << msg0 << "\n";
3068   ret << "Number of nodes : ";
3069   if(_coords!=0)
3070     ret << getNumberOfNodes() << "\n";
3071   else
3072     ret << msg0 << "\n";
3073   ret << "Number of cells : ";
3074   if(_nodal_connec!=0 && _nodal_connec_index!=0)
3075     ret << getNumberOfCells() << "\n";
3076   else
3077     ret << "No connectivity specified !" << "\n";
3078   ret << "Cell types present : ";
3079   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
3080     {
3081       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter);
3082       ret << cm.getRepr() << " ";
3083     }
3084   ret << "\n";
3085   return ret.str();
3086 }
3087
3088 std::string MEDCouplingUMesh::advancedRepr() const
3089 {
3090   std::ostringstream ret;
3091   ret << simpleRepr();
3092   ret << "\nCoordinates array : \n___________________\n\n";
3093   if(_coords)
3094     _coords->reprWithoutNameStream(ret);
3095   else
3096     ret << "No array set !\n";
3097   ret << "\n\nConnectivity arrays : \n_____________________\n\n";
3098   reprConnectivityOfThisLL(ret);
3099   return ret.str();
3100 }
3101
3102 /*!
3103  * This method returns a C++ code that is a dump of \a this.
3104  * This method will throw if this is not fully defined.
3105  */
3106 std::string MEDCouplingUMesh::cppRepr() const
3107 {
3108   static const char coordsName[]="coords";
3109   static const char connName[]="conn";
3110   static const char connIName[]="connI";
3111   checkFullyDefined();
3112   std::ostringstream ret; ret << "// coordinates" << std::endl;
3113   _coords->reprCppStream(coordsName,ret); ret << std::endl << "// connectivity" << std::endl;
3114   _nodal_connec->reprCppStream(connName,ret); ret << std::endl;
3115   _nodal_connec_index->reprCppStream(connIName,ret); ret << std::endl;
3116   ret << "MEDCouplingUMesh *mesh=MEDCouplingUMesh::New(\"" << getName() << "\"," << getMeshDimension() << ");" << std::endl;
3117   ret << "mesh->setCoords(" << coordsName << ");" << std::endl;
3118   ret << "mesh->setConnectivity(" << connName << "," << connIName << ",true);" << std::endl;
3119   ret << coordsName << "->decrRef(); " << connName << "->decrRef(); " << connIName << "->decrRef();" << std::endl;
3120   return ret.str();
3121 }
3122
3123 std::string MEDCouplingUMesh::reprConnectivityOfThis() const
3124 {
3125   std::ostringstream ret;
3126   reprConnectivityOfThisLL(ret);
3127   return ret.str();
3128 }
3129
3130 /*!
3131  * This method builds a newly allocated instance (with the same name than \a this) that the caller has the responsability to deal with.
3132  * This method returns an instance with all arrays allocated (connectivity, connectivity index, coordinates)
3133  * but with length of these arrays set to 0. It allows to define an "empty" mesh (with nor cells nor nodes but compliant with
3134  * some algos).
3135  * 
3136  * This method expects that \a this has a mesh dimension set and higher or equal to 0. If not an exception will be thrown.
3137  * 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
3138  * with number of tuples set to 0, if not the array is taken as this in the returned instance.
3139  */
3140 MEDCouplingUMesh *MEDCouplingUMesh::buildSetInstanceFromThis(int spaceDim) const
3141 {
3142   int mdim=getMeshDimension();
3143   if(mdim<0)
3144     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSetInstanceFromThis : invalid mesh dimension ! Should be >= 0 !");
3145   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
3146   MCAuto<DataArrayInt> tmp1,tmp2;
3147   bool needToCpyCT=true;
3148   if(!_nodal_connec)
3149     {
3150       tmp1=DataArrayInt::New(); tmp1->alloc(0,1);
3151       needToCpyCT=false;
3152     }
3153   else
3154     {
3155       tmp1=_nodal_connec;
3156       tmp1->incrRef();
3157     }
3158   if(!_nodal_connec_index)
3159     {
3160       tmp2=DataArrayInt::New(); tmp2->alloc(1,1); tmp2->setIJ(0,0,0);
3161       needToCpyCT=false;
3162     }
3163   else
3164     {
3165       tmp2=_nodal_connec_index;
3166       tmp2->incrRef();
3167     }
3168   ret->setConnectivity(tmp1,tmp2,false);
3169   if(needToCpyCT)
3170     ret->_types=_types;
3171   if(!_coords)
3172     {
3173       MCAuto<DataArrayDouble> coords=DataArrayDouble::New(); coords->alloc(0,spaceDim);
3174       ret->setCoords(coords);
3175     }
3176   else
3177     ret->setCoords(_coords);
3178   return ret.retn();
3179 }
3180
3181 void MEDCouplingUMesh::reprConnectivityOfThisLL(std::ostringstream& stream) const
3182 {
3183   if(_nodal_connec!=0 && _nodal_connec_index!=0)
3184     {
3185       int nbOfCells=getNumberOfCells();
3186       const int *c=_nodal_connec->getConstPointer();
3187       const int *ci=_nodal_connec_index->getConstPointer();
3188       for(int i=0;i<nbOfCells;i++)
3189         {
3190           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c[ci[i]]);
3191           stream << "Cell #" << i << " " << cm.getRepr() << " : ";
3192           std::copy(c+ci[i]+1,c+ci[i+1],std::ostream_iterator<int>(stream," "));
3193           stream << "\n";
3194         }
3195     }
3196   else
3197     stream << "Connectivity not defined !\n";
3198 }
3199
3200 int MEDCouplingUMesh::getNumberOfNodesInCell(int cellId) const
3201 {
3202   const int *ptI=_nodal_connec_index->getConstPointer();
3203   const int *pt=_nodal_connec->getConstPointer();
3204   if(pt[ptI[cellId]]!=INTERP_KERNEL::NORM_POLYHED)
3205     return ptI[cellId+1]-ptI[cellId]-1;
3206   else
3207     return (int)std::count_if(pt+ptI[cellId]+1,pt+ptI[cellId+1],std::bind2nd(std::not_equal_to<int>(),-1));
3208 }
3209
3210 /*!
3211  * Returns types of cells of the specified part of \a this mesh.
3212  * This method avoids computing sub-mesh explicitely to get its types.
3213  *  \param [in] begin - an array of cell ids of interest.
3214  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3215  *  \return std::set<INTERP_KERNEL::NormalizedCellType> - a set of enumeration items
3216  *         describing the cell types. 
3217  *  \throw If the coordinates array is not set.
3218  *  \throw If the nodal connectivity of cells is not defined.
3219  *  \sa getAllGeoTypes()
3220  */
3221 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getTypesOfPart(const int *begin, const int *end) const
3222 {
3223   checkFullyDefined();
3224   std::set<INTERP_KERNEL::NormalizedCellType> ret;
3225   const int *conn=_nodal_connec->getConstPointer();
3226   const int *connIndex=_nodal_connec_index->getConstPointer();
3227   for(const int *w=begin;w!=end;w++)
3228     ret.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]);
3229   return ret;
3230 }
3231
3232 /*!
3233  * Defines the nodal connectivity using given connectivity arrays in \ref numbering-indirect format.
3234  * Optionally updates
3235  * a set of types of cells constituting \a this mesh. 
3236  * This method is for advanced users having prepared their connectivity before. For
3237  * more info on using this method see \ref MEDCouplingUMeshAdvBuild.
3238  *  \param [in] conn - the nodal connectivity array. 
3239  *  \param [in] connIndex - the nodal connectivity index array.
3240  *  \param [in] isComputingTypes - if \c true, the set of types constituting \a this
3241  *         mesh is updated.
3242  */
3243 void MEDCouplingUMesh::setConnectivity(DataArrayInt *conn, DataArrayInt *connIndex, bool isComputingTypes)
3244 {
3245   DataArrayInt::SetArrayIn(conn,_nodal_connec);
3246   DataArrayInt::SetArrayIn(connIndex,_nodal_connec_index);
3247   if(isComputingTypes)
3248     computeTypes();
3249   declareAsNew();
3250 }
3251
3252 /*!
3253  * Copy constructor. If 'deepCopy' is false \a this is a shallow copy of other.
3254  * If 'deeCpy' is true all arrays (coordinates and connectivities) are deeply copied.
3255  */
3256 MEDCouplingUMesh::MEDCouplingUMesh(const MEDCouplingUMesh& other, bool deepCopy):MEDCouplingPointSet(other,deepCopy),_mesh_dim(other._mesh_dim),
3257     _nodal_connec(0),_nodal_connec_index(0),
3258     _types(other._types)
3259 {
3260   if(other._nodal_connec)
3261     _nodal_connec=other._nodal_connec->performCopyOrIncrRef(deepCopy);
3262   if(other._nodal_connec_index)
3263     _nodal_connec_index=other._nodal_connec_index->performCopyOrIncrRef(deepCopy);
3264 }
3265
3266 MEDCouplingUMesh::~MEDCouplingUMesh()
3267 {
3268   if(_nodal_connec)
3269     _nodal_connec->decrRef();
3270   if(_nodal_connec_index)
3271     _nodal_connec_index->decrRef();
3272 }
3273
3274 /*!
3275  * Recomputes a set of cell types of \a this mesh. For more info see
3276  * \ref MEDCouplingUMeshNodalConnectivity.
3277  */
3278 void MEDCouplingUMesh::computeTypes()
3279 {
3280   ComputeAllTypesInternal(_types,_nodal_connec,_nodal_connec_index);
3281 }
3282
3283 /*!
3284  * This method checks that all arrays are set. If yes nothing done if no an exception is thrown.
3285  */
3286 void MEDCouplingUMesh::checkFullyDefined() const
3287 {
3288   if(!_nodal_connec_index || !_nodal_connec || !_coords)
3289     throw INTERP_KERNEL::Exception("Reverse nodal connectivity computation requires full connectivity and coordinates set in unstructured mesh.");
3290 }
3291
3292 /*!
3293  * This method checks that all connectivity arrays are set. If yes nothing done if no an exception is thrown.
3294  */
3295 void MEDCouplingUMesh::checkConnectivityFullyDefined() const
3296 {
3297   if(!_nodal_connec_index || !_nodal_connec)
3298     throw INTERP_KERNEL::Exception("Reverse nodal connectivity computation requires full connectivity set in unstructured mesh.");
3299 }
3300
3301 /*!
3302  * Returns a number of cells constituting \a this mesh. 
3303  *  \return int - the number of cells in \a this mesh.
3304  *  \throw If the nodal connectivity of cells is not defined.
3305  */
3306 int MEDCouplingUMesh::getNumberOfCells() const
3307
3308   if(_nodal_connec_index)
3309     return _nodal_connec_index->getNumberOfTuples()-1;
3310   else
3311     if(_mesh_dim==-1)
3312       return 1;
3313     else
3314       throw INTERP_KERNEL::Exception("Unable to get number of cells because no connectivity specified !");
3315 }
3316
3317 /*!
3318  * Returns a dimension of \a this mesh, i.e. a dimension of cells constituting \a this
3319  * mesh. For more info see \ref meshes.
3320  *  \return int - the dimension of \a this mesh.
3321  *  \throw If the mesh dimension is not defined using setMeshDimension().
3322  */
3323 int MEDCouplingUMesh::getMeshDimension() const
3324 {
3325   if(_mesh_dim<-1)
3326     throw INTERP_KERNEL::Exception("No mesh dimension specified !");
3327   return _mesh_dim;
3328 }
3329
3330 /*!
3331  * Returns a length of the nodal connectivity array.
3332  * This method is for test reason. Normally the integer returned is not useable by
3333  * user.  For more info see \ref MEDCouplingUMeshNodalConnectivity.
3334  *  \return int - the length of the nodal connectivity array.
3335  */
3336 int MEDCouplingUMesh::getNodalConnectivityArrayLen() const
3337 {
3338   return _nodal_connec->getNbOfElems();
3339 }
3340
3341 /*!
3342  * First step of serialization process. Used by ParaMEDMEM and MEDCouplingCorba to transfert data between process.
3343  */
3344 void MEDCouplingUMesh::getTinySerializationInformation(std::vector<double>& tinyInfoD, std::vector<int>& tinyInfo, std::vector<std::string>& littleStrings) const
3345 {
3346   MEDCouplingPointSet::getTinySerializationInformation(tinyInfoD,tinyInfo,littleStrings);
3347   tinyInfo.push_back(getMeshDimension());
3348   tinyInfo.push_back(getNumberOfCells());
3349   if(_nodal_connec)
3350     tinyInfo.push_back(getNodalConnectivityArrayLen());
3351   else
3352     tinyInfo.push_back(-1);
3353 }
3354
3355 /*!
3356  * First step of unserialization process.
3357  */
3358 bool MEDCouplingUMesh::isEmptyMesh(const std::vector<int>& tinyInfo) const
3359 {
3360   return tinyInfo[6]<=0;
3361 }
3362
3363 /*!
3364  * Second step of serialization process.
3365  * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3366  * \param a1
3367  * \param a2
3368  * \param littleStrings
3369  */
3370 void MEDCouplingUMesh::resizeForUnserialization(const std::vector<int>& tinyInfo, DataArrayInt *a1, DataArrayDouble *a2, std::vector<std::string>& littleStrings) const
3371 {
3372   MEDCouplingPointSet::resizeForUnserialization(tinyInfo,a1,a2,littleStrings);
3373   if(tinyInfo[5]!=-1)
3374     a1->alloc(tinyInfo[7]+tinyInfo[6]+1,1);
3375 }
3376
3377 /*!
3378  * Third and final step of serialization process.
3379  */
3380 void MEDCouplingUMesh::serialize(DataArrayInt *&a1, DataArrayDouble *&a2) const
3381 {
3382   MEDCouplingPointSet::serialize(a1,a2);
3383   if(getMeshDimension()>-1)
3384     {
3385       a1=DataArrayInt::New();
3386       a1->alloc(getNodalConnectivityArrayLen()+getNumberOfCells()+1,1);
3387       int *ptA1=a1->getPointer();
3388       const int *conn=getNodalConnectivity()->getConstPointer();
3389       const int *index=getNodalConnectivityIndex()->getConstPointer();
3390       ptA1=std::copy(index,index+getNumberOfCells()+1,ptA1);
3391       std::copy(conn,conn+getNodalConnectivityArrayLen(),ptA1);
3392     }
3393   else
3394     a1=0;
3395 }
3396
3397 /*!
3398  * Second and final unserialization process.
3399  * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3400  */
3401 void MEDCouplingUMesh::unserialization(const std::vector<double>& tinyInfoD, const std::vector<int>& tinyInfo, const DataArrayInt *a1, DataArrayDouble *a2, const std::vector<std::string>& littleStrings)
3402 {
3403   MEDCouplingPointSet::unserialization(tinyInfoD,tinyInfo,a1,a2,littleStrings);
3404   setMeshDimension(tinyInfo[5]);
3405   if(tinyInfo[7]!=-1)
3406     {
3407       // Connectivity
3408       const int *recvBuffer=a1->getConstPointer();
3409       MCAuto<DataArrayInt> myConnecIndex=DataArrayInt::New();
3410       myConnecIndex->alloc(tinyInfo[6]+1,1);
3411       std::copy(recvBuffer,recvBuffer+tinyInfo[6]+1,myConnecIndex->getPointer());
3412       MCAuto<DataArrayInt> myConnec=DataArrayInt::New();
3413       myConnec->alloc(tinyInfo[7],1);
3414       std::copy(recvBuffer+tinyInfo[6]+1,recvBuffer+tinyInfo[6]+1+tinyInfo[7],myConnec->getPointer());
3415       setConnectivity(myConnec, myConnecIndex);
3416     }
3417 }
3418
3419 /*!
3420  * This is the low algorithm of MEDCouplingUMesh::buildPartOfMySelfSlice.
3421  * CellIds are given using range specified by a start an end and step.
3422  */
3423 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfKeepCoordsSlice(int start, int end, int step) const
3424 {
3425   checkFullyDefined();
3426   int ncell=getNumberOfCells();
3427   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New();
3428   ret->_mesh_dim=_mesh_dim;
3429   ret->setCoords(_coords);
3430   int newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfKeepCoordsSlice : ");
3431   MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(newNbOfCells+1,1);
3432   int *newConnIPtr=newConnI->getPointer(); *newConnIPtr=0;
3433   int work=start;
3434   const int *conn=_nodal_connec->getConstPointer();
3435   const int *connIndex=_nodal_connec_index->getConstPointer();
3436   for(int i=0;i<newNbOfCells;i++,newConnIPtr++,work+=step)
3437     {
3438       if(work>=0 && work<ncell)
3439         {
3440           newConnIPtr[1]=newConnIPtr[0]+connIndex[work+1]-connIndex[work];
3441         }
3442       else
3443         {
3444           std::ostringstream oss; oss << "MEDCouplingUMesh::buildPartOfMySelfKeepCoordsSlice : On pos #" << i << " input cell id =" << work << " should be in [0," << ncell << ") !";
3445           throw INTERP_KERNEL::Exception(oss.str().c_str());
3446         }
3447     }
3448   MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(newConnIPtr[0],1);
3449   int *newConnPtr=newConn->getPointer();
3450   std::set<INTERP_KERNEL::NormalizedCellType> types;
3451   work=start;
3452   for(int i=0;i<newNbOfCells;i++,newConnIPtr++,work+=step)
3453     {
3454       types.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[work]]);
3455       newConnPtr=std::copy(conn+connIndex[work],conn+connIndex[work+1],newConnPtr);
3456     }
3457   ret->setConnectivity(newConn,newConnI,false);
3458   ret->_types=types;
3459   ret->copyTinyInfoFrom(this);
3460   return ret.retn();
3461 }
3462
3463 /*!
3464  * This is the low algorithm of MEDCouplingUMesh::buildPartOfMySelf.
3465  * Keeps from \a this only cells which constituing point id are in the ids specified by [ \a begin,\a end ).
3466  * The return newly allocated mesh will share the same coordinates as \a this.
3467  */
3468 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfKeepCoords(const int *begin, const int *end) const
3469 {
3470   checkConnectivityFullyDefined();
3471   int ncell=getNumberOfCells();
3472   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New();
3473   ret->_mesh_dim=_mesh_dim;
3474   ret->setCoords(_coords);
3475   std::size_t nbOfElemsRet=std::distance(begin,end);
3476   int *connIndexRet=(int *)malloc((nbOfElemsRet+1)*sizeof(int));
3477   connIndexRet[0]=0;
3478   const int *conn=_nodal_connec->getConstPointer();
3479   const int *connIndex=_nodal_connec_index->getConstPointer();
3480   int newNbring=0;
3481   for(const int *work=begin;work!=end;work++,newNbring++)
3482     {
3483       if(*work>=0 && *work<ncell)
3484         connIndexRet[newNbring+1]=connIndexRet[newNbring]+connIndex[*work+1]-connIndex[*work];
3485       else
3486         {
3487           free(connIndexRet);
3488           std::ostringstream oss; oss << "MEDCouplingUMesh::buildPartOfMySelfKeepCoords : On pos #" << std::distance(begin,work) << " input cell id =" << *work << " should be in [0," << ncell << ") !";
3489           throw INTERP_KERNEL::Exception(oss.str().c_str());
3490         }
3491     }
3492   int *connRet=(int *)malloc(connIndexRet[nbOfElemsRet]*sizeof(int));
3493   int *connRetWork=connRet;
3494   std::set<INTERP_KERNEL::NormalizedCellType> types;
3495   for(const int *work=begin;work!=end;work++)
3496     {
3497       types.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*work]]);
3498       connRetWork=std::copy(conn+connIndex[*work],conn+connIndex[*work+1],connRetWork);
3499     }
3500   MCAuto<DataArrayInt> connRetArr=DataArrayInt::New();
3501   connRetArr->useArray(connRet,true,C_DEALLOC,connIndexRet[nbOfElemsRet],1);
3502   MCAuto<DataArrayInt> connIndexRetArr=DataArrayInt::New();
3503   connIndexRetArr->useArray(connIndexRet,true,C_DEALLOC,(int)nbOfElemsRet+1,1);
3504   ret->setConnectivity(connRetArr,connIndexRetArr,false);
3505   ret->_types=types;
3506   ret->copyTinyInfoFrom(this);
3507   return ret.retn();
3508 }
3509
3510 /*!
3511  * Returns a new MEDCouplingFieldDouble containing volumes of cells constituting \a this
3512  * mesh.<br>
3513  * For 1D cells, the returned field contains lengths.<br>
3514  * For 2D cells, the returned field contains areas.<br>
3515  * For 3D cells, the returned field contains volumes.
3516  *  \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3517  *         orientation, i.e. the volume is always positive.
3518  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on cells
3519  *         and one time . The caller is to delete this field using decrRef() as it is no
3520  *         more needed.
3521  */
3522 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureField(bool isAbs) const
3523 {
3524   std::string name="MeasureOfMesh_";
3525   name+=getName();
3526   int nbelem=getNumberOfCells();
3527   MCAuto<MEDCouplingFieldDouble> field=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3528   field->setName(name);
3529   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3530   array->alloc(nbelem,1);
3531   double *area_vol=array->getPointer();
3532   field->setArray(array) ; array=0;
3533   field->setMesh(const_cast<MEDCouplingUMesh *>(this));
3534   field->synchronizeTimeWithMesh();
3535   if(getMeshDimension()!=-1)
3536     {
3537       int ipt;
3538       INTERP_KERNEL::NormalizedCellType type;
3539       int dim_space=getSpaceDimension();
3540       const double *coords=getCoords()->getConstPointer();
3541       const int *connec=getNodalConnectivity()->getConstPointer();
3542       const int *connec_index=getNodalConnectivityIndex()->getConstPointer();
3543       for(int iel=0;iel<nbelem;iel++)
3544         {
3545           ipt=connec_index[iel];
3546           type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3547           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);
3548         }
3549       if(isAbs)
3550         std::transform(area_vol,area_vol+nbelem,area_vol,std::ptr_fun<double,double>(fabs));
3551     }
3552   else
3553     {
3554       area_vol[0]=std::numeric_limits<double>::max();
3555     }
3556   return field.retn();
3557 }
3558
3559 /*!
3560  * Returns a new DataArrayDouble containing volumes of specified cells of \a this
3561  * mesh.<br>
3562  * For 1D cells, the returned array contains lengths.<br>
3563  * For 2D cells, the returned array contains areas.<br>
3564  * For 3D cells, the returned array contains volumes.
3565  * This method avoids building explicitly a part of \a this mesh to perform the work.
3566  *  \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3567  *         orientation, i.e. the volume is always positive.
3568  *  \param [in] begin - an array of cell ids of interest.
3569  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3570  *  \return DataArrayDouble * - a new instance of DataArrayDouble. The caller is to
3571  *          delete this array using decrRef() as it is no more needed.
3572  * 
3573  *  \if ENABLE_EXAMPLES
3574  *  \ref cpp_mcumesh_getPartMeasureField "Here is a C++ example".<br>
3575  *  \ref  py_mcumesh_getPartMeasureField "Here is a Python example".
3576  *  \endif
3577  *  \sa getMeasureField()
3578  */
3579 DataArrayDouble *MEDCouplingUMesh::getPartMeasureField(bool isAbs, const int *begin, const int *end) const
3580 {
3581   std::string name="PartMeasureOfMesh_";
3582   name+=getName();
3583   int nbelem=(int)std::distance(begin,end);
3584   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3585   array->setName(name);
3586   array->alloc(nbelem,1);
3587   double *area_vol=array->getPointer();
3588   if(getMeshDimension()!=-1)
3589     {
3590       int ipt;
3591       INTERP_KERNEL::NormalizedCellType type;
3592       int dim_space=getSpaceDimension();
3593       const double *coords=getCoords()->getConstPointer();
3594       const int *connec=getNodalConnectivity()->getConstPointer();
3595       const int *connec_index=getNodalConnectivityIndex()->getConstPointer();
3596       for(const int *iel=begin;iel!=end;iel++)
3597         {
3598           ipt=connec_index[*iel];
3599           type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3600           *area_vol++=INTERP_KERNEL::computeVolSurfOfCell2<int,INTERP_KERNEL::ALL_C_MODE>(type,connec+ipt+1,connec_index[*iel+1]-ipt-1,coords,dim_space);
3601         }
3602       if(isAbs)
3603         std::transform(array->getPointer(),area_vol,array->getPointer(),std::ptr_fun<double,double>(fabs));
3604     }
3605   else
3606     {
3607       area_vol[0]=std::numeric_limits<double>::max();
3608     }
3609   return array.retn();
3610 }
3611
3612 /*!
3613  * Returns a new MEDCouplingFieldDouble containing volumes of cells of a dual mesh of
3614  * \a this one. The returned field contains the dual cell volume for each corresponding
3615  * node in \a this mesh. In other words, the field returns the getMeasureField() of
3616  *  the dual mesh in P1 sens of \a this.<br>
3617  * For 1D cells, the returned field contains lengths.<br>
3618  * For 2D cells, the returned field contains areas.<br>
3619  * For 3D cells, the returned field contains volumes.
3620  * This method is useful to check "P1*" conservative interpolators.
3621  *  \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3622  *         orientation, i.e. the volume is always positive.
3623  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3624  *          nodes and one time. The caller is to delete this array using decrRef() as
3625  *          it is no more needed.
3626  */
3627 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureFieldOnNode(bool isAbs) const
3628 {
3629   MCAuto<MEDCouplingFieldDouble> tmp=getMeasureField(isAbs);
3630   std::string name="MeasureOnNodeOfMesh_";
3631   name+=getName();
3632   int nbNodes=getNumberOfNodes();
3633   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_NODES);
3634   double cst=1./((double)getMeshDimension()+1.);
3635   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3636   array->alloc(nbNodes,1);
3637   double *valsToFill=array->getPointer();
3638   std::fill(valsToFill,valsToFill+nbNodes,0.);
3639   const double *values=tmp->getArray()->getConstPointer();
3640   MCAuto<DataArrayInt> da=DataArrayInt::New();
3641   MCAuto<DataArrayInt> daInd=DataArrayInt::New();
3642   getReverseNodalConnectivity(da,daInd);
3643   const int *daPtr=da->getConstPointer();
3644   const int *daIPtr=daInd->getConstPointer();
3645   for(int i=0;i<nbNodes;i++)
3646     for(const int *cell=daPtr+daIPtr[i];cell!=daPtr+daIPtr[i+1];cell++)
3647       valsToFill[i]+=cst*values[*cell];
3648   ret->setMesh(this);
3649   ret->setArray(array);
3650   return ret.retn();
3651 }
3652
3653 /*!
3654  * Returns a new MEDCouplingFieldDouble holding normal vectors to cells of \a this
3655  * mesh. The returned normal vectors to each cell have a norm2 equal to 1.
3656  * The computed vectors have <em> this->getMeshDimension()+1 </em> components
3657  * and are normalized.
3658  * <br> \a this can be either 
3659  * - a  2D mesh in 2D or 3D space or 
3660  * - an 1D mesh in 2D space.
3661  * 
3662  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3663  *          cells and one time. The caller is to delete this field using decrRef() as
3664  *          it is no more needed.
3665  *  \throw If the nodal connectivity of cells is not defined.
3666  *  \throw If the coordinates array is not set.
3667  *  \throw If the mesh dimension is not set.
3668  *  \throw If the mesh and space dimension is not as specified above.
3669  */
3670 MEDCouplingFieldDouble *MEDCouplingUMesh::buildOrthogonalField() const
3671 {
3672   if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3673     throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3674   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3675   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3676   int nbOfCells=getNumberOfCells();
3677   int nbComp=getMeshDimension()+1;
3678   array->alloc(nbOfCells,nbComp);
3679   double *vals=array->getPointer();
3680   const int *connI=_nodal_connec_index->getConstPointer();
3681   const int *conn=_nodal_connec->getConstPointer();
3682   const double *coords=_coords->getConstPointer();
3683   if(getMeshDimension()==2)
3684     {
3685       if(getSpaceDimension()==3)
3686         {
3687           MCAuto<DataArrayDouble> loc=computeCellCenterOfMass();
3688           const double *locPtr=loc->getConstPointer();
3689           for(int i=0;i<nbOfCells;i++,vals+=3)
3690             {
3691               int offset=connI[i];
3692               INTERP_KERNEL::crossprod<3>(locPtr+3*i,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3693               double n=INTERP_KERNEL::norm<3>(vals);
3694               std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3695             }
3696         }
3697       else
3698         {
3699           MCAuto<MEDCouplingFieldDouble> isAbs=getMeasureField(false);
3700           const double *isAbsPtr=isAbs->getArray()->begin();
3701           for(int i=0;i<nbOfCells;i++,isAbsPtr++)
3702             { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=*isAbsPtr>0.?1.:-1.; }
3703         }
3704     }
3705   else//meshdimension==1
3706     {
3707       double tmp[2];
3708       for(int i=0;i<nbOfCells;i++)
3709         {
3710           int offset=connI[i];
3711           std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3712           double n=INTERP_KERNEL::norm<2>(tmp);
3713           std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3714           *vals++=-tmp[1];
3715           *vals++=tmp[0];
3716         }
3717     }
3718   ret->setArray(array);
3719   ret->setMesh(this);
3720   ret->synchronizeTimeWithSupport();
3721   return ret.retn();
3722 }
3723
3724 /*!
3725  * Returns a new MEDCouplingFieldDouble holding normal vectors to specified cells of
3726  * \a this mesh. The computed vectors have <em> this->getMeshDimension()+1 </em> components
3727  * and are normalized.
3728  * <br> \a this can be either 
3729  * - a  2D mesh in 2D or 3D space or 
3730  * - an 1D mesh in 2D space.
3731  * 
3732  * This method avoids building explicitly a part of \a this mesh to perform the work.
3733  *  \param [in] begin - an array of cell ids of interest.
3734  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3735  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3736  *          cells and one time. The caller is to delete this field using decrRef() as
3737  *          it is no more needed.
3738  *  \throw If the nodal connectivity of cells is not defined.
3739  *  \throw If the coordinates array is not set.
3740  *  \throw If the mesh dimension is not set.
3741  *  \throw If the mesh and space dimension is not as specified above.
3742  *  \sa buildOrthogonalField()
3743  *
3744  *  \if ENABLE_EXAMPLES
3745  *  \ref cpp_mcumesh_buildPartOrthogonalField "Here is a C++ example".<br>
3746  *  \ref  py_mcumesh_buildPartOrthogonalField "Here is a Python example".
3747  *  \endif
3748  */
3749 MEDCouplingFieldDouble *MEDCouplingUMesh::buildPartOrthogonalField(const int *begin, const int *end) const
3750 {
3751   if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3752     throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3753   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3754   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3755   std::size_t nbelems=std::distance(begin,end);
3756   int nbComp=getMeshDimension()+1;
3757   array->alloc((int)nbelems,nbComp);
3758   double *vals=array->getPointer();
3759   const int *connI=_nodal_connec_index->getConstPointer();
3760   const int *conn=_nodal_connec->getConstPointer();
3761   const double *coords=_coords->getConstPointer();
3762   if(getMeshDimension()==2)
3763     {
3764       if(getSpaceDimension()==3)
3765         {
3766           MCAuto<DataArrayDouble> loc=getPartBarycenterAndOwner(begin,end);
3767           const double *locPtr=loc->getConstPointer();
3768           for(const int *i=begin;i!=end;i++,vals+=3,locPtr+=3)
3769             {
3770               int offset=connI[*i];
3771               INTERP_KERNEL::crossprod<3>(locPtr,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3772               double n=INTERP_KERNEL::norm<3>(vals);
3773               std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3774             }
3775         }
3776       else
3777         {
3778           for(std::size_t i=0;i<nbelems;i++)
3779             { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=1.; }
3780         }
3781     }
3782   else//meshdimension==1
3783     {
3784       double tmp[2];
3785       for(const int *i=begin;i!=end;i++)
3786         {
3787           int offset=connI[*i];
3788           std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3789           double n=INTERP_KERNEL::norm<2>(tmp);
3790           std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3791           *vals++=-tmp[1];
3792           *vals++=tmp[0];
3793         }
3794     }
3795   ret->setArray(array);
3796   ret->setMesh(this);
3797   ret->synchronizeTimeWithSupport();
3798   return ret.retn();
3799 }
3800
3801 /*!
3802  * Returns a new MEDCouplingFieldDouble holding a direction vector for each SEG2 in \a
3803  * this 1D mesh. The computed vectors have <em> this->getSpaceDimension() </em> components
3804  * and are \b not normalized.
3805  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3806  *          cells and one time. The caller is to delete this field using decrRef() as
3807  *          it is no more needed.
3808  *  \throw If the nodal connectivity of cells is not defined.
3809  *  \throw If the coordinates array is not set.
3810  *  \throw If \a this->getMeshDimension() != 1.
3811  *  \throw If \a this mesh includes cells of type other than SEG2.
3812  */
3813 MEDCouplingFieldDouble *MEDCouplingUMesh::buildDirectionVectorField() const
3814 {
3815   if(getMeshDimension()!=1)
3816     throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for buildDirectionVectorField !");
3817   if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3818     throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for buildDirectionVectorField !");
3819   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3820   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3821   int nbOfCells=getNumberOfCells();
3822   int spaceDim=getSpaceDimension();
3823   array->alloc(nbOfCells,spaceDim);
3824   double *pt=array->getPointer();
3825   const double *coo=getCoords()->getConstPointer();
3826   std::vector<int> conn;
3827   conn.reserve(2);
3828   for(int i=0;i<nbOfCells;i++)
3829     {
3830       conn.resize(0);
3831       getNodeIdsOfCell(i,conn);
3832       pt=std::transform(coo+conn[1]*spaceDim,coo+(conn[1]+1)*spaceDim,coo+conn[0]*spaceDim,pt,std::minus<double>());
3833     }
3834   ret->setArray(array);
3835   ret->setMesh(this);
3836   ret->synchronizeTimeWithSupport();
3837   return ret.retn();
3838 }
3839
3840 /*!
3841  * Creates a 2D mesh by cutting \a this 3D mesh with a plane. In addition to the mesh,
3842  * returns a new DataArrayInt, of length equal to the number of 2D cells in the result
3843  * mesh, holding, for each cell in the result mesh, an id of a 3D cell it comes
3844  * from. If a result face is shared by two 3D cells, then the face in included twice in
3845  * the result mesh.
3846  *  \param [in] origin - 3 components of a point defining location of the plane.
3847  *  \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3848  *         must be greater than 1e-6.
3849  *  \param [in] eps - half-thickness of the plane.
3850  *  \param [out] cellIds - a new instance of DataArrayInt holding ids of 3D cells
3851  *         producing correspondent 2D cells. The caller is to delete this array
3852  *         using decrRef() as it is no more needed.
3853  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This mesh does
3854  *         not share the node coordinates array with \a this mesh. The caller is to
3855  *         delete this mesh using decrRef() as it is no more needed.  
3856  *  \throw If the coordinates array is not set.
3857  *  \throw If the nodal connectivity of cells is not defined.
3858  *  \throw If \a this->getMeshDimension() != 3 or \a this->getSpaceDimension() != 3.
3859  *  \throw If magnitude of \a vec is less than 1e-6.
3860  *  \throw If the plane does not intersect any 3D cell of \a this mesh.
3861  *  \throw If \a this includes quadratic cells.
3862  */
3863 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3D(const double *origin, const double *vec, double eps, DataArrayInt *&cellIds) const
3864 {
3865   checkFullyDefined();
3866   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3867     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3868   MCAuto<DataArrayInt> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3869   if(candidates->empty())
3870     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane considering bounding boxes !");
3871   std::vector<int> nodes;
3872   DataArrayInt *cellIds1D=0;
3873   MCAuto<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3874   subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3875   MCAuto<DataArrayInt> desc1=DataArrayInt::New(),desc2=DataArrayInt::New();
3876   MCAuto<DataArrayInt> descIndx1=DataArrayInt::New(),descIndx2=DataArrayInt::New();
3877   MCAuto<DataArrayInt> revDesc1=DataArrayInt::New(),revDesc2=DataArrayInt::New();
3878   MCAuto<DataArrayInt> revDescIndx1=DataArrayInt::New(),revDescIndx2=DataArrayInt::New();
3879   MCAuto<MEDCouplingUMesh> mDesc2=subMesh->buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2);//meshDim==2 spaceDim==3
3880   revDesc2=0; revDescIndx2=0;
3881   MCAuto<MEDCouplingUMesh> mDesc1=mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3882   revDesc1=0; revDescIndx1=0;
3883   mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3884   MCAuto<DataArrayInt> cellIds1DTmp(cellIds1D);
3885   //
3886   std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3887   for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3888     cut3DCurve[*it]=-1;
3889   mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3890   std::vector< std::pair<int,int> > cut3DSurf(mDesc2->getNumberOfCells());
3891   AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->getConstPointer(),mDesc2->getNodalConnectivityIndex()->getConstPointer(),
3892                               mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3893                               desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3894   MCAuto<DataArrayInt> conn(DataArrayInt::New()),connI(DataArrayInt::New()),cellIds2(DataArrayInt::New());
3895   connI->pushBackSilent(0); conn->alloc(0,1); cellIds2->alloc(0,1);
3896   subMesh->assemblyForSplitFrom3DSurf(cut3DSurf,desc2->getConstPointer(),descIndx2->getConstPointer(),conn,connI,cellIds2);
3897   if(cellIds2->empty())
3898     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3899   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3D",2);
3900   ret->setCoords(mDesc1->getCoords());
3901   ret->setConnectivity(conn,connI,true);
3902   cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3903   return ret.retn();
3904 }
3905
3906 /*!
3907  * Creates an 1D mesh by cutting \a this 2D mesh in 3D space with a plane. In
3908 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
3909 from. If a result segment is shared by two 2D cells, then the segment in included twice in
3910 the result mesh.
3911  *  \param [in] origin - 3 components of a point defining location of the plane.
3912  *  \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3913  *         must be greater than 1e-6.
3914  *  \param [in] eps - half-thickness of the plane.
3915  *  \param [out] cellIds - a new instance of DataArrayInt holding ids of faces
3916  *         producing correspondent segments. The caller is to delete this array
3917  *         using decrRef() as it is no more needed.
3918  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This is an 1D
3919  *         mesh in 3D space. This mesh does not share the node coordinates array with
3920  *         \a this mesh. The caller is to delete this mesh using decrRef() as it is
3921  *         no more needed. 
3922  *  \throw If the coordinates array is not set.
3923  *  \throw If the nodal connectivity of cells is not defined.
3924  *  \throw If \a this->getMeshDimension() != 2 or \a this->getSpaceDimension() != 3.
3925  *  \throw If magnitude of \a vec is less than 1e-6.
3926  *  \throw If the plane does not intersect any 2D cell of \a this mesh.
3927  *  \throw If \a this includes quadratic cells.
3928  */
3929 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3DSurf(const double *origin, const double *vec, double eps, DataArrayInt *&cellIds) const
3930 {
3931   checkFullyDefined();
3932   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
3933     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf works on umeshes with meshdim equal to 2 and spaceDim equal to 3 !");
3934   MCAuto<DataArrayInt> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3935   if(candidates->empty())
3936     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3D surf cells in this intercepts the specified plane considering bounding boxes !");
3937   std::vector<int> nodes;
3938   DataArrayInt *cellIds1D=0;
3939   MCAuto<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3940   subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3941   MCAuto<DataArrayInt> desc1=DataArrayInt::New();
3942   MCAuto<DataArrayInt> descIndx1=DataArrayInt::New();
3943   MCAuto<DataArrayInt> revDesc1=DataArrayInt::New();
3944   MCAuto<DataArrayInt> revDescIndx1=DataArrayInt::New();
3945   MCAuto<MEDCouplingUMesh> mDesc1=subMesh->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3946   mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3947   MCAuto<DataArrayInt> cellIds1DTmp(cellIds1D);
3948   //
3949   std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3950   for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3951     cut3DCurve[*it]=-1;
3952   mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3953   int ncellsSub=subMesh->getNumberOfCells();
3954   std::vector< std::pair<int,int> > cut3DSurf(ncellsSub);
3955   AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,subMesh->getNodalConnectivity()->getConstPointer(),subMesh->getNodalConnectivityIndex()->getConstPointer(),
3956                               mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3957                               desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3958   MCAuto<DataArrayInt> conn(DataArrayInt::New()),connI(DataArrayInt::New()),cellIds2(DataArrayInt::New()); connI->pushBackSilent(0);
3959   conn->alloc(0,1);
3960   const int *nodal=subMesh->getNodalConnectivity()->getConstPointer();
3961   const int *nodalI=subMesh->getNodalConnectivityIndex()->getConstPointer();
3962   for(int i=0;i<ncellsSub;i++)
3963     {
3964       if(cut3DSurf[i].first!=-1 && cut3DSurf[i].second!=-1)
3965         {
3966           if(cut3DSurf[i].first!=-2)
3967             {
3968               conn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG2); conn->pushBackSilent(cut3DSurf[i].first); conn->pushBackSilent(cut3DSurf[i].second);
3969               connI->pushBackSilent(conn->getNumberOfTuples());
3970               cellIds2->pushBackSilent(i);
3971             }
3972           else
3973             {
3974               int cellId3DSurf=cut3DSurf[i].second;
3975               int offset=nodalI[cellId3DSurf]+1;
3976               int nbOfEdges=nodalI[cellId3DSurf+1]-offset;
3977               for(int j=0;j<nbOfEdges;j++)
3978                 {
3979                   conn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG2); conn->pushBackSilent(nodal[offset+j]); conn->pushBackSilent(nodal[offset+(j+1)%nbOfEdges]);
3980                   connI->pushBackSilent(conn->getNumberOfTuples());
3981                   cellIds2->pushBackSilent(cellId3DSurf);
3982                 }
3983             }
3984         }
3985     }
3986   if(cellIds2->empty())
3987     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3DSurf cells in this intercepts the specified plane !");
3988   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3DSurf",1);
3989   ret->setCoords(mDesc1->getCoords());
3990   ret->setConnectivity(conn,connI,true);
3991   cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3992   return ret.retn();
3993 }
3994
3995 /*!
3996  * Finds cells whose bounding boxes intersect a given plane.
3997  *  \param [in] origin - 3 components of a point defining location of the plane.
3998  *  \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3999  *         must be greater than 1e-6.
4000  *  \param [in] eps - half-thickness of the plane.
4001  *  \return DataArrayInt * - a new instance of DataArrayInt holding ids of the found
4002  *         cells. The caller is to delete this array using decrRef() as it is no more
4003  *         needed.
4004  *  \throw If the coordinates array is not set.
4005  *  \throw If the nodal connectivity of cells is not defined.
4006  *  \throw If \a this->getSpaceDimension() != 3.
4007  *  \throw If magnitude of \a vec is less than 1e-6.
4008  *  \sa buildSlice3D()
4009  */
4010 DataArrayInt *MEDCouplingUMesh::getCellIdsCrossingPlane(const double *origin, const double *vec, double eps) const
4011 {
4012   checkFullyDefined();
4013   if(getSpaceDimension()!=3)
4014     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with spaceDim equal to 3 !");
4015   double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
4016   if(normm<1e-6)
4017     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellIdsCrossingPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
4018   double vec2[3];
4019   vec2[0]=vec[1]; vec2[1]=-vec[0]; vec2[2]=0.;//vec2 is the result of cross product of vec with (0,0,1)
4020   double angle=acos(vec[2]/normm);
4021   MCAuto<DataArrayInt> cellIds;
4022   double bbox[6];
4023   if(angle>eps)
4024     {
4025       MCAuto<DataArrayDouble> coo=_coords->deepCopy();
4026       double normm2(sqrt(vec2[0]*vec2[0]+vec2[1]*vec2[1]+vec2[2]*vec2[2]));
4027       if(normm2/normm>1e-6)
4028         MEDCouplingPointSet::Rotate3DAlg(origin,vec2,angle,coo->getNumberOfTuples(),coo->getPointer());
4029       MCAuto<MEDCouplingUMesh> mw=clone(false);//false -> shallow copy
4030       mw->setCoords(coo);
4031       mw->getBoundingBox(bbox);
4032       bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
4033       cellIds=mw->getCellsInBoundingBox(bbox,eps);
4034     }
4035   else
4036     {
4037       getBoundingBox(bbox);
4038       bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
4039       cellIds=getCellsInBoundingBox(bbox,eps);
4040     }
4041   return cellIds.retn();
4042 }
4043
4044 /*!
4045  * This method checks that \a this is a contiguous mesh. The user is expected to call this method on a mesh with meshdim==1.
4046  * If not an exception will thrown. If this is an empty mesh with no cell an exception will be thrown too.
4047  * No consideration of coordinate is done by this method.
4048  * 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)
4049  * If not false is returned. In case that false is returned a call to MEDCoupling::MEDCouplingUMesh::mergeNodes could be usefull.
4050  */
4051 bool MEDCouplingUMesh::isContiguous1D() const
4052 {
4053   if(getMeshDimension()!=1)
4054     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense only for 1D mesh !");
4055   int nbCells=getNumberOfCells();
4056   if(nbCells<1)
4057     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense for non empty mesh !");
4058   const int *connI=_nodal_connec_index->getConstPointer();
4059   const int *conn=_nodal_connec->getConstPointer();
4060   int ref=conn[connI[0]+2];
4061   for(int i=1;i<nbCells;i++)
4062     {
4063       if(conn[connI[i]+1]!=ref)
4064         return false;
4065       ref=conn[connI[i]+2];
4066     }
4067   return true;
4068 }
4069
4070 /*!
4071  * This method is only callable on mesh with meshdim == 1 containing only SEG2 and spaceDim==3.
4072  * This method projects this on the 3D line defined by (pt,v). This methods first checks that all SEG2 are along v vector.
4073  * \param pt reference point of the line
4074  * \param v normalized director vector of the line
4075  * \param eps max precision before throwing an exception
4076  * \param res output of size this->getNumberOfCells
4077  */
4078 void MEDCouplingUMesh::project1D(const double *pt, const double *v, double eps, double *res) const
4079 {
4080   if(getMeshDimension()!=1)
4081     throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for project1D !");
4082   if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
4083     throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for project1D !");
4084   if(getSpaceDimension()!=3)
4085     throw INTERP_KERNEL::Exception("Expected a umesh with spaceDim==3 for project1D !");
4086   MCAuto<MEDCouplingFieldDouble> f=buildDirectionVectorField();
4087   const double *fPtr=f->getArray()->getConstPointer();
4088   double tmp[3];
4089   for(int i=0;i<getNumberOfCells();i++)
4090     {
4091       const double *tmp1=fPtr+3*i;
4092       tmp[0]=tmp1[1]*v[2]-tmp1[2]*v[1];
4093       tmp[1]=tmp1[2]*v[0]-tmp1[0]*v[2];
4094       tmp[2]=tmp1[0]*v[1]-tmp1[1]*v[0];
4095       double n1=INTERP_KERNEL::norm<3>(tmp);
4096       n1/=INTERP_KERNEL::norm<3>(tmp1);
4097       if(n1>eps)
4098         throw INTERP_KERNEL::Exception("UMesh::Projection 1D failed !");
4099     }
4100   const double *coo=getCoords()->getConstPointer();
4101   for(int i=0;i<getNumberOfNodes();i++)
4102     {
4103       std::transform(coo+i*3,coo+i*3+3,pt,tmp,std::minus<double>());
4104       std::transform(tmp,tmp+3,v,tmp,std::multiplies<double>());
4105       res[i]=std::accumulate(tmp,tmp+3,0.);
4106     }
4107 }
4108
4109 /*!
4110  * 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. 
4111  * \a this is expected to be a mesh so that its space dimension is equal to its
4112  * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4113  * 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).
4114  *
4115  * 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
4116  * 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).
4117  * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4118  *
4119  * So this method is more accurate (so, more costly) than simply searching for the closest point in \a this.
4120  * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4121  *
4122  * \param [in] ptBg the start pointer (included) of the coordinates of the point
4123  * \param [in] ptEnd the end pointer (not included) of the coordinates of the point
4124  * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4125  * \return the positive value of the distance.
4126  * \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
4127  * dimension - 1.
4128  * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoints
4129  */
4130 double MEDCouplingUMesh::distanceToPoint(const double *ptBg, const double *ptEnd, int& cellId) const
4131 {
4132   int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4133   if(meshDim!=spaceDim-1)
4134     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint works only for spaceDim=meshDim+1 !");
4135   if(meshDim!=2 && meshDim!=1)
4136     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint : only mesh dimension 2 and 1 are implemented !");
4137   checkFullyDefined();
4138   if((int)std::distance(ptBg,ptEnd)!=spaceDim)
4139     { std::ostringstream oss; oss << "MEDCouplingUMesh::distanceToPoint : input point has to have dimension equal to the space dimension of this (" << spaceDim << ") !"; throw INTERP_KERNEL::Exception(oss.str().c_str()); }
4140   DataArrayInt *ret1=0;
4141   MCAuto<DataArrayDouble> pts=DataArrayDouble::New(); pts->useArray(ptBg,false,C_DEALLOC,1,spaceDim);
4142   MCAuto<DataArrayDouble> ret0=distanceToPoints(pts,ret1);
4143   MCAuto<DataArrayInt> ret1Safe(ret1);
4144   cellId=*ret1Safe->begin();
4145   return *ret0->begin();
4146 }
4147
4148 /*!
4149  * This method computes the distance from each point of points serie \a pts (stored in a DataArrayDouble in which each tuple represents a point)
4150  *  to \a this  and the first \a cellId in \a this corresponding to the returned distance. 
4151  * 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
4152  * 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).
4153  * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4154  * 
4155  * \a this is expected to be a mesh so that its space dimension is equal to its
4156  * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4157  * 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).
4158  *
4159  * So this method is more accurate (so, more costly) than simply searching for each point in \a pts the closest point in \a this.
4160  * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4161  *
4162  * \param [in] pts the list of points in which each tuple represents a point
4163  * \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.
4164  * \return a newly allocated object to be dealed by the caller that tells for each point in \a pts the distance to \a this.
4165  * \throw if number of components of \a pts is not equal to the space dimension.
4166  * \throw if mesh dimension of \a this is not equal to space dimension - 1.
4167  * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoint
4168  */
4169 DataArrayDouble *MEDCouplingUMesh::distanceToPoints(const DataArrayDouble *pts, DataArrayInt *& cellIds) const
4170 {
4171   if(!pts)
4172     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : input points pointer is NULL !");
4173   pts->checkAllocated();
4174   int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4175   if(meshDim!=spaceDim-1)
4176     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints works only for spaceDim=meshDim+1 !");
4177   if(meshDim!=2 && meshDim!=1)
4178     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only mesh dimension 2 and 1 are implemented !");
4179   if(pts->getNumberOfComponents()!=spaceDim)
4180     {
4181       std::ostringstream oss; oss << "MEDCouplingUMesh::distanceToPoints : input pts DataArrayDouble has " << pts->getNumberOfComponents() << " components whereas it should be equal to " << spaceDim << " (mesh spaceDimension) !";
4182       throw INTERP_KERNEL::Exception(oss.str().c_str());
4183     }
4184   checkFullyDefined();
4185   int nbCells=getNumberOfCells();
4186   if(nbCells==0)
4187     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : no cells in this !");
4188   int nbOfPts=pts->getNumberOfTuples();
4189   MCAuto<DataArrayDouble> ret0=DataArrayDouble::New(); ret0->alloc(nbOfPts,1);
4190   MCAuto<DataArrayInt> ret1=DataArrayInt::New(); ret1->alloc(nbOfPts,1);
4191   const int *nc=_nodal_connec->begin(),*ncI=_nodal_connec_index->begin(); const double *coords=_coords->begin();
4192   double *ret0Ptr=ret0->getPointer(); int *ret1Ptr=ret1->getPointer(); const double *ptsPtr=pts->begin();
4193   MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree());
4194   const double *bbox(bboxArr->begin());
4195   switch(spaceDim)
4196   {
4197     case 3:
4198       {
4199         BBTreeDst<3> myTree(bbox,0,0,nbCells);
4200         for(int i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=3)
4201           {
4202             double x=std::numeric_limits<double>::max();
4203             std::vector<int> elems;
4204             myTree.getMinDistanceOfMax(ptsPtr,x);
4205             myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4206             DistanceToPoint3DSurfAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4207           }
4208         break;
4209       }
4210     case 2:
4211       {
4212         BBTreeDst<2> myTree(bbox,0,0,nbCells);
4213         for(int i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=2)
4214           {
4215             double x=std::numeric_limits<double>::max();
4216             std::vector<int> elems;
4217             myTree.getMinDistanceOfMax(ptsPtr,x);
4218             myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4219             DistanceToPoint2DCurveAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4220           }
4221         break;
4222       }
4223     default:
4224       throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only spacedim 2 and 3 supported !");
4225   }
4226   cellIds=ret1.retn();
4227   return ret0.retn();
4228 }
4229
4230 /// @cond INTERNAL
4231
4232 /*!
4233  * \param [in] pt the start pointer (included) of the coordinates of the point
4234  * \param [in] cellIdsBg the start pointer (included) of cellIds
4235  * \param [in] cellIdsEnd the end pointer (excluded) of cellIds
4236  * \param [in] nc nodal connectivity
4237  * \param [in] ncI nodal connectivity index
4238  * \param [in,out] ret0 the min distance between \a this and the external input 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  * \sa MEDCouplingUMesh::distanceToPoint, MEDCouplingUMesh::distanceToPoints
4241  */
4242 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)
4243 {
4244   cellId=-1;
4245   ret0=std::numeric_limits<double>::max();
4246   for(const int *zeCell=cellIdsBg;zeCell!=cellIdsEnd;zeCell++)
4247     {
4248       switch((INTERP_KERNEL::NormalizedCellType)nc[ncI[*zeCell]])
4249       {
4250         case INTERP_KERNEL::NORM_TRI3:
4251           {
4252             double tmp=INTERP_KERNEL::DistanceFromPtToTriInSpaceDim3(pt,coords+3*nc[ncI[*zeCell]+1],coords+3*nc[ncI[*zeCell]+2],coords+3*nc[ncI[*zeCell]+3]);
4253             if(tmp<ret0)
4254               { ret0=tmp; cellId=*zeCell; }
4255             break;
4256           }
4257         case INTERP_KERNEL::NORM_QUAD4:
4258         case INTERP_KERNEL::NORM_POLYGON:
4259           {
4260             double tmp=INTERP_KERNEL::DistanceFromPtToPolygonInSpaceDim3(pt,nc+ncI[*zeCell]+1,nc+ncI[*zeCell+1],coords);
4261             if(tmp<ret0)
4262               { ret0=tmp; cellId=*zeCell; }
4263             break;
4264           }
4265         default:
4266           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint3DSurfAlg : not managed cell type ! Supporting TRI3, QUAD4 and POLYGON !");
4267       }
4268     }
4269 }
4270
4271 /*!
4272  * \param [in] pt the start pointer (included) of the coordinates of the point
4273  * \param [in] cellIdsBg the start pointer (included) of cellIds
4274  * \param [in] cellIdsEnd the end pointer (excluded) of cellIds
4275  * \param [in] nc nodal connectivity
4276  * \param [in] ncI nodal connectivity index
4277  * \param [in,out] ret0 the min distance between \a this and the external input point
4278  * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4279  * \sa MEDCouplingUMesh::distanceToPoint, MEDCouplingUMesh::distanceToPoints
4280  */
4281 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)
4282 {
4283   cellId=-1;
4284   ret0=std::numeric_limits<double>::max();
4285   for(const int *zeCell=cellIdsBg;zeCell!=cellIdsEnd;zeCell++)
4286     {
4287       switch((INTERP_KERNEL::NormalizedCellType)nc[ncI[*zeCell]])
4288       {
4289         case INTERP_KERNEL::NORM_SEG2:
4290           {
4291             std::size_t uselessEntry=0;
4292             double tmp=INTERP_KERNEL::SquareDistanceFromPtToSegInSpaceDim2(pt,coords+2*nc[ncI[*zeCell]+1],coords+2*nc[ncI[*zeCell]+2],uselessEntry);
4293             tmp=sqrt(tmp);
4294             if(tmp<ret0)
4295               { ret0=tmp; cellId=*zeCell; }
4296             break;
4297           }
4298         default:
4299           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint2DCurveAlg : not managed cell type ! Supporting SEG2 !");
4300       }
4301     }
4302 }
4303 /// @endcond
4304
4305 /*!
4306  * Finds cells in contact with a ball (i.e. a point with precision). 
4307  * 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.
4308  * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4309  *
4310  * \warning This method is suitable if the caller intends to evaluate only one
4311  *          point, for more points getCellsContainingPoints() is recommended as it is
4312  *          faster. 
4313  *  \param [in] pos - array of coordinates of the ball central point.
4314  *  \param [in] eps - ball radius.
4315  *  \return int - a smallest id of cells being in contact with the ball, -1 in case
4316  *         if there are no such cells.
4317  *  \throw If the coordinates array is not set.
4318  *  \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4319  */
4320 int MEDCouplingUMesh::getCellContainingPoint(const double *pos, double eps) const
4321 {
4322   std::vector<int> elts;
4323   getCellsContainingPoint(pos,eps,elts);
4324   if(elts.empty())
4325     return -1;
4326   return elts.front();
4327 }
4328
4329 /*!
4330  * Finds cells in contact with a ball (i.e. a point with precision).
4331  * 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.
4332  * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4333  * \warning This method is suitable if the caller intends to evaluate only one
4334  *          point, for more points getCellsContainingPoints() is recommended as it is
4335  *          faster. 
4336  *  \param [in] pos - array of coordinates of the ball central point.
4337  *  \param [in] eps - ball radius.
4338  *  \param [out] elts - vector returning ids of the found cells. It is cleared
4339  *         before inserting ids.
4340  *  \throw If the coordinates array is not set.
4341  *  \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4342  *
4343  *  \if ENABLE_EXAMPLES
4344  *  \ref cpp_mcumesh_getCellsContainingPoint "Here is a C++ example".<br>
4345  *  \ref  py_mcumesh_getCellsContainingPoint "Here is a Python example".
4346  *  \endif
4347  */
4348 void MEDCouplingUMesh::getCellsContainingPoint(const double *pos, double eps, std::vector<int>& elts) const
4349 {
4350   MCAuto<DataArrayInt> eltsUg,eltsIndexUg;
4351   getCellsContainingPoints(pos,1,eps,eltsUg,eltsIndexUg);
4352   elts.clear(); elts.insert(elts.end(),eltsUg->begin(),eltsUg->end());
4353 }
4354
4355 /// @cond INTERNAL
4356
4357 namespace MEDCoupling
4358 {
4359   template<const int SPACEDIMM>
4360   class DummyClsMCUG
4361   {
4362   public:
4363     static const int MY_SPACEDIM=SPACEDIMM;
4364     static const int MY_MESHDIM=8;
4365     typedef int MyConnType;
4366     static const INTERP_KERNEL::NumberingPolicy My_numPol=INTERP_KERNEL::ALL_C_MODE;
4367     // begin
4368     // useless, but for windows compilation ...
4369     const double* getCoordinatesPtr() const { return 0; }
4370     const int* getConnectivityPtr() const { return 0; }
4371     const int* getConnectivityIndexPtr() const { return 0; }
4372     INTERP_KERNEL::NormalizedCellType getTypeOfElement(int) const { return (INTERP_KERNEL::NormalizedCellType)0; }
4373     // end
4374   };
4375
4376   INTERP_KERNEL::Edge *MEDCouplingUMeshBuildQPFromEdge2(INTERP_KERNEL::NormalizedCellType typ, const int *bg, const double *coords2D, std::map< MCAuto<INTERP_KERNEL::Node>,int>& m)
4377   {
4378     INTERP_KERNEL::Edge *ret(0);
4379     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]));
4380     m[n0]=bg[0]; m[n1]=bg[1];
4381     switch(typ)
4382     {
4383       case INTERP_KERNEL::NORM_SEG2:
4384         {
4385           ret=new INTERP_KERNEL::EdgeLin(n0,n1);
4386           break;
4387         }
4388       case INTERP_KERNEL::NORM_SEG3:
4389         {
4390           INTERP_KERNEL::Node *n2(new INTERP_KERNEL::Node(coords2D[2*bg[2]],coords2D[2*bg[2]+1])); m[n2]=bg[2];
4391           INTERP_KERNEL::EdgeLin *e1(new INTERP_KERNEL::EdgeLin(n0,n2)),*e2(new INTERP_KERNEL::EdgeLin(n2,n1));
4392           INTERP_KERNEL::SegSegIntersector inters(*e1,*e2);
4393           // is the SEG3 degenerated, and thus can be reduced to a SEG2?
4394           bool colinearity(inters.areColinears());
4395           delete e1; delete e2;
4396           if(colinearity)
4397             { ret=new INTERP_KERNEL::EdgeLin(n0,n1); }
4398           else
4399             { ret=new INTERP_KERNEL::EdgeArcCircle(n0,n2,n1); }
4400           break;
4401         }
4402       default:
4403         throw INTERP_KERNEL::Exception("MEDCouplingUMeshBuildQPFromEdge2 : Expecting a mesh with spaceDim==2 and meshDim==1 !");
4404     }
4405     return ret;
4406   }
4407
4408   INTERP_KERNEL::Edge *MEDCouplingUMeshBuildQPFromEdge(INTERP_KERNEL::NormalizedCellType typ, std::map<int, std::pair<INTERP_KERNEL::Node *,bool> >& mapp2, const int *bg)
4409   {
4410     INTERP_KERNEL::Edge *ret=0;
4411     switch(typ)
4412     {
4413       case INTERP_KERNEL::NORM_SEG2:
4414         {
4415           ret=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[1]].first);
4416           break;
4417         }
4418       case INTERP_KERNEL::NORM_SEG3:
4419         {
4420           INTERP_KERNEL::EdgeLin *e1=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[2]].first);
4421           INTERP_KERNEL::EdgeLin *e2=new INTERP_KERNEL::EdgeLin(mapp2[bg[2]].first,mapp2[bg[1]].first);
4422           INTERP_KERNEL::SegSegIntersector inters(*e1,*e2);
4423           // is the SEG3 degenerated, and thus can be reduced to a SEG2?
4424           bool colinearity=inters.areColinears();
4425           delete e1; delete e2;
4426           if(colinearity)
4427             ret=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[1]].first);
4428           else
4429             ret=new INTERP_KERNEL::EdgeArcCircle(mapp2[bg[0]].first,mapp2[bg[2]].first,mapp2[bg[1]].first);
4430           mapp2[bg[2]].second=false;
4431           break;
4432         }
4433       default:
4434         throw INTERP_KERNEL::Exception("MEDCouplingUMeshBuildQPFromEdge : Expecting a mesh with spaceDim==2 and meshDim==1 !");
4435     }
4436     return ret;
4437   }
4438
4439   /*!
4440    * This method creates a sub mesh in Geometric2D DS. The sub mesh is composed by the sub set of cells in 'candidates' taken from
4441    * the global mesh 'mDesc'.
4442    * The input mesh 'mDesc' must be so that mDim==1 and spaceDim==2.
4443    * 'mapp' returns a mapping between local numbering in submesh (represented by a Node*) and the global node numbering in 'mDesc'.
4444    */
4445   INTERP_KERNEL::QuadraticPolygon *MEDCouplingUMeshBuildQPFromMesh(const MEDCouplingUMesh *mDesc, const std::vector<int>& candidates,
4446                                                                    std::map<INTERP_KERNEL::Node *,int>& mapp)
4447   {
4448     mapp.clear();
4449     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.
4450     const double *coo=mDesc->getCoords()->getConstPointer();
4451     const int *c=mDesc->getNodalConnectivity()->getConstPointer();
4452     const int *cI=mDesc->getNodalConnectivityIndex()->getConstPointer();
4453     std::set<int> s;
4454     for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
4455       s.insert(c+cI[*it]+1,c+cI[(*it)+1]);
4456     for(std::set<int>::const_iterator it2=s.begin();it2!=s.end();it2++)
4457       {
4458         INTERP_KERNEL::Node *n=new INTERP_KERNEL::Node(coo[2*(*it2)],coo[2*(*it2)+1]);
4459         mapp2[*it2]=std::pair<INTERP_KERNEL::Node *,bool>(n,true);
4460       }
4461     INTERP_KERNEL::QuadraticPolygon *ret=new INTERP_KERNEL::QuadraticPolygon;
4462     for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
4463       {
4464         INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[*it]];
4465         ret->pushBack(MEDCouplingUMeshBuildQPFromEdge(typ,mapp2,c+cI[*it]+1));
4466       }
4467     for(std::map<int, std::pair<INTERP_KERNEL::Node *,bool> >::const_iterator it2=mapp2.begin();it2!=mapp2.end();it2++)
4468       {
4469         if((*it2).second.second)
4470           mapp[(*it2).second.first]=(*it2).first;
4471         ((*it2).second.first)->decrRef();
4472       }
4473     return ret;
4474   }
4475
4476   INTERP_KERNEL::Node *MEDCouplingUMeshBuildQPNode(int nodeId, const double *coo1, int offset1, const double *coo2, int offset2, const std::vector<double>& addCoo)
4477   {
4478     if(nodeId>=offset2)
4479       {
4480         int locId=nodeId-offset2;
4481         return new INTERP_KERNEL::Node(addCoo[2*locId],addCoo[2*locId+1]);
4482       }
4483     if(nodeId>=offset1)
4484       {
4485         int locId=nodeId-offset1;
4486         return new INTERP_KERNEL::Node(coo2[2*locId],coo2[2*locId+1]);
4487       }
4488     return new INTERP_KERNEL::Node(coo1[2*nodeId],coo1[2*nodeId+1]);
4489   }
4490
4491   /**
4492    * Construct a mapping between set of Nodes and the standart MEDCoupling connectivity format (c, cI).
4493    */
4494   void MEDCouplingUMeshBuildQPFromMesh3(const double *coo1, int offset1, const double *coo2, int offset2, const std::vector<double>& addCoo,
4495                                         const int *desc1Bg, const int *desc1End, const std::vector<std::vector<int> >& intesctEdges1,
4496                                         /*output*/std::map<INTERP_KERNEL::Node *,int>& mapp, std::map<int,INTERP_KERNEL::Node *>& mappRev)
4497   {
4498     for(const int *desc1=desc1Bg;desc1!=desc1End;desc1++)
4499       {
4500         int eltId1=abs(*desc1)-1;
4501         for(std::vector<int>::const_iterator it1=intesctEdges1[eltId1].begin();it1!=intesctEdges1[eltId1].end();it1++)
4502           {
4503             std::map<int,INTERP_KERNEL::Node *>::const_iterator it=mappRev.find(*it1);
4504             if(it==mappRev.end())
4505               {
4506                 INTERP_KERNEL::Node *node=MEDCouplingUMeshBuildQPNode(*it1,coo1,offset1,coo2,offset2,addCoo);
4507                 mapp[node]=*it1;
4508                 mappRev[*it1]=node;
4509               }
4510           }
4511       }
4512   }
4513 }
4514
4515 /// @endcond
4516
4517 template<int SPACEDIM>
4518 void MEDCouplingUMesh::getCellsContainingPointsAlg(const double *coords, const double *pos, int nbOfPoints,
4519                                                    double eps, MCAuto<DataArrayInt>& elts, MCAuto<DataArrayInt>& eltsIndex) const
4520 {
4521   elts=DataArrayInt::New(); eltsIndex=DataArrayInt::New(); eltsIndex->alloc(nbOfPoints+1,1); eltsIndex->setIJ(0,0,0); elts->alloc(0,1);
4522   int *eltsIndexPtr(eltsIndex->getPointer());
4523   MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree(eps));
4524   const double *bbox(bboxArr->begin());
4525   int nbOfCells=getNumberOfCells();
4526   const int *conn=_nodal_connec->getConstPointer();
4527   const int *connI=_nodal_connec_index->getConstPointer();
4528   double bb[2*SPACEDIM];
4529   BBTree<SPACEDIM,int> myTree(&bbox[0],0,0,nbOfCells,-eps);
4530   for(int i=0;i<nbOfPoints;i++)
4531     {
4532       eltsIndexPtr[i+1]=eltsIndexPtr[i];
4533       for(int j=0;j<SPACEDIM;j++)
4534         {
4535           bb[2*j]=pos[SPACEDIM*i+j];
4536           bb[2*j+1]=pos[SPACEDIM*i+j];
4537         }
4538       std::vector<int> candidates;
4539       myTree.getIntersectingElems(bb,candidates);
4540       for(std::vector<int>::const_iterator iter=candidates.begin();iter!=candidates.end();iter++)
4541         {
4542           int sz(connI[(*iter)+1]-connI[*iter]-1);
4543           INTERP_KERNEL::NormalizedCellType ct((INTERP_KERNEL::NormalizedCellType)conn[connI[*iter]]);
4544           bool status(false);
4545           if(ct!=INTERP_KERNEL::NORM_POLYGON && ct!=INTERP_KERNEL::NORM_QPOLYG)
4546             status=INTERP_KERNEL::PointLocatorAlgos<DummyClsMCUG<SPACEDIM> >::isElementContainsPoint(pos+i*SPACEDIM,ct,coords,conn+connI[*iter]+1,sz,eps);
4547           else
4548             {
4549               if(SPACEDIM!=2)
4550                 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPointsAlg : not implemented yet for POLYGON and QPOLYGON in spaceDim 3 !");
4551               INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
4552               INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
4553               std::vector<INTERP_KERNEL::Node *> nodes(sz);
4554               INTERP_KERNEL::QuadraticPolygon *pol(0);
4555               for(int j=0;j<sz;j++)
4556                 {
4557                   int nodeId(conn[connI[*iter]+1+j]);
4558                   nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*SPACEDIM],coords[nodeId*SPACEDIM+1]);
4559                 }
4560               if(!INTERP_KERNEL::CellModel::GetCellModel(ct).isQuadratic())
4561                 pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
4562               else
4563                 pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
4564               INTERP_KERNEL::Node *n(new INTERP_KERNEL::Node(pos[i*SPACEDIM],pos[i*SPACEDIM+1]));
4565               double a(0.),b(0.),c(0.);
4566               a=pol->normalizeMe(b,c); n->applySimilarity(b,c,a);
4567               status=pol->isInOrOut2(n);
4568               delete pol; n->decrRef();
4569             }
4570           if(status)
4571             {
4572               eltsIndexPtr[i+1]++;
4573               elts->pushBackSilent(*iter);
4574             }
4575         }
4576     }
4577 }
4578 /*!
4579  * Finds cells in contact with several balls (i.e. points with precision).
4580  * This method is an extension of getCellContainingPoint() and
4581  * getCellsContainingPoint() for the case of multiple points.
4582  * 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.
4583  * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4584  *  \param [in] pos - an array of coordinates of points in full interlace mode :
4585  *         X0,Y0,Z0,X1,Y1,Z1,... Size of the array must be \a
4586  *         this->getSpaceDimension() * \a nbOfPoints 
4587  *  \param [in] nbOfPoints - number of points to locate within \a this mesh.
4588  *  \param [in] eps - radius of balls (i.e. the precision).
4589  *  \param [out] elts - vector returning ids of found cells.
4590  *  \param [out] eltsIndex - an array, of length \a nbOfPoints + 1,
4591  *         dividing cell ids in \a elts into groups each referring to one
4592  *         point. Its every element (except the last one) is an index pointing to the
4593  *         first id of a group of cells. For example cells in contact with the *i*-th
4594  *         point are described by following range of indices:
4595  *         [ \a eltsIndex[ *i* ], \a eltsIndex[ *i*+1 ] ) and the cell ids are
4596  *         \a elts[ \a eltsIndex[ *i* ]], \a elts[ \a eltsIndex[ *i* ] + 1 ], ...
4597  *         Number of cells in contact with the *i*-th point is
4598  *         \a eltsIndex[ *i*+1 ] - \a eltsIndex[ *i* ].
4599  *  \throw If the coordinates array is not set.
4600  *  \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4601  *
4602  *  \if ENABLE_EXAMPLES
4603  *  \ref cpp_mcumesh_getCellsContainingPoints "Here is a C++ example".<br>
4604  *  \ref  py_mcumesh_getCellsContainingPoints "Here is a Python example".
4605  *  \endif
4606  */
4607 void MEDCouplingUMesh::getCellsContainingPoints(const double *pos, int nbOfPoints, double eps,
4608                                                 MCAuto<DataArrayInt>& elts, MCAuto<DataArrayInt>& eltsIndex) const
4609 {
4610   int spaceDim=getSpaceDimension();
4611   int mDim=getMeshDimension();
4612   if(spaceDim==3)
4613     {
4614       if(mDim==3)
4615         {
4616           const double *coords=_coords->getConstPointer();
4617           getCellsContainingPointsAlg<3>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4618         }
4619       /*else if(mDim==2)
4620         {
4621
4622         }*/
4623       else
4624         throw INTERP_KERNEL::Exception("For spaceDim==3 only meshDim==3 implemented for getelementscontainingpoints !");
4625     }
4626   else if(spaceDim==2)
4627     {
4628       if(mDim==2)
4629         {
4630           const double *coords=_coords->getConstPointer();
4631           getCellsContainingPointsAlg<2>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4632         }
4633       else
4634         throw INTERP_KERNEL::Exception("For spaceDim==2 only meshDim==2 implemented for getelementscontainingpoints !");
4635     }
4636   else if(spaceDim==1)
4637     {
4638       if(mDim==1)
4639         {
4640           const double *coords=_coords->getConstPointer();
4641           getCellsContainingPointsAlg<1>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4642         }
4643       else
4644         throw INTERP_KERNEL::Exception("For spaceDim==1 only meshDim==1 implemented for getelementscontainingpoints !");
4645     }
4646   else
4647     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPoints : not managed for mdim not in [1,2,3] !");
4648 }
4649
4650 /*!
4651  * Finds butterfly cells in \a this mesh. A 2D cell is considered to be butterfly if at
4652  * least two its edges intersect each other anywhere except their extremities. An
4653  * INTERP_KERNEL::NORM_NORI3 cell can \b not be butterfly.
4654  *  \param [in,out] cells - a vector returning ids of the found cells. It is not
4655  *         cleared before filling in.
4656  *  \param [in] eps - precision.
4657  *  \throw If \a this->getMeshDimension() != 2.
4658  *  \throw If \a this->getSpaceDimension() != 2 && \a this->getSpaceDimension() != 3.
4659  */
4660 void MEDCouplingUMesh::checkButterflyCells(std::vector<int>& cells, double eps) const
4661 {
4662   const char msg[]="Butterfly detection work only for 2D cells with spaceDim==2 or 3!";
4663   if(getMeshDimension()!=2)
4664     throw INTERP_KERNEL::Exception(msg);
4665   int spaceDim=getSpaceDimension();
4666   if(spaceDim!=2 && spaceDim!=3)
4667     throw INTERP_KERNEL::Exception(msg);
4668   const int *conn=_nodal_connec->getConstPointer();
4669   const int *connI=_nodal_connec_index->getConstPointer();
4670   int nbOfCells=getNumberOfCells();
4671   std::vector<double> cell2DinS2;
4672   for(int i=0;i<nbOfCells;i++)
4673     {
4674       int offset=connI[i];
4675       int nbOfNodesForCell=connI[i+1]-offset-1;
4676       if(nbOfNodesForCell<=3)
4677         continue;
4678       bool isQuad=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[offset]).isQuadratic();
4679       project2DCellOnXY(conn+offset+1,conn+connI[i+1],cell2DinS2);
4680       if(isButterfly2DCell(cell2DinS2,isQuad,eps))
4681         cells.push_back(i);
4682       cell2DinS2.clear();
4683     }
4684 }
4685
4686 /*!
4687  * This method is typically requested to unbutterfly 2D linear cells in \b this.
4688  *
4689  * 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.
4690  * 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.
4691  * 
4692  * For each 2D linear cell in \b this, this method builds the convex envelop (or the convex hull) of the current cell.
4693  * This convex envelop is computed using Jarvis march algorithm.
4694  * The coordinates and the number of cells of \b this remain unchanged on invocation of this method.
4695  * 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)
4696  * 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.
4697  *
4698  * \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.
4699  * \sa MEDCouplingUMesh::colinearize2D
4700  */
4701 DataArrayInt *MEDCouplingUMesh::convexEnvelop2D()
4702 {
4703   if(getMeshDimension()!=2 || getSpaceDimension()!=2)
4704     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convexEnvelop2D  works only for meshDim=2 and spaceDim=2 !");
4705   checkFullyDefined();
4706   const double *coords=getCoords()->getConstPointer();
4707   int nbOfCells=getNumberOfCells();
4708   MCAuto<DataArrayInt> nodalConnecIndexOut=DataArrayInt::New();
4709   nodalConnecIndexOut->alloc(nbOfCells+1,1);
4710   MCAuto<DataArrayInt> nodalConnecOut(DataArrayInt::New());
4711   int *workIndexOut=nodalConnecIndexOut->getPointer();
4712   *workIndexOut=0;
4713   const int *nodalConnecIn=_nodal_connec->getConstPointer();
4714   const int *nodalConnecIndexIn=_nodal_connec_index->getConstPointer();
4715   std::set<INTERP_KERNEL::NormalizedCellType> types;
4716   MCAuto<DataArrayInt> isChanged(DataArrayInt::New());
4717   isChanged->alloc(0,1);
4718   for(int i=0;i<nbOfCells;i++,workIndexOut++)
4719     {
4720       int pos=nodalConnecOut->getNumberOfTuples();
4721       if(BuildConvexEnvelopOf2DCellJarvis(coords,nodalConnecIn+nodalConnecIndexIn[i],nodalConnecIn+nodalConnecIndexIn[i+1],nodalConnecOut))
4722         isChanged->pushBackSilent(i);
4723       types.insert((INTERP_KERNEL::NormalizedCellType)nodalConnecOut->getIJ(pos,0));
4724       workIndexOut[1]=nodalConnecOut->getNumberOfTuples();
4725     }
4726   if(isChanged->empty())
4727     return 0;
4728   setConnectivity(nodalConnecOut,nodalConnecIndexOut,false);
4729   _types=types;
4730   return isChanged.retn();
4731 }
4732
4733 /*!
4734  * This method is \b NOT const because it can modify \a this.
4735  * \a this is expected to be an unstructured mesh with meshDim==2 and spaceDim==3. If not an exception will be thrown.
4736  * \param mesh1D is an unstructured mesh with MeshDim==1 and spaceDim==3. If not an exception will be thrown.
4737  * \param policy specifies the type of extrusion chosen:
4738  *   - \b 0 for translation only (most simple): the cells of the 1D mesh represent the vectors along which the 2D mesh
4739  *   will be repeated to build each level
4740  *   - \b 1 for translation and rotation: the translation is done as above. For each level, an arc of circle is fitted on
4741  *   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
4742  *   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
4743  *   arc.
4744  * \return an unstructured mesh with meshDim==3 and spaceDim==3. The returned mesh has the same coords than \a this.  
4745  */
4746 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMesh(const MEDCouplingUMesh *mesh1D, int policy)
4747 {
4748   checkFullyDefined();
4749   mesh1D->checkFullyDefined();
4750   if(!mesh1D->isContiguous1D())
4751     throw INTERP_KERNEL::Exception("buildExtrudedMesh : 1D mesh passed in parameter is not contiguous !");
4752   if(getSpaceDimension()!=mesh1D->getSpaceDimension())
4753     throw INTERP_KERNEL::Exception("Invalid call to buildExtrudedMesh this and mesh1D must have same space dimension !");
4754   if((getMeshDimension()!=2 || getSpaceDimension()!=3) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
4755     throw INTERP_KERNEL::Exception("Invalid 'this' for buildExtrudedMesh method : must be (meshDim==2 and spaceDim==3) or (meshDim==1 and spaceDim==2) !");
4756   if(mesh1D->getMeshDimension()!=1)
4757     throw INTERP_KERNEL::Exception("Invalid 'mesh1D' for buildExtrudedMesh method : must be meshDim==1 !");
4758   bool isQuad=false;
4759   if(isPresenceOfQuadratic())
4760     {
4761       if(mesh1D->isFullyQuadratic())
4762         isQuad=true;
4763       else
4764         throw INTERP_KERNEL::Exception("Invalid 2D mesh and 1D mesh because 2D mesh has quadratic cells and 1D is not fully quadratic !");
4765     }
4766   int oldNbOfNodes(getNumberOfNodes());
4767   MCAuto<DataArrayDouble> newCoords;
4768   switch(policy)
4769   {
4770     case 0:
4771       {
4772         newCoords=fillExtCoordsUsingTranslation(mesh1D,isQuad);
4773         break;
4774       }
4775     case 1:
4776       {
4777         newCoords=fillExtCoordsUsingTranslAndAutoRotation(mesh1D,isQuad);
4778         break;
4779       }
4780     default:
4781       throw INTERP_KERNEL::Exception("Not implemented extrusion policy : must be in (0) !");
4782   }
4783   setCoords(newCoords);
4784   MCAuto<MEDCouplingUMesh> ret(buildExtrudedMeshFromThisLowLev(oldNbOfNodes,isQuad));
4785   updateTime();
4786   return ret.retn();
4787 }
4788
4789 /*!
4790  * This method works on a 3D curve linear mesh that is to say (meshDim==1 and spaceDim==3).
4791  * If it is not the case an exception will be thrown.
4792  * This method is non const because the coordinate of \a this can be appended with some new points issued from
4793  * intersection of plane defined by ('origin','vec').
4794  * This method has one in/out parameter : 'cut3DCurve'.
4795  * Param 'cut3DCurve' is expected to be of size 'this->getNumberOfCells()'. For each i in [0,'this->getNumberOfCells()')
4796  * if cut3DCurve[i]==-2, it means that for cell #i in \a this nothing has been detected previously.
4797  * if cut3DCurve[i]==-1, it means that cell#i has been already detected to be fully part of plane defined by ('origin','vec').
4798  * This method will throw an exception if \a this contains a non linear segment.
4799  */
4800 void MEDCouplingUMesh::split3DCurveWithPlane(const double *origin, const double *vec, double eps, std::vector<int>& cut3DCurve)
4801 {
4802   checkFullyDefined();
4803   if(getMeshDimension()!=1 || getSpaceDimension()!=3)
4804     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane works on umeshes with meshdim equal to 1 and spaceDim equal to 3 !");
4805   int ncells=getNumberOfCells();
4806   int nnodes=getNumberOfNodes();
4807   double vec2[3],vec3[3],vec4[3];
4808   double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
4809   if(normm<1e-6)
4810     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
4811   vec2[0]=vec[0]/normm; vec2[1]=vec[1]/normm; vec2[2]=vec[2]/normm;
4812   const int *conn=_nodal_connec->getConstPointer();
4813   const int *connI=_nodal_connec_index->getConstPointer();
4814   const double *coo=_coords->getConstPointer();
4815   std::vector<double> addCoo;
4816   for(int i=0;i<ncells;i++)
4817     {
4818       if(conn[connI[i]]==(int)INTERP_KERNEL::NORM_SEG2)
4819         {
4820           if(cut3DCurve[i]==-2)
4821             {
4822               int st=conn[connI[i]+1],endd=conn[connI[i]+2];
4823               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];
4824               double normm2=sqrt(vec3[0]*vec3[0]+vec3[1]*vec3[1]+vec3[2]*vec3[2]);
4825               double colin=std::abs((vec3[0]*vec2[0]+vec3[1]*vec2[1]+vec3[2]*vec2[2])/normm2);
4826               if(colin>eps)//if colin<=eps -> current SEG2 is colinear to the input plane
4827                 {
4828                   const double *st2=coo+3*st;
4829                   vec4[0]=st2[0]-origin[0]; vec4[1]=st2[1]-origin[1]; vec4[2]=st2[2]-origin[2];
4830                   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]));
4831                   if(pos>eps && pos<1-eps)
4832                     {
4833                       int nNode=((int)addCoo.size())/3;
4834                       vec4[0]=st2[0]+pos*vec3[0]; vec4[1]=st2[1]+pos*vec3[1]; vec4[2]=st2[2]+pos*vec3[2];
4835                       addCoo.insert(addCoo.end(),vec4,vec4+3);
4836                       cut3DCurve[i]=nnodes+nNode;
4837                     }
4838                 }
4839             }
4840         }
4841       else
4842         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane : this method is only available for linear cell (NORM_SEG2) !");
4843     }
4844   if(!addCoo.empty())
4845     {
4846       int newNbOfNodes=nnodes+((int)addCoo.size())/3;
4847       MCAuto<DataArrayDouble> coo2=DataArrayDouble::New();
4848       coo2->alloc(newNbOfNodes,3);
4849       double *tmp=coo2->getPointer();
4850       tmp=std::copy(_coords->begin(),_coords->end(),tmp);
4851       std::copy(addCoo.begin(),addCoo.end(),tmp);
4852       DataArrayDouble::SetArrayIn(coo2,_coords);
4853     }
4854 }
4855
4856 /*!
4857  * This method incarnates the policy 0 for MEDCouplingUMesh::buildExtrudedMesh method.
4858  * \param mesh1D is the input 1D mesh used for translation computation.
4859  * \return newCoords new coords filled by this method. 
4860  */
4861 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslation(const MEDCouplingUMesh *mesh1D, bool isQuad) const
4862 {
4863   int oldNbOfNodes=getNumberOfNodes();
4864   int nbOf1DCells=mesh1D->getNumberOfCells();
4865   int spaceDim=getSpaceDimension();
4866   DataArrayDouble *ret=DataArrayDouble::New();
4867   std::vector<bool> isQuads;
4868   int nbOfLevsInVec=isQuad?2*nbOf1DCells+1:nbOf1DCells+1;
4869   ret->alloc(oldNbOfNodes*nbOfLevsInVec,spaceDim);
4870   double *retPtr=ret->getPointer();
4871   const double *coords=getCoords()->getConstPointer();
4872   double *work=std::copy(coords,coords+spaceDim*oldNbOfNodes,retPtr);
4873   std::vector<int> v;
4874   std::vector<double> c;
4875   double vec[3];
4876   v.reserve(3);
4877   c.reserve(6);
4878   for(int i=0;i<nbOf1DCells;i++)
4879     {
4880       v.resize(0);
4881       mesh1D->getNodeIdsOfCell(i,v);
4882       c.resize(0);
4883       mesh1D->getCoordinatesOfNode(v[isQuad?2:1],c);
4884       mesh1D->getCoordinatesOfNode(v[0],c);
4885       std::transform(c.begin(),c.begin()+spaceDim,c.begin()+spaceDim,vec,std::minus<double>());
4886       for(int j=0;j<oldNbOfNodes;j++)
4887         work=std::transform(vec,vec+spaceDim,retPtr+spaceDim*(i*oldNbOfNodes+j),work,std::plus<double>());
4888       if(isQuad)
4889         {
4890           c.resize(0);
4891           mesh1D->getCoordinatesOfNode(v[1],c);
4892           mesh1D->getCoordinatesOfNode(v[0],c);
4893           std::transform(c.begin(),c.begin()+spaceDim,c.begin()+spaceDim,vec,std::minus<double>());
4894           for(int j=0;j<oldNbOfNodes;j++)
4895             work=std::transform(vec,vec+spaceDim,retPtr+spaceDim*(i*oldNbOfNodes+j),work,std::plus<double>());
4896         }
4897     }
4898   ret->copyStringInfoFrom(*getCoords());
4899   return ret;
4900 }
4901
4902 /*!
4903  * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method.
4904  * \param mesh1D is the input 1D mesh used for translation and automatic rotation computation.
4905  * \return newCoords new coords filled by this method. 
4906  */
4907 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation(const MEDCouplingUMesh *mesh1D, bool isQuad) const
4908 {
4909   if(mesh1D->getSpaceDimension()==2)
4910     return fillExtCoordsUsingTranslAndAutoRotation2D(mesh1D,isQuad);
4911   if(mesh1D->getSpaceDimension()==3)
4912     return fillExtCoordsUsingTranslAndAutoRotation3D(mesh1D,isQuad);
4913   throw INTERP_KERNEL::Exception("Not implemented rotation and translation alg. for spacedim other than 2 and 3 !");
4914 }
4915
4916 /*!
4917  * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method.
4918  * \param mesh1D is the input 1D mesh used for translation and automatic rotation computation.
4919  * \return newCoords new coords filled by this method. 
4920  */
4921 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D(const MEDCouplingUMesh *mesh1D, bool isQuad) const
4922 {
4923   if(isQuad)
4924     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D : not implemented for quadratic cells !");
4925   int oldNbOfNodes=getNumberOfNodes();
4926   int nbOf1DCells=mesh1D->getNumberOfCells();
4927   if(nbOf1DCells<2)
4928     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D : impossible to detect any angle of rotation ! Change extrusion policy 1->0 !");
4929   MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
4930   int nbOfLevsInVec=nbOf1DCells+1;
4931   ret->alloc(oldNbOfNodes*nbOfLevsInVec,2);
4932   double *retPtr=ret->getPointer();
4933   retPtr=std::copy(getCoords()->getConstPointer(),getCoords()->getConstPointer()+getCoords()->getNbOfElems(),retPtr);
4934   MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
4935   MCAuto<DataArrayDouble> tmp2=getCoords()->deepCopy();
4936   tmp->setCoords(tmp2);
4937   const double *coo1D=mesh1D->getCoords()->getConstPointer();
4938   const int *conn1D=mesh1D->getNodalConnectivity()->getConstPointer();
4939   const int *connI1D=mesh1D->getNodalConnectivityIndex()->getConstPointer();
4940   for(int i=1;i<nbOfLevsInVec;i++)
4941     {
4942       const double *begin=coo1D+2*conn1D[connI1D[i-1]+1];
4943       const double *end=coo1D+2*conn1D[connI1D[i-1]+2];
4944       const double *third=i+1<nbOfLevsInVec?coo1D+2*conn1D[connI1D[i]+2]:coo1D+2*conn1D[connI1D[i-2]+1];
4945       const double vec[2]={end[0]-begin[0],end[1]-begin[1]};
4946       tmp->translate(vec);
4947       double tmp3[2],radius,alpha,alpha0;
4948       const double *p0=i+1<nbOfLevsInVec?begin:third;
4949       const double *p1=i+1<nbOfLevsInVec?end:begin;
4950       const double *p2=i+1<nbOfLevsInVec?third:end;
4951       INTERP_KERNEL::EdgeArcCircle::GetArcOfCirclePassingThru(p0,p1,p2,tmp3,radius,alpha,alpha0);
4952       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]);
4953       double angle=acos(cosangle/(radius*radius));
4954       tmp->rotate(end,0,angle);
4955       retPtr=std::copy(tmp2->getConstPointer(),tmp2->getConstPointer()+tmp2->getNbOfElems(),retPtr);
4956     }
4957   return ret.retn();
4958 }
4959
4960 /*!
4961  * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method.
4962  * \param mesh1D is the input 1D mesh used for translation and automatic rotation computation.
4963  * \return newCoords new coords filled by this method. 
4964  */
4965 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D(const MEDCouplingUMesh *mesh1D, bool isQuad) const
4966 {
4967   if(isQuad)
4968     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D : not implemented for quadratic cells !");
4969   int oldNbOfNodes=getNumberOfNodes();
4970   int nbOf1DCells=mesh1D->getNumberOfCells();
4971   if(nbOf1DCells<2)
4972     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D : impossible to detect any angle of rotation ! Change extrusion policy 1->0 !");
4973   MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
4974   int nbOfLevsInVec=nbOf1DCells+1;
4975   ret->alloc(oldNbOfNodes*nbOfLevsInVec,3);
4976   double *retPtr=ret->getPointer();
4977   retPtr=std::copy(getCoords()->getConstPointer(),getCoords()->getConstPointer()+getCoords()->getNbOfElems(),retPtr);
4978   MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
4979   MCAuto<DataArrayDouble> tmp2=getCoords()->deepCopy();
4980   tmp->setCoords(tmp2);
4981   const double *coo1D=mesh1D->getCoords()->getConstPointer();
4982   const int *conn1D=mesh1D->getNodalConnectivity()->getConstPointer();
4983   const int *connI1D=mesh1D->getNodalConnectivityIndex()->getConstPointer();
4984   for(int i=1;i<nbOfLevsInVec;i++)
4985     {
4986       const double *begin=coo1D+3*conn1D[connI1D[i-1]+1];
4987       const double *end=coo1D+3*conn1D[connI1D[i-1]+2];
4988       const double *third=i+1<nbOfLevsInVec?coo1D+3*conn1D[connI1D[i]+2]:coo1D+3*conn1D[connI1D[i-2]+1];
4989       const double vec[3]={end[0]-begin[0],end[1]-begin[1],end[2]-begin[2]};
4990       tmp->translate(vec);
4991       double tmp3[2],radius,alpha,alpha0;
4992       const double *p0=i+1<nbOfLevsInVec?begin:third;
4993       const double *p1=i+1<nbOfLevsInVec?end:begin;
4994       const double *p2=i+1<nbOfLevsInVec?third:end;
4995       double vecPlane[3]={
4996         (p1[1]-p0[1])*(p2[2]-p1[2])-(p1[2]-p0[2])*(p2[1]-p1[1]),
4997         (p1[2]-p0[2])*(p2[0]-p1[0])-(p1[0]-p0[0])*(p2[2]-p1[2]),
4998         (p1[0]-p0[0])*(p2[1]-p1[1])-(p1[1]-p0[1])*(p2[0]-p1[0]),
4999       };
5000       double norm=sqrt(vecPlane[0]*vecPlane[0]+vecPlane[1]*vecPlane[1]+vecPlane[2]*vecPlane[2]);
5001       if(norm>1.e-7)
5002         {
5003           vecPlane[0]/=norm; vecPlane[1]/=norm; vecPlane[2]/=norm;
5004           double norm2=sqrt(vecPlane[0]*vecPlane[0]+vecPlane[1]*vecPlane[1]);
5005           double vec2[2]={vecPlane[1]/norm2,-vecPlane[0]/norm2};
5006           double s2=norm2;
5007           double c2=cos(asin(s2));
5008           double m[3][3]={
5009             {vec2[0]*vec2[0]*(1-c2)+c2, vec2[0]*vec2[1]*(1-c2), vec2[1]*s2},
5010             {vec2[0]*vec2[1]*(1-c2), vec2[1]*vec2[1]*(1-c2)+c2, -vec2[0]*s2},
5011             {-vec2[1]*s2, vec2[0]*s2, c2}
5012           };
5013           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]};
5014           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]};
5015           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]};
5016           INTERP_KERNEL::EdgeArcCircle::GetArcOfCirclePassingThru(p0r,p1r,p2r,tmp3,radius,alpha,alpha0);
5017           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]);
5018           double angle=acos(cosangle/(radius*radius));
5019           tmp->rotate(end,vecPlane,angle);
5020         }
5021       retPtr=std::copy(tmp2->getConstPointer(),tmp2->getConstPointer()+tmp2->getNbOfElems(),retPtr);
5022     }
5023   return ret.retn();
5024 }
5025
5026 /*!
5027  * This method is private because not easy to use for end user. This method is const contrary to
5028  * MEDCouplingUMesh::buildExtrudedMesh method because this->_coords are expected to contain
5029  * the coords sorted slice by slice.
5030  * \param isQuad specifies presence of quadratic cells.
5031  */
5032 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMeshFromThisLowLev(int nbOfNodesOf1Lev, bool isQuad) const
5033 {
5034   int nbOf1DCells(getNumberOfNodes()/nbOfNodesOf1Lev-1);
5035   int nbOf2DCells(getNumberOfCells());
5036   int nbOf3DCells(nbOf2DCells*nbOf1DCells);
5037   MEDCouplingUMesh *ret(MEDCouplingUMesh::New("Extruded",getMeshDimension()+1));
5038   const int *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5039   MCAuto<DataArrayInt> newConn(DataArrayInt::New()),newConnI(DataArrayInt::New());
5040   newConnI->alloc(nbOf3DCells+1,1);
5041   int *newConnIPtr(newConnI->getPointer());
5042   *newConnIPtr++=0;
5043   std::vector<int> newc;
5044   for(int j=0;j<nbOf2DCells;j++)
5045     {
5046       AppendExtrudedCell(conn+connI[j],conn+connI[j+1],nbOfNodesOf1Lev,isQuad,newc);
5047       *newConnIPtr++=(int)newc.size();
5048     }
5049   newConn->alloc((int)(newc.size())*nbOf1DCells,1);
5050   int *newConnPtr(newConn->getPointer());
5051   int deltaPerLev(isQuad?2*nbOfNodesOf1Lev:nbOfNodesOf1Lev);
5052   newConnIPtr=newConnI->getPointer();
5053   for(int iz=0;iz<nbOf1DCells;iz++)
5054     {
5055       if(iz!=0)
5056         std::transform(newConnIPtr+1,newConnIPtr+1+nbOf2DCells,newConnIPtr+1+iz*nbOf2DCells,std::bind2nd(std::plus<int>(),newConnIPtr[iz*nbOf2DCells]));
5057       const int *posOfTypeOfCell(newConnIPtr);
5058       for(std::vector<int>::const_iterator iter=newc.begin();iter!=newc.end();iter++,newConnPtr++)
5059         {
5060           int icell((int)(iter-newc.begin()));//std::distance unfortunately cannot been called here in C++98
5061           if(icell!=*posOfTypeOfCell)
5062             {
5063               if(*iter!=-1)
5064                 *newConnPtr=(*iter)+iz*deltaPerLev;
5065               else
5066                 *newConnPtr=-1;
5067             }
5068           else
5069             {
5070               *newConnPtr=*iter;
5071               posOfTypeOfCell++;
5072             }
5073         }
5074     }
5075   ret->setConnectivity(newConn,newConnI,true);
5076   ret->setCoords(getCoords());
5077   return ret;
5078 }
5079
5080 /*!
5081  * Checks if \a this mesh is constituted by only quadratic cells.
5082  *  \return bool - \c true if there are only quadratic cells in \a this mesh.
5083  *  \throw If the coordinates array is not set.
5084  *  \throw If the nodal connectivity of cells is not defined.
5085  */
5086 bool MEDCouplingUMesh::isFullyQuadratic() const
5087 {
5088   checkFullyDefined();
5089   bool ret=true;
5090   int nbOfCells=getNumberOfCells();
5091   for(int i=0;i<nbOfCells && ret;i++)
5092     {
5093       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
5094       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5095       ret=cm.isQuadratic();
5096     }
5097   return ret;
5098 }
5099
5100 /*!
5101  * Checks if \a this mesh includes any quadratic cell.
5102  *  \return bool - \c true if there is at least one quadratic cells in \a this mesh.
5103  *  \throw If the coordinates array is not set.
5104  *  \throw If the nodal connectivity of cells is not defined.
5105  */
5106 bool MEDCouplingUMesh::isPresenceOfQuadratic() const
5107 {
5108   checkFullyDefined();
5109   bool ret=false;
5110   int nbOfCells=getNumberOfCells();
5111   for(int i=0;i<nbOfCells && !ret;i++)
5112     {
5113       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
5114       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5115       ret=cm.isQuadratic();
5116     }
5117   return ret;
5118 }
5119
5120 /*!
5121  * Converts all quadratic cells to linear ones. If there are no quadratic cells in \a
5122  * this mesh, it remains unchanged.
5123  *  \throw If the coordinates array is not set.
5124  *  \throw If the nodal connectivity of cells is not defined.
5125  */
5126 void MEDCouplingUMesh::convertQuadraticCellsToLinear()
5127 {
5128   checkFullyDefined();
5129   int nbOfCells=getNumberOfCells();
5130   int delta=0;
5131   const int *iciptr=_nodal_connec_index->getConstPointer();
5132   for(int i=0;i<nbOfCells;i++)
5133     {
5134       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
5135       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5136       if(cm.isQuadratic())
5137         {
5138           INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
5139           const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
5140           if(!cml.isDynamic())
5141             delta+=cm.getNumberOfNodes()-cml.getNumberOfNodes();
5142           else
5143             delta+=(iciptr[i+1]-iciptr[i]-1)/2;
5144         }
5145     }
5146   if(delta==0)
5147     return ;
5148   MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5149   MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5150   const int *icptr=_nodal_connec->getConstPointer();
5151   newConn->alloc(getNodalConnectivityArrayLen()-delta,1);
5152   newConnI->alloc(nbOfCells+1,1);
5153   int *ocptr=newConn->getPointer();
5154   int *ociptr=newConnI->getPointer();
5155   *ociptr=0;
5156   _types.clear();
5157   for(int i=0;i<nbOfCells;i++,ociptr++)
5158     {
5159       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)icptr[iciptr[i]];
5160       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5161       if(!cm.isQuadratic())
5162         {
5163           _types.insert(type);
5164           ocptr=std::copy(icptr+iciptr[i],icptr+iciptr[i+1],ocptr);
5165           ociptr[1]=ociptr[0]+iciptr[i+1]-iciptr[i];
5166         }
5167       else
5168         {
5169           INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
5170           _types.insert(typel);
5171           const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
5172           int newNbOfNodes=cml.getNumberOfNodes();
5173           if(cml.isDynamic())
5174             newNbOfNodes=(iciptr[i+1]-iciptr[i]-1)/2;
5175           *ocptr++=(int)typel;
5176           ocptr=std::copy(icptr+iciptr[i]+1,icptr+iciptr[i]+newNbOfNodes+1,ocptr);
5177           ociptr[1]=ociptr[0]+newNbOfNodes+1;
5178         }
5179     }
5180   setConnectivity(newConn,newConnI,false);
5181 }
5182
5183 /*!
5184  * This method converts all linear cell in \a this to quadratic one.
5185  * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, here it is needed to specify the target
5186  * 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)
5187  * 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.
5188  * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, the coordinates in \a this can be become bigger. All created nodes will be put at the
5189  * end of the existing coordinates.
5190  * 
5191  * \param [in] conversionType specifies the type of conversion expected. Only 0 (default) and 1 are supported presently. 0 those that creates the 'most' simple
5192  *             corresponding quadratic cells. 1 is those creating the 'most' complex.
5193  * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5194  * 
5195  * \throw if \a this is not fully defined. It throws too if \a conversionType is not in [0,1].
5196  *
5197  * \sa MEDCouplingUMesh::convertQuadraticCellsToLinear
5198  */
5199 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic(int conversionType)
5200 {
5201   DataArrayInt *conn=0,*connI=0;
5202   DataArrayDouble *coords=0;
5203   std::set<INTERP_KERNEL::NormalizedCellType> types;
5204   checkFullyDefined();
5205   MCAuto<DataArrayInt> ret,connSafe,connISafe;
5206   MCAuto<DataArrayDouble> coordsSafe;
5207   int meshDim=getMeshDimension();
5208   switch(conversionType)
5209   {
5210     case 0:
5211       switch(meshDim)
5212       {
5213         case 1:
5214           ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);
5215           connSafe=conn; connISafe=connI; coordsSafe=coords;
5216           break;
5217         case 2:
5218           ret=convertLinearCellsToQuadratic2D0(conn,connI,coords,types);
5219           connSafe=conn; connISafe=connI; coordsSafe=coords;
5220           break;
5221         case 3:
5222           ret=convertLinearCellsToQuadratic3D0(conn,connI,coords,types);
5223           connSafe=conn; connISafe=connI; coordsSafe=coords;
5224           break;
5225         default:
5226           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 0 mesh dimensions available are [1,2,3] !");
5227       }
5228       break;
5229         case 1:
5230           {
5231             switch(meshDim)
5232             {
5233               case 1:
5234                 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);//it is not a bug. In 1D policy 0 and 1 are equals
5235                 connSafe=conn; connISafe=connI; coordsSafe=coords;
5236                 break;
5237               case 2:
5238                 ret=convertLinearCellsToQuadratic2D1(conn,connI,coords,types);
5239                 connSafe=conn; connISafe=connI; coordsSafe=coords;
5240                 break;
5241               case 3:
5242                 ret=convertLinearCellsToQuadratic3D1(conn,connI,coords,types);
5243                 connSafe=conn; connISafe=connI; coordsSafe=coords;
5244                 break;
5245               default:
5246                 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 1 mesh dimensions available are [1,2,3] !");
5247             }
5248             break;
5249           }
5250         default:
5251           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion type available are 0 (default, the simplest) and 1 (the most complex) !");
5252   }
5253   setConnectivity(connSafe,connISafe,false);
5254   _types=types;
5255   setCoords(coordsSafe);
5256   return ret.retn();
5257 }
5258
5259 /*!
5260  * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
5261  * so that the number of cells remains the same. Quadratic faces are converted to
5262  * polygons. This method works only for 2D meshes in
5263  * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
5264  * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
5265  * \warning This method can lead to a huge amount of nodes if \a eps is very low.
5266  *  \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
5267  *         a polylinized edge constituting the input polygon.
5268  *  \throw If the coordinates array is not set.
5269  *  \throw If the nodal connectivity of cells is not defined.
5270  *  \throw If \a this->getMeshDimension() != 2.
5271  *  \throw If \a this->getSpaceDimension() != 2.
5272  */
5273 void MEDCouplingUMesh::tessellate2D(double eps)
5274 {
5275   int meshDim(getMeshDimension()),spaceDim(getSpaceDimension());
5276   if(spaceDim!=2)
5277     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : works only with space dimension equal to 2 !");
5278   switch(meshDim)
5279     {
5280     case 1:
5281       return tessellate2DCurveInternal(eps);
5282     case 2:
5283       return tessellate2DInternal(eps);
5284     default:
5285       throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : mesh dimension must be in [1,2] !");
5286     }
5287 }
5288 /*!
5289  * Tessellates \a this 1D mesh in 2D space by dividing not straight quadratic edges.
5290  * \warning This method can lead to a huge amount of nodes if \a eps is very low.
5291  *  \param [in] eps - specifies the maximal angle (in radian) between 2 sub-edges of
5292  *         a sub-divided edge.
5293  *  \throw If the coordinates array is not set.
5294  *  \throw If the nodal connectivity of cells is not defined.
5295  *  \throw If \a this->getMeshDimension() != 1.
5296  *  \throw If \a this->getSpaceDimension() != 2.
5297  */
5298
5299 #if 0
5300 /*!
5301  * This method only works if \a this has spaceDimension equal to 2 and meshDimension also equal to 2.
5302  * This method allows to modify connectivity of cells in \a this that shares some edges in \a edgeIdsToBeSplit.
5303  * The nodes to be added in those 2D cells are defined by the pair of \a  nodeIdsToAdd and \a nodeIdsIndexToAdd.
5304  * Length of \a nodeIdsIndexToAdd is expected to equal to length of \a edgeIdsToBeSplit + 1.
5305  * The node ids in \a nodeIdsToAdd should be valid. Those nodes have to be sorted exactly following exactly the direction of the edge.
5306  * This method can be seen as the opposite method of colinearize2D.
5307  * 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
5308  * to avoid to modify the numbering of existing nodes.
5309  *
5310  * \param [in] nodeIdsToAdd - the list of node ids to be added (\a nodeIdsIndexToAdd array allows to walk on this array)
5311  * \param [in] nodeIdsIndexToAdd - the entry point of \a nodeIdsToAdd to point to the corresponding nodes to be added.
5312  * \param [in] mesh1Desc - 1st output of buildDescendingConnectivity2 on \a this.
5313  * \param [in] desc - 2nd output of buildDescendingConnectivity2 on \a this.
5314  * \param [in] descI - 3rd output of buildDescendingConnectivity2 on \a this.
5315  * \param [in] revDesc - 4th output of buildDescendingConnectivity2 on \a this.
5316  * \param [in] revDescI - 5th output of buildDescendingConnectivity2 on \a this.
5317  *
5318  * \sa buildDescendingConnectivity2
5319  */
5320 void MEDCouplingUMesh::splitSomeEdgesOf2DMesh(const DataArrayInt *nodeIdsToAdd, const DataArrayInt *nodeIdsIndexToAdd, const DataArrayInt *edgeIdsToBeSplit,
5321                                               const MEDCouplingUMesh *mesh1Desc, const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *revDesc, const DataArrayInt *revDescI)
5322 {
5323   if(!nodeIdsToAdd || !nodeIdsIndexToAdd || !edgeIdsToBeSplit || !mesh1Desc || !desc || !descI || !revDesc || !revDescI)
5324     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : input pointers must be not NULL !");
5325   nodeIdsToAdd->checkAllocated(); nodeIdsIndexToAdd->checkAllocated(); edgeIdsToBeSplit->checkAllocated(); desc->checkAllocated(); descI->checkAllocated(); revDesc->checkAllocated(); revDescI->checkAllocated();
5326   if(getSpaceDimension()!=2 || getMeshDimension()!=2)
5327     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : this must have spacedim=meshdim=2 !");
5328   if(mesh1Desc->getSpaceDimension()!=2 || mesh1Desc->getMeshDimension()!=1)
5329     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : mesh1Desc must be the explosion of this with spaceDim=2 and meshDim = 1 !");
5330   //DataArrayInt *out0(0),*outi0(0);
5331   //MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
5332   //MCAuto<DataArrayInt> out0s(out0),outi0s(outi0);
5333   //out0s=out0s->buildUnique(); out0s->sort(true);
5334 }
5335 #endif
5336
5337 /*!
5338  * Implementes \a conversionType 0 for meshes with meshDim = 1, of MEDCouplingUMesh::convertLinearCellsToQuadratic method.
5339  * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5340  * \sa MEDCouplingUMesh::convertLinearCellsToQuadratic.
5341  */
5342 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic1D0(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5343 {
5344   MCAuto<DataArrayDouble> bary=computeCellCenterOfMass();
5345   MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5346   MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5347   MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
5348   int nbOfCells=getNumberOfCells();
5349   int nbOfNodes=getNumberOfNodes();
5350   const int *cPtr=_nodal_connec->getConstPointer();
5351   const int *icPtr=_nodal_connec_index->getConstPointer();
5352   int lastVal=0,offset=nbOfNodes;
5353   for(int i=0;i<nbOfCells;i++,icPtr++)
5354     {
5355       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5356       if(type==INTERP_KERNEL::NORM_SEG2)
5357         {
5358           types.insert(INTERP_KERNEL::NORM_SEG3);
5359           newConn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG3);
5360           newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[0]+3);
5361           newConn->pushBackSilent(offset++);
5362           lastVal+=4;
5363           newConnI->pushBackSilent(lastVal);
5364           ret->pushBackSilent(i);
5365         }
5366       else
5367         {
5368           types.insert(type);
5369           lastVal+=(icPtr[1]-icPtr[0]);
5370           newConnI->pushBackSilent(lastVal);
5371           newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5372         }
5373     }
5374   MCAuto<DataArrayDouble> tmp=bary->selectByTupleIdSafe(ret->begin(),ret->end());
5375   coords=DataArrayDouble::Aggregate(getCoords(),tmp); conn=newConn.retn(); connI=newConnI.retn();
5376   return ret.retn();
5377 }
5378
5379 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
5380 {
5381   MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5382   MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5383   MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
5384   //
5385   const int *descPtr(desc->begin()),*descIPtr(descI->begin());
5386   DataArrayInt *conn1D=0,*conn1DI=0;
5387   std::set<INTERP_KERNEL::NormalizedCellType> types1D;
5388   DataArrayDouble *coordsTmp=0;
5389   MCAuto<DataArrayInt> ret1D=m1D->convertLinearCellsToQuadratic1D0(conn1D,conn1DI,coordsTmp,types1D); ret1D=0;
5390   MCAuto<DataArrayDouble> coordsTmpSafe(coordsTmp);
5391   MCAuto<DataArrayInt> conn1DSafe(conn1D),conn1DISafe(conn1DI);
5392   const int *c1DPtr=conn1D->begin();
5393   const int *c1DIPtr=conn1DI->begin();
5394   int nbOfCells=getNumberOfCells();
5395   const int *cPtr=_nodal_connec->getConstPointer();
5396   const int *icPtr=_nodal_connec_index->getConstPointer();
5397   int lastVal=0;
5398   for(int i=0;i<nbOfCells;i++,icPtr++,descIPtr++)
5399     {
5400       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5401       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
5402       if(!cm.isQuadratic())
5403         {
5404           INTERP_KERNEL::NormalizedCellType typ2=cm.getQuadraticType();
5405           types.insert(typ2); newConn->pushBackSilent(typ2);
5406           newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[1]);
5407           for(const int *d=descPtr+descIPtr[0];d!=descPtr+descIPtr[1];d++)
5408             newConn->pushBackSilent(c1DPtr[c1DIPtr[*d]+3]);
5409           lastVal+=(icPtr[1]-icPtr[0])+(descIPtr[1]-descIPtr[0]);
5410           newConnI->pushBackSilent(lastVal);
5411           ret->pushBackSilent(i);
5412         }
5413       else
5414         {
5415           types.insert(typ);
5416           lastVal+=(icPtr[1]-icPtr[0]);
5417           newConnI->pushBackSilent(lastVal);
5418           newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5419         }
5420     }
5421   conn=newConn.retn(); connI=newConnI.retn(); coords=coordsTmpSafe.retn();
5422   return ret.retn();
5423 }
5424
5425 /*!
5426  * Implementes \a conversionType 0 for meshes with meshDim = 2, of MEDCouplingUMesh::convertLinearCellsToQuadratic method.
5427  * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5428  * \sa MEDCouplingUMesh::convertLinearCellsToQuadratic.
5429  */
5430 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic2D0(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5431 {
5432   MCAuto<DataArrayInt> desc(DataArrayInt::New()),descI(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5433   MCAuto<MEDCouplingUMesh> m1D=buildDescendingConnectivity(desc,descI,tmp2,tmp3); tmp2=0; tmp3=0;
5434   return convertLinearCellsToQuadratic2DAnd3D0(m1D,desc,descI,conn,connI,coords,types);
5435 }
5436
5437 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic2D1(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5438 {
5439   MCAuto<DataArrayInt> desc(DataArrayInt::New()),descI(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5440   MCAuto<MEDCouplingUMesh> m1D=buildDescendingConnectivity(desc,descI,tmp2,tmp3); tmp2=0; tmp3=0;
5441   //
5442   MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5443   MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5444   MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
5445   //
5446   MCAuto<DataArrayDouble> bary=computeCellCenterOfMass();
5447   const int *descPtr(desc->begin()),*descIPtr(descI->begin());
5448   DataArrayInt *conn1D=0,*conn1DI=0;
5449   std::set<INTERP_KERNEL::NormalizedCellType> types1D;
5450   DataArrayDouble *coordsTmp=0;
5451   MCAuto<DataArrayInt> ret1D=m1D->convertLinearCellsToQuadratic1D0(conn1D,conn1DI,coordsTmp,types1D); ret1D=0;
5452   MCAuto<DataArrayDouble> coordsTmpSafe(coordsTmp);
5453   MCAuto<DataArrayInt> conn1DSafe(conn1D),conn1DISafe(conn1DI);
5454   const int *c1DPtr=conn1D->begin();
5455   const int *c1DIPtr=conn1DI->begin();
5456   int nbOfCells=getNumberOfCells();
5457   const int *cPtr=_nodal_connec->getConstPointer();
5458   const int *icPtr=_nodal_connec_index->getConstPointer();
5459   int lastVal=0,offset=coordsTmpSafe->getNumberOfTuples();
5460   for(int i=0;i<nbOfCells;i++,icPtr++,descIPtr++)
5461     {
5462       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5463       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
5464       if(!cm.isQuadratic())
5465         {
5466           INTERP_KERNEL::NormalizedCellType typ2=cm.getQuadraticType2();
5467           types.insert(typ2); newConn->pushBackSilent(typ2);
5468           newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[1]);
5469           for(const int *d=descPtr+descIPtr[0];d!=descPtr+descIPtr[1];d++)
5470             newConn->pushBackSilent(c1DPtr[c1DIPtr[*d]+3]);
5471           newConn->pushBackSilent(offset+ret->getNumberOfTuples());
5472           lastVal+=(icPtr[1]-icPtr[0])+(descIPtr[1]-descIPtr[0])+1;
5473           newConnI->pushBackSilent(lastVal);
5474           ret->pushBackSilent(i);
5475         }
5476       else
5477         {
5478           types.insert(typ);
5479           lastVal+=(icPtr[1]-icPtr[0]);
5480           newConnI->pushBackSilent(lastVal);
5481           newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5482         }
5483     }
5484   MCAuto<DataArrayDouble> tmp=bary->selectByTupleIdSafe(ret->begin(),ret->end());
5485   coords=DataArrayDouble::Aggregate(coordsTmpSafe,tmp); conn=newConn.retn(); connI=newConnI.retn();
5486   return ret.retn();
5487 }
5488
5489 /*!
5490  * Implementes \a conversionType 0 for meshes with meshDim = 3, of MEDCouplingUMesh::convertLinearCellsToQuadratic method.
5491  * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5492  * \sa MEDCouplingUMesh::convertLinearCellsToQuadratic.
5493  */
5494 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic3D0(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5495 {
5496   MCAuto<DataArrayInt> desc(DataArrayInt::New()),descI(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5497   MCAuto<MEDCouplingUMesh> m1D=explode3DMeshTo1D(desc,descI,tmp2,tmp3); tmp2=0; tmp3=0;
5498   return convertLinearCellsToQuadratic2DAnd3D0(m1D,desc,descI,conn,connI,coords,types);
5499 }
5500
5501 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic3D1(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5502 {
5503   MCAuto<DataArrayInt> desc2(DataArrayInt::New()),desc2I(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5504   MCAuto<MEDCouplingUMesh> m2D=buildDescendingConnectivityGen<MinusOneSonsGeneratorBiQuadratic>(desc2,desc2I,tmp2,tmp3,MEDCouplingFastNbrer); tmp2=0; tmp3=0;
5505   MCAuto<DataArrayInt> desc1(DataArrayInt::New()),desc1I(DataArrayInt::New()),tmp4(DataArrayInt::New()),tmp5(DataArrayInt::New());
5506   MCAuto<MEDCouplingUMesh> m1D=explode3DMeshTo1D(desc1,desc1I,tmp4,tmp5); tmp4=0; tmp5=0;
5507   //
5508   MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5509   MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5510   MCAuto<DataArrayInt> ret=DataArrayInt::New(),ret2=DataArrayInt::New(); ret->alloc(0,1); ret2->alloc(0,1);
5511   //
5512   MCAuto<DataArrayDouble> bary=computeCellCenterOfMass();
5513   const int *descPtr(desc1->begin()),*descIPtr(desc1I->begin()),*desc2Ptr(desc2->begin()),*desc2IPtr(desc2I->begin());
5514   DataArrayInt *conn1D=0,*conn1DI=0,*conn2D=0,*conn2DI=0;
5515   std::set<INTERP_KERNEL::NormalizedCellType> types1D,types2D;
5516   DataArrayDouble *coordsTmp=0,*coordsTmp2=0;
5517   MCAuto<DataArrayInt> ret1D=m1D->convertLinearCellsToQuadratic1D0(conn1D,conn1DI,coordsTmp,types1D); ret1D=DataArrayInt::New(); ret1D->alloc(0,1);
5518   MCAuto<DataArrayInt> conn1DSafe(conn1D),conn1DISafe(conn1DI);
5519   MCAuto<DataArrayDouble> coordsTmpSafe(coordsTmp);
5520   MCAuto<DataArrayInt> ret2D=m2D->convertLinearCellsToQuadratic2D1(conn2D,conn2DI,coordsTmp2,types2D); ret2D=DataArrayInt::New(); ret2D->alloc(0,1);
5521   MCAuto<DataArrayDouble> coordsTmp2Safe(coordsTmp2);
5522   MCAuto<DataArrayInt> conn2DSafe(conn2D),conn2DISafe(conn2DI);
5523   const int *c1DPtr=conn1D->begin(),*c1DIPtr=conn1DI->begin(),*c2DPtr=conn2D->begin(),*c2DIPtr=conn2DI->begin();
5524   int nbOfCells=getNumberOfCells();
5525   const int *cPtr=_nodal_connec->getConstPointer();
5526   const int *icPtr=_nodal_connec_index->getConstPointer();
5527   int lastVal=0,offset=coordsTmpSafe->getNumberOfTuples();
5528   for(int i=0;i<nbOfCells;i++,icPtr++,descIPtr++,desc2IPtr++)
5529     {
5530       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5531       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
5532       if(!cm.isQuadratic())
5533         {
5534           INTERP_KERNEL::NormalizedCellType typ2=cm.getQuadraticType2();
5535           if(typ2==INTERP_KERNEL::NORM_ERROR)
5536             {
5537               std::ostringstream oss; oss << "MEDCouplingUMesh::convertLinearCellsToQuadratic3D1 : On cell #" << i << " the linear cell type does not support advanced quadratization !";
5538               throw INTERP_KERNEL::Exception(oss.str().c_str());
5539             }
5540           types.insert(typ2); newConn->pushBackSilent(typ2);
5541           newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[1]);
5542           for(const int *d=descPtr+descIPtr[0];d!=descPtr+descIPtr[1];d++)
5543             newConn->pushBackSilent(c1DPtr[c1DIPtr[*d]+3]);
5544           for(const int *d=desc2Ptr+desc2IPtr[0];d!=desc2Ptr+desc2IPtr[1];d++)
5545             {
5546               int nodeId2=c2DPtr[c2DIPtr[(*d)+1]-1];
5547               int tmpPos=newConn->getNumberOfTuples();
5548               newConn->pushBackSilent(nodeId2);
5549               ret2D->pushBackSilent(nodeId2); ret1D->pushBackSilent(tmpPos);
5550             }
5551           newConn->pushBackSilent(offset+ret->getNumberOfTuples());
5552           lastVal+=(icPtr[1]-icPtr[0])+(descIPtr[1]-descIPtr[0])+(desc2IPtr[1]-desc2IPtr[0])+1;
5553           newConnI->pushBackSilent(lastVal);
5554           ret->pushBackSilent(i);
5555         }
5556       else
5557         {
5558           types.insert(typ);
5559           lastVal+=(icPtr[1]-icPtr[0]);
5560           newConnI->pushBackSilent(lastVal);
5561           newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5562         }
5563     }
5564   MCAuto<DataArrayInt> diffRet2D=ret2D->getDifferentValues();
5565   MCAuto<DataArrayInt> o2nRet2D=diffRet2D->invertArrayN2O2O2N(coordsTmp2Safe->getNumberOfTuples());
5566   coordsTmp2Safe=coordsTmp2Safe->selectByTupleId(diffRet2D->begin(),diffRet2D->end());
5567   MCAuto<DataArrayDouble> tmp=bary->selectByTupleIdSafe(ret->begin(),ret->end());
5568   std::vector<const DataArrayDouble *> v(3); v[0]=coordsTmpSafe; v[1]=coordsTmp2Safe; v[2]=tmp;
5569   int *c=newConn->getPointer();
5570   const int *cI(newConnI->begin());
5571   for(const int *elt=ret1D->begin();elt!=ret1D->end();elt++)
5572     c[*elt]=o2nRet2D->getIJ(c[*elt],0)+offset;
5573   offset=coordsTmp2Safe->getNumberOfTuples();
5574   for(const int *elt=ret->begin();elt!=ret->end();elt++)
5575     c[cI[(*elt)+1]-1]+=offset;
5576   coords=DataArrayDouble::Aggregate(v); conn=newConn.retn(); connI=newConnI.retn();
5577   return ret.retn();
5578 }
5579
5580 /*!
5581  * Divides every cell of \a this mesh into simplices (triangles in 2D and tetrahedra in 3D).
5582  * In addition, returns an array mapping new cells to old ones. <br>
5583  * This method typically increases the number of cells in \a this mesh
5584  * but the number of nodes remains \b unchanged.
5585  * That's why the 3D splitting policies
5586  * INTERP_KERNEL::GENERAL_24 and INTERP_KERNEL::GENERAL_48 are not available here.
5587  *  \param [in] policy - specifies a pattern used for splitting.
5588  * The semantic of \a policy is:
5589  * - 0 - to split QUAD4 by cutting it along 0-2 diagonal (for 2D mesh only).
5590  * - 1 - to split QUAD4 by cutting it along 1-3 diagonal (for 2D mesh only).
5591  * - INTERP_KERNEL::PLANAR_FACE_5 - to split HEXA8  into 5 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
5592  * - INTERP_KERNEL::PLANAR_FACE_6 - to split HEXA8  into 6 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
5593  *
5594  *
5595  *  \return DataArrayInt * - a new instance of DataArrayInt holding, for each new cell,
5596  *          an id of old cell producing it. The caller is to delete this array using
5597  *         decrRef() as it is no more needed.
5598  *
5599  *  \throw If \a policy is 0 or 1 and \a this->getMeshDimension() != 2.
5600  *  \throw If \a policy is INTERP_KERNEL::PLANAR_FACE_5 or INTERP_KERNEL::PLANAR_FACE_6
5601  *          and \a this->getMeshDimension() != 3. 
5602  *  \throw If \a policy is not one of the four discussed above.
5603  *  \throw If the nodal connectivity of cells is not defined.
5604  * \sa MEDCouplingUMesh::tetrahedrize, MEDCoupling1SGTUMesh::sortHexa8EachOther
5605  */
5606 DataArrayInt *MEDCouplingUMesh::simplexize(int policy)
5607 {
5608   switch(policy)
5609   {
5610     case 0:
5611       return simplexizePol0();
5612     case 1:
5613       return simplexizePol1();
5614     case (int) INTERP_KERNEL::PLANAR_FACE_5:
5615         return simplexizePlanarFace5();
5616     case (int) INTERP_KERNEL::PLANAR_FACE_6:
5617         return simplexizePlanarFace6();
5618     default:
5619       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)");
5620   }
5621 }
5622
5623 /*!
5624  * Checks if \a this mesh is constituted by simplex cells only. Simplex cells are:
5625  * - 1D: INTERP_KERNEL::NORM_SEG2
5626  * - 2D: INTERP_KERNEL::NORM_TRI3
5627  * - 3D: INTERP_KERNEL::NORM_TETRA4.
5628  *
5629  * This method is useful for users that need to use P1 field services as
5630  * MEDCouplingFieldDouble::getValueOn(), MEDCouplingField::buildMeasureField() etc.
5631  * All these methods need mesh support containing only simplex cells.
5632  *  \return bool - \c true if there are only simplex cells in \a this mesh.
5633  *  \throw If the coordinates array is not set.
5634  *  \throw If the nodal connectivity of cells is not defined.
5635  *  \throw If \a this->getMeshDimension() < 1.
5636  */
5637 bool MEDCouplingUMesh::areOnlySimplexCells() const
5638 {
5639   checkFullyDefined();
5640   int mdim=getMeshDimension();
5641   if(mdim<1 || mdim>3)
5642     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::areOnlySimplexCells : only available with meshes having a meshdim 1, 2 or 3 !");
5643   int nbCells=getNumberOfCells();
5644   const int *conn=_nodal_connec->getConstPointer();
5645   const int *connI=_nodal_connec_index->getConstPointer();
5646   for(int i=0;i<nbCells;i++)
5647     {
5648       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5649       if(!cm.isSimplex())
5650         return false;
5651     }
5652   return true;
5653 }
5654
5655 /*!
5656  * This method implements policy 0 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5657  */
5658 DataArrayInt *MEDCouplingUMesh::simplexizePol0()
5659 {
5660   checkConnectivityFullyDefined();
5661   if(getMeshDimension()!=2)
5662     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePol0 : this policy is only available for mesh with meshdim == 2 !");
5663   int nbOfCells=getNumberOfCells();
5664   MCAuto<DataArrayInt> ret=DataArrayInt::New();
5665   int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_QUAD4);
5666   ret->alloc(nbOfCells+nbOfCutCells,1);
5667   if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5668   int *retPt=ret->getPointer();
5669   MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5670   MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5671   newConnI->alloc(nbOfCells+nbOfCutCells+1,1);
5672   newConn->alloc(getNodalConnectivityArrayLen()+3*nbOfCutCells,1);
5673   int *pt=newConn->getPointer();
5674   int *ptI=newConnI->getPointer();
5675   ptI[0]=0;
5676   const int *oldc=_nodal_connec->getConstPointer();
5677   const int *ci=_nodal_connec_index->getConstPointer();
5678   for(int i=0;i<nbOfCells;i++,ci++)
5679     {
5680       if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_QUAD4)
5681         {
5682           const int tmp[8]={(int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+1],oldc[ci[0]+2],oldc[ci[0]+3],
5683             (int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+1],oldc[ci[0]+3],oldc[ci[0]+4]};
5684           pt=std::copy(tmp,tmp+8,pt);
5685           ptI[1]=ptI[0]+4;
5686           ptI[2]=ptI[0]+8;
5687           *retPt++=i;
5688           *retPt++=i;
5689           ptI+=2;
5690         }
5691       else
5692         {
5693           pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5694           ptI[1]=ptI[0]+ci[1]-ci[0];
5695           ptI++;
5696           *retPt++=i;
5697         }
5698     }
5699   _nodal_connec->decrRef();
5700   _nodal_connec=newConn.retn();
5701   _nodal_connec_index->decrRef();
5702   _nodal_connec_index=newConnI.retn();
5703   computeTypes();
5704   updateTime();
5705   return ret.retn();
5706 }
5707
5708 /*!
5709  * This method implements policy 1 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5710  */
5711 DataArrayInt *MEDCouplingUMesh::simplexizePol1()
5712 {
5713   checkConnectivityFullyDefined();
5714   if(getMeshDimension()!=2)
5715     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePol0 : this policy is only available for mesh with meshdim == 2 !");
5716   int nbOfCells=getNumberOfCells();
5717   MCAuto<DataArrayInt> ret=DataArrayInt::New();
5718   int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_QUAD4);
5719   ret->alloc(nbOfCells+nbOfCutCells,1);
5720   if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5721   int *retPt=ret->getPointer();
5722   MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5723   MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5724   newConnI->alloc(nbOfCells+nbOfCutCells+1,1);
5725   newConn->alloc(getNodalConnectivityArrayLen()+3*nbOfCutCells,1);
5726   int *pt=newConn->getPointer();
5727   int *ptI=newConnI->getPointer();
5728   ptI[0]=0;
5729   const int *oldc=_nodal_connec->getConstPointer();
5730   const int *ci=_nodal_connec_index->getConstPointer();
5731   for(int i=0;i<nbOfCells;i++,ci++)
5732     {
5733       if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_QUAD4)
5734         {
5735           const int tmp[8]={(int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+1],oldc[ci[0]+2],oldc[ci[0]+4],
5736             (int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+2],oldc[ci[0]+3],oldc[ci[0]+4]};
5737           pt=std::copy(tmp,tmp+8,pt);
5738           ptI[1]=ptI[0]+4;
5739           ptI[2]=ptI[0]+8;
5740           *retPt++=i;
5741           *retPt++=i;
5742           ptI+=2;
5743         }
5744       else
5745         {
5746           pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5747           ptI[1]=ptI[0]+ci[1]-ci[0];
5748           ptI++;
5749           *retPt++=i;
5750         }
5751     }
5752   _nodal_connec->decrRef();
5753   _nodal_connec=newConn.retn();
5754   _nodal_connec_index->decrRef();
5755   _nodal_connec_index=newConnI.retn();
5756   computeTypes();
5757   updateTime();
5758   return ret.retn();
5759 }
5760
5761 /*!
5762  * This method implements policy INTERP_KERNEL::PLANAR_FACE_5 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5763  */
5764 DataArrayInt *MEDCouplingUMesh::simplexizePlanarFace5()
5765 {
5766   checkConnectivityFullyDefined();
5767   if(getMeshDimension()!=3)
5768     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePlanarFace5 : this policy is only available for mesh with meshdim == 3 !");
5769   int nbOfCells=getNumberOfCells();
5770   MCAuto<DataArrayInt> ret=DataArrayInt::New();
5771   int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_HEXA8);
5772   ret->alloc(nbOfCells+4*nbOfCutCells,1);
5773   if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5774   int *retPt=ret->getPointer();
5775   MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5776   MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5777   newConnI->alloc(nbOfCells+4*nbOfCutCells+1,1);
5778   newConn->alloc(getNodalConnectivityArrayLen()+16*nbOfCutCells,1);//21
5779   int *pt=newConn->getPointer();
5780   int *ptI=newConnI->getPointer();
5781   ptI[0]=0;
5782   const int *oldc=_nodal_connec->getConstPointer();
5783   const int *ci=_nodal_connec_index->getConstPointer();
5784   for(int i=0;i<nbOfCells;i++,ci++)
5785     {
5786       if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_HEXA8)
5787         {
5788           for(int j=0;j<5;j++,pt+=5,ptI++)
5789             {
5790               pt[0]=(int)INTERP_KERNEL::NORM_TETRA4;
5791               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];
5792               *retPt++=i;
5793               ptI[1]=ptI[0]+5;
5794             }
5795         }
5796       else
5797         {
5798           pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5799           ptI[1]=ptI[0]+ci[1]-ci[0];
5800           ptI++;
5801           *retPt++=i;
5802         }
5803     }
5804   _nodal_connec->decrRef();
5805   _nodal_connec=newConn.retn();
5806   _nodal_connec_index->decrRef();
5807   _nodal_connec_index=newConnI.retn();
5808   computeTypes();
5809   updateTime();
5810   return ret.retn();
5811 }
5812
5813 /*!
5814  * This method implements policy INTERP_KERNEL::PLANAR_FACE_6 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5815  */
5816 DataArrayInt *MEDCouplingUMesh::simplexizePlanarFace6()
5817 {
5818   checkConnectivityFullyDefined();
5819   if(getMeshDimension()!=3)
5820     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePlanarFace6 : this policy is only available for mesh with meshdim == 3 !");
5821   int nbOfCells=getNumberOfCells();
5822   MCAuto<DataArrayInt> ret=DataArrayInt::New();
5823   int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_HEXA8);
5824   ret->alloc(nbOfCells+5*nbOfCutCells,1);
5825   if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5826   int *retPt=ret->getPointer();
5827   MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5828   MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5829   newConnI->alloc(nbOfCells+5*nbOfCutCells+1,1);
5830   newConn->alloc(getNodalConnectivityArrayLen()+21*nbOfCutCells,1);
5831   int *pt=newConn->getPointer();
5832   int *ptI=newConnI->getPointer();
5833   ptI[0]=0;
5834   const int *oldc=_nodal_connec->getConstPointer();
5835   const int *ci=_nodal_connec_index->getConstPointer();
5836   for(int i=0;i<nbOfCells;i++,ci++)
5837     {
5838       if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_HEXA8)
5839         {
5840           for(int j=0;j<6;j++,pt+=5,ptI++)
5841             {
5842               pt[0]=(int)INTERP_KERNEL::NORM_TETRA4;
5843               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];
5844               *retPt++=i;
5845               ptI[1]=ptI[0]+5;
5846             }
5847         }
5848       else
5849         {
5850           pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5851           ptI[1]=ptI[0]+ci[1]-ci[0];
5852           ptI++;
5853           *retPt++=i;
5854         }
5855     }
5856   _nodal_connec->decrRef();
5857   _nodal_connec=newConn.retn();
5858   _nodal_connec_index->decrRef();
5859   _nodal_connec_index=newConnI.retn();
5860   computeTypes();
5861   updateTime();
5862   return ret.retn();
5863 }
5864
5865 /*!
5866  * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
5867  * so that the number of cells remains the same. Quadratic faces are converted to
5868  * polygons. This method works only for 2D meshes in
5869  * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
5870  * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
5871  * \warning This method can lead to a huge amount of nodes if \a eps is very low.
5872  *  \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
5873  *         a polylinized edge constituting the input polygon.
5874  *  \throw If the coordinates array is not set.
5875  *  \throw If the nodal connectivity of cells is not defined.
5876  *  \throw If \a this->getMeshDimension() != 2.
5877  *  \throw If \a this->getSpaceDimension() != 2.
5878  */
5879 void MEDCouplingUMesh::tessellate2DInternal(double eps)
5880 {
5881   checkFullyDefined();
5882   if(getMeshDimension()!=2 || getSpaceDimension()!=2)  
5883     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2DInternal works on umeshes with meshdim equal to 2 and spaceDim equal to 2 too!");
5884   double epsa=fabs(eps);
5885   if(epsa<std::numeric_limits<double>::min())
5886     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 !");
5887   MCAuto<DataArrayInt> desc1(DataArrayInt::New()),descIndx1(DataArrayInt::New()),revDesc1(DataArrayInt::New()),revDescIndx1(DataArrayInt::New());
5888   MCAuto<MEDCouplingUMesh> mDesc(buildDescendingConnectivity2(desc1,descIndx1,revDesc1,revDescIndx1));
5889   revDesc1=0; revDescIndx1=0;
5890   mDesc->tessellate2D(eps);
5891   subDivide2DMesh(mDesc->_nodal_connec->getConstPointer(),mDesc->_nodal_connec_index->getConstPointer(),desc1->getConstPointer(),descIndx1->getConstPointer());
5892   setCoords(mDesc->getCoords());
5893 }
5894
5895 /*!
5896  * Tessellates \a this 1D mesh in 2D space by dividing not straight quadratic edges.
5897  * \warning This method can lead to a huge amount of nodes if \a eps is very low.
5898  *  \param [in] eps - specifies the maximal angle (in radian) between 2 sub-edges of
5899  *         a sub-divided edge.
5900  *  \throw If the coordinates array is not set.
5901  *  \throw If the nodal connectivity of cells is not defined.
5902  *  \throw If \a this->getMeshDimension() != 1.
5903  *  \throw If \a this->getSpaceDimension() != 2.
5904  */
5905 void MEDCouplingUMesh::tessellate2DCurveInternal(double eps)
5906 {
5907   checkFullyDefined();
5908   if(getMeshDimension()!=1 || getSpaceDimension()!=2)
5909     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2DCurveInternal works on umeshes with meshdim equal to 1 and spaceDim equal to 2 too!");
5910   double epsa=fabs(eps);
5911   if(epsa<std::numeric_limits<double>::min())
5912     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 !");
5913   INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=1.e-10;
5914   int nbCells=getNumberOfCells();
5915   int nbNodes=getNumberOfNodes();
5916   const int *conn=_nodal_connec->getConstPointer();
5917   const int *connI=_nodal_connec_index->getConstPointer();
5918   const double *coords=_coords->getConstPointer();
5919   std::vector<double> addCoo;
5920   std::vector<int> newConn;//no direct DataArrayInt because interface with Geometric2D
5921   MCAuto<DataArrayInt> newConnI(DataArrayInt::New());
5922   newConnI->alloc(nbCells+1,1);
5923   int *newConnIPtr=newConnI->getPointer();
5924   *newConnIPtr=0;
5925   int tmp1[3];
5926   INTERP_KERNEL::Node *tmp2[3];
5927   std::set<INTERP_KERNEL::NormalizedCellType> types;
5928   for(int i=0;i<nbCells;i++,newConnIPtr++)
5929     {
5930       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5931       if(cm.isQuadratic())
5932         {//assert(connI[i+1]-connI[i]-1==3)
5933           tmp1[0]=conn[connI[i]+1+0]; tmp1[1]=conn[connI[i]+1+1]; tmp1[2]=conn[connI[i]+1+2];
5934           tmp2[0]=new INTERP_KERNEL::Node(coords[2*tmp1[0]],coords[2*tmp1[0]+1]);
5935           tmp2[1]=new INTERP_KERNEL::Node(coords[2*tmp1[1]],coords[2*tmp1[1]+1]);
5936           tmp2[2]=new INTERP_KERNEL::Node(coords[2*tmp1[2]],coords[2*tmp1[2]+1]);
5937           INTERP_KERNEL::EdgeArcCircle *eac=INTERP_KERNEL::EdgeArcCircle::BuildFromNodes(tmp2[0],tmp2[2],tmp2[1]);
5938           if(eac)
5939             {
5940               eac->tesselate(tmp1,nbNodes,epsa,newConn,addCoo);
5941               types.insert((INTERP_KERNEL::NormalizedCellType)newConn[newConnIPtr[0]]);
5942               delete eac;
5943               newConnIPtr[1]=(int)newConn.size();
5944             }
5945           else
5946             {
5947               types.insert(INTERP_KERNEL::NORM_SEG2);
5948               newConn.push_back(INTERP_KERNEL::NORM_SEG2);
5949               newConn.insert(newConn.end(),conn+connI[i]+1,conn+connI[i]+3);
5950               newConnIPtr[1]=newConnIPtr[0]+3;
5951             }
5952         }
5953       else
5954         {
5955           types.insert((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5956           newConn.insert(newConn.end(),conn+connI[i],conn+connI[i+1]);
5957           newConnIPtr[1]=newConnIPtr[0]+3;
5958         }
5959     }
5960   if(addCoo.empty() && ((int)newConn.size())==_nodal_connec->getNumberOfTuples())//nothing happens during tessellation : no update needed
5961     return ;
5962   _types=types;
5963   DataArrayInt::SetArrayIn(newConnI,_nodal_connec_index);
5964   MCAuto<DataArrayInt> newConnArr=DataArrayInt::New();
5965   newConnArr->alloc((int)newConn.size(),1);
5966   std::copy(newConn.begin(),newConn.end(),newConnArr->getPointer());
5967   DataArrayInt::SetArrayIn(newConnArr,_nodal_connec);
5968   MCAuto<DataArrayDouble> newCoords=DataArrayDouble::New();
5969   newCoords->alloc(nbNodes+((int)addCoo.size())/2,2);
5970   double *work=std::copy(_coords->begin(),_coords->end(),newCoords->getPointer());
5971   std::copy(addCoo.begin(),addCoo.end(),work);
5972   DataArrayDouble::SetArrayIn(newCoords,_coords);
5973   updateTime();
5974 }
5975
5976 /*!
5977  * 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.
5978  * This method completly ignore coordinates.
5979  * \param nodeSubdived is the nodal connectivity of subdivision of edges
5980  * \param nodeIndxSubdived is the nodal connectivity index of subdivision of edges
5981  * \param desc is descending connectivity in format specified in MEDCouplingUMesh::buildDescendingConnectivity2
5982  * \param descIndex is descending connectivity index in format specified in MEDCouplingUMesh::buildDescendingConnectivity2
5983  */
5984 void MEDCouplingUMesh::subDivide2DMesh(const int *nodeSubdived, const int *nodeIndxSubdived, const int *desc, const int *descIndex)
5985 {
5986   checkFullyDefined();
5987   if(getMeshDimension()!=2)
5988     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::subDivide2DMesh : works only on umesh with meshdim==2 !");
5989   int nbOfCells=getNumberOfCells();
5990   int *connI=_nodal_connec_index->getPointer();
5991   int newConnLgth=0;
5992   for(int i=0;i<nbOfCells;i++,connI++)
5993     {
5994       int offset=descIndex[i];
5995       int nbOfEdges=descIndex[i+1]-offset;
5996       //
5997       bool ddirect=desc[offset+nbOfEdges-1]>0;
5998       int eedgeId=std::abs(desc[offset+nbOfEdges-1])-1;
5999       int ref=ddirect?nodeSubdived[nodeIndxSubdived[eedgeId+1]-1]:nodeSubdived[nodeIndxSubdived[eedgeId]+1];
6000       for(int j=0;j<nbOfEdges;j++)
6001         {
6002           bool direct=desc[offset+j]>0;
6003           int edgeId=std::abs(desc[offset+j])-1;
6004           if(!INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)nodeSubdived[nodeIndxSubdived[edgeId]]).isQuadratic())
6005             {
6006               int id1=nodeSubdived[nodeIndxSubdived[edgeId]+1];
6007               int id2=nodeSubdived[nodeIndxSubdived[edgeId+1]-1];
6008               int ref2=direct?id1:id2;
6009               if(ref==ref2)
6010                 {
6011                   int nbOfSubNodes=nodeIndxSubdived[edgeId+1]-nodeIndxSubdived[edgeId]-1;
6012                   newConnLgth+=nbOfSubNodes-1;
6013                   ref=direct?id2:id1;
6014                 }
6015               else
6016                 {
6017                   std::ostringstream oss; oss << "MEDCouplingUMesh::subDivide2DMesh : On polygon #" << i << " edgeid #" << j << " subedges mismatch : end subedge k!=start subedge k+1 !";
6018                   throw INTERP_KERNEL::Exception(oss.str().c_str());
6019                 }
6020             }
6021           else
6022             {
6023               throw INTERP_KERNEL::Exception("MEDCouplingUMesh::subDivide2DMesh : this method only subdivides into linear edges !");
6024             }
6025         }
6026       newConnLgth++;//+1 is for cell type
6027       connI[1]=newConnLgth;
6028     }
6029   //
6030   MCAuto<DataArrayInt> newConn=DataArrayInt::New();
6031   newConn->alloc(newConnLgth,1);
6032   int *work=newConn->getPointer();
6033   for(int i=0;i<nbOfCells;i++)
6034     {
6035       *work++=INTERP_KERNEL::NORM_POLYGON;
6036       int offset=descIndex[i];
6037       int nbOfEdges=descIndex[i+1]-offset;
6038       for(int j=0;j<nbOfEdges;j++)
6039         {
6040           bool direct=desc[offset+j]>0;
6041           int edgeId=std::abs(desc[offset+j])-1;
6042           if(direct)
6043             work=std::copy(nodeSubdived+nodeIndxSubdived[edgeId]+1,nodeSubdived+nodeIndxSubdived[edgeId+1]-1,work);
6044           else
6045             {
6046               int nbOfSubNodes=nodeIndxSubdived[edgeId+1]-nodeIndxSubdived[edgeId]-1;
6047               std::reverse_iterator<const int *> it(nodeSubdived+nodeIndxSubdived[edgeId+1]);
6048               work=std::copy(it,it+nbOfSubNodes-1,work);
6049             }
6050         }
6051     }
6052   DataArrayInt::SetArrayIn(newConn,_nodal_connec);
6053   _types.clear();
6054   if(nbOfCells>0)
6055     _types.insert(INTERP_KERNEL::NORM_POLYGON);
6056 }
6057
6058 /*!
6059  * Converts degenerated 2D or 3D linear cells of \a this mesh into cells of simpler
6060  * type. For example an INTERP_KERNEL::NORM_QUAD4 cell having only three unique nodes in
6061  * its connectivity is transformed into an INTERP_KERNEL::NORM_TRI3 cell. This method
6062  * does \b not perform geometrical checks and checks only nodal connectivity of cells,
6063  * so it can be useful to call mergeNodes() before calling this method.
6064  *  \throw If \a this->getMeshDimension() <= 1.
6065  *  \throw If the coordinates array is not set.
6066  *  \throw If the nodal connectivity of cells is not defined.
6067  */
6068 void MEDCouplingUMesh::convertDegeneratedCells()
6069 {
6070   checkFullyDefined();
6071   if(getMeshDimension()<=1)
6072     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
6073   int nbOfCells=getNumberOfCells();
6074   if(nbOfCells<1)
6075     return ;
6076   int initMeshLgth=getNodalConnectivityArrayLen();
6077   int *conn=_nodal_connec->getPointer();
6078   int *index=_nodal_connec_index->getPointer();
6079   int posOfCurCell=0;
6080   int newPos=0;
6081   int lgthOfCurCell;
6082   for(int i=0;i<nbOfCells;i++)
6083     {
6084       lgthOfCurCell=index[i+1]-posOfCurCell;
6085       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
6086       int newLgth;
6087       INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
6088                                                                                                      conn+newPos+1,newLgth);
6089       conn[newPos]=newType;
6090       newPos+=newLgth+1;
6091       posOfCurCell=index[i+1];
6092       index[i+1]=newPos;
6093     }
6094   if(newPos!=initMeshLgth)
6095     _nodal_connec->reAlloc(newPos);
6096   computeTypes();
6097 }
6098
6099 /*!
6100  * Finds incorrectly oriented cells of this 2D mesh in 3D space.
6101  * A cell is considered to be oriented correctly if an angle between its
6102  * normal vector and a given vector is less than \c PI / \c 2.
6103  *  \param [in] vec - 3 components of the vector specifying the correct orientation of
6104  *         cells. 
6105  *  \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
6106  *         checked.
6107  *  \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
6108  *         is not cleared before filling in.
6109  *  \throw If \a this->getMeshDimension() != 2.
6110  *  \throw If \a this->getSpaceDimension() != 3.
6111  *
6112  *  \if ENABLE_EXAMPLES
6113  *  \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
6114  *  \ref  py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
6115  *  \endif
6116  */
6117 void MEDCouplingUMesh::are2DCellsNotCorrectlyOriented(const double *vec, bool polyOnly, std::vector<int>& cells) const
6118 {
6119   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
6120     throw INTERP_KERNEL::Exception("Invalid mesh to apply are2DCellsNotCorrectlyOriented on it : must be meshDim==2 and spaceDim==3 !");
6121   int nbOfCells=getNumberOfCells();
6122   const int *conn=_nodal_connec->getConstPointer();
6123   const int *connI=_nodal_connec_index->getConstPointer();
6124   const double *coordsPtr=_coords->getConstPointer();
6125   for(int i=0;i<nbOfCells;i++)
6126     {
6127       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6128       if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
6129         {
6130           bool isQuadratic=INTERP_KERNEL::CellModel::GetCellModel(type).isQuadratic();
6131           if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6132             cells.push_back(i);
6133         }
6134     }
6135 }
6136
6137 /*!
6138  * Reverse connectivity of 2D cells whose orientation is not correct. A cell is
6139  * considered to be oriented correctly if an angle between its normal vector and a
6140  * given vector is less than \c PI / \c 2. 
6141  *  \param [in] vec - 3 components of the vector specifying the correct orientation of
6142  *         cells. 
6143  *  \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
6144  *         checked.
6145  *  \throw If \a this->getMeshDimension() != 2.
6146  *  \throw If \a this->getSpaceDimension() != 3.
6147  *
6148  *  \if ENABLE_EXAMPLES
6149  *  \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
6150  *  \ref  py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
6151  *  \endif
6152  *
6153  *  \sa changeOrientationOfCells
6154  */
6155 void MEDCouplingUMesh::orientCorrectly2DCells(const double *vec, bool polyOnly)
6156 {
6157   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
6158     throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectly2DCells on it : must be meshDim==2 and spaceDim==3 !");
6159   int nbOfCells(getNumberOfCells()),*conn(_nodal_connec->getPointer());
6160   const int *connI(_nodal_connec_index->getConstPointer());
6161   const double *coordsPtr(_coords->getConstPointer());
6162   bool isModified(false);
6163   for(int i=0;i<nbOfCells;i++)
6164     {
6165       INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6166       if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
6167         {
6168           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
6169           bool isQuadratic(cm.isQuadratic());
6170           if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6171             {
6172               isModified=true;
6173               cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
6174             }
6175         }
6176     }
6177   if(isModified)
6178     _nodal_connec->declareAsNew();
6179   updateTime();
6180 }
6181
6182 /*!
6183  * This method change the orientation of cells in \a this without any consideration of coordinates. Only connectivity is impacted.
6184  *
6185  * \sa orientCorrectly2DCells
6186  */
6187 void MEDCouplingUMesh::changeOrientationOfCells()
6188 {
6189   int mdim(getMeshDimension());
6190   if(mdim!=2 && mdim!=1)
6191     throw INTERP_KERNEL::Exception("Invalid mesh to apply changeOrientationOfCells on it : must be meshDim==2 or meshDim==1 !");
6192   int nbOfCells(getNumberOfCells()),*conn(_nodal_connec->getPointer());
6193   const int *connI(_nodal_connec_index->getConstPointer());
6194   if(mdim==2)
6195     {//2D
6196       for(int i=0;i<nbOfCells;i++)
6197         {
6198           INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6199           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
6200           cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
6201         }
6202     }
6203   else
6204     {//1D
6205       for(int i=0;i<nbOfCells;i++)
6206         {
6207           INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6208           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
6209           cm.changeOrientationOf1D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
6210         }
6211     }
6212 }
6213
6214 /*!
6215  * Finds incorrectly oriented polyhedral cells, i.e. polyhedrons having correctly
6216  * oriented facets. The normal vector of the facet should point out of the cell.
6217  *  \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
6218  *         is not cleared before filling in.
6219  *  \throw If \a this->getMeshDimension() != 3.
6220  *  \throw If \a this->getSpaceDimension() != 3.
6221  *  \throw If the coordinates array is not set.
6222  *  \throw If the nodal connectivity of cells is not defined.
6223  *
6224  *  \if ENABLE_EXAMPLES
6225  *  \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
6226  *  \ref  py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
6227  *  \endif
6228  */
6229 void MEDCouplingUMesh::arePolyhedronsNotCorrectlyOriented(std::vector<int>& cells) const
6230 {
6231   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
6232     throw INTERP_KERNEL::Exception("Invalid mesh to apply arePolyhedronsNotCorrectlyOriented on it : must be meshDim==3 and spaceDim==3 !");
6233   int nbOfCells=getNumberOfCells();
6234   const int *conn=_nodal_connec->getConstPointer();
6235   const int *connI=_nodal_connec_index->getConstPointer();
6236   const double *coordsPtr=_coords->getConstPointer();
6237   for(int i=0;i<nbOfCells;i++)
6238     {
6239       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6240       if(type==INTERP_KERNEL::NORM_POLYHED)
6241         {
6242           if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6243             cells.push_back(i);
6244         }
6245     }
6246 }
6247
6248 /*!
6249  * Tries to fix connectivity of polyhedra, so that normal vector of all facets to point
6250  * out of the cell. 
6251  *  \throw If \a this->getMeshDimension() != 3.
6252  *  \throw If \a this->getSpaceDimension() != 3.
6253  *  \throw If the coordinates array is not set.
6254  *  \throw If the nodal connectivity of cells is not defined.
6255  *  \throw If the reparation fails.
6256  *
6257  *  \if ENABLE_EXAMPLES
6258  *  \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
6259  *  \ref  py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
6260  *  \endif
6261  * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
6262  */
6263 void MEDCouplingUMesh::orientCorrectlyPolyhedrons()
6264 {
6265   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
6266     throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectlyPolyhedrons on it : must be meshDim==3 and spaceDim==3 !");
6267   int nbOfCells=getNumberOfCells();
6268   int *conn=_nodal_connec->getPointer();
6269   const int *connI=_nodal_connec_index->getConstPointer();
6270   const double *coordsPtr=_coords->getConstPointer();
6271   for(int i=0;i<nbOfCells;i++)
6272     {
6273       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6274       if(type==INTERP_KERNEL::NORM_POLYHED)
6275         {
6276           try
6277           {
6278               if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6279                 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
6280           }
6281           catch(INTERP_KERNEL::Exception& e)
6282           {
6283               std::ostringstream oss; oss << "Something wrong in polyhedron #" << i << " : " << e.what();
6284               throw INTERP_KERNEL::Exception(oss.str().c_str());
6285           }
6286         }
6287     }
6288   updateTime();
6289 }
6290
6291 /*!
6292  * Finds and fixes incorrectly oriented linear extruded volumes (INTERP_KERNEL::NORM_HEXA8,
6293  * INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXGP12 etc) to respect the MED convention
6294  * according to which the first facet of the cell should be oriented to have the normal vector
6295  * pointing out of cell.
6296  *  \return DataArrayInt * - a new instance of DataArrayInt holding ids of fixed
6297  *         cells. The caller is to delete this array using decrRef() as it is no more
6298  *         needed. 
6299  *  \throw If \a this->getMeshDimension() != 3.
6300  *  \throw If \a this->getSpaceDimension() != 3.
6301  *  \throw If the coordinates array is not set.
6302  *  \throw If the nodal connectivity of cells is not defined.
6303  *
6304  *  \if ENABLE_EXAMPLES
6305  *  \ref cpp_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a C++ example".<br>
6306  *  \ref  py_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a Python example".
6307  *  \endif
6308  * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
6309  */
6310 DataArrayInt *MEDCouplingUMesh::findAndCorrectBadOriented3DExtrudedCells()
6311 {
6312   const char msg[]="check3DCellsWellOriented detection works only for 3D cells !";
6313   if(getMeshDimension()!=3)
6314     throw INTERP_KERNEL::Exception(msg);
6315   int spaceDim=getSpaceDimension();
6316   if(spaceDim!=3)
6317     throw INTERP_KERNEL::Exception(msg);
6318   //
6319   int nbOfCells=getNumberOfCells();
6320   int *conn=_nodal_connec->getPointer();
6321   const int *connI=_nodal_connec_index->getConstPointer();
6322   const double *coo=getCoords()->getConstPointer();
6323   MCAuto<DataArrayInt> cells(DataArrayInt::New()); cells->alloc(0,1);
6324   for(int i=0;i<nbOfCells;i++)
6325     {
6326       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6327       if(cm.isExtruded() && !cm.isDynamic() && !cm.isQuadratic())
6328         {
6329           if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coo))
6330             {
6331               CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
6332               cells->pushBackSilent(i);
6333             }
6334         }
6335     }
6336   return cells.retn();
6337 }
6338
6339 /*!
6340  * This method is a faster method to correct orientation of all 3D cells in \a this.
6341  * 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.
6342  * This method makes the hypothesis that \a this a coherent that is to say MEDCouplingUMesh::checkConsistency should throw no exception.
6343  * 
6344  * \return a newly allocated int array with one components containing cell ids renumbered to fit the convention of MED (MED file and MEDCoupling)
6345  * \sa MEDCouplingUMesh::orientCorrectlyPolyhedrons, 
6346  */
6347 DataArrayInt *MEDCouplingUMesh::findAndCorrectBadOriented3DCells()
6348 {
6349   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
6350     throw INTERP_KERNEL::Exception("Invalid mesh to apply findAndCorrectBadOriented3DCells on it : must be meshDim==3 and spaceDim==3 !");
6351   int nbOfCells=getNumberOfCells();
6352   int *conn=_nodal_connec->getPointer();
6353   const int *connI=_nodal_connec_index->getConstPointer();
6354   const double *coordsPtr=_coords->getConstPointer();
6355   MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
6356   for(int i=0;i<nbOfCells;i++)
6357     {
6358       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6359       switch(type)
6360       {
6361         case INTERP_KERNEL::NORM_TETRA4:
6362           {
6363             if(!IsTetra4WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6364               {
6365                 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+3));
6366                 ret->pushBackSilent(i);
6367               }
6368             break;
6369           }
6370         case INTERP_KERNEL::NORM_PYRA5:
6371           {
6372             if(!IsPyra5WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6373               {
6374                 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+4));
6375                 ret->pushBackSilent(i);
6376               }
6377             break;
6378           }
6379         case INTERP_KERNEL::NORM_PENTA6:
6380         case INTERP_KERNEL::NORM_HEXA8:
6381         case INTERP_KERNEL::NORM_HEXGP12:
6382           {
6383             if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6384               {
6385                 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
6386                 ret->pushBackSilent(i);
6387               }
6388             break;
6389           }
6390         case INTERP_KERNEL::NORM_POLYHED:
6391           {
6392             if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6393               {
6394                 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
6395                 ret->pushBackSilent(i);
6396               }
6397             break;
6398           }
6399         default:
6400           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 !");
6401       }
6402     }
6403   updateTime();
6404   return ret.retn();
6405 }
6406
6407 /*!
6408  * This method has a sense for meshes with spaceDim==3 and meshDim==2.
6409  * If it is not the case an exception will be thrown.
6410  * This method is fast because the first cell of \a this is used to compute the plane.
6411  * \param vec output of size at least 3 used to store the normal vector (with norm equal to Area ) of searched plane.
6412  * \param pos output of size at least 3 used to store a point owned of searched plane.
6413  */
6414 void MEDCouplingUMesh::getFastAveragePlaneOfThis(double *vec, double *pos) const
6415 {
6416   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
6417     throw INTERP_KERNEL::Exception("Invalid mesh to apply getFastAveragePlaneOfThis on it : must be meshDim==2 and spaceDim==3 !");
6418   const int *conn=_nodal_connec->getConstPointer();
6419   const int *connI=_nodal_connec_index->getConstPointer();
6420   const double *coordsPtr=_coords->getConstPointer();
6421   INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(conn+1,connI[1]-connI[0]-1,coordsPtr,vec);
6422   std::copy(coordsPtr+3*conn[1],coordsPtr+3*conn[1]+3,pos);
6423 }
6424
6425 /*!
6426  * Creates a new MEDCouplingFieldDouble holding Edge Ratio values of all
6427  * cells. Currently cells of the following types are treated:
6428  * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
6429  * For a cell of other type an exception is thrown.
6430  * Space dimension of a 2D mesh can be either 2 or 3.
6431  * The Edge Ratio of a cell \f$t\f$ is: 
6432  *  \f$\frac{|t|_\infty}{|t|_0}\f$,
6433  *  where \f$|t|_\infty\f$ and \f$|t|_0\f$ respectively denote the greatest and
6434  *  the smallest edge lengths of \f$t\f$.
6435  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6436  *          cells and one time, lying on \a this mesh. The caller is to delete this
6437  *          field using decrRef() as it is no more needed. 
6438  *  \throw If the coordinates array is not set.
6439  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6440  *  \throw If the connectivity data array has more than one component.
6441  *  \throw If the connectivity data array has a named component.
6442  *  \throw If the connectivity index data array has more than one component.
6443  *  \throw If the connectivity index data array has a named component.
6444  *  \throw If \a this->getMeshDimension() is neither 2 nor 3.
6445  *  \throw If \a this->getSpaceDimension() is neither 2 nor 3.
6446  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
6447  */
6448 MEDCouplingFieldDouble *MEDCouplingUMesh::getEdgeRatioField() const
6449 {
6450   checkConsistencyLight();
6451   int spaceDim=getSpaceDimension();
6452   int meshDim=getMeshDimension();
6453   if(spaceDim!=2 && spaceDim!=3)
6454     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : SpaceDimension must be equal to 2 or 3 !");
6455   if(meshDim!=2 && meshDim!=3)
6456     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : MeshDimension must be equal to 2 or 3 !");
6457   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6458   ret->setMesh(this);
6459   int nbOfCells=getNumberOfCells();
6460   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6461   arr->alloc(nbOfCells,1);
6462   double *pt=arr->getPointer();
6463   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6464   const int *conn=_nodal_connec->getConstPointer();
6465   const int *connI=_nodal_connec_index->getConstPointer();
6466   const double *coo=_coords->getConstPointer();
6467   double tmp[12];
6468   for(int i=0;i<nbOfCells;i++,pt++)
6469     {
6470       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6471       switch(t)
6472       {
6473         case INTERP_KERNEL::NORM_TRI3:
6474           {
6475             FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
6476             *pt=INTERP_KERNEL::triEdgeRatio(tmp);
6477             break;
6478           }
6479         case INTERP_KERNEL::NORM_QUAD4:
6480           {
6481             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6482             *pt=INTERP_KERNEL::quadEdgeRatio(tmp);
6483             break;
6484           }
6485         case INTERP_KERNEL::NORM_TETRA4:
6486           {
6487             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6488             *pt=INTERP_KERNEL::tetraEdgeRatio(tmp);
6489             break;
6490           }
6491         default:
6492           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
6493       }
6494       conn+=connI[i+1]-connI[i];
6495     }
6496   ret->setName("EdgeRatio");
6497   ret->synchronizeTimeWithSupport();
6498   return ret.retn();
6499 }
6500
6501 /*!
6502  * Creates a new MEDCouplingFieldDouble holding Aspect Ratio values of all
6503  * cells. Currently cells of the following types are treated:
6504  * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
6505  * For a cell of other type an exception is thrown.
6506  * Space dimension of a 2D mesh can be either 2 or 3.
6507  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6508  *          cells and one time, lying on \a this mesh. The caller is to delete this
6509  *          field using decrRef() as it is no more needed. 
6510  *  \throw If the coordinates array is not set.
6511  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6512  *  \throw If the connectivity data array has more than one component.
6513  *  \throw If the connectivity data array has a named component.
6514  *  \throw If the connectivity index data array has more than one component.
6515  *  \throw If the connectivity index data array has a named component.
6516  *  \throw If \a this->getMeshDimension() is neither 2 nor 3.
6517  *  \throw If \a this->getSpaceDimension() is neither 2 nor 3.
6518  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
6519  */
6520 MEDCouplingFieldDouble *MEDCouplingUMesh::getAspectRatioField() const
6521 {
6522   checkConsistencyLight();
6523   int spaceDim=getSpaceDimension();
6524   int meshDim=getMeshDimension();
6525   if(spaceDim!=2 && spaceDim!=3)
6526     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : SpaceDimension must be equal to 2 or 3 !");
6527   if(meshDim!=2 && meshDim!=3)
6528     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : MeshDimension must be equal to 2 or 3 !");
6529   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6530   ret->setMesh(this);
6531   int nbOfCells=getNumberOfCells();
6532   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6533   arr->alloc(nbOfCells,1);
6534   double *pt=arr->getPointer();
6535   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6536   const int *conn=_nodal_connec->getConstPointer();
6537   const int *connI=_nodal_connec_index->getConstPointer();
6538   const double *coo=_coords->getConstPointer();
6539   double tmp[12];
6540   for(int i=0;i<nbOfCells;i++,pt++)
6541     {
6542       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6543       switch(t)
6544       {
6545         case INTERP_KERNEL::NORM_TRI3:
6546           {
6547             FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
6548             *pt=INTERP_KERNEL::triAspectRatio(tmp);
6549             break;
6550           }
6551         case INTERP_KERNEL::NORM_QUAD4:
6552           {
6553             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6554             *pt=INTERP_KERNEL::quadAspectRatio(tmp);
6555             break;
6556           }
6557         case INTERP_KERNEL::NORM_TETRA4:
6558           {
6559             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6560             *pt=INTERP_KERNEL::tetraAspectRatio(tmp);
6561             break;
6562           }
6563         default:
6564           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
6565       }
6566       conn+=connI[i+1]-connI[i];
6567     }
6568   ret->setName("AspectRatio");
6569   ret->synchronizeTimeWithSupport();
6570   return ret.retn();
6571 }
6572
6573 /*!
6574  * Creates a new MEDCouplingFieldDouble holding Warping factor values of all
6575  * cells of \a this 2D mesh in 3D space. It is a measure of the "planarity" of 2D cell
6576  * in 3D space. Currently only cells of the following types are
6577  * treated: INTERP_KERNEL::NORM_QUAD4.
6578  * For a cell of other type an exception is thrown.
6579  * The warp field is computed as follows: let (a,b,c,d) be the points of the quad.
6580  * Defining
6581  * \f$t=\vec{da}\times\vec{ab}\f$,
6582  * \f$u=\vec{ab}\times\vec{bc}\f$
6583  * \f$v=\vec{bc}\times\vec{cd}\f$
6584  * \f$w=\vec{cd}\times\vec{da}\f$, the warp is defined as \f$W^3\f$ with
6585  *  \f[
6586  *     W=min(\frac{t}{|t|}\cdot\frac{v}{|v|}, \frac{u}{|u|}\cdot\frac{w}{|w|})
6587  *  \f]
6588  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6589  *          cells and one time, lying on \a this mesh. The caller is to delete this
6590  *          field using decrRef() as it is no more needed. 
6591  *  \throw If the coordinates array is not set.
6592  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6593  *  \throw If the connectivity data array has more than one component.
6594  *  \throw If the connectivity data array has a named component.
6595  *  \throw If the connectivity index data array has more than one component.
6596  *  \throw If the connectivity index data array has a named component.
6597  *  \throw If \a this->getMeshDimension() != 2.
6598  *  \throw If \a this->getSpaceDimension() != 3.
6599  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
6600  */
6601 MEDCouplingFieldDouble *MEDCouplingUMesh::getWarpField() const
6602 {
6603   checkConsistencyLight();
6604   int spaceDim=getSpaceDimension();
6605   int meshDim=getMeshDimension();
6606   if(spaceDim!=3)
6607     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : SpaceDimension must be equal to 3 !");
6608   if(meshDim!=2)
6609     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : MeshDimension must be equal to 2 !");
6610   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6611   ret->setMesh(this);
6612   int nbOfCells=getNumberOfCells();
6613   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6614   arr->alloc(nbOfCells,1);
6615   double *pt=arr->getPointer();
6616   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6617   const int *conn=_nodal_connec->getConstPointer();
6618   const int *connI=_nodal_connec_index->getConstPointer();
6619   const double *coo=_coords->getConstPointer();
6620   double tmp[12];
6621   for(int i=0;i<nbOfCells;i++,pt++)
6622     {
6623       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6624       switch(t)
6625       {
6626         case INTERP_KERNEL::NORM_QUAD4:
6627           {
6628             FillInCompact3DMode(3,4,conn+1,coo,tmp);
6629             *pt=INTERP_KERNEL::quadWarp(tmp);
6630             break;
6631           }
6632         default:
6633           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : A cell with not manged type (NORM_QUAD4) has been detected !");
6634       }
6635       conn+=connI[i+1]-connI[i];
6636     }
6637   ret->setName("Warp");
6638   ret->synchronizeTimeWithSupport();
6639   return ret.retn();
6640 }
6641
6642
6643 /*!
6644  * Creates a new MEDCouplingFieldDouble holding Skew factor values of all
6645  * cells of \a this 2D mesh in 3D space. Currently cells of the following types are
6646  * treated: INTERP_KERNEL::NORM_QUAD4.
6647  * The skew is computed as follow for a quad with points (a,b,c,d): let
6648  * \f$u=\vec{ab}+\vec{dc}\f$ and \f$v=\vec{ac}+\vec{bd}\f$
6649  * then the skew is computed as:
6650  *  \f[
6651  *    s=\frac{u}{|u|}\cdot\frac{v}{|v|}
6652  *  \f]
6653  *
6654  * For a cell of other type an exception is thrown.
6655  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6656  *          cells and one time, lying on \a this mesh. The caller is to delete this
6657  *          field using decrRef() as it is no more needed. 
6658  *  \throw If the coordinates array is not set.
6659  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6660  *  \throw If the connectivity data array has more than one component.
6661  *  \throw If the connectivity data array has a named component.
6662  *  \throw If the connectivity index data array has more than one component.
6663  *  \throw If the connectivity index data array has a named component.
6664  *  \throw If \a this->getMeshDimension() != 2.
6665  *  \throw If \a this->getSpaceDimension() != 3.
6666  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
6667  */
6668 MEDCouplingFieldDouble *MEDCouplingUMesh::getSkewField() const
6669 {
6670   checkConsistencyLight();
6671   int spaceDim=getSpaceDimension();
6672   int meshDim=getMeshDimension();
6673   if(spaceDim!=3)
6674     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : SpaceDimension must be equal to 3 !");
6675   if(meshDim!=2)
6676     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : MeshDimension must be equal to 2 !");
6677   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6678   ret->setMesh(this);
6679   int nbOfCells=getNumberOfCells();
6680   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6681   arr->alloc(nbOfCells,1);
6682   double *pt=arr->getPointer();
6683   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6684   const int *conn=_nodal_connec->getConstPointer();
6685   const int *connI=_nodal_connec_index->getConstPointer();
6686   const double *coo=_coords->getConstPointer();
6687   double tmp[12];
6688   for(int i=0;i<nbOfCells;i++,pt++)
6689     {
6690       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6691       switch(t)
6692       {
6693         case INTERP_KERNEL::NORM_QUAD4:
6694           {
6695             FillInCompact3DMode(3,4,conn+1,coo,tmp);
6696             *pt=INTERP_KERNEL::quadSkew(tmp);
6697             break;
6698           }
6699         default:
6700           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : A cell with not manged type (NORM_QUAD4) has been detected !");
6701       }
6702       conn+=connI[i+1]-connI[i];
6703     }
6704   ret->setName("Skew");
6705   ret->synchronizeTimeWithSupport();
6706   return ret.retn();
6707 }
6708
6709 /*!
6710  * 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.
6711  *
6712  * \return a new instance of field containing the result. The returned instance has to be deallocated by the caller.
6713  *
6714  * \sa getSkewField, getWarpField, getAspectRatioField, getEdgeRatioField
6715  */
6716 MEDCouplingFieldDouble *MEDCouplingUMesh::computeDiameterField() const
6717 {
6718   checkConsistencyLight();
6719   MCAuto<MEDCouplingFieldDouble> ret(MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME));
6720   ret->setMesh(this);
6721   std::set<INTERP_KERNEL::NormalizedCellType> types;
6722   ComputeAllTypesInternal(types,_nodal_connec,_nodal_connec_index);
6723   int spaceDim(getSpaceDimension()),nbCells(getNumberOfCells());
6724   MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
6725   arr->alloc(nbCells,1);
6726   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++)
6727     {
6728       INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::DiameterCalculator> dc(INTERP_KERNEL::CellModel::GetCellModel(*it).buildInstanceOfDiameterCalulator(spaceDim));
6729       MCAuto<DataArrayInt> cellIds(giveCellsWithType(*it));
6730       dc->computeForListOfCellIdsUMeshFrmt(cellIds->begin(),cellIds->end(),_nodal_connec_index->begin(),_nodal_connec->begin(),getCoords()->begin(),arr->getPointer());
6731     }
6732   ret->setArray(arr);
6733   ret->setName("Diameter");
6734   return ret.retn();
6735 }
6736
6737 /*!
6738  * This method aggregate the bbox of each cell and put it into bbox parameter (xmin,xmax,ymin,ymax,zmin,zmax).
6739  * 
6740  * \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)
6741  *                         For all other cases this input parameter is ignored.
6742  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6743  * 
6744  * \throw If \a this is not fully set (coordinates and connectivity).
6745  * \throw If a cell in \a this has no valid nodeId.
6746  * \sa MEDCouplingUMesh::getBoundingBoxForBBTreeFast, MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
6747  */
6748 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree(double arcDetEps) const
6749 {
6750   int mDim(getMeshDimension()),sDim(getSpaceDimension());
6751   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.
6752     return getBoundingBoxForBBTreeFast();
6753   if((mDim==2 && sDim==2) || (mDim==1 && sDim==2))
6754     {
6755       bool presenceOfQuadratic(false);
6756       for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=_types.begin();it!=_types.end();it++)
6757         {
6758           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(*it));
6759           if(cm.isQuadratic())
6760             presenceOfQuadratic=true;
6761         }
6762       if(!presenceOfQuadratic)
6763         return getBoundingBoxForBBTreeFast();
6764       if(mDim==2 && sDim==2)
6765         return getBoundingBoxForBBTree2DQuadratic(arcDetEps);
6766       else
6767         return getBoundingBoxForBBTree1DQuadratic(arcDetEps);
6768     }
6769   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) !");
6770 }
6771
6772 /*!
6773  * This method aggregate the bbox of each cell only considering the nodes constituting each cell and put it into bbox parameter.
6774  * So meshes having quadratic cells the computed bounding boxes can be invalid !
6775  * 
6776  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6777  * 
6778  * \throw If \a this is not fully set (coordinates and connectivity).
6779  * \throw If a cell in \a this has no valid nodeId.
6780  */
6781 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTreeFast() const
6782 {
6783   checkFullyDefined();
6784   int spaceDim(getSpaceDimension()),nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
6785   MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
6786   double *bbox(ret->getPointer());
6787   for(int i=0;i<nbOfCells*spaceDim;i++)
6788     {
6789       bbox[2*i]=std::numeric_limits<double>::max();
6790       bbox[2*i+1]=-std::numeric_limits<double>::max();
6791     }
6792   const double *coordsPtr(_coords->getConstPointer());
6793   const int *conn(_nodal_connec->getConstPointer()),*connI(_nodal_connec_index->getConstPointer());
6794   for(int i=0;i<nbOfCells;i++)
6795     {
6796       int offset=connI[i]+1;
6797       int nbOfNodesForCell(connI[i+1]-offset),kk(0);
6798       for(int j=0;j<nbOfNodesForCell;j++)
6799         {
6800           int nodeId=conn[offset+j];
6801           if(nodeId>=0 && nodeId<nbOfNodes)
6802             {
6803               for(int k=0;k<spaceDim;k++)
6804                 {
6805                   bbox[2*spaceDim*i+2*k]=std::min(bbox[2*spaceDim*i+2*k],coordsPtr[spaceDim*nodeId+k]);
6806                   bbox[2*spaceDim*i+2*k+1]=std::max(bbox[2*spaceDim*i+2*k+1],coordsPtr[spaceDim*nodeId+k]);
6807                 }
6808               kk++;
6809             }
6810         }
6811       if(kk==0)
6812         {
6813           std::ostringstream oss; oss << "MEDCouplingUMesh::getBoundingBoxForBBTree : cell #" << i << " contains no valid nodeId !";
6814           throw INTERP_KERNEL::Exception(oss.str().c_str());
6815         }
6816     }
6817   return ret.retn();
6818 }
6819
6820 /*!
6821  * This method aggregates the bbox of each 2D cell in \a this considering the whole shape. This method is particularly
6822  * useful for 2D meshes having quadratic cells
6823  * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
6824  * the two extremities of the arc of circle).
6825  * 
6826  * \param [in] arcDetEps - a parameter specifying in case of 2D quadratic polygon cell the detection limit between linear and arc circle. (By default 1e-12)
6827  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6828  * \throw If \a this is not fully defined.
6829  * \throw If \a this is not a mesh with meshDimension equal to 2.
6830  * \throw If \a this is not a mesh with spaceDimension equal to 2.
6831  * \sa MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic
6832  */
6833 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic(double arcDetEps) const
6834 {
6835   checkFullyDefined();
6836   int spaceDim(getSpaceDimension()),mDim(getMeshDimension()),nbOfCells(getNumberOfCells());
6837   if(spaceDim!=2 || mDim!=2)
6838     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!");
6839   MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
6840   double *bbox(ret->getPointer());
6841   const double *coords(_coords->getConstPointer());
6842   const int *conn(_nodal_connec->getConstPointer()),*connI(_nodal_connec_index->getConstPointer());
6843   for(int i=0;i<nbOfCells;i++,bbox+=4,connI++)
6844     {
6845       const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
6846       int sz(connI[1]-connI[0]-1);
6847       INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=arcDetEps;
6848       std::vector<INTERP_KERNEL::Node *> nodes(sz);
6849       INTERP_KERNEL::QuadraticPolygon *pol(0);
6850       for(int j=0;j<sz;j++)
6851         {
6852           int nodeId(conn[*connI+1+j]);
6853           nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
6854         }
6855       if(!cm.isQuadratic())
6856         pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
6857       else
6858         pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
6859       INTERP_KERNEL::Bounds b; b.prepareForAggregation(); pol->fillBounds(b); delete pol;
6860       bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax(); 
6861     }
6862   return ret.retn();
6863 }
6864
6865 /*!
6866  * This method aggregates the bbox of each 1D cell in \a this considering the whole shape. This method is particularly
6867  * useful for 2D meshes having quadratic cells
6868  * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
6869  * the two extremities of the arc of circle).
6870  * 
6871  * \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)
6872  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6873  * \throw If \a this is not fully defined.
6874  * \throw If \a this is not a mesh with meshDimension equal to 1.
6875  * \throw If \a this is not a mesh with spaceDimension equal to 2.
6876  * \sa MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
6877  */
6878 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic(double arcDetEps) const
6879 {
6880   checkFullyDefined();
6881   int spaceDim(getSpaceDimension()),mDim(getMeshDimension()),nbOfCells(getNumberOfCells());
6882   if(spaceDim!=2 || mDim!=1)
6883     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!");
6884   MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
6885   double *bbox(ret->getPointer());
6886   const double *coords(_coords->getConstPointer());
6887   const int *conn(_nodal_connec->getConstPointer()),*connI(_nodal_connec_index->getConstPointer());
6888   for(int i=0;i<nbOfCells;i++,bbox+=4,connI++)
6889     {
6890       const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
6891       int sz(connI[1]-connI[0]-1);
6892       INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=arcDetEps;
6893       std::vector<INTERP_KERNEL::Node *> nodes(sz);
6894       INTERP_KERNEL::Edge *edge(0);
6895       for(int j=0;j<sz;j++)
6896         {
6897           int nodeId(conn[*connI+1+j]);
6898           nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
6899         }
6900       if(!cm.isQuadratic())
6901         edge=INTERP_KERNEL::QuadraticPolygon::BuildLinearEdge(nodes);
6902       else
6903         edge=INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(nodes);
6904       const INTERP_KERNEL::Bounds& b(edge->getBounds());
6905       bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax(); edge->decrRef();
6906     }
6907   return ret.retn();
6908 }
6909
6910 /// @cond INTERNAL
6911
6912 namespace MEDCouplingImpl
6913 {
6914   class ConnReader
6915   {
6916   public:
6917     ConnReader(const int *c, int val):_conn(c),_val(val) { }
6918     bool operator() (const int& pos) { return _conn[pos]!=_val; }
6919   private:
6920     const int *_conn;
6921     int _val;
6922   };
6923
6924   class ConnReader2
6925   {
6926   public:
6927     ConnReader2(const int *c, int val):_conn(c),_val(val) { }
6928     bool operator() (const int& pos) { return _conn[pos]==_val; }
6929   private:
6930     const int *_conn;
6931     int _val;
6932   };
6933 }
6934
6935 /// @endcond
6936
6937 /*!
6938  * This method expects that \a this is sorted by types. If not an exception will be thrown.
6939  * This method returns in the same format as code (see MEDCouplingUMesh::checkTypeConsistencyAndContig or MEDCouplingUMesh::splitProfilePerType) how
6940  * \a this is composed in cell types.
6941  * The returned array is of size 3*n where n is the number of different types present in \a this. 
6942  * For every k in [0,n] ret[3*k+2]==-1 because it has no sense here. 
6943  * This parameter is kept only for compatibility with other methode listed above.
6944  */
6945 std::vector<int> MEDCouplingUMesh::getDistributionOfTypes() const
6946 {
6947   checkConnectivityFullyDefined();
6948   const int *conn=_nodal_connec->getConstPointer();
6949   const int *connI=_nodal_connec_index->getConstPointer();
6950   const int *work=connI;
6951   int nbOfCells=getNumberOfCells();
6952   std::size_t n=getAllGeoTypes().size();
6953   std::vector<int> ret(3*n,-1); //ret[3*k+2]==-1 because it has no sense here
6954   std::set<INTERP_KERNEL::NormalizedCellType> types;
6955   for(std::size_t i=0;work!=connI+nbOfCells;i++)
6956     {
6957       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn[*work];
6958       if(types.find(typ)!=types.end())
6959         {
6960           std::ostringstream oss; oss << "MEDCouplingUMesh::getDistributionOfTypes : Type " << INTERP_KERNEL::CellModel::GetCellModel(typ).getRepr();
6961           oss << " is not contiguous !";
6962           throw INTERP_KERNEL::Exception(oss.str().c_str());
6963         }
6964       types.insert(typ);
6965       ret[3*i]=typ;
6966       const int *work2=std::find_if(work+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,typ));
6967       ret[3*i+1]=(int)std::distance(work,work2);
6968       work=work2;
6969     }
6970   return ret;
6971 }
6972
6973 /*!
6974  * This method is used to check that this has contiguous cell type in same order than described in \a code.
6975  * only for types cell, type node is not managed.
6976  * Format of \a code is the following. \a code should be of size 3*n and non empty. If not an exception is thrown.
6977  * foreach k in [0,n) on 3*k pos represent the geometric type and 3*k+1 number of elements of type 3*k.
6978  * 3*k+2 refers if different from -1 the pos in 'idsPerType' to get the corresponding array.
6979  * If 2 or more same geometric type is in \a code and exception is thrown too.
6980  *
6981  * This method firstly checks
6982  * If it exists k so that 3*k geometric type is not in geometric types of this an exception will be thrown.
6983  * If it exists k so that 3*k geometric type exists but the number of consecutive cell types does not match,
6984  * an exception is thrown too.
6985  * 
6986  * If all geometric types in \a code are exactly those in \a this null pointer is returned.
6987  * If it exists a geometric type in \a this \b not in \a code \b no exception is thrown 
6988  * and a DataArrayInt instance is returned that the user has the responsability to deallocate.
6989  */
6990 DataArrayInt *MEDCouplingUMesh::checkTypeConsistencyAndContig(const std::vector<int>& code, const std::vector<const DataArrayInt *>& idsPerType) const
6991 {
6992   if(code.empty())
6993     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code is empty, should not !");
6994   std::size_t sz=code.size();
6995   std::size_t n=sz/3;
6996   if(sz%3!=0)
6997     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code size is NOT %3 !");
6998   std::vector<INTERP_KERNEL::NormalizedCellType> types;
6999   int nb=0;
7000   bool isNoPflUsed=true;
7001   for(std::size_t i=0;i<n;i++)
7002     if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)code[3*i])==types.end())
7003       {
7004         types.push_back((INTERP_KERNEL::NormalizedCellType)code[3*i]);
7005         nb+=code[3*i+1];
7006         if(_types.find((INTERP_KERNEL::NormalizedCellType)code[3*i])==_types.end())
7007           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : expected geo types not in this !");
7008         isNoPflUsed=isNoPflUsed && (code[3*i+2]==-1);
7009       }
7010   if(types.size()!=n)
7011     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code contains duplication of types in unstructured mesh !");
7012   if(isNoPflUsed)
7013     {
7014       if(!checkConsecutiveCellTypesAndOrder(&types[0],&types[0]+types.size()))
7015         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : non contiguous type !");
7016       if(types.size()==_types.size())
7017         return 0;
7018     }
7019   MCAuto<DataArrayInt> ret=DataArrayInt::New();
7020   ret->alloc(nb,1);
7021   int *retPtr=ret->getPointer();
7022   const int *connI=_nodal_connec_index->getConstPointer();
7023   const int *conn=_nodal_connec->getConstPointer();
7024   int nbOfCells=getNumberOfCells();
7025   const int *i=connI;
7026   int kk=0;
7027   for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++,kk++)
7028     {
7029       i=std::find_if(i,connI+nbOfCells,MEDCouplingImpl::ConnReader2(conn,(int)(*it)));
7030       int offset=(int)std::distance(connI,i);
7031       const int *j=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)(*it)));
7032       int nbOfCellsOfCurType=(int)std::distance(i,j);
7033       if(code[3*kk+2]==-1)
7034         for(int k=0;k<nbOfCellsOfCurType;k++)
7035           *retPtr++=k+offset;
7036       else
7037         {
7038           int idInIdsPerType=code[3*kk+2];
7039           if(idInIdsPerType>=0 && idInIdsPerType<(int)idsPerType.size())
7040             {
7041               const DataArrayInt *zePfl=idsPerType[idInIdsPerType];
7042               if(zePfl)
7043                 {
7044                   zePfl->checkAllocated();
7045                   if(zePfl->getNumberOfComponents()==1)
7046                     {
7047                       for(const int *k=zePfl->begin();k!=zePfl->end();k++,retPtr++)
7048                         {
7049                           if(*k>=0 && *k<nbOfCellsOfCurType)
7050                             *retPtr=(*k)+offset;
7051                           else
7052                             {
7053                               std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : the section " << kk << " points to the profile #" << idInIdsPerType;
7054                               oss << ", and this profile contains a value " << *k << " should be in [0," << nbOfCellsOfCurType << ") !";
7055                               throw INTERP_KERNEL::Exception(oss.str().c_str());
7056                             }
7057                         }
7058                     }
7059                   else
7060                     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of a profile with nb of compo != 1 !");
7061                 }
7062               else
7063                 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of null profile !");
7064             }
7065           else
7066             {
7067               std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : at section " << kk << " of code it points to the array #" << idInIdsPerType;
7068               oss << " should be in [0," << idsPerType.size() << ") !";
7069               throw INTERP_KERNEL::Exception(oss.str().c_str());
7070             }
7071         }
7072       i=j;
7073     }
7074   return ret.retn();
7075 }
7076
7077 /*!
7078  * This method makes the hypothesis that \a this is sorted by type. If not an exception will be thrown.
7079  * 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.
7080  * 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.
7081  * This method has 1 input \a profile and 3 outputs \a code \a idsInPflPerType and \a idsPerType.
7082  * 
7083  * \param [in] profile
7084  * \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.
7085  * \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,
7086  *              \a idsInPflPerType[i] stores the tuple ids in \a profile that correspond to the geometric type code[3*i+0]
7087  * \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.
7088  *              This vector can be empty in case of all geometric type cells are fully covered in ascending in the given input \a profile.
7089  * \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
7090  */
7091 void MEDCouplingUMesh::splitProfilePerType(const DataArrayInt *profile, std::vector<int>& code, std::vector<DataArrayInt *>& idsInPflPerType, std::vector<DataArrayInt *>& idsPerType) const
7092 {
7093   if(!profile)
7094     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile is NULL !");
7095   if(profile->getNumberOfComponents()!=1)
7096     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile should have exactly one component !");
7097   checkConnectivityFullyDefined();
7098   const int *conn=_nodal_connec->getConstPointer();
7099   const int *connI=_nodal_connec_index->getConstPointer();
7100   int nbOfCells=getNumberOfCells();
7101   std::vector<INTERP_KERNEL::NormalizedCellType> types;
7102   std::vector<int> typeRangeVals(1);
7103   for(const int *i=connI;i!=connI+nbOfCells;)
7104     {
7105       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7106       if(std::find(types.begin(),types.end(),curType)!=types.end())
7107         {
7108           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : current mesh is not sorted by type !");
7109         }
7110       types.push_back(curType);
7111       i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7112       typeRangeVals.push_back((int)std::distance(connI,i));
7113     }
7114   //
7115   DataArrayInt *castArr=0,*rankInsideCast=0,*castsPresent=0;
7116   profile->splitByValueRange(&typeRangeVals[0],&typeRangeVals[0]+typeRangeVals.size(),castArr,rankInsideCast,castsPresent);
7117   MCAuto<DataArrayInt> tmp0=castArr;
7118   MCAuto<DataArrayInt> tmp1=rankInsideCast;
7119   MCAuto<DataArrayInt> tmp2=castsPresent;
7120   //
7121   int nbOfCastsFinal=castsPresent->getNumberOfTuples();
7122   code.resize(3*nbOfCastsFinal);
7123   std::vector< MCAuto<DataArrayInt> > idsInPflPerType2;
7124   std::vector< MCAuto<DataArrayInt> > idsPerType2;
7125   for(int i=0;i<nbOfCastsFinal;i++)
7126     {
7127       int castId=castsPresent->getIJ(i,0);
7128       MCAuto<DataArrayInt> tmp3=castArr->findIdsEqual(castId);
7129       idsInPflPerType2.push_back(tmp3);
7130       code[3*i]=(int)types[castId];
7131       code[3*i+1]=tmp3->getNumberOfTuples();
7132       MCAuto<DataArrayInt> tmp4=rankInsideCast->selectByTupleId(tmp3->getConstPointer(),tmp3->getConstPointer()+tmp3->getNumberOfTuples());
7133       if(!tmp4->isIota(typeRangeVals[castId+1]-typeRangeVals[castId]))
7134         {
7135           tmp4->copyStringInfoFrom(*profile);
7136           idsPerType2.push_back(tmp4);
7137           code[3*i+2]=(int)idsPerType2.size()-1;
7138         }
7139       else
7140         {
7141           code[3*i+2]=-1;
7142         }
7143     }
7144   std::size_t sz2=idsInPflPerType2.size();
7145   idsInPflPerType.resize(sz2);
7146   for(std::size_t i=0;i<sz2;i++)
7147     {
7148       DataArrayInt *locDa=idsInPflPerType2[i];
7149       locDa->incrRef();
7150       idsInPflPerType[i]=locDa;
7151     }
7152   std::size_t sz=idsPerType2.size();
7153   idsPerType.resize(sz);
7154   for(std::size_t i=0;i<sz;i++)
7155     {
7156       DataArrayInt *locDa=idsPerType2[i];
7157       locDa->incrRef();
7158       idsPerType[i]=locDa;
7159     }
7160 }
7161
7162 /*!
7163  * This method is here too emulate the MEDMEM behaviour on BDC (buildDescendingConnectivity). Hoping this method becomes deprecated very soon.
7164  * This method make the assumption that \a this and 'nM1LevMesh' mesh lyies on same coords (same pointer) as MED and MEDMEM does.
7165  * The following equality should be verified 'nM1LevMesh->getMeshDimension()==this->getMeshDimension()-1'
7166  * 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.
7167  */
7168 MEDCouplingUMesh *MEDCouplingUMesh::emulateMEDMEMBDC(const MEDCouplingUMesh *nM1LevMesh, DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *&revDesc, DataArrayInt *&revDescIndx, DataArrayInt *& nM1LevMeshIds, DataArrayInt *&meshnM1Old2New) const
7169 {
7170   checkFullyDefined();
7171   nM1LevMesh->checkFullyDefined();
7172   if(getMeshDimension()-1!=nM1LevMesh->getMeshDimension())
7173     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : The mesh passed as first argument should have a meshDim equal to this->getMeshDimension()-1 !" );
7174   if(_coords!=nM1LevMesh->getCoords())
7175     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : 'this' and mesh in first argument should share the same coords : Use tryToShareSameCoords method !");
7176   MCAuto<DataArrayInt> tmp0=DataArrayInt::New();
7177   MCAuto<DataArrayInt> tmp1=DataArrayInt::New();
7178   MCAuto<MEDCouplingUMesh> ret1=buildDescendingConnectivity(desc,descIndx,tmp0,tmp1);
7179   MCAuto<DataArrayInt> ret0=ret1->sortCellsInMEDFileFrmt();
7180   desc->transformWithIndArr(ret0->getConstPointer(),ret0->getConstPointer()+ret0->getNbOfElems());
7181   MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
7182   tmp->setConnectivity(tmp0,tmp1);
7183   tmp->renumberCells(ret0->getConstPointer(),false);
7184   revDesc=tmp->getNodalConnectivity();
7185   revDescIndx=tmp->getNodalConnectivityIndex();
7186   DataArrayInt *ret=0;
7187   if(!ret1->areCellsIncludedIn(nM1LevMesh,2,ret))
7188     {
7189       int tmp2;
7190       ret->getMaxValue(tmp2);
7191       ret->decrRef();
7192       std::ostringstream oss; oss << "MEDCouplingUMesh::emulateMEDMEMBDC : input N-1 mesh present a cell not in descending mesh ... Id of cell is " << tmp2 << " !";
7193       throw INTERP_KERNEL::Exception(oss.str().c_str());
7194     }
7195   nM1LevMeshIds=ret;
7196   //
7197   revDesc->incrRef();
7198   revDescIndx->incrRef();
7199   ret1->incrRef();
7200   ret0->incrRef();
7201   meshnM1Old2New=ret0;
7202   return ret1;
7203 }
7204
7205 /*!
7206  * Permutes the nodal connectivity arrays so that the cells are sorted by type, which is
7207  * necessary for writing the mesh to MED file. Additionally returns a permutation array
7208  * in "Old to New" mode.
7209  *  \return DataArrayInt * - a new instance of DataArrayInt. The caller is to delete
7210  *          this array using decrRef() as it is no more needed.
7211  *  \throw If the nodal connectivity of cells is not defined.
7212  */
7213 DataArrayInt *MEDCouplingUMesh::sortCellsInMEDFileFrmt()
7214 {
7215   checkConnectivityFullyDefined();
7216   MCAuto<DataArrayInt> ret=getRenumArrForMEDFileFrmt();
7217   renumberCells(ret->getConstPointer(),false);
7218   return ret.retn();
7219 }
7220
7221 /*!
7222  * This methods checks that cells are sorted by their types.
7223  * This method makes asumption (no check) that connectivity is correctly set before calling.
7224  */
7225 bool MEDCouplingUMesh::checkConsecutiveCellTypes() const
7226 {
7227   checkFullyDefined();
7228   const int *conn=_nodal_connec->getConstPointer();
7229   const int *connI=_nodal_connec_index->getConstPointer();
7230   int nbOfCells=getNumberOfCells();
7231   std::set<INTERP_KERNEL::NormalizedCellType> types;
7232   for(const int *i=connI;i!=connI+nbOfCells;)
7233     {
7234       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7235       if(types.find(curType)!=types.end())
7236         return false;
7237       types.insert(curType);
7238       i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7239     }
7240   return true;
7241 }
7242
7243 /*!
7244  * This method is a specialization of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method that is called here.
7245  * The geometric type order is specified by MED file.
7246  * 
7247  * \sa  MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder
7248  */
7249 bool MEDCouplingUMesh::checkConsecutiveCellTypesForMEDFileFrmt() const
7250 {
7251   return checkConsecutiveCellTypesAndOrder(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
7252 }
7253
7254 /*!
7255  * This method performs the same job as checkConsecutiveCellTypes except that the order of types sequence is analyzed to check
7256  * that the order is specified in array defined by [ \a orderBg , \a orderEnd ).
7257  * If there is some geo types in \a this \b NOT in [ \a orderBg, \a orderEnd ) it is OK (return true) if contiguous.
7258  * If there is some geo types in [ \a orderBg, \a orderEnd ) \b NOT in \a this it is OK too (return true) if contiguous.
7259  */
7260 bool MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
7261 {
7262   checkFullyDefined();
7263   const int *conn=_nodal_connec->getConstPointer();
7264   const int *connI=_nodal_connec_index->getConstPointer();
7265   int nbOfCells=getNumberOfCells();
7266   if(nbOfCells==0)
7267     return true;
7268   int lastPos=-1;
7269   std::set<INTERP_KERNEL::NormalizedCellType> sg;
7270   for(const int *i=connI;i!=connI+nbOfCells;)
7271     {
7272       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7273       const INTERP_KERNEL::NormalizedCellType *isTypeExists=std::find(orderBg,orderEnd,curType);
7274       if(isTypeExists!=orderEnd)
7275         {
7276           int pos=(int)std::distance(orderBg,isTypeExists);
7277           if(pos<=lastPos)
7278             return false;
7279           lastPos=pos;
7280           i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7281         }
7282       else
7283         {
7284           if(sg.find(curType)==sg.end())
7285             {
7286               i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7287               sg.insert(curType);
7288             }
7289           else
7290             return false;
7291         }
7292     }
7293   return true;
7294 }
7295
7296 /*!
7297  * This method returns 2 newly allocated DataArrayInt instances. The first is an array of size 'this->getNumberOfCells()' with one component,
7298  * 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
7299  * 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'.
7300  */
7301 DataArrayInt *MEDCouplingUMesh::getLevArrPerCellTypes(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd, DataArrayInt *&nbPerType) const
7302 {
7303   checkConnectivityFullyDefined();
7304   int nbOfCells=getNumberOfCells();
7305   const int *conn=_nodal_connec->getConstPointer();
7306   const int *connI=_nodal_connec_index->getConstPointer();
7307   MCAuto<DataArrayInt> tmpa=DataArrayInt::New();
7308   MCAuto<DataArrayInt> tmpb=DataArrayInt::New();
7309   tmpa->alloc(nbOfCells,1);
7310   tmpb->alloc((int)std::distance(orderBg,orderEnd),1);
7311   tmpb->fillWithZero();
7312   int *tmp=tmpa->getPointer();
7313   int *tmp2=tmpb->getPointer();
7314   for(const int *i=connI;i!=connI+nbOfCells;i++)
7315     {
7316       const INTERP_KERNEL::NormalizedCellType *where=std::find(orderBg,orderEnd,(INTERP_KERNEL::NormalizedCellType)conn[*i]);
7317       if(where!=orderEnd)
7318         {
7319           int pos=(int)std::distance(orderBg,where);
7320           tmp2[pos]++;
7321           tmp[std::distance(connI,i)]=pos;
7322         }
7323       else
7324         {
7325           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*i]);
7326           std::ostringstream oss; oss << "MEDCouplingUMesh::getLevArrPerCellTypes : Cell #" << std::distance(connI,i);
7327           oss << " has a type " << cm.getRepr() << " not in input array of type !";
7328           throw INTERP_KERNEL::Exception(oss.str().c_str());
7329         }
7330     }
7331   nbPerType=tmpb.retn();
7332   return tmpa.retn();
7333 }
7334
7335 /*!
7336  * This method behaves exactly as MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec but the order is those defined in MED file spec.
7337  *
7338  * \return a new object containing the old to new correspondance.
7339  *
7340  * \sa MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec, MEDCouplingUMesh::sortCellsInMEDFileFrmt.
7341  */
7342 DataArrayInt *MEDCouplingUMesh::getRenumArrForMEDFileFrmt() const
7343 {
7344   return getRenumArrForConsecutiveCellTypesSpec(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
7345 }
7346
7347 /*!
7348  * 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.
7349  * This method returns an array of size getNumberOfCells() that gives a renumber array old2New that can be used as input of MEDCouplingMesh::renumberCells.
7350  * The mesh after this call to MEDCouplingMesh::renumberCells will pass the test of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder with the same inputs.
7351  * The returned array minimizes the permutations that is to say the order of cells inside same geometric type remains the same.
7352  */
7353 DataArrayInt *MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
7354 {
7355   DataArrayInt *nbPerType=0;
7356   MCAuto<DataArrayInt> tmpa=getLevArrPerCellTypes(orderBg,orderEnd,nbPerType);
7357   nbPerType->decrRef();
7358   return tmpa->buildPermArrPerLevel();
7359 }
7360
7361 /*!
7362  * This method reorganize the cells of \a this so that the cells with same geometric types are put together.
7363  * The number of cells remains unchanged after the call of this method.
7364  * This method tries to minimizes the number of needed permutations. So, this method behaves not exactly as
7365  * MEDCouplingUMesh::sortCellsInMEDFileFrmt.
7366  *
7367  * \return the array giving the correspondance old to new.
7368  */
7369 DataArrayInt *MEDCouplingUMesh::rearrange2ConsecutiveCellTypes()
7370 {
7371   checkFullyDefined();
7372   computeTypes();
7373   const int *conn=_nodal_connec->getConstPointer();
7374   const int *connI=_nodal_connec_index->getConstPointer();
7375   int nbOfCells=getNumberOfCells();
7376   std::vector<INTERP_KERNEL::NormalizedCellType> types;
7377   for(const int *i=connI;i!=connI+nbOfCells && (types.size()!=_types.size());)
7378     if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)conn[*i])==types.end())
7379       {
7380         INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7381         types.push_back(curType);
7382         for(i++;i!=connI+nbOfCells && (INTERP_KERNEL::NormalizedCellType)conn[*i]==curType;i++);
7383       }
7384   DataArrayInt *ret=DataArrayInt::New();
7385   ret->alloc(nbOfCells,1);
7386   int *retPtr=ret->getPointer();
7387   std::fill(retPtr,retPtr+nbOfCells,-1);
7388   int newCellId=0;
7389   for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
7390     {
7391       for(const int *i=connI;i!=connI+nbOfCells;i++)
7392         if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
7393           retPtr[std::distance(connI,i)]=newCellId++;
7394     }
7395   renumberCells(retPtr,false);
7396   return ret;
7397 }
7398
7399 /*!
7400  * This method splits \a this into as mush as untructured meshes that consecutive set of same type cells.
7401  * So this method has typically a sense if MEDCouplingUMesh::checkConsecutiveCellTypes has a sense.
7402  * This method makes asumption that connectivity is correctly set before calling.
7403  */
7404 std::vector<MEDCouplingUMesh *> MEDCouplingUMesh::splitByType() const
7405 {
7406   checkConnectivityFullyDefined();
7407   const int *conn=_nodal_connec->getConstPointer();
7408   const int *connI=_nodal_connec_index->getConstPointer();
7409   int nbOfCells=getNumberOfCells();
7410   std::vector<MEDCouplingUMesh *> ret;
7411   for(const int *i=connI;i!=connI+nbOfCells;)
7412     {
7413       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7414       int beginCellId=(int)std::distance(connI,i);
7415       i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7416       int endCellId=(int)std::distance(connI,i);
7417       int sz=endCellId-beginCellId;
7418       int *cells=new int[sz];
7419       for(int j=0;j<sz;j++)
7420         cells[j]=beginCellId+j;
7421       MEDCouplingUMesh *m=(MEDCouplingUMesh *)buildPartOfMySelf(cells,cells+sz,true);
7422       delete [] cells;
7423       ret.push_back(m);
7424     }
7425   return ret;
7426 }
7427
7428 /*!
7429  * This method performs the opposite operation than those in MEDCoupling1SGTUMesh::buildUnstructured.
7430  * If \a this is a single geometric type unstructured mesh, it will be converted into a more compact data structure,
7431  * MEDCoupling1GTUMesh instance. The returned instance will aggregate the same DataArrayDouble instance of coordinates than \a this.
7432  *
7433  * \return a newly allocated instance, that the caller must manage.
7434  * \throw If \a this contains more than one geometric type.
7435  * \throw If the nodal connectivity of \a this is not fully defined.
7436  * \throw If the internal data is not coherent.
7437  */
7438 MEDCoupling1GTUMesh *MEDCouplingUMesh::convertIntoSingleGeoTypeMesh() const
7439 {
7440   checkConnectivityFullyDefined();
7441   if(_types.size()!=1)
7442     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : current mesh does not contain exactly one geometric type !");
7443   INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
7444   MCAuto<MEDCoupling1GTUMesh> ret=MEDCoupling1GTUMesh::New(getName(),typ);
7445   ret->setCoords(getCoords());
7446   MEDCoupling1SGTUMesh *retC=dynamic_cast<MEDCoupling1SGTUMesh *>((MEDCoupling1GTUMesh*)ret);
7447   if(retC)
7448     {
7449       MCAuto<DataArrayInt> c=convertNodalConnectivityToStaticGeoTypeMesh();
7450       retC->setNodalConnectivity(c);
7451     }
7452   else
7453     {
7454       MEDCoupling1DGTUMesh *retD=dynamic_cast<MEDCoupling1DGTUMesh *>((MEDCoupling1GTUMesh*)ret);
7455       if(!retD)
7456         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : Internal error !");
7457       DataArrayInt *c=0,*ci=0;
7458       convertNodalConnectivityToDynamicGeoTypeMesh(c,ci);
7459       MCAuto<DataArrayInt> cs(c),cis(ci);
7460       retD->setNodalConnectivity(cs,cis);
7461     }
7462   return ret.retn();
7463 }
7464
7465 DataArrayInt *MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh() const
7466 {
7467   checkConnectivityFullyDefined();
7468   if(_types.size()!=1)
7469     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : current mesh does not contain exactly one geometric type !");
7470   INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
7471   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
7472   if(cm.isDynamic())
7473     {
7474       std::ostringstream oss; oss << "MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : this contains a single geo type (" << cm.getRepr() << ") but ";
7475       oss << "this type is dynamic ! Only static geometric type is possible for that type ! call convertNodalConnectivityToDynamicGeoTypeMesh instead !";
7476       throw INTERP_KERNEL::Exception(oss.str().c_str());
7477     }
7478   int nbCells=getNumberOfCells();
7479   int typi=(int)typ;
7480   int nbNodesPerCell=(int)cm.getNumberOfNodes();
7481   MCAuto<DataArrayInt> connOut=DataArrayInt::New(); connOut->alloc(nbCells*nbNodesPerCell,1);
7482   int *outPtr=connOut->getPointer();
7483   const int *conn=_nodal_connec->begin();
7484   const int *connI=_nodal_connec_index->begin();
7485   nbNodesPerCell++;
7486   for(int i=0;i<nbCells;i++,connI++)
7487     {
7488       if(conn[connI[0]]==typi && connI[1]-connI[0]==nbNodesPerCell)
7489         outPtr=std::copy(conn+connI[0]+1,conn+connI[1],outPtr);
7490       else
7491         {
7492           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 << ") !";
7493           throw INTERP_KERNEL::Exception(oss.str().c_str());
7494         }
7495     }
7496   return connOut.retn();
7497 }
7498
7499 /*!
7500  * Convert the nodal connectivity of the mesh so that all the cells are of dynamic types (polygon or quadratic
7501  * polygon). This returns the corresponding new nodal connectivity in \ref numbering-indirect format.
7502  * \param nodalConn
7503  * \param nodalConnI
7504  */
7505 void MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh(DataArrayInt *&nodalConn, DataArrayInt *&nodalConnIndex) const
7506 {
7507   static const char msg0[]="MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : nodal connectivity in this are invalid ! Call checkConsistency !";
7508   checkConnectivityFullyDefined();
7509   if(_types.size()!=1)
7510     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : current mesh does not contain exactly one geometric type !");
7511   int nbCells=getNumberOfCells(),lgth=_nodal_connec->getNumberOfTuples();
7512   if(lgth<nbCells)
7513     throw INTERP_KERNEL::Exception(msg0);
7514   MCAuto<DataArrayInt> c(DataArrayInt::New()),ci(DataArrayInt::New());
7515   c->alloc(lgth-nbCells,1); ci->alloc(nbCells+1,1);
7516   int *cp(c->getPointer()),*cip(ci->getPointer());
7517   const int *incp(_nodal_connec->begin()),*incip(_nodal_connec_index->begin());
7518   cip[0]=0;
7519   for(int i=0;i<nbCells;i++,cip++,incip++)
7520     {
7521       int strt(incip[0]+1),stop(incip[1]);//+1 to skip geo type
7522       int delta(stop-strt);
7523       if(delta>=1)
7524         {
7525           if((strt>=0 && strt<lgth) && (stop>=0 && stop<=lgth))
7526             cp=std::copy(incp+strt,incp+stop,cp);
7527           else
7528             throw INTERP_KERNEL::Exception(msg0);
7529         }
7530       else
7531         throw INTERP_KERNEL::Exception(msg0);
7532       cip[1]=cip[0]+delta;
7533     }
7534   nodalConn=c.retn(); nodalConnIndex=ci.retn();
7535 }
7536
7537 /*!
7538  * This method takes in input a vector of MEDCouplingUMesh instances lying on the same coordinates with same mesh dimensions.
7539  * Each mesh in \b ms must be sorted by type with the same order (typically using MEDCouplingUMesh::sortCellsInMEDFileFrmt).
7540  * This method is particulary useful for MED file interaction. It allows to aggregate several meshes and keeping the type sorting
7541  * and the track of the permutation by chunk of same geotype cells to retrieve it. The traditional formats old2new and new2old
7542  * are not used here to avoid the build of big permutation array.
7543  *
7544  * \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
7545  *                those specified in MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
7546  * \param [out] szOfCellGrpOfSameType is a newly allocated DataArrayInt instance whose number of tuples is equal to the number of chunks of same geotype
7547  *              in all meshes in \b ms. The accumulation of all values of this array is equal to the number of cells of returned mesh.
7548  * \param [out] idInMsOfCellGrpOfSameType is a newly allocated DataArrayInt instance having the same size than \b szOfCellGrpOfSameType. This
7549  *              output array gives for each chunck of same type the corresponding mesh id in \b ms.
7550  * \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
7551  *         is sorted by type following the geo cell types order of MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
7552  */
7553 MEDCouplingUMesh *MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& ms,
7554                                                                             DataArrayInt *&szOfCellGrpOfSameType,
7555                                                                             DataArrayInt *&idInMsOfCellGrpOfSameType)
7556 {
7557   std::vector<const MEDCouplingUMesh *> ms2;
7558   for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms.begin();it!=ms.end();it++)
7559     if(*it)
7560       {
7561         (*it)->checkConnectivityFullyDefined();
7562         ms2.push_back(*it);
7563       }
7564   if(ms2.empty())
7565     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : input vector is empty !");
7566   const DataArrayDouble *refCoo=ms2[0]->getCoords();
7567   int meshDim=ms2[0]->getMeshDimension();
7568   std::vector<const MEDCouplingUMesh *> m1ssm;
7569   std::vector< MCAuto<MEDCouplingUMesh> > m1ssmAuto;
7570   //
7571   std::vector<const MEDCouplingUMesh *> m1ssmSingle;
7572   std::vector< MCAuto<MEDCouplingUMesh> > m1ssmSingleAuto;
7573   int fake=0,rk=0;
7574   MCAuto<DataArrayInt> ret1(DataArrayInt::New()),ret2(DataArrayInt::New());
7575   ret1->alloc(0,1); ret2->alloc(0,1);
7576   for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms2.begin();it!=ms2.end();it++,rk++)
7577     {
7578       if(meshDim!=(*it)->getMeshDimension())
7579         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshdims mismatch !");
7580       if(refCoo!=(*it)->getCoords())
7581         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshes are not shared by a single coordinates coords !");
7582       std::vector<MEDCouplingUMesh *> sp=(*it)->splitByType();
7583       std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<const MEDCouplingUMesh *> >(m1ssm));
7584       std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<MCAuto<MEDCouplingUMesh> > >(m1ssmAuto));
7585       for(std::vector<MEDCouplingUMesh *>::const_iterator it2=sp.begin();it2!=sp.end();it2++)
7586         {
7587           MEDCouplingUMesh *singleCell=static_cast<MEDCouplingUMesh *>((*it2)->buildPartOfMySelf(&fake,&fake+1,true));
7588           m1ssmSingleAuto.push_back(singleCell);
7589           m1ssmSingle.push_back(singleCell);
7590           ret1->pushBackSilent((*it2)->getNumberOfCells()); ret2->pushBackSilent(rk);
7591         }
7592     }
7593   MCAuto<MEDCouplingUMesh> m1ssmSingle2=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmSingle);
7594   MCAuto<DataArrayInt> renum=m1ssmSingle2->sortCellsInMEDFileFrmt();
7595   std::vector<const MEDCouplingUMesh *> m1ssmfinal(m1ssm.size());
7596   for(std::size_t i=0;i<m1ssm.size();i++)
7597     m1ssmfinal[renum->getIJ(i,0)]=m1ssm[i];
7598   MCAuto<MEDCouplingUMesh> ret0=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmfinal);
7599   szOfCellGrpOfSameType=ret1->renumber(renum->getConstPointer());
7600   idInMsOfCellGrpOfSameType=ret2->renumber(renum->getConstPointer());
7601   return ret0.retn();
7602 }
7603
7604 /*!
7605  * This method returns a newly created DataArrayInt instance.
7606  * This method retrieves cell ids in [ \a begin, \a end ) that have the type \a type.
7607  */
7608 DataArrayInt *MEDCouplingUMesh::keepCellIdsByType(INTERP_KERNEL::NormalizedCellType type, const int *begin, const int *end) const
7609 {
7610   checkFullyDefined();
7611   const int *conn=_nodal_connec->getConstPointer();
7612   const int *connIndex=_nodal_connec_index->getConstPointer();
7613   MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(0,1);
7614   for(const int *w=begin;w!=end;w++)
7615     if((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]==type)
7616       ret->pushBackSilent(*w);
7617   return ret.retn();
7618 }
7619
7620 /*!
7621  * This method makes the assumption that da->getNumberOfTuples()<this->getNumberOfCells(). This method makes the assumption that ids contained in 'da'
7622  * are in [0:getNumberOfCells())
7623  */
7624 DataArrayInt *MEDCouplingUMesh::convertCellArrayPerGeoType(const DataArrayInt *da) const
7625 {
7626   checkFullyDefined();
7627   const int *conn=_nodal_connec->getConstPointer();
7628   const int *connI=_nodal_connec_index->getConstPointer();
7629   int nbOfCells=getNumberOfCells();
7630   std::set<INTERP_KERNEL::NormalizedCellType> types(getAllGeoTypes());
7631   int *tmp=new int[nbOfCells];
7632   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
7633     {
7634       int j=0;
7635       for(const int *i=connI;i!=connI+nbOfCells;i++)
7636         if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
7637           tmp[std::distance(connI,i)]=j++;
7638     }
7639   DataArrayInt *ret=DataArrayInt::New();
7640   ret->alloc(da->getNumberOfTuples(),da->getNumberOfComponents());
7641   ret->copyStringInfoFrom(*da);
7642   int *retPtr=ret->getPointer();
7643   const int *daPtr=da->getConstPointer();
7644   int nbOfElems=da->getNbOfElems();
7645   for(int k=0;k<nbOfElems;k++)
7646     retPtr[k]=tmp[daPtr[k]];
7647   delete [] tmp;
7648   return ret;
7649 }
7650
7651 /*!
7652  * This method reduced number of cells of this by keeping cells whose type is different from 'type' and if type=='type'
7653  * This method \b works \b for mesh sorted by type.
7654  * cells whose ids is in 'idsPerGeoType' array.
7655  * This method conserves coords and name of mesh.
7656  */
7657 MEDCouplingUMesh *MEDCouplingUMesh::keepSpecifiedCells(INTERP_KERNEL::NormalizedCellType type, const int *idsPerGeoTypeBg, const int *idsPerGeoTypeEnd) const
7658 {
7659   std::vector<int> code=getDistributionOfTypes();
7660   std::size_t nOfTypesInThis=code.size()/3;
7661   int sz=0,szOfType=0;
7662   for(std::size_t i=0;i<nOfTypesInThis;i++)
7663     {
7664       if(code[3*i]!=type)
7665         sz+=code[3*i+1];
7666       else
7667         szOfType=code[3*i+1];
7668     }
7669   for(const int *work=idsPerGeoTypeBg;work!=idsPerGeoTypeEnd;work++)
7670     if(*work<0 || *work>=szOfType)
7671       {
7672         std::ostringstream oss; oss << "MEDCouplingUMesh::keepSpecifiedCells : Request on type " << type << " at place #" << std::distance(idsPerGeoTypeBg,work) << " value " << *work;
7673         oss << ". It should be in [0," << szOfType << ") !";
7674         throw INTERP_KERNEL::Exception(oss.str().c_str());
7675       }
7676   MCAuto<DataArrayInt> idsTokeep=DataArrayInt::New(); idsTokeep->alloc(sz+(int)std::distance(idsPerGeoTypeBg,idsPerGeoTypeEnd),1);
7677   int *idsPtr=idsTokeep->getPointer();
7678   int offset=0;
7679   for(std::size_t i=0;i<nOfTypesInThis;i++)
7680     {
7681       if(code[3*i]!=type)
7682         for(int j=0;j<code[3*i+1];j++)
7683           *idsPtr++=offset+j;
7684       else
7685         idsPtr=std::transform(idsPerGeoTypeBg,idsPerGeoTypeEnd,idsPtr,std::bind2nd(std::plus<int>(),offset));
7686       offset+=code[3*i+1];
7687     }
7688   MCAuto<MEDCouplingUMesh> ret=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(idsTokeep->begin(),idsTokeep->end(),true));
7689   ret->copyTinyInfoFrom(this);
7690   return ret.retn();
7691 }
7692
7693 /*!
7694  * This method returns a vector of size 'this->getNumberOfCells()'.
7695  * This method retrieves for each cell in \a this if it is linear (false) or quadratic(true).
7696  */
7697 std::vector<bool> MEDCouplingUMesh::getQuadraticStatus() const
7698 {
7699   int ncell=getNumberOfCells();
7700   std::vector<bool> ret(ncell);
7701   const int *cI=getNodalConnectivityIndex()->getConstPointer();
7702   const int *c=getNodalConnectivity()->getConstPointer();
7703   for(int i=0;i<ncell;i++)
7704     {
7705       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[i]];
7706       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
7707       ret[i]=cm.isQuadratic();
7708     }
7709   return ret;
7710 }
7711
7712 /*!
7713  * Returns a newly created mesh (with ref count ==1) that contains merge of \a this and \a other.
7714  */
7715 MEDCouplingMesh *MEDCouplingUMesh::mergeMyselfWith(const MEDCouplingMesh *other) const
7716 {
7717   if(other->getType()!=UNSTRUCTURED)
7718     throw INTERP_KERNEL::Exception("Merge of umesh only available with umesh each other !");
7719   const MEDCouplingUMesh *otherC=static_cast<const MEDCouplingUMesh *>(other);
7720   return MergeUMeshes(this,otherC);
7721 }
7722
7723 /*!
7724  * Returns a new DataArrayDouble holding barycenters of all cells. The barycenter is
7725  * computed by averaging coordinates of cell nodes, so this method is not a right
7726  * choice for degnerated meshes (not well oriented, cells with measure close to zero).
7727  *  \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
7728  *          this->getNumberOfCells() tuples per \a this->getSpaceDimension()
7729  *          components. The caller is to delete this array using decrRef() as it is
7730  *          no more needed.
7731  *  \throw If the coordinates array is not set.
7732  *  \throw If the nodal connectivity of cells is not defined.
7733  *  \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
7734  */
7735 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMass() const
7736 {
7737   MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
7738   int spaceDim=getSpaceDimension();
7739   int nbOfCells=getNumberOfCells();
7740   ret->alloc(nbOfCells,spaceDim);
7741   ret->copyStringInfoFrom(*getCoords());
7742   double *ptToFill=ret->getPointer();
7743   const int *nodal=_nodal_connec->getConstPointer();
7744   const int *nodalI=_nodal_connec_index->getConstPointer();
7745   const double *coor=_coords->getConstPointer();
7746   for(int i=0;i<nbOfCells;i++)
7747     {
7748       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
7749       INTERP_KERNEL::computeBarycenter2<int,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[i]+1,nodalI[i+1]-nodalI[i]-1,coor,spaceDim,ptToFill);
7750       ptToFill+=spaceDim;
7751     }
7752   return ret.retn();
7753 }
7754
7755 /*!
7756  * This method computes for each cell in \a this, the location of the iso barycenter of nodes constituting
7757  * the cell. Contrary to badly named MEDCouplingUMesh::computeCellCenterOfMass method that returns the center of inertia of the 
7758  * 
7759  * \return a newly allocated DataArrayDouble instance that the caller has to deal with. The returned 
7760  *          DataArrayDouble instance will have \c this->getNumberOfCells() tuples and \c this->getSpaceDimension() components.
7761  * 
7762  * \sa MEDCouplingUMesh::computeCellCenterOfMass
7763  * \throw If \a this is not fully defined (coordinates and connectivity)
7764  * \throw If there is presence in nodal connectivity in \a this of node ids not in [0, \c this->getNumberOfNodes() )
7765  */
7766 DataArrayDouble *MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell() const
7767 {
7768   checkFullyDefined();
7769   MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
7770   int spaceDim=getSpaceDimension();
7771   int nbOfCells=getNumberOfCells();
7772   int nbOfNodes=getNumberOfNodes();
7773   ret->alloc(nbOfCells,spaceDim);
7774   double *ptToFill=ret->getPointer();
7775   const int *nodal=_nodal_connec->getConstPointer();
7776   const int *nodalI=_nodal_connec_index->getConstPointer();
7777   const double *coor=_coords->getConstPointer();
7778   for(int i=0;i<nbOfCells;i++,ptToFill+=spaceDim)
7779     {
7780       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
7781       std::fill(ptToFill,ptToFill+spaceDim,0.);
7782       if(type!=INTERP_KERNEL::NORM_POLYHED)
7783         {
7784           for(const int *conn=nodal+nodalI[i]+1;conn!=nodal+nodalI[i+1];conn++)
7785             {
7786               if(*conn>=0 && *conn<nbOfNodes)
7787                 std::transform(coor+spaceDim*conn[0],coor+spaceDim*(conn[0]+1),ptToFill,ptToFill,std::plus<double>());
7788               else
7789                 {
7790                   std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of nodeId #" << *conn << " should be in [0," <<   nbOfNodes << ") !";
7791                   throw INTERP_KERNEL::Exception(oss.str().c_str());
7792                 }
7793             }
7794           int nbOfNodesInCell=nodalI[i+1]-nodalI[i]-1;
7795           if(nbOfNodesInCell>0)
7796             std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies<double>(),1./(double)nbOfNodesInCell));
7797           else
7798             {
7799               std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of cell with no nodes !";
7800               throw INTERP_KERNEL::Exception(oss.str().c_str());
7801             }
7802         }
7803       else
7804         {
7805           std::set<int> s(nodal+nodalI[i]+1,nodal+nodalI[i+1]);
7806           s.erase(-1);
7807           for(std::set<int>::const_iterator it=s.begin();it!=s.end();it++)
7808             {
7809               if(*it>=0 && *it<nbOfNodes)
7810                 std::transform(coor+spaceDim*(*it),coor+spaceDim*((*it)+1),ptToFill,ptToFill,std::plus<double>());
7811               else
7812                 {
7813                   std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell polyhedron cell #" << i << " presence of nodeId #" << *it << " should be in [0," <<   nbOfNodes << ") !";
7814                   throw INTERP_KERNEL::Exception(oss.str().c_str());
7815                 }
7816             }
7817           if(!s.empty())
7818             std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies<double>(),1./(double)s.size()));
7819           else
7820             {
7821               std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on polyhedron cell #" << i << " there are no nodes !";
7822               throw INTERP_KERNEL::Exception(oss.str().c_str());
7823             }
7824         }
7825     }
7826   return ret.retn();
7827 }
7828
7829 /*!
7830  * Returns a new DataArrayDouble holding barycenters of specified cells. The
7831  * barycenter is computed by averaging coordinates of cell nodes. The cells to treat
7832  * are specified via an array of cell ids. 
7833  *  \warning Validity of the specified cell ids is not checked! 
7834  *           Valid range is [ 0, \a this->getNumberOfCells() ).
7835  *  \param [in] begin - an array of cell ids of interest.
7836  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
7837  *  \return DataArrayDouble * - a new instance of DataArrayDouble, of size ( \a
7838  *          end - \a begin ) tuples per \a this->getSpaceDimension() components. The
7839  *          caller is to delete this array using decrRef() as it is no more needed. 
7840  *  \throw If the coordinates array is not set.
7841  *  \throw If the nodal connectivity of cells is not defined.
7842  *
7843  *  \if ENABLE_EXAMPLES
7844  *  \ref cpp_mcumesh_getPartBarycenterAndOwner "Here is a C++ example".<br>
7845  *  \ref  py_mcumesh_getPartBarycenterAndOwner "Here is a Python example".
7846  *  \endif
7847  */
7848 DataArrayDouble *MEDCouplingUMesh::getPartBarycenterAndOwner(const int *begin, const int *end) const
7849 {
7850   DataArrayDouble *ret=DataArrayDouble::New();
7851   int spaceDim=getSpaceDimension();
7852   int nbOfTuple=(int)std::distance(begin,end);
7853   ret->alloc(nbOfTuple,spaceDim);
7854   double *ptToFill=ret->getPointer();
7855   double *tmp=new double[spaceDim];
7856   const int *nodal=_nodal_connec->getConstPointer();
7857   const int *nodalI=_nodal_connec_index->getConstPointer();
7858   const double *coor=_coords->getConstPointer();
7859   for(const int *w=begin;w!=end;w++)
7860     {
7861       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[*w]];
7862       INTERP_KERNEL::computeBarycenter2<int,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[*w]+1,nodalI[*w+1]-nodalI[*w]-1,coor,spaceDim,ptToFill);
7863       ptToFill+=spaceDim;
7864     }
7865   delete [] tmp;
7866   return ret;
7867 }
7868
7869 /*!
7870  * 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".
7871  * So the returned instance will have 4 components and \c this->getNumberOfCells() tuples.
7872  * So this method expects that \a this has a spaceDimension equal to 3 and meshDimension equal to 2.
7873  * The computation of the plane equation is done using each time the 3 first nodes of 2D cells.
7874  * This method is useful to detect 2D cells in 3D space that are not coplanar.
7875  * 
7876  * \return DataArrayDouble * - a new instance of DataArrayDouble having 4 components and a number of tuples equal to number of cells in \a this.
7877  * \throw If spaceDim!=3 or meshDim!=2.
7878  * \throw If connectivity of \a this is invalid.
7879  * \throw If connectivity of a cell in \a this points to an invalid node.
7880  */
7881 DataArrayDouble *MEDCouplingUMesh::computePlaneEquationOf3DFaces() const
7882 {
7883   MCAuto<DataArrayDouble> ret(DataArrayDouble::New());
7884   int nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
7885   if(getSpaceDimension()!=3 || getMeshDimension()!=2)
7886     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computePlaneEquationOf3DFaces : This method must be applied on a mesh having meshDimension equal 2 and a spaceDimension equal to 3 !");
7887   ret->alloc(nbOfCells,4);
7888   double *retPtr(ret->getPointer());
7889   const int *nodal(_nodal_connec->begin()),*nodalI(_nodal_connec_index->begin());
7890   const double *coor(_coords->begin());
7891   for(int i=0;i<nbOfCells;i++,nodalI++,retPtr+=4)
7892     {
7893       double matrix[16]={0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,0},matrix2[16];
7894       if(nodalI[1]-nodalI[0]>=3)
7895         {
7896           for(int j=0;j<3;j++)
7897             {
7898               int nodeId(nodal[nodalI[0]+1+j]);
7899               if(nodeId>=0 && nodeId<nbOfNodes)
7900                 std::copy(coor+nodeId*3,coor+(nodeId+1)*3,matrix+4*j);
7901               else
7902                 {
7903                   std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! This cell points to an invalid nodeId : " << nodeId << " !";
7904                   throw INTERP_KERNEL::Exception(oss.str().c_str());
7905                 }
7906             }
7907         }
7908       else
7909         {
7910           std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! Must be constitued by more than 3 nodes !";
7911           throw INTERP_KERNEL::Exception(oss.str().c_str());
7912         }
7913       INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
7914       retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
7915     }
7916   return ret.retn();
7917 }
7918
7919 /*!
7920  * This method expects as input a DataArrayDouble non nul instance 'da' that should be allocated. If not an exception is thrown.
7921  * 
7922  */
7923 MEDCouplingUMesh *MEDCouplingUMesh::Build0DMeshFromCoords(DataArrayDouble *da)
7924 {
7925   if(!da)
7926     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build0DMeshFromCoords : instance of DataArrayDouble must be not null !");
7927   da->checkAllocated();
7928   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(da->getName(),0);
7929   ret->setCoords(da);
7930   int nbOfTuples=da->getNumberOfTuples();
7931   MCAuto<DataArrayInt> c=DataArrayInt::New();
7932   MCAuto<DataArrayInt> cI=DataArrayInt::New();
7933   c->alloc(2*nbOfTuples,1);
7934   cI->alloc(nbOfTuples+1,1);
7935   int *cp=c->getPointer();
7936   int *cip=cI->getPointer();
7937   *cip++=0;
7938   for(int i=0;i<nbOfTuples;i++)
7939     {
7940       *cp++=INTERP_KERNEL::NORM_POINT1;
7941       *cp++=i;
7942       *cip++=2*(i+1);
7943     }
7944   ret->setConnectivity(c,cI,true);
7945   return ret.retn();
7946 }
7947 /*!
7948  * Creates a new MEDCouplingUMesh by concatenating two given meshes of the same dimension.
7949  * Cells and nodes of
7950  * the first mesh precede cells and nodes of the second mesh within the result mesh.
7951  *  \param [in] mesh1 - the first mesh.
7952  *  \param [in] mesh2 - the second mesh.
7953  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7954  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7955  *          is no more needed.
7956  *  \throw If \a mesh1 == NULL or \a mesh2 == NULL.
7957  *  \throw If the coordinates array is not set in none of the meshes.
7958  *  \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
7959  *  \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
7960  */
7961 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
7962 {
7963   std::vector<const MEDCouplingUMesh *> tmp(2);
7964   tmp[0]=const_cast<MEDCouplingUMesh *>(mesh1); tmp[1]=const_cast<MEDCouplingUMesh *>(mesh2);
7965   return MergeUMeshes(tmp);
7966 }
7967
7968 /*!
7969  * Creates a new MEDCouplingUMesh by concatenating all given meshes of the same dimension.
7970  * Cells and nodes of
7971  * the *i*-th mesh precede cells and nodes of the (*i*+1)-th mesh within the result mesh.
7972  *  \param [in] a - a vector of meshes (MEDCouplingUMesh) to concatenate.
7973  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7974  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7975  *          is no more needed.
7976  *  \throw If \a a.size() == 0.
7977  *  \throw If \a a[ *i* ] == NULL.
7978  *  \throw If the coordinates array is not set in none of the meshes.
7979  *  \throw If \a a[ *i* ]->getMeshDimension() < 0.
7980  *  \throw If the meshes in \a a are of different dimension (getMeshDimension()).
7981  */
7982 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(std::vector<const MEDCouplingUMesh *>& a)
7983 {
7984   std::size_t sz=a.size();
7985   if(sz==0)
7986     return MergeUMeshesLL(a);
7987   for(std::size_t ii=0;ii<sz;ii++)
7988     if(!a[ii])
7989       {
7990         std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshes : item #" << ii << " in input array of size "<< sz << " is empty !";
7991         throw INTERP_KERNEL::Exception(oss.str().c_str());
7992       }
7993   std::vector< MCAuto<MEDCouplingUMesh> > bb(sz);
7994   std::vector< const MEDCouplingUMesh * > aa(sz);
7995   int spaceDim=-3;
7996   for(std::size_t i=0;i<sz && spaceDim==-3;i++)
7997     {
7998       const MEDCouplingUMesh *cur=a[i];
7999       const DataArrayDouble *coo=cur->getCoords();
8000       if(coo)
8001         spaceDim=coo->getNumberOfComponents();
8002     }
8003   if(spaceDim==-3)
8004     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : no spaceDim specified ! unable to perform merge !");
8005   for(std::size_t i=0;i<sz;i++)
8006     {
8007       bb[i]=a[i]->buildSetInstanceFromThis(spaceDim);
8008       aa[i]=bb[i];
8009     }
8010   return MergeUMeshesLL(aa);
8011 }
8012
8013 /// @cond INTERNAL
8014
8015 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesLL(std::vector<const MEDCouplingUMesh *>& a)
8016 {
8017   if(a.empty())
8018     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : input array must be NON EMPTY !");
8019   std::vector<const MEDCouplingUMesh *>::const_iterator it=a.begin();
8020   int meshDim=(*it)->getMeshDimension();
8021   int nbOfCells=(*it)->getNumberOfCells();
8022   int meshLgth=(*it++)->getNodalConnectivityArrayLen();
8023   for(;it!=a.end();it++)
8024     {
8025       if(meshDim!=(*it)->getMeshDimension())
8026         throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, MergeUMeshes impossible !");
8027       nbOfCells+=(*it)->getNumberOfCells();
8028       meshLgth+=(*it)->getNodalConnectivityArrayLen();
8029     }
8030   std::vector<const MEDCouplingPointSet *> aps(a.size());
8031   std::copy(a.begin(),a.end(),aps.begin());
8032   MCAuto<DataArrayDouble> pts=MergeNodesArray(aps);
8033   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("merge",meshDim);
8034   ret->setCoords(pts);
8035   MCAuto<DataArrayInt> c=DataArrayInt::New();
8036   c->alloc(meshLgth,1);
8037   int *cPtr=c->getPointer();
8038   MCAuto<DataArrayInt> cI=DataArrayInt::New();
8039   cI->alloc(nbOfCells+1,1);
8040   int *cIPtr=cI->getPointer();
8041   *cIPtr++=0;
8042   int offset=0;
8043   int offset2=0;
8044   for(it=a.begin();it!=a.end();it++)
8045     {
8046       int curNbOfCell=(*it)->getNumberOfCells();
8047       const int *curCI=(*it)->_nodal_connec_index->getConstPointer();
8048       const int *curC=(*it)->_nodal_connec->getConstPointer();
8049       cIPtr=std::transform(curCI+1,curCI+curNbOfCell+1,cIPtr,std::bind2nd(std::plus<int>(),offset));
8050       for(int j=0;j<curNbOfCell;j++)
8051         {
8052           const int *src=curC+curCI[j];
8053           *cPtr++=*src++;
8054           for(;src!=curC+curCI[j+1];src++,cPtr++)
8055             {
8056               if(*src!=-1)
8057                 *cPtr=*src+offset2;
8058               else
8059                 *cPtr=-1;
8060             }
8061         }
8062       offset+=curCI[curNbOfCell];
8063       offset2+=(*it)->getNumberOfNodes();
8064     }
8065   //
8066   ret->setConnectivity(c,cI,true);
8067   return ret.retn();
8068 }
8069
8070 /// @endcond
8071
8072 /*!
8073  * Creates a new MEDCouplingUMesh by concatenating cells of two given meshes of same
8074  * dimension and sharing the node coordinates array.
8075  * All cells of the first mesh precede all cells of the second mesh
8076  * within the result mesh. 
8077  *  \param [in] mesh1 - the first mesh.
8078  *  \param [in] mesh2 - the second mesh.
8079  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
8080  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
8081  *          is no more needed.
8082  *  \throw If \a mesh1 == NULL or \a mesh2 == NULL.
8083  *  \throw If the meshes do not share the node coordinates array.
8084  *  \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
8085  *  \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
8086  */
8087 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
8088 {
8089   std::vector<const MEDCouplingUMesh *> tmp(2);
8090   tmp[0]=mesh1; tmp[1]=mesh2;
8091   return MergeUMeshesOnSameCoords(tmp);
8092 }
8093
8094 /*!
8095  * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
8096  * dimension and sharing the node coordinates array.
8097  * All cells of the *i*-th mesh precede all cells of the
8098  * (*i*+1)-th mesh within the result mesh.
8099  *  \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
8100  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
8101  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
8102  *          is no more needed.
8103  *  \throw If \a a.size() == 0.
8104  *  \throw If \a a[ *i* ] == NULL.
8105  *  \throw If the meshes do not share the node coordinates array.
8106  *  \throw If \a a[ *i* ]->getMeshDimension() < 0.
8107  *  \throw If the meshes in \a a are of different dimension (getMeshDimension()).
8108  */
8109 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes)
8110 {
8111   if(meshes.empty())
8112     throw INTERP_KERNEL::Exception("meshes input parameter is expected to be non empty.");
8113   for(std::size_t ii=0;ii<meshes.size();ii++)
8114     if(!meshes[ii])
8115       {
8116         std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshesOnSameCoords : item #" << ii << " in input array of size "<< meshes.size() << " is empty !";
8117         throw INTERP_KERNEL::Exception(oss.str().c_str());
8118       }
8119   const DataArrayDouble *coords=meshes.front()->getCoords();
8120   int meshDim=meshes.front()->getMeshDimension();
8121   std::vector<const MEDCouplingUMesh *>::const_iterator iter=meshes.begin();
8122   int meshLgth=0;
8123   int meshIndexLgth=0;
8124   for(;iter!=meshes.end();iter++)
8125     {
8126       if(coords!=(*iter)->getCoords())
8127         throw INTERP_KERNEL::Exception("meshes does not share the same coords ! Try using tryToShareSameCoords method !");
8128       if(meshDim!=(*iter)->getMeshDimension())
8129         throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, FuseUMeshesOnSameCoords impossible !");
8130       meshLgth+=(*iter)->getNodalConnectivityArrayLen();
8131       meshIndexLgth+=(*iter)->getNumberOfCells();
8132     }
8133   MCAuto<DataArrayInt> nodal=DataArrayInt::New();
8134   nodal->alloc(meshLgth,1);
8135   int *nodalPtr=nodal->getPointer();
8136   MCAuto<DataArrayInt> nodalIndex=DataArrayInt::New();
8137   nodalIndex->alloc(meshIndexLgth+1,1);
8138   int *nodalIndexPtr=nodalIndex->getPointer();
8139   int offset=0;
8140   for(iter=meshes.begin();iter!=meshes.end();iter++)
8141     {
8142       const int *nod=(*iter)->getNodalConnectivity()->getConstPointer();
8143       const int *index=(*iter)->getNodalConnectivityIndex()->getConstPointer();
8144       int nbOfCells=(*iter)->getNumberOfCells();
8145       int meshLgth2=(*iter)->getNodalConnectivityArrayLen();
8146       nodalPtr=std::copy(nod,nod+meshLgth2,nodalPtr);
8147       if(iter!=meshes.begin())
8148         nodalIndexPtr=std::transform(index+1,index+nbOfCells+1,nodalIndexPtr,std::bind2nd(std::plus<int>(),offset));
8149       else
8150         nodalIndexPtr=std::copy(index,index+nbOfCells+1,nodalIndexPtr);
8151       offset+=meshLgth2;
8152     }
8153   MEDCouplingUMesh *ret=MEDCouplingUMesh::New();
8154   ret->setName("merge");
8155   ret->setMeshDimension(meshDim);
8156   ret->setConnectivity(nodal,nodalIndex,true);
8157   ret->setCoords(coords);
8158   return ret;
8159 }
8160
8161 /*!
8162  * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
8163  * dimension and sharing the node coordinates array. Cells of the *i*-th mesh precede
8164  * cells of the (*i*+1)-th mesh within the result mesh. Duplicates of cells are
8165  * removed from \a this mesh and arrays mapping between new and old cell ids in "Old to
8166  * New" mode are returned for each input mesh.
8167  *  \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
8168  *  \param [in] compType - specifies a cell comparison technique. For meaning of its
8169  *          valid values [0,1,2], see zipConnectivityTraducer().
8170  *  \param [in,out] corr - an array of DataArrayInt, of the same size as \a
8171  *          meshes. The *i*-th array describes cell ids mapping for \a meshes[ *i* ]
8172  *          mesh. The caller is to delete each of the arrays using decrRef() as it is
8173  *          no more needed.
8174  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
8175  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
8176  *          is no more needed.
8177  *  \throw If \a meshes.size() == 0.
8178  *  \throw If \a meshes[ *i* ] == NULL.
8179  *  \throw If the meshes do not share the node coordinates array.
8180  *  \throw If \a meshes[ *i* ]->getMeshDimension() < 0.
8181  *  \throw If the \a meshes are of different dimension (getMeshDimension()).
8182  *  \throw If the nodal connectivity of cells of any of \a meshes is not defined.
8183  *  \throw If the nodal connectivity any of \a meshes includes an invalid id.
8184  */
8185 MEDCouplingUMesh *MEDCouplingUMesh::FuseUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes, int compType, std::vector<DataArrayInt *>& corr)
8186 {
8187   //All checks are delegated to MergeUMeshesOnSameCoords
8188   MCAuto<MEDCouplingUMesh> ret=MergeUMeshesOnSameCoords(meshes);
8189   MCAuto<DataArrayInt> o2n=ret->zipConnectivityTraducer(compType);
8190   corr.resize(meshes.size());
8191   std::size_t nbOfMeshes=meshes.size();
8192   int offset=0;
8193   const int *o2nPtr=o2n->getConstPointer();
8194   for(std::size_t i=0;i<nbOfMeshes;i++)
8195     {
8196       DataArrayInt *tmp=DataArrayInt::New();
8197       int curNbOfCells=meshes[i]->getNumberOfCells();
8198       tmp->alloc(curNbOfCells,1);
8199       std::copy(o2nPtr+offset,o2nPtr+offset+curNbOfCells,tmp->getPointer());
8200       offset+=curNbOfCells;
8201       tmp->setName(meshes[i]->getName());
8202       corr[i]=tmp;
8203     }
8204   return ret.retn();
8205 }
8206
8207 /*!
8208  * Makes all given meshes share the nodal connectivity array. The common connectivity
8209  * array is created by concatenating the connectivity arrays of all given meshes. All
8210  * the given meshes must be of the same space dimension but dimension of cells **can
8211  * differ**. This method is particulary useful in MEDLoader context to build a \ref
8212  * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
8213  * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
8214  *  \param [in,out] meshes - a vector of meshes to update.
8215  *  \throw If any of \a meshes is NULL.
8216  *  \throw If the coordinates array is not set in any of \a meshes.
8217  *  \throw If the nodal connectivity of cells is not defined in any of \a meshes.
8218  *  \throw If \a meshes are of different space dimension.
8219  */
8220 void MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords(const std::vector<MEDCouplingUMesh *>& meshes)
8221 {
8222   std::size_t sz=meshes.size();
8223   if(sz==0 || sz==1)
8224     return;
8225   std::vector< const DataArrayDouble * > coords(meshes.size());
8226   std::vector< const DataArrayDouble * >::iterator it2=coords.begin();
8227   for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++,it2++)
8228     {
8229       if((*it))
8230         {
8231           (*it)->checkConnectivityFullyDefined();
8232           const DataArrayDouble *coo=(*it)->getCoords();
8233           if(coo)
8234             *it2=coo;
8235           else
8236             {
8237               std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
8238               oss << " has no coordinate array defined !";
8239               throw INTERP_KERNEL::Exception(oss.str().c_str());
8240             }
8241         }
8242       else
8243         {
8244           std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
8245           oss << " is null !";
8246           throw INTERP_KERNEL::Exception(oss.str().c_str());
8247         }
8248     }
8249   MCAuto<DataArrayDouble> res=DataArrayDouble::Aggregate(coords);
8250   std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();
8251   int offset=(*it)->getNumberOfNodes();
8252   (*it++)->setCoords(res);
8253   for(;it!=meshes.end();it++)
8254     {
8255       int oldNumberOfNodes=(*it)->getNumberOfNodes();
8256       (*it)->setCoords(res);
8257       (*it)->shiftNodeNumbersInConn(offset);
8258       offset+=oldNumberOfNodes;
8259     }
8260 }
8261
8262 /*!
8263  * Merges nodes coincident with a given precision within all given meshes that share
8264  * the nodal connectivity array. The given meshes **can be of different** mesh
8265  * dimension. This method is particulary useful in MEDLoader context to build a \ref
8266  * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
8267  * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array. 
8268  *  \param [in,out] meshes - a vector of meshes to update.
8269  *  \param [in] eps - the precision used to detect coincident nodes (infinite norm).
8270  *  \throw If any of \a meshes is NULL.
8271  *  \throw If the \a meshes do not share the same node coordinates array.
8272  *  \throw If the nodal connectivity of cells is not defined in any of \a meshes.
8273  */
8274 void MEDCouplingUMesh::MergeNodesOnUMeshesSharingSameCoords(const std::vector<MEDCouplingUMesh *>& meshes, double eps)
8275 {
8276   if(meshes.empty())
8277     return ;
8278   std::set<const DataArrayDouble *> s;
8279   for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
8280     {
8281       if(*it)
8282         s.insert((*it)->getCoords());
8283       else
8284         {
8285           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 !";
8286           throw INTERP_KERNEL::Exception(oss.str().c_str());
8287         }
8288     }
8289   if(s.size()!=1)
8290     {
8291       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 !";
8292       throw INTERP_KERNEL::Exception(oss.str().c_str());
8293     }
8294   const DataArrayDouble *coo=*(s.begin());
8295   if(!coo)
8296     return;
8297   //
8298   DataArrayInt *comm,*commI;
8299   coo->findCommonTuples(eps,-1,comm,commI);
8300   MCAuto<DataArrayInt> tmp1(comm),tmp2(commI);
8301   int oldNbOfNodes=coo->getNumberOfTuples();
8302   int newNbOfNodes;
8303   MCAuto<DataArrayInt> o2n=DataArrayInt::ConvertIndexArrayToO2N(oldNbOfNodes,comm->begin(),commI->begin(),commI->end(),newNbOfNodes);
8304   if(oldNbOfNodes==newNbOfNodes)
8305     return ;
8306   MCAuto<DataArrayDouble> newCoords=coo->renumberAndReduce(o2n->getConstPointer(),newNbOfNodes);
8307   for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
8308     {
8309       (*it)->renumberNodesInConn(o2n->getConstPointer());
8310       (*it)->setCoords(newCoords);
8311     } 
8312 }
8313
8314 /*!
8315  * 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.
8316  * \param nbOfNodesPerLev in parameter that specifies the number of nodes of one slice of global dataset
8317  * \param isQuad specifies the policy of connectivity.
8318  * @ret in/out parameter in which the result will be append
8319  */
8320 void MEDCouplingUMesh::AppendExtrudedCell(const int *connBg, const int *connEnd, int nbOfNodesPerLev, bool isQuad, std::vector<int>& ret)
8321 {
8322   INTERP_KERNEL::NormalizedCellType flatType=(INTERP_KERNEL::NormalizedCellType)connBg[0];
8323   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(flatType);
8324   ret.push_back(cm.getExtrudedType());
8325   int deltaz=isQuad?2*nbOfNodesPerLev:nbOfNodesPerLev;
8326   switch(flatType)
8327   {
8328     case INTERP_KERNEL::NORM_POINT1:
8329       {
8330         ret.push_back(connBg[1]);
8331         ret.push_back(connBg[1]+nbOfNodesPerLev);
8332         break;
8333       }
8334     case INTERP_KERNEL::NORM_SEG2:
8335       {
8336         int conn[4]={connBg[1],connBg[2],connBg[2]+deltaz,connBg[1]+deltaz};
8337         ret.insert(ret.end(),conn,conn+4);
8338         break;
8339       }
8340     case INTERP_KERNEL::NORM_SEG3:
8341       {
8342         int conn[8]={connBg[1],connBg[3],connBg[3]+deltaz,connBg[1]+deltaz,connBg[2],connBg[3]+nbOfNodesPerLev,connBg[2]+deltaz,connBg[1]+nbOfNodesPerLev};
8343         ret.insert(ret.end(),conn,conn+8);
8344         break;
8345       }
8346     case INTERP_KERNEL::NORM_QUAD4:
8347       {
8348         int conn[8]={connBg[1],connBg[2],connBg[3],connBg[4],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz,connBg[4]+deltaz};
8349         ret.insert(ret.end(),conn,conn+8);
8350         break;
8351       }
8352     case INTERP_KERNEL::NORM_TRI3:
8353       {
8354         int conn[6]={connBg[1],connBg[2],connBg[3],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz};
8355         ret.insert(ret.end(),conn,conn+6);
8356         break;
8357       }
8358     case INTERP_KERNEL::NORM_TRI6:
8359       {
8360         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,
8361           connBg[1]+nbOfNodesPerLev,connBg[2]+nbOfNodesPerLev,connBg[3]+nbOfNodesPerLev};
8362         ret.insert(ret.end(),conn,conn+15);
8363         break;
8364       }
8365     case INTERP_KERNEL::NORM_QUAD8:
8366       {
8367         int conn[20]={
8368           connBg[1],connBg[2],connBg[3],connBg[4],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz,connBg[4]+deltaz,
8369           connBg[5],connBg[6],connBg[7],connBg[8],connBg[5]+deltaz,connBg[6]+deltaz,connBg[7]+deltaz,connBg[8]+deltaz,
8370           connBg[1]+nbOfNodesPerLev,connBg[2]+nbOfNodesPerLev,connBg[3]+nbOfNodesPerLev,connBg[4]+nbOfNodesPerLev
8371         };
8372         ret.insert(ret.end(),conn,conn+20);
8373         break;
8374       }
8375     case INTERP_KERNEL::NORM_POLYGON:
8376       {
8377         std::back_insert_iterator< std::vector<int> > ii(ret);
8378         std::copy(connBg+1,connEnd,ii);
8379         *ii++=-1;
8380         std::reverse_iterator<const int *> rConnBg(connEnd);
8381         std::reverse_iterator<const int *> rConnEnd(connBg+1);
8382         std::transform(rConnBg,rConnEnd,ii,std::bind2nd(std::plus<int>(),deltaz));
8383         std::size_t nbOfRadFaces=std::distance(connBg+1,connEnd);
8384         for(std::size_t i=0;i<nbOfRadFaces;i++)
8385           {
8386             *ii++=-1;
8387             int conn[4]={connBg[(i+1)%nbOfRadFaces+1],connBg[i+1],connBg[i+1]+deltaz,connBg[(i+1)%nbOfRadFaces+1]+deltaz};
8388             std::copy(conn,conn+4,ii);
8389           }
8390         break;
8391       }
8392     default:
8393       throw INTERP_KERNEL::Exception("A flat type has been detected that has not its extruded representation !");
8394   }
8395 }
8396
8397 /*!
8398  * This static operates only for coords in 3D. The polygon is specfied by its connectivity nodes in [ \a begin , \a end ).
8399  */
8400 bool MEDCouplingUMesh::IsPolygonWellOriented(bool isQuadratic, const double *vec, const int *begin, const int *end, const double *coords)
8401 {
8402   std::size_t i, ip1;
8403   double v[3]={0.,0.,0.};
8404   std::size_t sz=std::distance(begin,end);
8405   if(isQuadratic)
8406     sz/=2;
8407   for(i=0;i<sz;i++)
8408     {
8409       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];
8410       v[1]+=coords[3*begin[i]+2]*coords[3*begin[(i+1)%sz]]-coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+2];
8411       v[2]+=coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+1]-coords[3*begin[i]+1]*coords[3*begin[(i+1)%sz]];
8412     }
8413   double ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
8414
8415   // Try using quadratic points if standard points are degenerated (for example a QPOLYG with two
8416   // SEG3 forming a circle):
8417   if (fabs(ret) < INTERP_KERNEL::DEFAULT_ABS_TOL && isQuadratic)
8418     {
8419       v[0] = 0.0; v[1] = 0.0; v[2] = 0.0;
8420       for(std::size_t j=0;j<sz;j++)
8421         {
8422           if (j%2)  // current point i is quadratic, next point i+1 is standard
8423             {
8424               i = sz+j;
8425               ip1 = (j+1)%sz; // ip1 = "i+1"
8426             }
8427           else      // current point i is standard, next point i+1 is quadratic
8428             {
8429               i = j;
8430               ip1 = j+sz;
8431             }
8432           v[0]+=coords[3*begin[i]+1]*coords[3*begin[ip1]+2]-coords[3*begin[i]+2]*coords[3*begin[ip1]+1];
8433           v[1]+=coords[3*begin[i]+2]*coords[3*begin[ip1]]-coords[3*begin[i]]*coords[3*begin[ip1]+2];
8434           v[2]+=coords[3*begin[i]]*coords[3*begin[ip1]+1]-coords[3*begin[i]+1]*coords[3*begin[ip1]];
8435         }
8436       ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
8437     }
8438   return (ret>0.);
8439 }
8440
8441 /*!
8442  * The polyhedron is specfied by its connectivity nodes in [ \a begin , \a end ).
8443  */
8444 bool MEDCouplingUMesh::IsPolyhedronWellOriented(const int *begin, const int *end, const double *coords)
8445 {
8446   std::vector<std::pair<int,int> > edges;
8447   std::size_t nbOfFaces=std::count(begin,end,-1)+1;
8448   const int *bgFace=begin;
8449   for(std::size_t i=0;i<nbOfFaces;i++)
8450     {
8451       const int *endFace=std::find(bgFace+1,end,-1);
8452       std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
8453       for(std::size_t j=0;j<nbOfEdgesInFace;j++)
8454         {
8455           std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
8456           if(std::find(edges.begin(),edges.end(),p1)!=edges.end())
8457             return false;
8458           edges.push_back(p1);
8459         }
8460       bgFace=endFace+1;
8461     }
8462   return INTERP_KERNEL::calculateVolumeForPolyh2<int,INTERP_KERNEL::ALL_C_MODE>(begin,(int)std::distance(begin,end),coords)>-EPS_FOR_POLYH_ORIENTATION;
8463 }
8464
8465 /*!
8466  * The 3D extruded static cell (PENTA6,HEXA8,HEXAGP12...) its connectivity nodes in [ \a begin , \a end ).
8467  */
8468 bool MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented(const int *begin, const int *end, const double *coords)
8469 {
8470   double vec0[3],vec1[3];
8471   std::size_t sz=std::distance(begin,end);
8472   if(sz%2!=0)
8473     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented : the length of nodal connectivity of extruded cell is not even !");
8474   int nbOfNodes=(int)sz/2;
8475   INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(begin,nbOfNodes,coords,vec0);
8476   const double *pt0=coords+3*begin[0];
8477   const double *pt1=coords+3*begin[nbOfNodes];
8478   vec1[0]=pt1[0]-pt0[0]; vec1[1]=pt1[1]-pt0[1]; vec1[2]=pt1[2]-pt0[2];
8479   return (vec0[0]*vec1[0]+vec0[1]*vec1[1]+vec0[2]*vec1[2])<0.;
8480 }
8481
8482 void MEDCouplingUMesh::CorrectExtrudedStaticCell(int *begin, int *end)
8483 {
8484   std::size_t sz=std::distance(begin,end);
8485   INTERP_KERNEL::AutoPtr<int> tmp=new int[sz];
8486   std::size_t nbOfNodes(sz/2);
8487   std::copy(begin,end,(int *)tmp);
8488   for(std::size_t j=1;j<nbOfNodes;j++)
8489     {
8490       begin[j]=tmp[nbOfNodes-j];
8491       begin[j+nbOfNodes]=tmp[nbOfNodes+nbOfNodes-j];
8492     }
8493 }
8494
8495 bool MEDCouplingUMesh::IsTetra4WellOriented(const int *begin, const int *end, const double *coords)
8496 {
8497   std::size_t sz=std::distance(begin,end);
8498   if(sz!=4)
8499     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsTetra4WellOriented : Tetra4 cell with not 4 nodes ! Call checkConsistency !");
8500   double vec0[3],vec1[3];
8501   const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[1],*pt2=coords+3*begin[2],*pt3=coords+3*begin[3];
8502   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]; 
8503   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;
8504 }
8505
8506 bool MEDCouplingUMesh::IsPyra5WellOriented(const int *begin, const int *end, const double *coords)
8507 {
8508   std::size_t sz=std::distance(begin,end);
8509   if(sz!=5)
8510     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsPyra5WellOriented : Pyra5 cell with not 5 nodes ! Call checkConsistency !");
8511   double vec0[3];
8512   INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(begin,4,coords,vec0);
8513   const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[4];
8514   return (vec0[0]*(pt1[0]-pt0[0])+vec0[1]*(pt1[1]-pt0[1])+vec0[2]*(pt1[2]-pt0[2]))<0.;
8515 }
8516
8517 /*!
8518  * 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 ) 
8519  * 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
8520  * a 2D space.
8521  *
8522  * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not.
8523  * \param [in] coords the coordinates with nb of components exactly equal to 3
8524  * \param [in] begin begin of the nodal connectivity (geometric type included) of a single polyhedron cell
8525  * \param [in] end end of nodal connectivity of a single polyhedron cell (excluded)
8526  * \param [out] res the result is put at the end of the vector without any alteration of the data.
8527  */
8528 void MEDCouplingUMesh::SimplifyPolyhedronCell(double eps, const DataArrayDouble *coords, const int *begin, const int *end, DataArrayInt *res)
8529 {
8530   int nbFaces=std::count(begin+1,end,-1)+1;
8531   MCAuto<DataArrayDouble> v=DataArrayDouble::New(); v->alloc(nbFaces,3);
8532   double *vPtr=v->getPointer();
8533   MCAuto<DataArrayDouble> p=DataArrayDouble::New(); p->alloc(nbFaces,1);
8534   double *pPtr=p->getPointer();
8535   const int *stFaceConn=begin+1;
8536   for(int i=0;i<nbFaces;i++,vPtr+=3,pPtr++)
8537     {
8538       const int *endFaceConn=std::find(stFaceConn,end,-1);
8539       ComputeVecAndPtOfFace(eps,coords->getConstPointer(),stFaceConn,endFaceConn,vPtr,pPtr);
8540       stFaceConn=endFaceConn+1;
8541     }
8542   pPtr=p->getPointer(); vPtr=v->getPointer();
8543   DataArrayInt *comm1=0,*commI1=0;
8544   v->findCommonTuples(eps,-1,comm1,commI1);
8545   MCAuto<DataArrayInt> comm1Auto(comm1),commI1Auto(commI1);
8546   const int *comm1Ptr=comm1->getConstPointer();
8547   const int *commI1Ptr=commI1->getConstPointer();
8548   int nbOfGrps1=commI1Auto->getNumberOfTuples()-1;
8549   res->pushBackSilent((int)INTERP_KERNEL::NORM_POLYHED);
8550   //
8551   MCAuto<MEDCouplingUMesh> mm=MEDCouplingUMesh::New("",3);
8552   mm->setCoords(const_cast<DataArrayDouble *>(coords)); mm->allocateCells(1); mm->insertNextCell(INTERP_KERNEL::NORM_POLYHED,(int)std::distance(begin+1,end),begin+1);
8553   mm->finishInsertingCells();
8554   //
8555   for(int i=0;i<nbOfGrps1;i++)
8556     {
8557       int vecId=comm1Ptr[commI1Ptr[i]];
8558       MCAuto<DataArrayDouble> tmpgrp2=p->selectByTupleId(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
8559       DataArrayInt *comm2=0,*commI2=0;
8560       tmpgrp2->findCommonTuples(eps,-1,comm2,commI2);
8561       MCAuto<DataArrayInt> comm2Auto(comm2),commI2Auto(commI2);
8562       const int *comm2Ptr=comm2->getConstPointer();
8563       const int *commI2Ptr=commI2->getConstPointer();
8564       int nbOfGrps2=commI2Auto->getNumberOfTuples()-1;
8565       for(int j=0;j<nbOfGrps2;j++)
8566         {
8567           if(commI2Ptr[j+1]-commI2Ptr[j]<=1)
8568             {
8569               res->insertAtTheEnd(begin,end);
8570               res->pushBackSilent(-1);
8571             }
8572           else
8573             {
8574               int pointId=comm1Ptr[commI1Ptr[i]+comm2Ptr[commI2Ptr[j]]];
8575               MCAuto<DataArrayInt> ids2=comm2->selectByTupleIdSafeSlice(commI2Ptr[j],commI2Ptr[j+1],1);
8576               ids2->transformWithIndArr(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
8577               DataArrayInt *tmp0=DataArrayInt::New(),*tmp1=DataArrayInt::New(),*tmp2=DataArrayInt::New(),*tmp3=DataArrayInt::New();
8578               MCAuto<MEDCouplingUMesh> mm2=mm->buildDescendingConnectivity(tmp0,tmp1,tmp2,tmp3); tmp0->decrRef(); tmp1->decrRef(); tmp2->decrRef(); tmp3->decrRef();
8579               MCAuto<MEDCouplingUMesh> mm3=static_cast<MEDCouplingUMesh *>(mm2->buildPartOfMySelf(ids2->begin(),ids2->end(),true));
8580               MCAuto<DataArrayInt> idsNodeTmp=mm3->zipCoordsTraducer();
8581               MCAuto<DataArrayInt> idsNode=idsNodeTmp->invertArrayO2N2N2O(mm3->getNumberOfNodes());
8582               const int *idsNodePtr=idsNode->getConstPointer();
8583               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];
8584               double vec[3]; vec[0]=vPtr[3*vecId+1]; vec[1]=-vPtr[3*vecId]; vec[2]=0.;
8585               double norm=vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2];
8586               if(std::abs(norm)>eps)
8587                 {
8588                   double angle=INTERP_KERNEL::EdgeArcCircle::SafeAsin(norm);
8589                   mm3->rotate(center,vec,angle);
8590                 }
8591               mm3->changeSpaceDimension(2);
8592               MCAuto<MEDCouplingUMesh> mm4=mm3->buildSpreadZonesWithPoly();
8593               const int *conn4=mm4->getNodalConnectivity()->getConstPointer();
8594               const int *connI4=mm4->getNodalConnectivityIndex()->getConstPointer();
8595               int nbOfCells=mm4->getNumberOfCells();
8596               for(int k=0;k<nbOfCells;k++)
8597                 {
8598                   int l=0;
8599                   for(const int *work=conn4+connI4[k]+1;work!=conn4+connI4[k+1];work++,l++)
8600                     res->pushBackSilent(idsNodePtr[*work]);
8601                   res->pushBackSilent(-1);
8602                 }
8603             }
8604         }
8605     }
8606   res->popBackSilent();
8607 }
8608
8609 /*!
8610  * 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
8611  * through origin. The plane is defined by its nodal connectivity [ \b begin, \b end ).
8612  * 
8613  * \param [in] eps below that value the dot product of 2 vectors is considered as colinears
8614  * \param [in] coords coordinates expected to have 3 components.
8615  * \param [in] begin start of the nodal connectivity of the face.
8616  * \param [in] end end of the nodal connectivity (excluded) of the face.
8617  * \param [out] v the normalized vector of size 3
8618  * \param [out] p the pos of plane
8619  */
8620 void MEDCouplingUMesh::ComputeVecAndPtOfFace(double eps, const double *coords, const int *begin, const int *end, double *v, double *p)
8621 {
8622   std::size_t nbPoints=std::distance(begin,end);
8623   if(nbPoints<3)
8624     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeVecAndPtOfFace : < of 3 points in face ! not able to find a plane on that face !");
8625   double vec[3]={0.,0.,0.};
8626   std::size_t j=0;
8627   bool refFound=false;
8628   for(;j<nbPoints-1 && !refFound;j++)
8629     {
8630       vec[0]=coords[3*begin[j+1]]-coords[3*begin[j]];
8631       vec[1]=coords[3*begin[j+1]+1]-coords[3*begin[j]+1];
8632       vec[2]=coords[3*begin[j+1]+2]-coords[3*begin[j]+2];
8633       double norm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
8634       if(norm>eps)
8635         {
8636           refFound=true;
8637           vec[0]/=norm; vec[1]/=norm; vec[2]/=norm;
8638         }
8639     }
8640   for(std::size_t i=j;i<nbPoints-1;i++)
8641     {
8642       double curVec[3];
8643       curVec[0]=coords[3*begin[i+1]]-coords[3*begin[i]];
8644       curVec[1]=coords[3*begin[i+1]+1]-coords[3*begin[i]+1];
8645       curVec[2]=coords[3*begin[i+1]+2]-coords[3*begin[i]+2];
8646       double norm=sqrt(curVec[0]*curVec[0]+curVec[1]*curVec[1]+curVec[2]*curVec[2]);
8647       if(norm<eps)
8648         continue;
8649       curVec[0]/=norm; curVec[1]/=norm; curVec[2]/=norm;
8650       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];
8651       norm=sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
8652       if(norm>eps)
8653         {
8654           v[0]/=norm; v[1]/=norm; v[2]/=norm;
8655           *p=v[0]*coords[3*begin[i]]+v[1]*coords[3*begin[i]+1]+v[2]*coords[3*begin[i]+2];
8656           return ;
8657         }
8658     }
8659   throw INTERP_KERNEL::Exception("Not able to find a normal vector of that 3D face !");
8660 }
8661
8662 /*!
8663  * This method tries to obtain a well oriented polyhedron.
8664  * If the algorithm fails, an exception will be thrown.
8665  */
8666 void MEDCouplingUMesh::TryToCorrectPolyhedronOrientation(int *begin, int *end, const double *coords)
8667 {
8668   std::list< std::pair<int,int> > edgesOK,edgesFinished;
8669   std::size_t nbOfFaces=std::count(begin,end,-1)+1;
8670   std::vector<bool> isPerm(nbOfFaces,false);//field on faces False: I don't know, True : oriented
8671   isPerm[0]=true;
8672   int *bgFace=begin,*endFace=std::find(begin+1,end,-1);
8673   std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
8674   for(std::size_t l=0;l<nbOfEdgesInFace;l++) { std::pair<int,int> p1(bgFace[l],bgFace[(l+1)%nbOfEdgesInFace]); edgesOK.push_back(p1); }
8675   //
8676   while(std::find(isPerm.begin(),isPerm.end(),false)!=isPerm.end())
8677     {
8678       bgFace=begin;
8679       std::size_t smthChanged=0;
8680       for(std::size_t i=0;i<nbOfFaces;i++)
8681         {
8682           endFace=std::find(bgFace+1,end,-1);
8683           nbOfEdgesInFace=std::distance(bgFace,endFace);
8684           if(!isPerm[i])
8685             {
8686               bool b;
8687               for(std::size_t j=0;j<nbOfEdgesInFace;j++)
8688                 {
8689                   std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
8690                   std::pair<int,int> p2(p1.second,p1.first);
8691                   bool b1=std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end();
8692                   bool b2=std::find(edgesOK.begin(),edgesOK.end(),p2)!=edgesOK.end();
8693                   if(b1 || b2) { b=b2; isPerm[i]=true; smthChanged++; break; }
8694                 }
8695               if(isPerm[i])
8696                 { 
8697                   if(!b)
8698                     std::reverse(bgFace+1,endFace);
8699                   for(std::size_t j=0;j<nbOfEdgesInFace;j++)
8700                     {
8701                       std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
8702                       std::pair<int,int> p2(p1.second,p1.first);
8703                       if(std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end())
8704                         { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str().c_str()); }
8705                       if(std::find(edgesFinished.begin(),edgesFinished.end(),p1)!=edgesFinished.end() || std::find(edgesFinished.begin(),edgesFinished.end(),p2)!=edgesFinished.end())
8706                         { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str().c_str()); }
8707                       std::list< std::pair<int,int> >::iterator it=std::find(edgesOK.begin(),edgesOK.end(),p2);
8708                       if(it!=edgesOK.end())
8709                         {
8710                           edgesOK.erase(it);
8711                           edgesFinished.push_back(p1);
8712                         }
8713                       else
8714                         edgesOK.push_back(p1);
8715                     }
8716                 }
8717             }
8718           bgFace=endFace+1;
8719         }
8720       if(smthChanged==0)
8721         { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired !"); }
8722     }
8723   if(!edgesOK.empty())
8724     { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired : Some edges are shared only once !"); }
8725   if(INTERP_KERNEL::calculateVolumeForPolyh2<int,INTERP_KERNEL::ALL_C_MODE>(begin,(int)std::distance(begin,end),coords)<-EPS_FOR_POLYH_ORIENTATION)
8726     {//not lucky ! The first face was not correctly oriented : reorient all faces...
8727       bgFace=begin;
8728       for(std::size_t i=0;i<nbOfFaces;i++)
8729         {
8730           endFace=std::find(bgFace+1,end,-1);
8731           std::reverse(bgFace+1,endFace);
8732           bgFace=endFace+1;
8733         }
8734     }
8735 }
8736
8737 DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMeshLinear(const MEDCouplingUMesh *skin, const DataArrayInt *n2o) const
8738 {
8739   int nbOfNodesExpected(skin->getNumberOfNodes());
8740   const int *n2oPtr(n2o->getConstPointer());
8741   MCAuto<DataArrayInt> revNodal(DataArrayInt::New()),revNodalI(DataArrayInt::New());
8742   skin->getReverseNodalConnectivity(revNodal,revNodalI);
8743   const int *revNodalPtr(revNodal->getConstPointer()),*revNodalIPtr(revNodalI->getConstPointer());
8744   const int *nodalPtr(skin->getNodalConnectivity()->getConstPointer());
8745   const int *nodalIPtr(skin->getNodalConnectivityIndex()->getConstPointer());
8746   MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(nbOfNodesExpected+1,1);
8747   int *work(ret->getPointer());  *work++=INTERP_KERNEL::NORM_POLYGON;
8748   if(nbOfNodesExpected<1)
8749     return ret.retn();
8750   int prevCell(0),prevNode(nodalPtr[nodalIPtr[0]+1]);
8751   *work++=n2oPtr[prevNode];
8752   for(int i=1;i<nbOfNodesExpected;i++)
8753     {
8754       if(nodalIPtr[prevCell+1]-nodalIPtr[prevCell]==3)
8755         {
8756           std::set<int> conn(nodalPtr+nodalIPtr[prevCell]+1,nodalPtr+nodalIPtr[prevCell]+3);
8757           conn.erase(prevNode);
8758           if(conn.size()==1)
8759             {
8760               int curNode(*(conn.begin()));
8761               *work++=n2oPtr[curNode];
8762               std::set<int> shar(revNodalPtr+revNodalIPtr[curNode],revNodalPtr+revNodalIPtr[curNode+1]);
8763               shar.erase(prevCell);
8764               if(shar.size()==1)
8765                 {
8766                   prevCell=*(shar.begin());
8767                   prevNode=curNode;
8768                 }
8769               else
8770                 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshLinear : presence of unexpected 2 !");
8771             }
8772           else
8773             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshLinear : presence of unexpected 1 !");
8774         }
8775       else
8776         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshLinear : presence of unexpected cell !");
8777     }
8778   return ret.retn();
8779 }
8780
8781 DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMeshQuadratic(const MEDCouplingUMesh *skin, const DataArrayInt *n2o) const
8782 {
8783   int nbOfNodesExpected(skin->getNumberOfNodes());
8784   int nbOfTurn(nbOfNodesExpected/2);
8785   const int *n2oPtr(n2o->getConstPointer());
8786   MCAuto<DataArrayInt> revNodal(DataArrayInt::New()),revNodalI(DataArrayInt::New());
8787   skin->getReverseNodalConnectivity(revNodal,revNodalI);
8788   const int *revNodalPtr(revNodal->getConstPointer()),*revNodalIPtr(revNodalI->getConstPointer());
8789   const int *nodalPtr(skin->getNodalConnectivity()->getConstPointer());
8790   const int *nodalIPtr(skin->getNodalConnectivityIndex()->getConstPointer());
8791   MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(nbOfNodesExpected+1,1);
8792   int *work(ret->getPointer());  *work++=INTERP_KERNEL::NORM_QPOLYG;
8793   if(nbOfNodesExpected<1)
8794     return ret.retn();
8795   int prevCell(0),prevNode(nodalPtr[nodalIPtr[0]+1]);
8796   *work=n2oPtr[prevNode]; work[nbOfTurn]=n2oPtr[nodalPtr[nodalIPtr[0]+3]]; work++;
8797   for(int i=1;i<nbOfTurn;i++)
8798     {
8799       if(nodalIPtr[prevCell+1]-nodalIPtr[prevCell]==4)
8800         {
8801           std::set<int> conn(nodalPtr+nodalIPtr[prevCell]+1,nodalPtr+nodalIPtr[prevCell]+3);
8802           conn.erase(prevNode);
8803           if(conn.size()==1)
8804             {
8805               int curNode(*(conn.begin()));
8806               *work=n2oPtr[curNode];
8807               std::set<int> shar(revNodalPtr+revNodalIPtr[curNode],revNodalPtr+revNodalIPtr[curNode+1]);
8808               shar.erase(prevCell);
8809               if(shar.size()==1)
8810                 {
8811                   int curCell(*(shar.begin()));
8812                   work[nbOfTurn]=n2oPtr[nodalPtr[nodalIPtr[curCell]+3]];
8813                   prevCell=curCell;
8814                   prevNode=curNode;
8815                   work++;
8816                 }
8817               else
8818                 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshQuadratic : presence of unexpected 2 !");
8819             }
8820           else
8821             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshQuadratic : presence of unexpected 1 !");
8822         }
8823       else
8824         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshQuadratic : presence of unexpected cell !");
8825     }
8826   return ret.retn();
8827 }
8828
8829 /*!
8830  * This method makes the assumption spacedimension == meshdimension == 2.
8831  * This method works only for linear cells.
8832  * 
8833  * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYGON in pos#0)
8834  */
8835 DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMesh() const
8836 {
8837   if(getMeshDimension()!=2 || getSpaceDimension()!=2)
8838     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : meshdimension, spacedimension must be equal to 2 !");
8839   MCAuto<MEDCouplingUMesh> skin(computeSkin());
8840   int oldNbOfNodes(skin->getNumberOfNodes());
8841   MCAuto<DataArrayInt> o2n(skin->zipCoordsTraducer());
8842   int nbOfNodesExpected(skin->getNumberOfNodes());
8843   MCAuto<DataArrayInt> n2o(o2n->invertArrayO2N2N2O(oldNbOfNodes));
8844   int nbCells(skin->getNumberOfCells());
8845   if(nbCells==nbOfNodesExpected)
8846     return buildUnionOf2DMeshLinear(skin,n2o);
8847   else if(2*nbCells==nbOfNodesExpected)
8848     return buildUnionOf2DMeshQuadratic(skin,n2o);
8849   else
8850     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : the mesh 2D in input appears to be not in a single part of a 2D mesh !");
8851 }
8852
8853 /*!
8854  * This method makes the assumption spacedimension == meshdimension == 3.
8855  * This method works only for linear cells.
8856  * 
8857  * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYHED in pos#0)
8858  */
8859 DataArrayInt *MEDCouplingUMesh::buildUnionOf3DMesh() const
8860 {
8861   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
8862     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf3DMesh : meshdimension, spacedimension must be equal to 2 !");
8863   MCAuto<MEDCouplingUMesh> m=computeSkin();
8864   const int *conn=m->getNodalConnectivity()->getConstPointer();
8865   const int *connI=m->getNodalConnectivityIndex()->getConstPointer();
8866   int nbOfCells=m->getNumberOfCells();
8867   MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(m->getNodalConnectivity()->getNumberOfTuples(),1);
8868   int *work=ret->getPointer();  *work++=INTERP_KERNEL::NORM_POLYHED;
8869   if(nbOfCells<1)
8870     return ret.retn();
8871   work=std::copy(conn+connI[0]+1,conn+connI[1],work);
8872   for(int i=1;i<nbOfCells;i++)
8873     {
8874       *work++=-1;
8875       work=std::copy(conn+connI[i]+1,conn+connI[i+1],work);
8876     }
8877   return ret.retn();
8878 }
8879
8880 /*!
8881  * \brief Creates a graph of cell neighbors
8882  *  \return MEDCouplingSkyLineArray * - an sky line array the user should delete.
8883  *  In the sky line array, graph arcs are stored in terms of (index,value) notation.
8884  *  For example
8885  *  - index:  0 3 5 6 6
8886  *  - value:  1 2 3 2 3 3
8887  *  means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
8888  *  Arcs are not doubled but reflexive (1,1) arcs are present for each cell
8889  */
8890 MEDCouplingSkyLineArray *MEDCouplingUMesh::generateGraph() const
8891 {
8892   checkConnectivityFullyDefined();
8893
8894   int meshDim = this->getMeshDimension();
8895   MEDCoupling::DataArrayInt* indexr=MEDCoupling::DataArrayInt::New();
8896   MEDCoupling::DataArrayInt* revConn=MEDCoupling::DataArrayInt::New();
8897   this->getReverseNodalConnectivity(revConn,indexr);
8898   const int* indexr_ptr=indexr->getConstPointer();
8899   const int* revConn_ptr=revConn->getConstPointer();
8900
8901   const MEDCoupling::DataArrayInt* index;
8902   const MEDCoupling::DataArrayInt* conn;
8903   conn=this->getNodalConnectivity(); // it includes a type as the 1st element!!!
8904   index=this->getNodalConnectivityIndex();
8905   int nbCells=this->getNumberOfCells();
8906   const int* index_ptr=index->getConstPointer();
8907   const int* conn_ptr=conn->getConstPointer();
8908
8909   //creating graph arcs (cell to cell relations)
8910   //arcs are stored in terms of (index,value) notation
8911   // 0 3 5 6 6
8912   // 1 2 3 2 3 3
8913   // means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
8914   // in present version arcs are not doubled but reflexive (1,1) arcs are present for each cell
8915
8916   //warning here one node have less than or equal effective number of cell with it
8917   //but cell could have more than effective nodes
8918   //because other equals nodes in other domain (with other global inode)
8919   std::vector <int> cell2cell_index(nbCells+1,0);
8920   std::vector <int> cell2cell;
8921   cell2cell.reserve(3*nbCells);
8922
8923   for (int icell=0; icell<nbCells;icell++)
8924     {
8925       std::map<int,int > counter;
8926       for (int iconn=index_ptr[icell]+1; iconn<index_ptr[icell+1];iconn++)
8927         {
8928           int inode=conn_ptr[iconn];
8929           for (int iconnr=indexr_ptr[inode]; iconnr<indexr_ptr[inode+1];iconnr++)
8930             {
8931               int icell2=revConn_ptr[iconnr];
8932               std::map<int,int>::iterator iter=counter.find(icell2);
8933               if (iter!=counter.end()) (iter->second)++;
8934               else counter.insert(std::make_pair(icell2,1));
8935             }
8936         }
8937       for (std::map<int,int>::const_iterator iter=counter.begin();
8938            iter!=counter.end(); iter++)
8939         if (iter->second >= meshDim)
8940           {
8941             cell2cell_index[icell+1]++;
8942             cell2cell.push_back(iter->first);
8943           }
8944     }
8945   indexr->decrRef();
8946   revConn->decrRef();
8947   cell2cell_index[0]=0;
8948   for (int icell=0; icell<nbCells;icell++)
8949     cell2cell_index[icell+1]=cell2cell_index[icell]+cell2cell_index[icell+1];
8950
8951   //filling up index and value to create skylinearray structure
8952   MEDCouplingSkyLineArray* array=new MEDCouplingSkyLineArray(cell2cell_index,cell2cell);
8953   return array;
8954 }
8955
8956 /*!
8957  * This method put in zip format into parameter 'zipFrmt' in full interlace mode.
8958  * This format is often asked by INTERP_KERNEL algorithms to avoid many indirections into coordinates array.
8959  */
8960 void MEDCouplingUMesh::FillInCompact3DMode(int spaceDim, int nbOfNodesInCell, const int *conn, const double *coo, double *zipFrmt)
8961 {
8962   double *w=zipFrmt;
8963   if(spaceDim==3)
8964     for(int i=0;i<nbOfNodesInCell;i++)
8965       w=std::copy(coo+3*conn[i],coo+3*conn[i]+3,w);
8966   else if(spaceDim==2)
8967     {
8968       for(int i=0;i<nbOfNodesInCell;i++)
8969         {
8970           w=std::copy(coo+2*conn[i],coo+2*conn[i]+2,w);
8971           *w++=0.;
8972         }
8973     }
8974   else
8975     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::FillInCompact3DMode : Invalid spaceDim specified : must be 2 or 3 !");
8976 }
8977
8978 void MEDCouplingUMesh::writeVTKLL(std::ostream& ofs, const std::string& cellData, const std::string& pointData, DataArrayByte *byteData) const
8979 {
8980   int nbOfCells=getNumberOfCells();
8981   if(nbOfCells<=0)
8982     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::writeVTK : the unstructured mesh has no cells !");
8983   ofs << "  <" << getVTKDataSetType() << ">\n";
8984   ofs << "    <Piece NumberOfPoints=\"" << getNumberOfNodes() << "\" NumberOfCells=\"" << nbOfCells << "\">\n";
8985   ofs << "      <PointData>\n" << pointData << std::endl;
8986   ofs << "      </PointData>\n";
8987   ofs << "      <CellData>\n" << cellData << std::endl;
8988   ofs << "      </CellData>\n";
8989   ofs << "      <Points>\n";
8990   if(getSpaceDimension()==3)
8991     _coords->writeVTK(ofs,8,"Points",byteData);
8992   else
8993     {
8994       MCAuto<DataArrayDouble> coo=_coords->changeNbOfComponents(3,0.);
8995       coo->writeVTK(ofs,8,"Points",byteData);
8996     }
8997   ofs << "      </Points>\n";
8998   ofs << "      <Cells>\n";
8999   const int *cPtr=_nodal_connec->getConstPointer();
9000   const int *cIPtr=_nodal_connec_index->getConstPointer();
9001   MCAuto<DataArrayInt> faceoffsets=DataArrayInt::New(); faceoffsets->alloc(nbOfCells,1);
9002   MCAuto<DataArrayInt> types=DataArrayInt::New(); types->alloc(nbOfCells,1);
9003   MCAuto<DataArrayInt> offsets=DataArrayInt::New(); offsets->alloc(nbOfCells,1);
9004   MCAuto<DataArrayInt> connectivity=DataArrayInt::New(); connectivity->alloc(_nodal_connec->getNumberOfTuples()-nbOfCells,1);
9005   int *w1=faceoffsets->getPointer(),*w2=types->getPointer(),*w3=offsets->getPointer(),*w4=connectivity->getPointer();
9006   int szFaceOffsets=0,szConn=0;
9007   for(int i=0;i<nbOfCells;i++,w1++,w2++,w3++)
9008     {
9009       *w2=cPtr[cIPtr[i]];
9010       if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]!=INTERP_KERNEL::NORM_POLYHED)
9011         {
9012           *w1=-1;
9013           *w3=szConn+cIPtr[i+1]-cIPtr[i]-1; szConn+=cIPtr[i+1]-cIPtr[i]-1;
9014           w4=std::copy(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],w4);
9015         }
9016       else
9017         {
9018           int deltaFaceOffset=cIPtr[i+1]-cIPtr[i]+1;
9019           *w1=szFaceOffsets+deltaFaceOffset; szFaceOffsets+=deltaFaceOffset;
9020           std::set<int> c(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1]); c.erase(-1);
9021           *w3=szConn+(int)c.size(); szConn+=(int)c.size();
9022           w4=std::copy(c.begin(),c.end(),w4);
9023         }
9024     }
9025   types->transformWithIndArr(MEDCOUPLING2VTKTYPETRADUCER,MEDCOUPLING2VTKTYPETRADUCER+INTERP_KERNEL::NORM_MAXTYPE+1);
9026   types->writeVTK(ofs,8,"UInt8","types",byteData);
9027   offsets->writeVTK(ofs,8,"Int32","offsets",byteData);
9028   if(szFaceOffsets!=0)
9029     {//presence of Polyhedra
9030       connectivity->reAlloc(szConn);
9031       faceoffsets->writeVTK(ofs,8,"Int32","faceoffsets",byteData);
9032       MCAuto<DataArrayInt> faces=DataArrayInt::New(); faces->alloc(szFaceOffsets,1);
9033       w1=faces->getPointer();
9034       for(int i=0;i<nbOfCells;i++)
9035         if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]==INTERP_KERNEL::NORM_POLYHED)
9036           {
9037             int nbFaces=std::count(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],-1)+1;
9038             *w1++=nbFaces;
9039             const int *w6=cPtr+cIPtr[i]+1,*w5=0;
9040             for(int j=0;j<nbFaces;j++)
9041               {
9042                 w5=std::find(w6,cPtr+cIPtr[i+1],-1);
9043                 *w1++=(int)std::distance(w6,w5);
9044                 w1=std::copy(w6,w5,w1);
9045                 w6=w5+1;
9046               }
9047           }
9048       faces->writeVTK(ofs,8,"Int32","faces",byteData);
9049     }
9050   connectivity->writeVTK(ofs,8,"Int32","connectivity",byteData);
9051   ofs << "      </Cells>\n";
9052   ofs << "    </Piece>\n";
9053   ofs << "  </" << getVTKDataSetType() << ">\n";
9054 }
9055
9056 void MEDCouplingUMesh::reprQuickOverview(std::ostream& stream) const
9057 {
9058   stream << "MEDCouplingUMesh C++ instance at " << this << ". Name : \"" << getName() << "\".";
9059   if(_mesh_dim==-2)
9060     { stream << " Not set !"; return ; }
9061   stream << " Mesh dimension : " << _mesh_dim << ".";
9062   if(_mesh_dim==-1)
9063     return ;
9064   if(!_coords)
9065     { stream << " No coordinates set !"; return ; }
9066   if(!_coords->isAllocated())
9067     { stream << " Coordinates set but not allocated !"; return ; }
9068   stream << " Space dimension : " << _coords->getNumberOfComponents() << "." << std::endl;
9069   stream << "Number of nodes : " << _coords->getNumberOfTuples() << ".";
9070   if(!_nodal_connec_index)
9071     { stream << std::endl << "Nodal connectivity NOT set !"; return ; }
9072   if(!_nodal_connec_index->isAllocated())
9073     { stream << std::endl << "Nodal connectivity set but not allocated !"; return ; }
9074   int lgth=_nodal_connec_index->getNumberOfTuples();
9075   int cpt=_nodal_connec_index->getNumberOfComponents();
9076   if(cpt!=1 || lgth<1)
9077     return ;
9078   stream << std::endl << "Number of cells : " << lgth-1 << ".";
9079 }
9080
9081 std::string MEDCouplingUMesh::getVTKDataSetType() const
9082 {
9083   return std::string("UnstructuredGrid");
9084 }
9085
9086 std::string MEDCouplingUMesh::getVTKFileExtension() const
9087 {
9088   return std::string("vtu");
9089 }
9090
9091 /*!
9092  * Partitions the first given 2D mesh using the second given 2D mesh as a tool, and
9093  * returns a result mesh constituted by polygons.
9094  * Thus the final result contains all nodes from m1 plus new nodes. However it doesn't necessarily contains
9095  * all nodes from m2.
9096  * The meshes should be in 2D space. In
9097  * addition, returns two arrays mapping cells of the result mesh to cells of the input
9098  * meshes.
9099  *  \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
9100  *                      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)
9101  *  \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
9102  *                      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)
9103  *  \param [in] eps - precision used to detect coincident mesh entities.
9104  *  \param [out] cellNb1 - a new instance of DataArrayInt holding for each result
9105  *         cell an id of the cell of \a m1 it comes from. The caller is to delete
9106  *         this array using decrRef() as it is no more needed.
9107  *  \param [out] cellNb2 - a new instance of DataArrayInt holding for each result
9108  *         cell an id of the cell of \a m2 it comes from. -1 value means that a
9109  *         result cell comes from a cell (or part of cell) of \a m1 not overlapped by
9110  *         any cell of \a m2. The caller is to delete this array using decrRef() as
9111  *         it is no more needed.  
9112  *  \return MEDCouplingUMesh * - the result 2D mesh which is a new instance of
9113  *         MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
9114  *         is no more needed.  
9115  *  \throw If the coordinates array is not set in any of the meshes.
9116  *  \throw If the nodal connectivity of cells is not defined in any of the meshes.
9117  *  \throw If any of the meshes is not a 2D mesh in 2D space.
9118  *
9119  *  \sa conformize2D, mergeNodes
9120  */
9121 MEDCouplingUMesh *MEDCouplingUMesh::Intersect2DMeshes(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2,
9122                                                       double eps, DataArrayInt *&cellNb1, DataArrayInt *&cellNb2)
9123 {
9124   if(!m1 || !m2)
9125     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshes : input meshes must be not NULL !");
9126   m1->checkFullyDefined();
9127   m2->checkFullyDefined();
9128   if(m1->getMeshDimension()!=2 || m1->getSpaceDimension()!=2 || m2->getMeshDimension()!=2 || m2->getSpaceDimension()!=2)
9129     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshes works on umeshes m1 AND m2  with meshdim equal to 2 and spaceDim equal to 2 too!");
9130
9131   // Step 1: compute all edge intersections (new nodes)
9132   std::vector< std::vector<int> > intersectEdge1, colinear2, subDiv2;
9133   MEDCouplingUMesh *m1Desc=0,*m2Desc=0; // descending connec. meshes
9134   DataArrayInt *desc1=0,*descIndx1=0,*revDesc1=0,*revDescIndx1=0,*desc2=0,*descIndx2=0,*revDesc2=0,*revDescIndx2=0;
9135   std::vector<double> addCoo,addCoordsQuadratic;  // coordinates of newly created nodes
9136   IntersectDescending2DMeshes(m1,m2,eps,intersectEdge1,colinear2, subDiv2,
9137                               m1Desc,desc1,descIndx1,revDesc1,revDescIndx1,
9138                               addCoo, m2Desc,desc2,descIndx2,revDesc2,revDescIndx2);
9139   revDesc1->decrRef(); revDescIndx1->decrRef(); revDesc2->decrRef(); revDescIndx2->decrRef();
9140   MCAuto<DataArrayInt> dd1(desc1),dd2(descIndx1),dd3(desc2),dd4(descIndx2);
9141   MCAuto<MEDCouplingUMesh> dd5(m1Desc),dd6(m2Desc);
9142
9143   // Step 2: re-order newly created nodes according to the ordering found in m2
9144   std::vector< std::vector<int> > intersectEdge2;
9145   BuildIntersectEdges(m1Desc,m2Desc,addCoo,subDiv2,intersectEdge2);
9146   subDiv2.clear(); dd5=0; dd6=0;
9147
9148   // Step 3:
9149   std::vector<int> cr,crI; //no DataArrayInt because interface with Geometric2D
9150   std::vector<int> cNb1,cNb2; //no DataArrayInt because interface with Geometric2D
9151   BuildIntersecting2DCellsFromEdges(eps,m1,desc1->getConstPointer(),descIndx1->getConstPointer(),intersectEdge1,colinear2,m2,desc2->getConstPointer(),descIndx2->getConstPointer(),intersectEdge2,addCoo,
9152                                     /* outputs -> */addCoordsQuadratic,cr,crI,cNb1,cNb2);
9153
9154   // Step 4: Prepare final result:
9155   MCAuto<DataArrayDouble> addCooDa(DataArrayDouble::New());
9156   addCooDa->alloc((int)(addCoo.size())/2,2);
9157   std::copy(addCoo.begin(),addCoo.end(),addCooDa->getPointer());
9158   MCAuto<DataArrayDouble> addCoordsQuadraticDa(DataArrayDouble::New());
9159   addCoordsQuadraticDa->alloc((int)(addCoordsQuadratic.size())/2,2);
9160   std::copy(addCoordsQuadratic.begin(),addCoordsQuadratic.end(),addCoordsQuadraticDa->getPointer());
9161   std::vector<const DataArrayDouble *> coordss(4);
9162   coordss[0]=m1->getCoords(); coordss[1]=m2->getCoords(); coordss[2]=addCooDa; coordss[3]=addCoordsQuadraticDa;
9163   MCAuto<DataArrayDouble> coo(DataArrayDouble::Aggregate(coordss));
9164   MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("Intersect2D",2));
9165   MCAuto<DataArrayInt> conn(DataArrayInt::New()); conn->alloc((int)cr.size(),1); std::copy(cr.begin(),cr.end(),conn->getPointer());
9166   MCAuto<DataArrayInt> connI(DataArrayInt::New()); connI->alloc((int)crI.size(),1); std::copy(crI.begin(),crI.end(),connI->getPointer());
9167   MCAuto<DataArrayInt> c1(DataArrayInt::New()); c1->alloc((int)cNb1.size(),1); std::copy(cNb1.begin(),cNb1.end(),c1->getPointer());
9168   MCAuto<DataArrayInt> c2(DataArrayInt::New()); c2->alloc((int)cNb2.size(),1); std::copy(cNb2.begin(),cNb2.end(),c2->getPointer());
9169   ret->setConnectivity(conn,connI,true);
9170   ret->setCoords(coo);
9171   cellNb1=c1.retn(); cellNb2=c2.retn();
9172   return ret.retn();
9173 }
9174
9175 /// @cond INTERNAL
9176
9177 bool IsColinearOfACellOf(const std::vector< std::vector<int> >& intersectEdge1, const std::vector<int>& candidates, int start, int stop, int& retVal)
9178 {
9179   if(candidates.empty())
9180     return false;
9181   for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
9182     {
9183       const std::vector<int>& pool(intersectEdge1[*it]);
9184       int tmp[2]; tmp[0]=start; tmp[1]=stop;
9185       if(std::search(pool.begin(),pool.end(),tmp,tmp+2)!=pool.end())
9186         {
9187           retVal=*it+1;
9188           return true;
9189         }
9190       tmp[0]=stop; tmp[1]=start;
9191       if(std::search(pool.begin(),pool.end(),tmp,tmp+2)!=pool.end())
9192         {
9193           retVal=-*it-1;
9194           return true;
9195         }
9196     }
9197   return false;
9198 }
9199
9200 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,
9201                                      MCAuto<DataArrayInt>& idsInRetColinear, MCAuto<DataArrayInt>& idsInMesh1DForIdsInRetColinear)
9202 {
9203   idsInRetColinear=DataArrayInt::New(); idsInRetColinear->alloc(0,1);
9204   idsInMesh1DForIdsInRetColinear=DataArrayInt::New(); idsInMesh1DForIdsInRetColinear->alloc(0,1);
9205   int nCells(mesh1D->getNumberOfCells());
9206   if(nCells!=(int)intersectEdge2.size())
9207     throw INTERP_KERNEL::Exception("BuildMesh1DCutFrom : internal error # 1 !");
9208   const DataArrayDouble *coo2(mesh1D->getCoords());
9209   const int *c(mesh1D->getNodalConnectivity()->begin()),*ci(mesh1D->getNodalConnectivityIndex()->begin());
9210   const double *coo2Ptr(coo2->begin());
9211   int offset1(coords1->getNumberOfTuples());
9212   int offset2(offset1+coo2->getNumberOfTuples());
9213   int offset3(offset2+addCoo.size()/2);
9214   std::vector<double> addCooQuad;
9215   MCAuto<DataArrayInt> cOut(DataArrayInt::New()),ciOut(DataArrayInt::New()); cOut->alloc(0,1); ciOut->alloc(1,1); ciOut->setIJ(0,0,0);
9216   int tmp[4],cicnt(0),kk(0);
9217   for(int i=0;i<nCells;i++)
9218     {
9219       std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
9220       INTERP_KERNEL::Edge *e(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[i]],c+ci[i]+1,coo2Ptr,m));
9221       const std::vector<int>& subEdges(intersectEdge2[i]);
9222       int nbSubEdge(subEdges.size()/2);
9223       for(int j=0;j<nbSubEdge;j++,kk++)
9224         {
9225           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));
9226           MCAuto<INTERP_KERNEL::Edge> e2(e->buildEdgeLyingOnMe(n1,n2));
9227           INTERP_KERNEL::Edge *e2Ptr(e2);
9228           std::map<int,int>::const_iterator itm;
9229           if(dynamic_cast<INTERP_KERNEL::EdgeArcCircle *>(e2Ptr))
9230             {
9231               tmp[0]=INTERP_KERNEL::NORM_SEG3;
9232               itm=mergedNodes.find(subEdges[2*j]);
9233               tmp[1]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j];
9234               itm=mergedNodes.find(subEdges[2*j+1]);
9235               tmp[2]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j+1];
9236               tmp[3]=offset3+(int)addCooQuad.size()/2;
9237               double tmp2[2];
9238               e2->getBarycenter(tmp2); addCooQuad.insert(addCooQuad.end(),tmp2,tmp2+2);
9239               cicnt+=4;
9240               cOut->insertAtTheEnd(tmp,tmp+4);
9241               ciOut->pushBackSilent(cicnt);
9242             }
9243           else
9244             {
9245               tmp[0]=INTERP_KERNEL::NORM_SEG2;
9246               itm=mergedNodes.find(subEdges[2*j]);
9247               tmp[1]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j];
9248               itm=mergedNodes.find(subEdges[2*j+1]);
9249               tmp[2]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j+1];
9250               cicnt+=3;
9251               cOut->insertAtTheEnd(tmp,tmp+3);
9252               ciOut->pushBackSilent(cicnt);
9253             }
9254           int tmp00;
9255           if(IsColinearOfACellOf(intersectEdge1,colinear2[i],tmp[1],tmp[2],tmp00))
9256             {
9257               idsInRetColinear->pushBackSilent(kk);
9258               idsInMesh1DForIdsInRetColinear->pushBackSilent(tmp00);
9259             }
9260         }
9261       e->decrRef();
9262     }
9263   MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New(mesh1D->getName(),1));
9264   ret->setConnectivity(cOut,ciOut,true);
9265   MCAuto<DataArrayDouble> arr3(DataArrayDouble::New());
9266   arr3->useArray(&addCoo[0],false,C_DEALLOC,(int)addCoo.size()/2,2);
9267   MCAuto<DataArrayDouble> arr4(DataArrayDouble::New()); arr4->useArray(&addCooQuad[0],false,C_DEALLOC,(int)addCooQuad.size()/2,2);
9268   std::vector<const DataArrayDouble *> coordss(4);
9269   coordss[0]=coords1; coordss[1]=mesh1D->getCoords(); coordss[2]=arr3; coordss[3]=arr4;
9270   MCAuto<DataArrayDouble> arr(DataArrayDouble::Aggregate(coordss));
9271   ret->setCoords(arr);
9272   return ret.retn();
9273 }
9274
9275 MEDCouplingUMesh *BuildRefined2DCellLinear(const DataArrayDouble *coords, const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1)
9276 {
9277   std::vector<int> allEdges;
9278   for(const int *it2(descBg);it2!=descEnd;it2++)
9279     {
9280       const std::vector<int>& edge1(intersectEdge1[std::abs(*it2)-1]);
9281       if(*it2>0)
9282         allEdges.insert(allEdges.end(),edge1.begin(),edge1.end());
9283       else
9284         allEdges.insert(allEdges.end(),edge1.rbegin(),edge1.rend());
9285     }
9286   std::size_t nb(allEdges.size());
9287   if(nb%2!=0)
9288     throw INTERP_KERNEL::Exception("BuildRefined2DCellLinear : internal error 1 !");
9289   std::size_t nbOfEdgesOf2DCellSplit(nb/2);
9290   MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
9291   ret->setCoords(coords);
9292   ret->allocateCells(1);
9293   std::vector<int> connOut(nbOfEdgesOf2DCellSplit);
9294   for(std::size_t kk=0;kk<nbOfEdgesOf2DCellSplit;kk++)
9295     connOut[kk]=allEdges[2*kk];
9296   ret->insertNextCell(INTERP_KERNEL::NORM_POLYGON,connOut.size(),&connOut[0]);
9297   return ret.retn();
9298 }
9299
9300 MEDCouplingUMesh *BuildRefined2DCellQuadratic(const DataArrayDouble *coords, const MEDCouplingUMesh *mesh2D, int cellIdInMesh2D, const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1)
9301 {
9302   const int *c(mesh2D->getNodalConnectivity()->begin()),*ci(mesh2D->getNodalConnectivityIndex()->begin());
9303   const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c[ci[cellIdInMesh2D]]));
9304   std::size_t ii(0);
9305   unsigned sz(cm.getNumberOfSons2(c+ci[cellIdInMesh2D]+1,ci[cellIdInMesh2D+1]-ci[cellIdInMesh2D]-1));
9306   if(sz!=std::distance(descBg,descEnd))
9307     throw INTERP_KERNEL::Exception("BuildRefined2DCellQuadratic : internal error 1 !");
9308   INTERP_KERNEL::AutoPtr<int> tmpPtr(new int[ci[cellIdInMesh2D+1]-ci[cellIdInMesh2D]]);
9309   std::vector<int> allEdges,centers;
9310   const double *coordsPtr(coords->begin());
9311   MCAuto<DataArrayDouble> addCoo(DataArrayDouble::New()); addCoo->alloc(0,1);
9312   int offset(coords->getNumberOfTuples());
9313   for(const int *it2(descBg);it2!=descEnd;it2++,ii++)
9314     {
9315       INTERP_KERNEL::NormalizedCellType typeOfSon;
9316       cm.fillSonCellNodalConnectivity2(ii,c+ci[cellIdInMesh2D]+1,ci[cellIdInMesh2D+1]-ci[cellIdInMesh2D]-1,tmpPtr,typeOfSon);
9317       const std::vector<int>& edge1(intersectEdge1[std::abs(*it2)-1]);
9318       if(*it2>0)
9319         allEdges.insert(allEdges.end(),edge1.begin(),edge1.end());
9320       else
9321         allEdges.insert(allEdges.end(),edge1.rbegin(),edge1.rend());
9322       if(edge1.size()==2)
9323         centers.push_back(tmpPtr[2]);//special case where no subsplit of edge -> reuse the original center.
9324       else
9325         {//the current edge has been subsplit -> create corresponding centers.
9326           std::size_t nbOfCentersToAppend(edge1.size()/2);
9327           std::map< MCAuto<INTERP_KERNEL::Node>,int> m;
9328           MCAuto<INTERP_KERNEL::Edge> ee(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpPtr,coordsPtr,m));
9329           std::vector<int>::const_iterator it3(allEdges.end()-edge1.size());
9330           for(std::size_t k=0;k<nbOfCentersToAppend;k++)
9331             {
9332               double tmpp[2];
9333               const double *aa(coordsPtr+2*(*it3++));
9334               const double *bb(coordsPtr+2*(*it3++));
9335               ee->getMiddleOfPoints(aa,bb,tmpp);
9336               addCoo->insertAtTheEnd(tmpp,tmpp+2);
9337               centers.push_back(offset+k);
9338             }
9339         }
9340     }
9341   std::size_t nb(allEdges.size());
9342   if(nb%2!=0)
9343     throw INTERP_KERNEL::Exception("BuildRefined2DCellQuadratic : internal error 2 !");
9344   std::size_t nbOfEdgesOf2DCellSplit(nb/2);
9345   MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
9346   if(addCoo->empty())
9347     ret->setCoords(coords);
9348   else
9349     {
9350       addCoo->rearrange(2);
9351       addCoo=DataArrayDouble::Aggregate(coords,addCoo);
9352       ret->setCoords(addCoo);
9353     }
9354   ret->allocateCells(1);
9355   std::vector<int> connOut(nbOfEdgesOf2DCellSplit);
9356   for(std::size_t kk=0;kk<nbOfEdgesOf2DCellSplit;kk++)
9357     connOut[kk]=allEdges[2*kk];
9358   connOut.insert(connOut.end(),centers.begin(),centers.end());
9359   ret->insertNextCell(INTERP_KERNEL::NORM_QPOLYG,connOut.size(),&connOut[0]);
9360   return ret.retn();
9361 }
9362
9363 /*!
9364  * This method creates a refinement of a cell in \a mesh2D. Those cell is defined by descending connectivity and the sorted subdivided nodal connectivity
9365  * of those edges.
9366  *
9367  * \param [in] mesh2D - The origin 2D mesh. \b Warning \b coords are not those of \a mesh2D. But mesh2D->getCoords()==coords[:mesh2D->getNumberOfNodes()]
9368  */
9369 MEDCouplingUMesh *BuildRefined2DCell(const DataArrayDouble *coords, const MEDCouplingUMesh *mesh2D, int cellIdInMesh2D, const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1)
9370 {
9371   const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(mesh2D->getTypeOfCell(cellIdInMesh2D)));
9372   if(!cm.isQuadratic())
9373     return BuildRefined2DCellLinear(coords,descBg,descEnd,intersectEdge1);
9374   else
9375     return BuildRefined2DCellQuadratic(coords,mesh2D,cellIdInMesh2D,descBg,descEnd,intersectEdge1);
9376 }
9377
9378 void AddCellInMesh2D(MEDCouplingUMesh *mesh2D, const std::vector<int>& conn, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edges)
9379 {
9380   bool isQuad(false);
9381   for(std::vector< MCAuto<INTERP_KERNEL::Edge> >::const_iterator it=edges.begin();it!=edges.end();it++)
9382     {
9383       const INTERP_KERNEL::Edge *ee(*it);
9384       if(dynamic_cast<const INTERP_KERNEL::EdgeArcCircle *>(ee))
9385         isQuad=true;
9386     }
9387   if(!isQuad)
9388     mesh2D->insertNextCell(INTERP_KERNEL::NORM_POLYGON,conn.size(),&conn[0]);
9389   else
9390     {
9391       const double *coo(mesh2D->getCoords()->begin());
9392       std::size_t sz(conn.size());
9393       std::vector<double> addCoo;
9394       std::vector<int> conn2(conn);
9395       int offset(mesh2D->getNumberOfNodes());
9396       for(std::size_t i=0;i<sz;i++)
9397         {
9398           double tmp[2];
9399           edges[(i+1)%sz]->getMiddleOfPoints(coo+2*conn[i],coo+2*conn[(i+1)%sz],tmp);// tony a chier i+1 -> i
9400           addCoo.insert(addCoo.end(),tmp,tmp+2);
9401           conn2.push_back(offset+(int)i);
9402         }
9403       mesh2D->getCoords()->rearrange(1);
9404       mesh2D->getCoords()->pushBackValsSilent(&addCoo[0],&addCoo[0]+addCoo.size());
9405       mesh2D->getCoords()->rearrange(2);
9406       mesh2D->insertNextCell(INTERP_KERNEL::NORM_QPOLYG,conn2.size(),&conn2[0]);
9407     }
9408 }
9409
9410 /*!
9411  * \b WARNING edges in out1 coming from \a splitMesh1D are \b NOT oriented because only used for equation of curve.
9412  *
9413  * This method cuts in 2 parts the input 2D cell given using boundaries description (\a edge1Bis and \a edge1BisPtr) using
9414  * a set of edges defined in \a splitMesh1D.
9415  */
9416 void BuildMesh2DCutInternal2(const MEDCouplingUMesh *splitMesh1D, const std::vector<int>& edge1Bis, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edge1BisPtr,
9417                              std::vector< std::vector<int> >& out0, std::vector< std::vector< MCAuto<INTERP_KERNEL::Edge> > >& out1)
9418 {
9419   std::size_t nb(edge1Bis.size()/2);
9420   std::size_t nbOfEdgesOf2DCellSplit(nb/2);
9421   int iEnd(splitMesh1D->getNumberOfCells());
9422   if(iEnd==0)
9423     throw INTERP_KERNEL::Exception("BuildMesh2DCutInternal2 : internal error ! input 1D mesh must have at least one cell !");
9424   std::size_t ii,jj;
9425   const int *cSplitPtr(splitMesh1D->getNodalConnectivity()->begin()),*ciSplitPtr(splitMesh1D->getNodalConnectivityIndex()->begin());
9426   for(ii=0;ii<nb && edge1Bis[2*ii]!=cSplitPtr[ciSplitPtr[0]+1];ii++);
9427   for(jj=ii;jj<nb && edge1Bis[2*jj+1]!=cSplitPtr[ciSplitPtr[iEnd-1]+2];jj++);
9428   //
9429   if(jj==nb)
9430     {//the edges splitMesh1D[iStart:iEnd] does not fully cut the current 2D cell -> single output cell
9431       out0.resize(1); out1.resize(1);
9432       std::vector<int>& connOut(out0[0]);
9433       connOut.resize(nbOfEdgesOf2DCellSplit);
9434       std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr(out1[0]);
9435       edgesPtr.resize(nbOfEdgesOf2DCellSplit);
9436       for(std::size_t kk=0;kk<nbOfEdgesOf2DCellSplit;kk++)
9437         {
9438           connOut[kk]=edge1Bis[2*kk];
9439           edgesPtr[kk]=edge1BisPtr[2*kk];
9440         }
9441     }
9442   else
9443     {
9444       // [i,iEnd[ contains the
9445       out0.resize(2); out1.resize(2);
9446       std::vector<int>& connOutLeft(out0[0]);
9447       std::vector<int>& connOutRight(out0[1]);//connOutLeft should end with edge1Bis[2*ii] and connOutRight should end with edge1Bis[2*jj+1]
9448       std::vector< MCAuto<INTERP_KERNEL::Edge> >& eleft(out1[0]);
9449       std::vector< MCAuto<INTERP_KERNEL::Edge> >& eright(out1[1]);
9450       for(std::size_t k=ii;k<jj+1;k++)
9451         { connOutLeft.push_back(edge1Bis[2*k+1]); eleft.push_back(edge1BisPtr[2*k+1]); }
9452       std::vector< MCAuto<INTERP_KERNEL::Edge> > ees(iEnd);
9453       for(int ik=0;ik<iEnd;ik++)
9454         {
9455           std::map< MCAuto<INTERP_KERNEL::Node>,int> m;
9456           MCAuto<INTERP_KERNEL::Edge> ee(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)cSplitPtr[ciSplitPtr[ik]],cSplitPtr+ciSplitPtr[ik]+1,splitMesh1D->getCoords()->begin(),m));
9457           ees[ik]=ee;
9458         }
9459       for(int ik=iEnd-1;ik>=0;ik--)
9460         connOutLeft.push_back(cSplitPtr[ciSplitPtr[ik]+1]);
9461       for(std::size_t k=jj+1;k<nbOfEdgesOf2DCellSplit+ii;k++)
9462         { connOutRight.push_back(edge1Bis[2*k+1]); eright.push_back(edge1BisPtr[2*k+1]); }
9463       eleft.insert(eleft.end(),ees.rbegin(),ees.rend());
9464       for(int ik=0;ik<iEnd;ik++)
9465         connOutRight.push_back(cSplitPtr[ciSplitPtr[ik]+2]);
9466       eright.insert(eright.end(),ees.begin(),ees.end());
9467     }
9468 }
9469
9470 /// @endcond
9471
9472 /// @cond INTERNAL
9473
9474 struct CellInfo
9475 {
9476 public:
9477   CellInfo() { }
9478   CellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr);
9479 public:
9480   std::vector<int> _edges;
9481   std::vector< MCAuto<INTERP_KERNEL::Edge> > _edges_ptr;
9482 };
9483
9484 CellInfo::CellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr)
9485 {
9486   std::size_t nbe(edges.size());
9487   std::vector<int> edges2(2*nbe); std::vector< MCAuto<INTERP_KERNEL::Edge> > edgesPtr2(2*nbe);
9488   for(std::size_t i=0;i<nbe;i++)
9489     {
9490       edges2[2*i]=edges[i]; edges2[2*i+1]=edges[(i+1)%nbe];
9491       edgesPtr2[2*i]=edgesPtr[(i+1)%nbe]; edgesPtr2[2*i+1]=edgesPtr[(i+1)%nbe];//tony a chier
9492     }
9493   _edges.resize(4*nbe); _edges_ptr.resize(4*nbe);
9494   std::copy(edges2.begin(),edges2.end(),_edges.begin()); std::copy(edges2.begin(),edges2.end(),_edges.begin()+2*nbe);
9495   std::copy(edgesPtr2.begin(),edgesPtr2.end(),_edges_ptr.begin()); std::copy(edgesPtr2.begin(),edgesPtr2.end(),_edges_ptr.begin()+2*nbe);
9496 }
9497
9498 class EdgeInfo
9499 {
9500 public:
9501   EdgeInfo(int istart, int iend, const MCAuto<MEDCouplingUMesh>& mesh):_istart(istart),_iend(iend),_mesh(mesh),_left(-7),_right(-7) { }
9502   EdgeInfo(int istart, int iend, int pos, const MCAuto<INTERP_KERNEL::Edge>& edge):_istart(istart),_iend(iend),_edge(edge),_left(pos),_right(pos+1) { }
9503   bool isInMyRange(int pos) const { return pos>=_istart && pos<_iend; }
9504   void somethingHappendAt(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight);
9505   void feedEdgeInfoAt(double eps, const MEDCouplingUMesh *mesh2D, int offset, int neighbors[2]) const;
9506 private:
9507   int _istart;
9508   int _iend;
9509   MCAuto<MEDCouplingUMesh> _mesh;
9510   MCAuto<INTERP_KERNEL::Edge> _edge;
9511   int _left;
9512   int _right;
9513 };
9514
9515 void EdgeInfo::somethingHappendAt(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight)
9516 {
9517   const MEDCouplingUMesh *mesh(_mesh);
9518   if(mesh)
9519     return ;
9520   if(_right<pos)
9521     return ;
9522   if(_left>pos)
9523     { _left++; _right++; return ; }
9524   if(_right==pos)
9525     {
9526       bool isLeft(std::find(newLeft.begin(),newLeft.end(),_edge)!=newLeft.end()),isRight(std::find(newRight.begin(),newRight.end(),_edge)!=newRight.end());
9527       if((isLeft && isRight) || (!isLeft && !isRight))
9528         throw INTERP_KERNEL::Exception("EdgeInfo::somethingHappendAt : internal error # 1 !");
9529       if(isLeft)
9530         return ;
9531       if(isRight)
9532         {
9533           _right++;
9534           return ;
9535         }
9536     }
9537   if(_left==pos)
9538     {
9539       bool isLeft(std::find(newLeft.begin(),newLeft.end(),_edge)!=newLeft.end()),isRight(std::find(newRight.begin(),newRight.end(),_edge)!=newRight.end());
9540       if((isLeft && isRight) || (!isLeft && !isRight))
9541         throw INTERP_KERNEL::Exception("EdgeInfo::somethingHappendAt : internal error # 2 !");
9542       if(isLeft)
9543         {
9544           _right++;
9545           return ;
9546         }
9547       if(isRight)
9548         {
9549           _left++;
9550           _right++;
9551           return ;
9552         }
9553     }
9554 }
9555
9556 void EdgeInfo::feedEdgeInfoAt(double eps, const MEDCouplingUMesh *mesh2D, int offset, int neighbors[2]) const
9557 {
9558   const MEDCouplingUMesh *mesh(_mesh);
9559   if(!mesh)
9560     {
9561       neighbors[0]=offset+_left; neighbors[1]=offset+_right;
9562     }
9563   else
9564     {// not fully splitting cell case
9565       if(mesh2D->getNumberOfCells()==1)
9566         {//little optimization. 1 cell no need to find in which cell mesh is !
9567           neighbors[0]=offset; neighbors[1]=offset;
9568           return;
9569         }
9570       else
9571         {
9572           MCAuto<DataArrayDouble> barys(mesh->computeCellCenterOfMass());
9573           int cellId(mesh2D->getCellContainingPoint(barys->begin(),eps));
9574           if(cellId==-1)
9575             throw INTERP_KERNEL::Exception("EdgeInfo::feedEdgeInfoAt : internal error !");
9576           neighbors[0]=offset+cellId; neighbors[1]=offset+cellId;
9577         }
9578     }
9579 }
9580
9581 class VectorOfCellInfo
9582 {
9583 public:
9584   VectorOfCellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr);
9585   std::size_t size() const { return _pool.size(); }
9586   int getPositionOf(double eps, const MEDCouplingUMesh *mesh) const;
9587   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);
9588   const std::vector<int>& getConnOf(int pos) const { return get(pos)._edges; }
9589   const std::vector< MCAuto<INTERP_KERNEL::Edge> >& getEdgePtrOf(int pos) const { return get(pos)._edges_ptr; }
9590   MCAuto<MEDCouplingUMesh> getZeMesh() const { return _ze_mesh; }
9591   void feedEdgeInfoAt(double eps, int pos, int offset, int neighbors[2]) const;
9592 private:
9593   int getZePosOfEdgeGivenItsGlobalId(int pos) const;
9594   void updateEdgeInfo(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight);
9595   const CellInfo& get(int pos) const;
9596   CellInfo& get(int pos);
9597 private:
9598   std::vector<CellInfo> _pool;
9599   MCAuto<MEDCouplingUMesh> _ze_mesh;
9600   std::vector<EdgeInfo> _edge_info;
9601 };
9602
9603 VectorOfCellInfo::VectorOfCellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr):_pool(1)
9604 {
9605   _pool[0]._edges=edges;
9606   _pool[0]._edges_ptr=edgesPtr;
9607 }
9608
9609 int VectorOfCellInfo::getPositionOf(double eps, const MEDCouplingUMesh *mesh) const
9610 {
9611   if(_pool.empty())
9612     throw INTERP_KERNEL::Exception("VectorOfCellSplitter::getPositionOf : empty !");
9613   if(_pool.size()==1)
9614     return 0;
9615   const MEDCouplingUMesh *zeMesh(_ze_mesh);
9616   if(!zeMesh)
9617     throw INTERP_KERNEL::Exception("VectorOfCellSplitter::getPositionOf : null aggregated mesh !");
9618   MCAuto<DataArrayDouble> barys(mesh->computeCellCenterOfMass());
9619   return zeMesh->getCellContainingPoint(barys->begin(),eps);
9620 }
9621
9622 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)
9623 {
9624   get(pos);//to check pos
9625   bool isFast(pos==0 && _pool.size()==1);
9626   std::size_t sz(edges.size());
9627   // dealing with edges
9628   if(sz==1)
9629     _edge_info.push_back(EdgeInfo(istart,iend,mesh1DInCase));
9630   else
9631     _edge_info.push_back(EdgeInfo(istart,iend,pos,edgePtrs[0].back()));
9632   //
9633   std::vector<CellInfo> pool(_pool.size()-1+sz);
9634   for(int i=0;i<pos;i++)
9635     pool[i]=_pool[i];
9636   for(std::size_t j=0;j<sz;j++)
9637     pool[pos+j]=CellInfo(edges[j],edgePtrs[j]);
9638   for(int i=pos+1;i<(int)_pool.size();i++)
9639     pool[i+sz-1]=_pool[i];
9640   _pool=pool;
9641   //
9642   if(sz==2)
9643     updateEdgeInfo(pos,edgePtrs[0],edgePtrs[1]);
9644   //
9645   if(isFast)
9646     {
9647       _ze_mesh=mesh;
9648       return ;
9649     }
9650   //
9651   std::vector< MCAuto<MEDCouplingUMesh> > ms;
9652   if(pos>0)
9653     {
9654       MCAuto<MEDCouplingUMesh> elt(static_cast<MEDCouplingUMesh *>(_ze_mesh->buildPartOfMySelfSlice(0,pos,true)));
9655       ms.push_back(elt);
9656     }
9657   ms.push_back(mesh);
9658   if(pos<_ze_mesh->getNumberOfCells()-1)
9659   {
9660     MCAuto<MEDCouplingUMesh> elt(static_cast<MEDCouplingUMesh *>(_ze_mesh->buildPartOfMySelfSlice(pos+1,_ze_mesh->getNumberOfCells(),true)));
9661     ms.push_back(elt);
9662   }
9663   std::vector< const MEDCouplingUMesh *> ms2(ms.size());
9664   for(std::size_t j=0;j<ms2.size();j++)
9665     ms2[j]=ms[j];
9666   _ze_mesh=MEDCouplingUMesh::MergeUMeshesOnSameCoords(ms2);
9667 }
9668
9669 void VectorOfCellInfo::feedEdgeInfoAt(double eps, int pos, int offset, int neighbors[2]) const
9670 {
9671   _edge_info[getZePosOfEdgeGivenItsGlobalId(pos)].feedEdgeInfoAt(eps,_ze_mesh,offset,neighbors);
9672 }
9673
9674 int VectorOfCellInfo::getZePosOfEdgeGivenItsGlobalId(int pos) const
9675 {
9676   if(pos<0)
9677     throw INTERP_KERNEL::Exception("VectorOfCellInfo::getZePosOfEdgeGivenItsGlobalId : invalid id ! Must be >=0 !");
9678   int ret(0);
9679   for(std::vector<EdgeInfo>::const_iterator it=_edge_info.begin();it!=_edge_info.end();it++,ret++)
9680     {
9681       if((*it).isInMyRange(pos))
9682         return ret;
9683     }
9684   throw INTERP_KERNEL::Exception("VectorOfCellInfo::getZePosOfEdgeGivenItsGlobalId : invalid id !");
9685 }
9686
9687 void VectorOfCellInfo::updateEdgeInfo(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight)
9688 {
9689   get(pos);//to check;
9690   if(_edge_info.empty())
9691     return ;
9692   std::size_t sz(_edge_info.size()-1);
9693   for(std::size_t i=0;i<sz;i++)
9694     _edge_info[i].somethingHappendAt(pos,newLeft,newRight);
9695 }
9696
9697 const CellInfo& VectorOfCellInfo::get(int pos) const
9698 {
9699   if(pos<0 || pos>=(int)_pool.size())
9700     throw INTERP_KERNEL::Exception("VectorOfCellSplitter::get const : invalid pos !");
9701   return _pool[pos];
9702 }
9703
9704 CellInfo& VectorOfCellInfo::get(int pos)
9705 {
9706   if(pos<0 || pos>=(int)_pool.size())
9707     throw INTERP_KERNEL::Exception("VectorOfCellSplitter::get : invalid pos !");
9708   return _pool[pos];
9709 }
9710
9711 /*!
9712  * Given :
9713  * - a \b closed set of edges ( \a allEdges and \a allEdgesPtr ) that defines the split descending 2D cell.
9714  * - \a splitMesh1D a split 2D curve mesh contained into 2D cell defined above.
9715  *
9716  * This method returns the 2D mesh and feeds \a idsLeftRight using offset.
9717  *
9718  * Algorithm : \a splitMesh1D is cut into contiguous parts. Each contiguous parts will build incrementally the output 2D cells.
9719  *
9720  * \param [in] allEdges a list of pairs (beginNode, endNode). Linked with \a allEdgesPtr to get the equation of edge.
9721  */
9722 MEDCouplingUMesh *BuildMesh2DCutInternal(double eps, const MEDCouplingUMesh *splitMesh1D, const std::vector<int>& allEdges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& allEdgesPtr, int offset,
9723                                          MCAuto<DataArrayInt>& idsLeftRight)
9724 {
9725   int nbCellsInSplitMesh1D(splitMesh1D->getNumberOfCells());
9726   if(nbCellsInSplitMesh1D==0)
9727     throw INTERP_KERNEL::Exception("BuildMesh2DCutInternal : internal error ! input 1D mesh must have at least one cell !");
9728   const int *cSplitPtr(splitMesh1D->getNodalConnectivity()->begin()),*ciSplitPtr(splitMesh1D->getNodalConnectivityIndex()->begin());
9729   std::size_t nb(allEdges.size()),jj;
9730   if(nb%2!=0)
9731     throw INTERP_KERNEL::Exception("BuildMesh2DCutFrom : internal error 2 !");
9732   std::vector<int> edge1Bis(nb*2);
9733   std::vector< MCAuto<INTERP_KERNEL::Edge> > edge1BisPtr(nb*2);
9734   std::copy(allEdges.begin(),allEdges.end(),edge1Bis.begin());
9735   std::copy(allEdges.begin(),allEdges.end(),edge1Bis.begin()+nb);
9736   std::copy(allEdgesPtr.begin(),allEdgesPtr.end(),edge1BisPtr.begin());
9737   std::copy(allEdgesPtr.begin(),allEdgesPtr.end(),edge1BisPtr.begin()+nb);
9738   //
9739   idsLeftRight=DataArrayInt::New(); idsLeftRight->alloc(nbCellsInSplitMesh1D*2); idsLeftRight->fillWithValue(-2); idsLeftRight->rearrange(2);
9740   int *idsLeftRightPtr(idsLeftRight->getPointer());
9741   VectorOfCellInfo pool(edge1Bis,edge1BisPtr);
9742   for(int iStart=0;iStart<nbCellsInSplitMesh1D;)
9743     {// split [0:nbCellsInSplitMesh1D) in contiguous parts [iStart:iEnd)
9744       int iEnd(iStart);
9745       for(;iEnd<nbCellsInSplitMesh1D;)
9746         {
9747           for(jj=0;jj<nb && edge1Bis[2*jj+1]!=cSplitPtr[ciSplitPtr[iEnd]+2];jj++);
9748           if(jj!=nb)
9749             break;
9750           else
9751             iEnd++;
9752         }
9753       if(iEnd<nbCellsInSplitMesh1D)
9754         iEnd++;
9755       //
9756       MCAuto<MEDCouplingUMesh> partOfSplitMesh1D(static_cast<MEDCouplingUMesh *>(splitMesh1D->buildPartOfMySelfSlice(iStart,iEnd,1,true)));
9757       int pos(pool.getPositionOf(eps,partOfSplitMesh1D));
9758       //
9759       MCAuto<MEDCouplingUMesh>retTmp(MEDCouplingUMesh::New("",2));
9760       retTmp->setCoords(splitMesh1D->getCoords());
9761       retTmp->allocateCells();
9762
9763       std::vector< std::vector<int> > out0;
9764       std::vector< std::vector< MCAuto<INTERP_KERNEL::Edge> > > out1;
9765
9766       BuildMesh2DCutInternal2(partOfSplitMesh1D,pool.getConnOf(pos),pool.getEdgePtrOf(pos),out0,out1);
9767       for(std::size_t cnt=0;cnt<out0.size();cnt++)
9768         AddCellInMesh2D(retTmp,out0[cnt],out1[cnt]);
9769       pool.setMeshAt(pos,retTmp,iStart,iEnd,partOfSplitMesh1D,out0,out1);
9770       //
9771       iStart=iEnd;
9772     }
9773   for(int mm=0;mm<nbCellsInSplitMesh1D;mm++)
9774     pool.feedEdgeInfoAt(eps,mm,offset,idsLeftRightPtr+2*mm);
9775   return pool.getZeMesh().retn();
9776 }
9777
9778 MEDCouplingUMesh *BuildMesh2DCutFrom(double eps, int cellIdInMesh2D, const MEDCouplingUMesh *mesh2DDesc, const MEDCouplingUMesh *splitMesh1D,
9779                                      const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1, int offset,
9780                                      MCAuto<DataArrayInt>& idsLeftRight)
9781 {
9782   const int *cdescPtr(mesh2DDesc->getNodalConnectivity()->begin()),*cidescPtr(mesh2DDesc->getNodalConnectivityIndex()->begin());
9783   //
9784   std::vector<int> allEdges;
9785   std::vector< MCAuto<INTERP_KERNEL::Edge> > allEdgesPtr; // for each sub edge in splitMesh2D the uncut Edge object of the original mesh2D
9786   for(const int *it(descBg);it!=descEnd;it++) // for all edges in the descending connectivity of the 2D mesh in relative Fortran mode
9787     {
9788       int edgeId(std::abs(*it)-1);
9789       std::map< MCAuto<INTERP_KERNEL::Node>,int> m;
9790       MCAuto<INTERP_KERNEL::Edge> ee(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)cdescPtr[cidescPtr[edgeId]],cdescPtr+cidescPtr[edgeId]+1,mesh2DDesc->getCoords()->begin(),m));
9791       const std::vector<int>& edge1(intersectEdge1[edgeId]);
9792       if(*it>0)
9793         allEdges.insert(allEdges.end(),edge1.begin(),edge1.end());
9794       else
9795         allEdges.insert(allEdges.end(),edge1.rbegin(),edge1.rend());
9796       std::size_t sz(edge1.size());
9797       for(std::size_t cnt=0;cnt<sz;cnt++)
9798         allEdgesPtr.push_back(ee);
9799     }
9800   //
9801   return BuildMesh2DCutInternal(eps,splitMesh1D,allEdges,allEdgesPtr,offset,idsLeftRight);
9802 }
9803
9804 bool AreEdgeEqual(const double *coo2D, const INTERP_KERNEL::CellModel& typ1, const int *conn1, const INTERP_KERNEL::CellModel& typ2, const int *conn2, double eps)
9805 {
9806   if(!typ1.isQuadratic() && !typ2.isQuadratic())
9807     {//easy case comparison not
9808       return conn1[0]==conn2[0] && conn1[1]==conn2[1];
9809     }
9810   else if(typ1.isQuadratic() && typ2.isQuadratic())
9811     {
9812       bool status0(conn1[0]==conn2[0] && conn1[1]==conn2[1]);
9813       if(!status0)
9814         return false;
9815       if(conn1[2]==conn2[2])
9816         return true;
9817       const double *a(coo2D+2*conn1[2]),*b(coo2D+2*conn2[2]);
9818       double dist(sqrt((a[0]-b[0])*(a[0]-b[0])+(a[1]-b[1])*(a[1]-b[1])));
9819       return dist<eps;
9820     }
9821   else
9822     {//only one is quadratic
9823       bool status0(conn1[0]==conn2[0] && conn1[1]==conn2[1]);
9824       if(!status0)
9825         return false;
9826       const double *a(0),*bb(0),*be(0);
9827       if(typ1.isQuadratic())
9828         {
9829           a=coo2D+2*conn1[2]; bb=coo2D+2*conn2[0]; be=coo2D+2*conn2[1];
9830         }
9831       else
9832         {
9833           a=coo2D+2*conn2[2]; bb=coo2D+2*conn1[0]; be=coo2D+2*conn1[1];
9834         }
9835       double b[2]; b[0]=(be[0]+bb[0])/2.; b[1]=(be[1]+bb[1])/2.;
9836       double dist(sqrt((a[0]-b[0])*(a[0]-b[0])+(a[1]-b[1])*(a[1]-b[1])));
9837       return dist<eps;
9838     }
9839 }
9840
9841 /*!
9842  * This method returns among the cellIds [ \a candidatesIn2DBg , \a candidatesIn2DEnd ) in \a mesh2DSplit those exactly sharing \a cellIdInMesh1DSplitRelative in \a mesh1DSplit.
9843  * \a mesh2DSplit and \a mesh1DSplit are expected to share the coordinates array.
9844  *
9845  * \param [in] cellIdInMesh1DSplitRelative is in Fortran mode using sign to specify direction.
9846  */
9847 int FindRightCandidateAmong(const MEDCouplingUMesh *mesh2DSplit, const int *candidatesIn2DBg, const int *candidatesIn2DEnd, const MEDCouplingUMesh *mesh1DSplit, int cellIdInMesh1DSplitRelative, double eps)
9848 {
9849   if(candidatesIn2DEnd==candidatesIn2DBg)
9850     throw INTERP_KERNEL::Exception("FindRightCandidateAmong : internal error 1 !");
9851   const double *coo(mesh2DSplit->getCoords()->begin());
9852   if(std::distance(candidatesIn2DBg,candidatesIn2DEnd)==1)
9853     return *candidatesIn2DBg;
9854   int edgeId(std::abs(cellIdInMesh1DSplitRelative)-1);
9855   MCAuto<MEDCouplingUMesh> cur1D(static_cast<MEDCouplingUMesh *>(mesh1DSplit->buildPartOfMySelf(&edgeId,&edgeId+1,true)));
9856   if(cellIdInMesh1DSplitRelative<0)
9857     cur1D->changeOrientationOfCells();
9858   const int *c1D(cur1D->getNodalConnectivity()->begin());
9859   const INTERP_KERNEL::CellModel& ref1DType(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c1D[0]));
9860   for(const int *it=candidatesIn2DBg;it!=candidatesIn2DEnd;it++)
9861     {
9862       MCAuto<MEDCouplingUMesh> cur2D(static_cast<MEDCouplingUMesh *>(mesh2DSplit->buildPartOfMySelf(it,it+1,true)));
9863       const int *c(cur2D->getNodalConnectivity()->begin()),*ci(cur2D->getNodalConnectivityIndex()->begin());
9864       const INTERP_KERNEL::CellModel &cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c[ci[0]]));
9865       unsigned sz(cm.getNumberOfSons2(c+ci[0]+1,ci[1]-ci[0]-1));
9866       INTERP_KERNEL::AutoPtr<int> tmpPtr(new int[ci[1]-ci[0]]);
9867       for(unsigned it2=0;it2<sz;it2++)
9868         {
9869           INTERP_KERNEL::NormalizedCellType typeOfSon;
9870           cm.fillSonCellNodalConnectivity2(it2,c+ci[0]+1,ci[1]-ci[0]-1,tmpPtr,typeOfSon);
9871           const INTERP_KERNEL::CellModel &curCM(INTERP_KERNEL::CellModel::GetCellModel(typeOfSon));
9872           if(AreEdgeEqual(coo,ref1DType,c1D+1,curCM,tmpPtr,eps))
9873             return *it;
9874         }
9875     }
9876   throw INTERP_KERNEL::Exception("FindRightCandidateAmong : internal error 2 ! Unable to find the edge among split cell !");
9877 }
9878
9879 /// @endcond
9880
9881 /*!
9882  * Partitions the first given 2D mesh using the second given 1D mesh as a tool.
9883  * 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
9884  * and finaly, in case of quadratic polygon the centers of edges new nodes.
9885  * The meshes should be in 2D space. In addition, returns two arrays mapping cells of the resulting mesh to cells of the input.
9886  *
9887  * \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
9888  *                      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)
9889  * \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
9890  *                      you can invoke orderConsecutiveCells1D on \a mesh1D.
9891  * \param [in] eps - precision used to perform intersections and localization operations.
9892  * \param [out] splitMesh2D - the result of the split of \a mesh2D mesh.
9893  * \param [out] splitMesh1D - the result of the split of \a mesh1D mesh.
9894  * \param [out] cellIdInMesh2D - the array that gives for each cell id \a i in \a splitMesh2D the id in \a mesh2D it comes from.
9895  *                               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.
9896  * \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
9897  *                               and the cell in \a splitMesh2D on the right for the 2nt component. -1 means no cell.
9898  *                               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.
9899  *
9900  * \sa Intersect2DMeshes, orderConsecutiveCells1D, conformize2D, mergeNodes
9901  */
9902 void MEDCouplingUMesh::Intersect2DMeshWith1DLine(const MEDCouplingUMesh *mesh2D, const MEDCouplingUMesh *mesh1D, double eps, MEDCouplingUMesh *&splitMesh2D, MEDCouplingUMesh *&splitMesh1D, DataArrayInt *&cellIdInMesh2D, DataArrayInt *&cellIdInMesh1D)
9903 {
9904   if(!mesh2D || !mesh1D)
9905     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshWith1DLine : input meshes must be not NULL !");
9906   mesh2D->checkFullyDefined();
9907   mesh1D->checkFullyDefined();
9908   const std::vector<std::string>& compNames(mesh2D->getCoords()->getInfoOnComponents());
9909   if(mesh2D->getMeshDimension()!=2 || mesh2D->getSpaceDimension()!=2 || mesh1D->getMeshDimension()!=1 || mesh1D->getSpaceDimension()!=2)
9910     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshWith1DLine works with mesh2D with spacedim=meshdim=2 and mesh1D with meshdim=1 spaceDim=2 !");
9911   // Step 1: compute all edge intersections (new nodes)
9912   std::vector< std::vector<int> > intersectEdge1, colinear2, subDiv2;
9913   std::vector<double> addCoo,addCoordsQuadratic;  // coordinates of newly created nodes
9914   INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
9915   INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
9916   //
9917   // Build desc connectivity
9918   DataArrayInt *desc1(DataArrayInt::New()),*descIndx1(DataArrayInt::New()),*revDesc1(DataArrayInt::New()),*revDescIndx1(DataArrayInt::New());
9919   MCAuto<DataArrayInt> dd1(desc1),dd2(descIndx1),dd3(revDesc1),dd4(revDescIndx1);
9920   MCAuto<MEDCouplingUMesh> m1Desc(mesh2D->buildDescendingConnectivity2(desc1,descIndx1,revDesc1,revDescIndx1));
9921   std::map<int,int> mergedNodes;
9922   Intersect1DMeshes(m1Desc,mesh1D,eps,intersectEdge1,colinear2,subDiv2,addCoo,mergedNodes);
9923   // use mergeNodes to fix intersectEdge1
9924   for(std::vector< std::vector<int> >::iterator it0=intersectEdge1.begin();it0!=intersectEdge1.end();it0++)
9925     {
9926       std::size_t n((*it0).size()/2);
9927       int eltStart((*it0)[0]),eltEnd((*it0)[2*n-1]);
9928       std::map<int,int>::const_iterator it1;
9929       it1=mergedNodes.find(eltStart);
9930       if(it1!=mergedNodes.end())
9931         (*it0)[0]=(*it1).second;
9932       it1=mergedNodes.find(eltEnd);
9933       if(it1!=mergedNodes.end())
9934         (*it0)[2*n-1]=(*it1).second;
9935     }
9936   //
9937   MCAuto<DataArrayDouble> addCooDa(DataArrayDouble::New());
9938   addCooDa->useArray(&addCoo[0],false,C_DEALLOC,(int)addCoo.size()/2,2);
9939   // Step 2: re-order newly created nodes according to the ordering found in m2
9940   std::vector< std::vector<int> > intersectEdge2;
9941   BuildIntersectEdges(m1Desc,mesh1D,addCoo,subDiv2,intersectEdge2);
9942   subDiv2.clear();
9943   // Step 3: compute splitMesh1D
9944   MCAuto<DataArrayInt> idsInRet1Colinear,idsInDescMesh2DForIdsInRetColinear;
9945   MCAuto<DataArrayInt> ret2(DataArrayInt::New()); ret2->alloc(0,1);
9946   MCAuto<MEDCouplingUMesh> ret1(BuildMesh1DCutFrom(mesh1D,intersectEdge2,mesh2D->getCoords(),addCoo,mergedNodes,colinear2,intersectEdge1,
9947       idsInRet1Colinear,idsInDescMesh2DForIdsInRetColinear));
9948   MCAuto<DataArrayInt> ret3(DataArrayInt::New()); ret3->alloc(ret1->getNumberOfCells()*2,1); ret3->fillWithValue(std::numeric_limits<int>::max()); ret3->rearrange(2);
9949   MCAuto<DataArrayInt> idsInRet1NotColinear(idsInRet1Colinear->buildComplement(ret1->getNumberOfCells()));
9950   // deal with cells in mesh2D that are not cut but only some of their edges are
9951   MCAuto<DataArrayInt> idsInDesc2DToBeRefined(idsInDescMesh2DForIdsInRetColinear->deepCopy());
9952   idsInDesc2DToBeRefined->abs(); idsInDesc2DToBeRefined->applyLin(1,-1);
9953   idsInDesc2DToBeRefined=idsInDesc2DToBeRefined->buildUnique();
9954   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
9955   if(!idsInDesc2DToBeRefined->empty())
9956     {
9957       DataArrayInt *out0(0),*outi0(0);
9958       MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
9959       MCAuto<DataArrayInt> outi0s(outi0);
9960       out0s=out0;
9961       out0s=out0s->buildUnique();
9962       out0s->sort(true);
9963     }
9964   //
9965   MCAuto<MEDCouplingUMesh> ret1NonCol(static_cast<MEDCouplingUMesh *>(ret1->buildPartOfMySelf(idsInRet1NotColinear->begin(),idsInRet1NotColinear->end())));
9966   MCAuto<DataArrayDouble> baryRet1(ret1NonCol->computeCellCenterOfMass());
9967   MCAuto<DataArrayInt> elts,eltsIndex;
9968   mesh2D->getCellsContainingPoints(baryRet1->begin(),baryRet1->getNumberOfTuples(),eps,elts,eltsIndex);
9969   MCAuto<DataArrayInt> eltsIndex2(eltsIndex->deltaShiftIndex());
9970   MCAuto<DataArrayInt> eltsIndex3(eltsIndex2->findIdsEqual(1));
9971   if(eltsIndex2->count(0)+eltsIndex3->getNumberOfTuples()!=ret1NonCol->getNumberOfCells())
9972     throw INTERP_KERNEL::Exception("Intersect2DMeshWith1DLine : internal error 1 !");
9973   MCAuto<DataArrayInt> cellsToBeModified(elts->buildUnique());
9974   MCAuto<DataArrayInt> untouchedCells(cellsToBeModified->buildComplement(mesh2D->getNumberOfCells()));
9975   if((DataArrayInt *)out0s)
9976     untouchedCells=untouchedCells->buildSubstraction(out0s);//if some edges in ret1 are colinear to descending mesh of mesh2D remove cells from untouched one
9977   std::vector< MCAuto<MEDCouplingUMesh> > outMesh2DSplit;
9978   // OK all is ready to insert in ret2 mesh
9979   if(!untouchedCells->empty())
9980     {// the most easy part, cells in mesh2D not impacted at all
9981       outMesh2DSplit.push_back(static_cast<MEDCouplingUMesh *>(mesh2D->buildPartOfMySelf(untouchedCells->begin(),untouchedCells->end())));
9982       outMesh2DSplit.back()->setCoords(ret1->getCoords());
9983       ret2->pushBackValsSilent(untouchedCells->begin(),untouchedCells->end());
9984     }
9985   if((DataArrayInt *)out0s)
9986     {// here dealing with cells in out0s but not in cellsToBeModified
9987       MCAuto<DataArrayInt> fewModifiedCells(out0s->buildSubstraction(cellsToBeModified));
9988       const int *rdptr(dd3->begin()),*rdiptr(dd4->begin()),*dptr(dd1->begin()),*diptr(dd2->begin());
9989       for(const int *it=fewModifiedCells->begin();it!=fewModifiedCells->end();it++)
9990         {
9991           outMesh2DSplit.push_back(BuildRefined2DCell(ret1->getCoords(),mesh2D,*it,dptr+diptr[*it],dptr+diptr[*it+1],intersectEdge1));
9992           ret1->setCoords(outMesh2DSplit.back()->getCoords());
9993         }
9994       int offset(ret2->getNumberOfTuples());
9995       ret2->pushBackValsSilent(fewModifiedCells->begin(),fewModifiedCells->end());
9996       MCAuto<DataArrayInt> partOfRet3(DataArrayInt::New()); partOfRet3->alloc(2*idsInRet1Colinear->getNumberOfTuples(),1);
9997       partOfRet3->fillWithValue(std::numeric_limits<int>::max()); partOfRet3->rearrange(2);
9998       int kk(0),*ret3ptr(partOfRet3->getPointer());
9999       for(const int *it=idsInDescMesh2DForIdsInRetColinear->begin();it!=idsInDescMesh2DForIdsInRetColinear->end();it++,kk++)
10000         {
10001           int faceId(std::abs(*it)-1);
10002           for(const int *it2=rdptr+rdiptr[faceId];it2!=rdptr+rdiptr[faceId+1];it2++)
10003             {
10004               int tmp(fewModifiedCells->findIdFirstEqual(*it2));
10005               if(tmp!=-1)
10006                 {
10007                   if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],-(*it))!=dptr+diptr[*it2+1])
10008                     ret3ptr[2*kk]=tmp+offset;
10009                   if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],(*it))!=dptr+diptr[*it2+1])
10010                     ret3ptr[2*kk+1]=tmp+offset;
10011                 }
10012               else
10013                 {//the current edge is shared by a 2D cell that will be split just after
10014                   if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],-(*it))!=dptr+diptr[*it2+1])
10015                     ret3ptr[2*kk]=-(*it2+1);
10016                   if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],(*it))!=dptr+diptr[*it2+1])
10017                     ret3ptr[2*kk+1]=-(*it2+1);
10018                 }
10019             }
10020         }
10021       m1Desc->setCoords(ret1->getCoords());
10022       ret1NonCol->setCoords(ret1->getCoords());
10023       ret3->setPartOfValues3(partOfRet3,idsInRet1Colinear->begin(),idsInRet1Colinear->end(),0,2,1,true);
10024       if(!outMesh2DSplit.empty())
10025         {
10026           DataArrayDouble *da(outMesh2DSplit.back()->getCoords());
10027           for(std::vector< MCAuto<MEDCouplingUMesh> >::iterator itt=outMesh2DSplit.begin();itt!=outMesh2DSplit.end();itt++)
10028             (*itt)->setCoords(da);
10029         }
10030     }
10031   cellsToBeModified=cellsToBeModified->buildUniqueNotSorted();
10032   for(const int *it=cellsToBeModified->begin();it!=cellsToBeModified->end();it++)
10033     {
10034       MCAuto<DataArrayInt> idsNonColPerCell(elts->findIdsEqual(*it));
10035       idsNonColPerCell->transformWithIndArr(eltsIndex3->begin(),eltsIndex3->end());
10036       MCAuto<DataArrayInt> idsNonColPerCell2(idsInRet1NotColinear->selectByTupleId(idsNonColPerCell->begin(),idsNonColPerCell->end()));
10037       MCAuto<MEDCouplingUMesh> partOfMesh1CuttingCur2DCell(static_cast<MEDCouplingUMesh *>(ret1NonCol->buildPartOfMySelf(idsNonColPerCell->begin(),idsNonColPerCell->end())));
10038       MCAuto<DataArrayInt> partOfRet3;
10039       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));
10040       ret3->setPartOfValues3(partOfRet3,idsNonColPerCell2->begin(),idsNonColPerCell2->end(),0,2,1,true);
10041       outMesh2DSplit.push_back(splitOfOneCell);
10042       for(int i=0;i<splitOfOneCell->getNumberOfCells();i++)
10043         ret2->pushBackSilent(*it);
10044     }
10045   //
10046   std::size_t nbOfMeshes(outMesh2DSplit.size());
10047   std::vector<const MEDCouplingUMesh *> tmp(nbOfMeshes);
10048   for(std::size_t i=0;i<nbOfMeshes;i++)
10049     tmp[i]=outMesh2DSplit[i];
10050   //
10051   ret1->getCoords()->setInfoOnComponents(compNames);
10052   MCAuto<MEDCouplingUMesh> ret2D(MEDCouplingUMesh::MergeUMeshesOnSameCoords(tmp));
10053   // To finish - filter ret3 - std::numeric_limits<int>::max() -> -1 - negate values must be resolved.
10054   ret3->rearrange(1);
10055   MCAuto<DataArrayInt> edgesToDealWith(ret3->findIdsStricltyNegative());
10056   for(const int *it=edgesToDealWith->begin();it!=edgesToDealWith->end();it++)
10057     {
10058       int old2DCellId(-ret3->getIJ(*it,0)-1);
10059       MCAuto<DataArrayInt> candidates(ret2->findIdsEqual(old2DCellId));
10060       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
10061     }
10062   ret3->changeValue(std::numeric_limits<int>::max(),-1);
10063   ret3->rearrange(2);
10064   //
10065   splitMesh1D=ret1.retn();
10066   splitMesh2D=ret2D.retn();
10067   cellIdInMesh2D=ret2.retn();
10068   cellIdInMesh1D=ret3.retn();
10069 }
10070
10071 /**
10072  * Private. Third step of the partitioning algorithm (Intersect2DMeshes): reconstruct full 2D cells from the
10073  * (newly created) nodes corresponding to the edge intersections.
10074  * Output params:
10075  * @param[out] cr, crI connectivity of the resulting mesh
10076  * @param[out] cNb1, cNb2 correspondance arrays giving for the merged mesh the initial cells IDs in m1 / m2
10077  * TODO: describe input parameters
10078  */
10079 void MEDCouplingUMesh::BuildIntersecting2DCellsFromEdges(double eps, const MEDCouplingUMesh *m1, const int *desc1, const int *descIndx1,
10080                                                          const std::vector<std::vector<int> >& intesctEdges1, const std::vector< std::vector<int> >& colinear2,
10081                                                          const MEDCouplingUMesh *m2, const int *desc2, const int *descIndx2, const std::vector<std::vector<int> >& intesctEdges2,
10082                                                          const std::vector<double>& addCoords,
10083                                                          std::vector<double>& addCoordsQuadratic, std::vector<int>& cr, std::vector<int>& crI, std::vector<int>& cNb1, std::vector<int>& cNb2)
10084 {
10085   static const int SPACEDIM=2;
10086   const double *coo1(m1->getCoords()->getConstPointer());
10087   const int *conn1(m1->getNodalConnectivity()->getConstPointer()),*connI1(m1->getNodalConnectivityIndex()->getConstPointer());
10088   int offset1(m1->getNumberOfNodes());
10089   const double *coo2(m2->getCoords()->getConstPointer());
10090   const int *conn2(m2->getNodalConnectivity()->getConstPointer()),*connI2(m2->getNodalConnectivityIndex()->getConstPointer());
10091   int offset2(offset1+m2->getNumberOfNodes());
10092   int offset3(offset2+((int)addCoords.size())/2);
10093   MCAuto<DataArrayDouble> bbox1Arr(m1->getBoundingBoxForBBTree()),bbox2Arr(m2->getBoundingBoxForBBTree());
10094   const double *bbox1(bbox1Arr->begin()),*bbox2(bbox2Arr->begin());
10095   // Here a BBTree on 2D-cells, not on segments:
10096   BBTree<SPACEDIM,int> myTree(bbox2,0,0,m2->getNumberOfCells(),eps);
10097   int ncell1(m1->getNumberOfCells());
10098   crI.push_back(0);
10099   for(int i=0;i<ncell1;i++)
10100     {
10101       std::vector<int> candidates2;
10102       myTree.getIntersectingElems(bbox1+i*2*SPACEDIM,candidates2);
10103       std::map<INTERP_KERNEL::Node *,int> mapp;
10104       std::map<int,INTERP_KERNEL::Node *> mappRev;
10105       INTERP_KERNEL::QuadraticPolygon pol1;
10106       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn1[connI1[i]];
10107       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
10108       // Populate mapp and mappRev with nodes from the current cell (i) from mesh1 - this also builds the Node* objects:
10109       MEDCouplingUMeshBuildQPFromMesh3(coo1,offset1,coo2,offset2,addCoords,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,/* output */mapp,mappRev);
10110       // pol1 is the full cell from mesh2, in QP format, with all the additional intersecting nodes.
10111       pol1.buildFromCrudeDataArray(mappRev,cm.isQuadratic(),conn1+connI1[i]+1,coo1,
10112           desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1);
10113       //
10114       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
10115       std::set<INTERP_KERNEL::Edge *> edgesBoundary2;// store all edges that are on boundary of (pol2 intersect pol1) minus edges on pol1.
10116       INTERP_KERNEL::IteratorOnComposedEdge it1(&pol1);
10117       for(it1.first();!it1.finished();it1.next())
10118         edges1.insert(it1.current()->getPtr());
10119       //
10120       std::map<int,std::vector<INTERP_KERNEL::ElementaryEdge *> > edgesIn2ForShare; // common edges
10121       std::vector<INTERP_KERNEL::QuadraticPolygon> pol2s(candidates2.size());
10122       int ii=0;
10123       for(std::vector<int>::const_iterator it2=candidates2.begin();it2!=candidates2.end();it2++,ii++)
10124         {
10125           INTERP_KERNEL::NormalizedCellType typ2=(INTERP_KERNEL::NormalizedCellType)conn2[connI2[*it2]];
10126           const INTERP_KERNEL::CellModel& cm2=INTERP_KERNEL::CellModel::GetCellModel(typ2);
10127           // Complete mapping with elements coming from the current cell it2 in mesh2:
10128           MEDCouplingUMeshBuildQPFromMesh3(coo1,offset1,coo2,offset2,addCoords,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,/* output */mapp,mappRev);
10129           // pol2 is the new QP in the final merged result.
10130           pol2s[ii].buildFromCrudeDataArray2(mappRev,cm2.isQuadratic(),conn2+connI2[*it2]+1,coo2,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,
10131               pol1,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,colinear2, /* output */ edgesIn2ForShare);
10132         }
10133       ii=0;
10134       for(std::vector<int>::const_iterator it2=candidates2.begin();it2!=candidates2.end();it2++,ii++)
10135         {
10136           INTERP_KERNEL::ComposedEdge::InitLocationsWithOther(pol1,pol2s[ii]);
10137           pol2s[ii].updateLocOfEdgeFromCrudeDataArray2(desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,pol1,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,colinear2);
10138           //MEDCouplingUMeshAssignOnLoc(pol1,pol2,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,colinear2);
10139           pol1.buildPartitionsAbs(pol2s[ii],edges1,edgesBoundary2,mapp,i,*it2,offset3,addCoordsQuadratic,cr,crI,cNb1,cNb2);
10140         }
10141       // Deals with remaining (non-consumed) edges from m1: these are the edges that were never touched
10142       // by m2 but that we still want to keep in the final result.
10143       if(!edges1.empty())
10144         {
10145           try
10146           {
10147               INTERP_KERNEL::QuadraticPolygon::ComputeResidual(pol1,edges1,edgesBoundary2,mapp,offset3,i,addCoordsQuadratic,cr,crI,cNb1,cNb2);
10148           }
10149           catch(INTERP_KERNEL::Exception& e)
10150           {
10151               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();
10152               throw INTERP_KERNEL::Exception(oss.str().c_str());
10153           }
10154         }
10155       for(std::map<int,INTERP_KERNEL::Node *>::const_iterator it=mappRev.begin();it!=mappRev.end();it++)
10156         (*it).second->decrRef();
10157     }
10158 }
10159
10160 /**
10161  * Provides a renumbering of the cells of this (which has to be a piecewise connected 1D line), so that
10162  * the segments of the line are indexed in consecutive order (i.e. cells \a i and \a i+1 are neighbors).
10163  * This doesn't modify the mesh. This method only works using nodal connectivity consideration. Coordinates of nodes are ignored here.
10164  * The caller is to deal with the resulting DataArrayInt.
10165  *  \throw If the coordinate array is not set.
10166  *  \throw If the nodal connectivity of the cells is not defined.
10167  *  \throw If m1 is not a mesh of dimension 2, or m1 is not a mesh of dimension 1
10168  *  \throw If m2 is not a (piecewise) line (i.e. if a point has more than 2 adjacent segments)
10169  *
10170  * \sa DataArrayInt::sortEachPairToMakeALinkedList
10171  */
10172 DataArrayInt *MEDCouplingUMesh::orderConsecutiveCells1D() const
10173 {
10174   checkFullyDefined();
10175   if(getMeshDimension()!=1)
10176     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D works on unstructured mesh with meshdim = 1 !");
10177
10178   // Check that this is a line (and not a more complex 1D mesh) - each point is used at most by 2 segments:
10179   MCAuto<DataArrayInt> _d(DataArrayInt::New()),_dI(DataArrayInt::New());
10180   MCAuto<DataArrayInt> _rD(DataArrayInt::New()),_rDI(DataArrayInt::New());
10181   MCAuto<MEDCouplingUMesh> m_points(buildDescendingConnectivity(_d, _dI, _rD, _rDI));
10182   const int *d(_d->getConstPointer()), *dI(_dI->getConstPointer());
10183   const int *rD(_rD->getConstPointer()), *rDI(_rDI->getConstPointer());
10184   MCAuto<DataArrayInt> _dsi(_rDI->deltaShiftIndex());
10185   const int * dsi(_dsi->getConstPointer());
10186   MCAuto<DataArrayInt> dsii = _dsi->findIdsNotInRange(0,3);
10187   m_points=0;
10188   if (dsii->getNumberOfTuples())
10189     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D only work with a mesh being a (piecewise) connected line!");
10190
10191   int nc(getNumberOfCells());
10192   MCAuto<DataArrayInt> result(DataArrayInt::New());
10193   result->alloc(nc,1);
10194
10195   // set of edges not used so far
10196   std::set<int> edgeSet;
10197   for (int i=0; i<nc; edgeSet.insert(i), i++);
10198
10199   int startSeg=0;
10200   int newIdx=0;
10201   // while we have points with only one neighbor segments
10202   do
10203     {
10204       std::list<int> linePiece;
10205       // fills a list of consecutive segment linked to startSeg. This can go forward or backward.
10206       for (int direction=0;direction<2;direction++) // direction=0 --> forward, direction=1 --> backward
10207         {
10208           // Fill the list forward (resp. backward) from the start segment:
10209           int activeSeg = startSeg;
10210           int prevPointId = -20;
10211           int ptId;
10212           while (!edgeSet.empty())
10213             {
10214               if (!(direction == 1 && prevPointId==-20)) // prevent adding twice startSeg
10215                 {
10216                   if (direction==0)
10217                     linePiece.push_back(activeSeg);
10218                   else
10219                     linePiece.push_front(activeSeg);
10220                   edgeSet.erase(activeSeg);
10221                 }
10222
10223               int ptId1 = d[dI[activeSeg]], ptId2 = d[dI[activeSeg]+1];
10224               ptId = direction ? (ptId1 == prevPointId ? ptId2 : ptId1) : (ptId2 == prevPointId ? ptId1 : ptId2);
10225               if (dsi[ptId] == 1) // hitting the end of the line
10226                 break;
10227               prevPointId = ptId;
10228               int seg1 = rD[rDI[ptId]], seg2 = rD[rDI[ptId]+1];
10229               activeSeg = (seg1 == activeSeg) ? seg2 : seg1;
10230             }
10231         }
10232       // Done, save final piece into DA:
10233       std::copy(linePiece.begin(), linePiece.end(), result->getPointer()+newIdx);
10234       newIdx += linePiece.size();
10235
10236       // identify next valid start segment (one which is not consumed)
10237       if(!edgeSet.empty())
10238         startSeg = *(edgeSet.begin());
10239     }
10240   while (!edgeSet.empty());
10241   return result.retn();
10242 }
10243
10244 /// @cond INTERNAL
10245
10246 void IKGeo2DInternalMapper2(INTERP_KERNEL::Node *n, const std::map<MCAuto<INTERP_KERNEL::Node>,int>& m, int forbVal0, int forbVal1, std::vector<int>& isect)
10247 {
10248   MCAuto<INTERP_KERNEL::Node> nTmp(n); nTmp->incrRef();
10249   std::map<MCAuto<INTERP_KERNEL::Node>,int>::const_iterator it(m.find(nTmp));
10250   if(it==m.end())
10251     throw INTERP_KERNEL::Exception("Internal error in remapping !");
10252   int v((*it).second);
10253   if(v==forbVal0 || v==forbVal1)
10254     return ;
10255   if(std::find(isect.begin(),isect.end(),v)==isect.end())
10256     isect.push_back(v);
10257 }
10258
10259 bool IKGeo2DInternalMapper(const INTERP_KERNEL::ComposedEdge& c, const std::map<MCAuto<INTERP_KERNEL::Node>,int>& m, int forbVal0, int forbVal1, std::vector<int>& isect)
10260 {
10261   int sz(c.size());
10262   if(sz<=1)
10263     return false;
10264   bool presenceOfOn(false);
10265   for(int i=0;i<sz;i++)
10266     {
10267       INTERP_KERNEL::ElementaryEdge *e(c[i]);
10268       if(e->getLoc()!=INTERP_KERNEL::FULL_ON_1)
10269         continue ;
10270       IKGeo2DInternalMapper2(e->getStartNode(),m,forbVal0,forbVal1,isect);
10271       IKGeo2DInternalMapper2(e->getEndNode(),m,forbVal0,forbVal1,isect);
10272     }
10273   return presenceOfOn;
10274 }
10275
10276 /// @endcond
10277
10278 /**
10279  * This method split some of edges of 2D cells in \a this. The edges to be split are specified in \a subNodesInSeg
10280  * and in \a subNodesInSegI using \ref numbering-indirect storage mode.
10281  * To do the work this method can optionally needs information about middle of subedges for quadratic cases if
10282  * a minimal creation of new nodes is wanted.
10283  * So this method try to reduce at most the number of new nodes. The only case that can lead this method to add
10284  * nodes if a SEG3 is split without information of middle.
10285  * \b WARNING : is returned value is different from 0 a call to MEDCouplingUMesh::mergeNodes is necessary to
10286  * avoid to have a non conform mesh.
10287  *
10288  * \return int - the number of new nodes created (in most of cases 0).
10289  * 
10290  * \throw If \a this is not coherent.
10291  * \throw If \a this has not spaceDim equal to 2.
10292  * \throw If \a this has not meshDim equal to 2.
10293  * \throw If some subcells needed to be split are orphan.
10294  * \sa MEDCouplingUMesh::conformize2D
10295  */
10296 int MEDCouplingUMesh::split2DCells(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI, const DataArrayInt *midOpt, const DataArrayInt *midOptI)
10297 {
10298   if(!desc || !descI || !subNodesInSeg || !subNodesInSegI)
10299     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : the 4 first arrays must be not null !");
10300   desc->checkAllocated(); descI->checkAllocated(); subNodesInSeg->checkAllocated(); subNodesInSegI->checkAllocated();
10301   if(getSpaceDimension()!=2 || getMeshDimension()!=2)
10302     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : This method only works for meshes with spaceDim=2 and meshDim=2 !");
10303   if(midOpt==0 && midOptI==0)
10304     {
10305       split2DCellsLinear(desc,descI,subNodesInSeg,subNodesInSegI);
10306       return 0;
10307     }
10308   else if(midOpt!=0 && midOptI!=0)
10309     return split2DCellsQuadratic(desc,descI,subNodesInSeg,subNodesInSegI,midOpt,midOptI);
10310   else
10311     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : middle parameters must be set to null for all or not null for all.");
10312 }
10313
10314 /*!
10315  * \b WARNING this method is \b potentially \b non \b const (if returned array is empty).
10316  * \b WARNING this method lead to have a non geometric type sorted mesh (for MED file users) !
10317  * 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
10318  * 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).
10319  * 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.
10320  * 
10321  * Whatever the returned value, this method does not alter the order of cells in \a this neither the orientation of cells.
10322  * The modified cells, if any, are systematically declared as NORM_POLYGON or NORM_QPOLYG depending on the initial quadraticness of geometric type.
10323  *
10324  * This method expects that \b this has a meshDim equal 2 and spaceDim equal to 2 too.
10325  * This method expects that all nodes in \a this are not closer than \a eps.
10326  * If it is not the case you can invoke MEDCouplingUMesh::mergeNodes before calling this method.
10327  * 
10328  * \param [in] eps the relative error to detect merged edges.
10329  * \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
10330  *                           that the user is expected to deal with.
10331  *
10332  * \throw If \a this is not coherent.
10333  * \throw If \a this has not spaceDim equal to 2.
10334  * \throw If \a this has not meshDim equal to 2.
10335  * \sa MEDCouplingUMesh::mergeNodes, MEDCouplingUMesh::split2DCells
10336  */
10337 DataArrayInt *MEDCouplingUMesh::conformize2D(double eps)
10338 {
10339   static const int SPACEDIM=2;
10340   checkConsistencyLight();
10341   if(getSpaceDimension()!=2 || getMeshDimension()!=2)
10342     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::conformize2D : This method only works for meshes with spaceDim=2 and meshDim=2 !");
10343   MCAuto<DataArrayInt> desc1(DataArrayInt::New()),descIndx1(DataArrayInt::New()),revDesc1(DataArrayInt::New()),revDescIndx1(DataArrayInt::New());
10344   MCAuto<MEDCouplingUMesh> mDesc(buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));
10345   const int *c(mDesc->getNodalConnectivity()->getConstPointer()),*ci(mDesc->getNodalConnectivityIndex()->getConstPointer()),*rd(revDesc1->getConstPointer()),*rdi(revDescIndx1->getConstPointer());
10346   MCAuto<DataArrayDouble> bboxArr(mDesc->getBoundingBoxForBBTree());
10347   const double *bbox(bboxArr->begin()),*coords(getCoords()->begin());
10348   int nCell(getNumberOfCells()),nDescCell(mDesc->getNumberOfCells());
10349   std::vector< std::vector<int> > intersectEdge(nDescCell),overlapEdge(nDescCell);
10350   std::vector<double> addCoo;
10351   BBTree<SPACEDIM,int> myTree(bbox,0,0,nDescCell,-eps);
10352   INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
10353   INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
10354   for(int i=0;i<nDescCell;i++)
10355     {
10356       std::vector<int> candidates;
10357       myTree.getIntersectingElems(bbox+i*2*SPACEDIM,candidates);
10358       for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
10359         if(*it>i)
10360           {
10361             std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
10362             INTERP_KERNEL::Edge *e1(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[i]],c+ci[i]+1,coords,m)),
10363                 *e2(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[*it]],c+ci[*it]+1,coords,m));
10364             INTERP_KERNEL::MergePoints merge;
10365             INTERP_KERNEL::QuadraticPolygon c1,c2;
10366             e1->intersectWith(e2,merge,c1,c2);
10367             e1->decrRef(); e2->decrRef();
10368             if(IKGeo2DInternalMapper(c1,m,c[ci[i]+1],c[ci[i]+2],intersectEdge[i]))
10369               overlapEdge[i].push_back(*it);
10370             if(IKGeo2DInternalMapper(c2,m,c[ci[*it]+1],c[ci[*it]+2],intersectEdge[*it]))
10371               overlapEdge[*it].push_back(i);
10372           }
10373     }
10374   // splitting done. sort intersect point in intersectEdge.
10375   std::vector< std::vector<int> > middle(nDescCell);
10376   int nbOf2DCellsToBeSplit(0);
10377   bool middleNeedsToBeUsed(false);
10378   std::vector<bool> cells2DToTreat(nDescCell,false);
10379   for(int i=0;i<nDescCell;i++)
10380     {
10381       std::vector<int>& isect(intersectEdge[i]);
10382       int sz((int)isect.size());
10383       if(sz>1)
10384         {
10385           std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
10386           INTERP_KERNEL::Edge *e(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[i]],c+ci[i]+1,coords,m));
10387           e->sortSubNodesAbs(coords,isect);
10388           e->decrRef();
10389         }
10390       if(sz!=0)
10391         {
10392           int idx0(rdi[i]),idx1(rdi[i+1]);
10393           if(idx1-idx0!=1)
10394             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::conformize2D : internal error #0 !");
10395           if(!cells2DToTreat[rd[idx0]])
10396             {
10397               cells2DToTreat[rd[idx0]]=true;
10398               nbOf2DCellsToBeSplit++;
10399             }
10400           // try to reuse at most eventual 'middle' of SEG3
10401           std::vector<int>& mid(middle[i]);
10402           mid.resize(sz+1,-1);
10403           if((INTERP_KERNEL::NormalizedCellType)c[ci[i]]==INTERP_KERNEL::NORM_SEG3)
10404             {
10405               middleNeedsToBeUsed=true;
10406               const std::vector<int>& candidates(overlapEdge[i]);
10407               std::vector<int> trueCandidates;
10408               for(std::vector<int>::const_iterator itc=candidates.begin();itc!=candidates.end();itc++)
10409                 if((INTERP_KERNEL::NormalizedCellType)c[ci[*itc]]==INTERP_KERNEL::NORM_SEG3)
10410                   trueCandidates.push_back(*itc);
10411               int stNode(c[ci[i]+1]),endNode(isect[0]);
10412               for(int j=0;j<sz+1;j++)
10413                 {
10414                   for(std::vector<int>::const_iterator itc=trueCandidates.begin();itc!=trueCandidates.end();itc++)
10415                     {
10416                       int tmpSt(c[ci[*itc]+1]),tmpEnd(c[ci[*itc]+2]);
10417                       if((tmpSt==stNode && tmpEnd==endNode) || (tmpSt==endNode && tmpEnd==stNode))
10418                         { mid[j]=*itc; break; }
10419                     }
10420                   stNode=endNode;
10421                   endNode=j<sz-1?isect[j+1]:c[ci[i]+2];
10422                 }
10423             }
10424         }
10425     }
10426   MCAuto<DataArrayInt> ret(DataArrayInt::New()),notRet(DataArrayInt::New()); ret->alloc(nbOf2DCellsToBeSplit,1);
10427   if(nbOf2DCellsToBeSplit==0)
10428     return ret.retn();
10429   //
10430   int *retPtr(ret->getPointer());
10431   for(int i=0;i<nCell;i++)
10432     if(cells2DToTreat[i])
10433       *retPtr++=i;
10434   //
10435   MCAuto<DataArrayInt> mSafe,nSafe,oSafe,pSafe,qSafe,rSafe;
10436   DataArrayInt *m(0),*n(0),*o(0),*p(0),*q(0),*r(0);
10437   MEDCouplingUMesh::ExtractFromIndexedArrays(ret->begin(),ret->end(),desc1,descIndx1,m,n); mSafe=m; nSafe=n;
10438   DataArrayInt::PutIntoToSkylineFrmt(intersectEdge,o,p); oSafe=o; pSafe=p;
10439   if(middleNeedsToBeUsed)
10440     { DataArrayInt::PutIntoToSkylineFrmt(middle,q,r); qSafe=q; rSafe=r; }
10441   MCAuto<MEDCouplingUMesh> modif(static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(ret->begin(),ret->end(),true)));
10442   int nbOfNodesCreated(modif->split2DCells(mSafe,nSafe,oSafe,pSafe,qSafe,rSafe));
10443   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.
10444   setPartOfMySelf(ret->begin(),ret->end(),*modif);
10445   {
10446     bool areNodesMerged; int newNbOfNodes;
10447     if(nbOfNodesCreated!=0)
10448       MCAuto<DataArrayInt> tmp(mergeNodes(eps,areNodesMerged,newNbOfNodes));
10449   }
10450   return ret.retn();
10451 }
10452
10453 /*!
10454  * 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.
10455  * 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).
10456  * 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
10457  * to invoke MEDCouplingUMesh::mergeNodes and MEDCouplingUMesh::conformize2D right after this call.
10458  * 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
10459  * new nodes for center of merged edges is are systematically created and appended at the end of the previously existing nodes.
10460  *
10461  * 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
10462  * using new instance, idem for coordinates.
10463  *
10464  * 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.
10465  * 
10466  * \return DataArrayInt  * - The list of cellIds in \a this that have at least one edge colinearized.
10467  *
10468  * \throw If \a this is not coherent.
10469  * \throw If \a this has not spaceDim equal to 2.
10470  * \throw If \a this has not meshDim equal to 2.
10471  * 
10472  * \sa MEDCouplingUMesh::conformize2D, MEDCouplingUMesh::mergeNodes, MEDCouplingUMesh::convexEnvelop2D.
10473  */
10474 DataArrayInt *MEDCouplingUMesh::colinearize2D(double eps)
10475 {
10476   MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(0,1);
10477   checkConsistencyLight();
10478   if(getSpaceDimension()!=2 || getMeshDimension()!=2)
10479     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::colinearize2D : This method only works for meshes with spaceDim=2 and meshDim=2 !");
10480   INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
10481   INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
10482   int nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
10483   const int *cptr(_nodal_connec->begin()),*ciptr(_nodal_connec_index->begin());
10484   MCAuto<DataArrayInt> newc(DataArrayInt::New()),newci(DataArrayInt::New()); newci->alloc(nbOfCells+1,1); newc->alloc(0,1); newci->setIJ(0,0,0);
10485   MCAuto<DataArrayDouble> appendedCoords(DataArrayDouble::New()); appendedCoords->alloc(0,1);//1 not 2 it is not a bug.
10486   const double *coords(_coords->begin());
10487   int *newciptr(newci->getPointer());
10488   for(int i=0;i<nbOfCells;i++,newciptr++,ciptr++)
10489     {
10490       if(Colinearize2DCell(coords,cptr+ciptr[0],cptr+ciptr[1],nbOfNodes,newc,appendedCoords))
10491         ret->pushBackSilent(i);
10492       newciptr[1]=newc->getNumberOfTuples();
10493     }
10494   //
10495   if(ret->empty())
10496     return ret.retn();
10497   if(!appendedCoords->empty())
10498     {
10499       appendedCoords->rearrange(2);
10500       MCAuto<DataArrayDouble> newCoords(DataArrayDouble::Aggregate(getCoords(),appendedCoords));//treat info on components
10501       //non const part
10502       setCoords(newCoords);
10503     }
10504   //non const part
10505   setConnectivity(newc,newci,true);
10506   return ret.retn();
10507 }
10508
10509 /*!
10510  * \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.
10511  *                               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.
10512  *                               And for each j in [1,n) intersect[i][2*(j-1)+1]==intersect[i][2*j].
10513  * \param [out] subDiv2 - for each cell in \a m2Desc returns nodes that split it using convention \a m1Desc first, then \a m2Desc, then addCoo
10514  * \param [out] colinear2 - for each cell in \a m2Desc returns the edges in \a m1Desc that are colinear to it.
10515  * \param [out] addCoo - nodes to be append at the end
10516  * \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.
10517  */
10518 void MEDCouplingUMesh::Intersect1DMeshes(const MEDCouplingUMesh *m1Desc, const MEDCouplingUMesh *m2Desc, double eps,
10519                                          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)
10520 {
10521   static const int SPACEDIM=2;
10522   INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
10523   INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
10524   const int *c1(m1Desc->getNodalConnectivity()->getConstPointer()),*ci1(m1Desc->getNodalConnectivityIndex()->getConstPointer());
10525   // Build BB tree of all edges in the tool mesh (second mesh)
10526   MCAuto<DataArrayDouble> bbox1Arr(m1Desc->getBoundingBoxForBBTree()),bbox2Arr(m2Desc->getBoundingBoxForBBTree());
10527   const double *bbox1(bbox1Arr->begin()),*bbox2(bbox2Arr->begin());
10528   int nDescCell1(m1Desc->getNumberOfCells()),nDescCell2(m2Desc->getNumberOfCells());
10529   intersectEdge1.resize(nDescCell1);
10530   colinear2.resize(nDescCell2);
10531   subDiv2.resize(nDescCell2);
10532   BBTree<SPACEDIM,int> myTree(bbox2,0,0,m2Desc->getNumberOfCells(),-eps);
10533
10534   std::vector<int> candidates1(1);
10535   int offset1(m1Desc->getNumberOfNodes());
10536   int offset2(offset1+m2Desc->getNumberOfNodes());
10537   for(int i=0;i<nDescCell1;i++)  // for all edges in the first mesh
10538     {
10539       std::vector<int> candidates2; // edges of mesh2 candidate for intersection
10540       myTree.getIntersectingElems(bbox1+i*2*SPACEDIM,candidates2);
10541       if(!candidates2.empty()) // candidates2 holds edges from the second mesh potentially intersecting current edge i in mesh1
10542         {
10543           std::map<INTERP_KERNEL::Node *,int> map1,map2;
10544           // pol2 is not necessarily a closed polygon: just a set of (quadratic) edges (same as candidates2) in the Geometric DS format
10545           INTERP_KERNEL::QuadraticPolygon *pol2=MEDCouplingUMeshBuildQPFromMesh(m2Desc,candidates2,map2);
10546           candidates1[0]=i;
10547           INTERP_KERNEL::QuadraticPolygon *pol1=MEDCouplingUMeshBuildQPFromMesh(m1Desc,candidates1,map1);
10548           // 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
10549           // This trick guarantees that Node * are discriminant (i.e. form a unique identifier)
10550           std::set<INTERP_KERNEL::Node *> nodes;
10551           pol1->getAllNodes(nodes); pol2->getAllNodes(nodes);
10552           std::size_t szz(nodes.size());
10553           std::vector< MCAuto<INTERP_KERNEL::Node> > nodesSafe(szz);
10554           std::set<INTERP_KERNEL::Node *>::const_iterator itt(nodes.begin());
10555           for(std::size_t iii=0;iii<szz;iii++,itt++)
10556             { (*itt)->incrRef(); nodesSafe[iii]=*itt; }
10557           // end of protection
10558           // Performs egde cutting:
10559           pol1->splitAbs(*pol2,map1,map2,offset1,offset2,candidates2,intersectEdge1[i],i,colinear2,subDiv2,addCoo,mergedNodes);
10560           delete pol2;
10561           delete pol1;
10562         }
10563       else
10564         // Copy the edge (take only the two first points, ie discard quadratic point at this stage)
10565         intersectEdge1[i].insert(intersectEdge1[i].end(),c1+ci1[i]+1,c1+ci1[i]+3);
10566     }
10567 }
10568
10569 /*!
10570  * This method is private and is the first step of Partition of 2D mesh (spaceDim==2 and meshDim==2).
10571  * It builds the descending connectivity of the two meshes, and then using a binary tree
10572  * it computes the edge intersections. This results in new points being created : they're stored in addCoo.
10573  * Documentation about parameters  colinear2 and subDiv2 can be found in method QuadraticPolygon::splitAbs().
10574  */
10575 void MEDCouplingUMesh::IntersectDescending2DMeshes(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2, double eps,
10576                                                    std::vector< std::vector<int> >& intersectEdge1, std::vector< std::vector<int> >& colinear2, std::vector< std::vector<int> >& subDiv2,
10577                                                    MEDCouplingUMesh *& m1Desc, DataArrayInt *&desc1, DataArrayInt *&descIndx1, DataArrayInt *&revDesc1, DataArrayInt *&revDescIndx1,
10578                                                    std::vector<double>& addCoo,
10579                                                    MEDCouplingUMesh *& m2Desc, DataArrayInt *&desc2, DataArrayInt *&descIndx2, DataArrayInt *&revDesc2, DataArrayInt *&revDescIndx2)
10580 {
10581   // Build desc connectivity
10582   desc1=DataArrayInt::New(); descIndx1=DataArrayInt::New(); revDesc1=DataArrayInt::New(); revDescIndx1=DataArrayInt::New();
10583   desc2=DataArrayInt::New();
10584   descIndx2=DataArrayInt::New();
10585   revDesc2=DataArrayInt::New();
10586   revDescIndx2=DataArrayInt::New();
10587   MCAuto<DataArrayInt> dd1(desc1),dd2(descIndx1),dd3(revDesc1),dd4(revDescIndx1);
10588   MCAuto<DataArrayInt> dd5(desc2),dd6(descIndx2),dd7(revDesc2),dd8(revDescIndx2);
10589   m1Desc=m1->buildDescendingConnectivity2(desc1,descIndx1,revDesc1,revDescIndx1);
10590   m2Desc=m2->buildDescendingConnectivity2(desc2,descIndx2,revDesc2,revDescIndx2);
10591   MCAuto<MEDCouplingUMesh> dd9(m1Desc),dd10(m2Desc);
10592   std::map<int,int> notUsedMap;
10593   Intersect1DMeshes(m1Desc,m2Desc,eps,intersectEdge1,colinear2,subDiv2,addCoo,notUsedMap);
10594   m1Desc->incrRef(); desc1->incrRef(); descIndx1->incrRef(); revDesc1->incrRef(); revDescIndx1->incrRef();
10595   m2Desc->incrRef(); desc2->incrRef(); descIndx2->incrRef(); revDesc2->incrRef(); revDescIndx2->incrRef();
10596 }
10597
10598 /*!
10599  * This method performs the 2nd step of Partition of 2D mesh.
10600  * This method has 4 inputs :
10601  *  - a mesh 'm1' with meshDim==1 and a SpaceDim==2
10602  *  - a mesh 'm2' with meshDim==1 and a SpaceDim==2
10603  *  - subDiv of size 'm2->getNumberOfCells()' that lists for each seg cell in 'm' the splitting node ids randomly sorted.
10604  * 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'
10605  * Nodes end up lying consecutively on a cutted edge.
10606  * \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.
10607  * (Only present for its coords in case of 'subDiv' shares some nodes of 'm1')
10608  * \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.
10609  * \param addCoo input parameter with additional nodes linked to intersection of the 2 meshes.
10610  * \param[out] intersectEdge the same content as subDiv, but correclty oriented.
10611  */
10612 void MEDCouplingUMesh::BuildIntersectEdges(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2,
10613                                            const std::vector<double>& addCoo,
10614                                            const std::vector< std::vector<int> >& subDiv, std::vector< std::vector<int> >& intersectEdge)
10615 {
10616   int offset1=m1->getNumberOfNodes();
10617   int ncell=m2->getNumberOfCells();
10618   const int *c=m2->getNodalConnectivity()->getConstPointer();
10619   const int *cI=m2->getNodalConnectivityIndex()->getConstPointer();
10620   const double *coo=m2->getCoords()->getConstPointer();
10621   const double *cooBis=m1->getCoords()->getConstPointer();
10622   int offset2=offset1+m2->getNumberOfNodes();
10623   intersectEdge.resize(ncell);
10624   for(int i=0;i<ncell;i++,cI++)
10625     {
10626       const std::vector<int>& divs=subDiv[i];
10627       int nnode=cI[1]-cI[0]-1;
10628       std::map<int, std::pair<INTERP_KERNEL::Node *,bool> > mapp2;
10629       std::map<INTERP_KERNEL::Node *, int> mapp22;
10630       for(int j=0;j<nnode;j++)
10631         {
10632           INTERP_KERNEL::Node *nn=new INTERP_KERNEL::Node(coo[2*c[(*cI)+j+1]],coo[2*c[(*cI)+j+1]+1]);
10633           int nnid=c[(*cI)+j+1];
10634           mapp2[nnid]=std::pair<INTERP_KERNEL::Node *,bool>(nn,true);
10635           mapp22[nn]=nnid+offset1;
10636         }
10637       INTERP_KERNEL::Edge *e=MEDCouplingUMeshBuildQPFromEdge((INTERP_KERNEL::NormalizedCellType)c[*cI],mapp2,c+(*cI)+1);
10638       for(std::map<int, std::pair<INTERP_KERNEL::Node *,bool> >::const_iterator it=mapp2.begin();it!=mapp2.end();it++)
10639         ((*it).second.first)->decrRef();
10640       std::vector<INTERP_KERNEL::Node *> addNodes(divs.size());
10641       std::map<INTERP_KERNEL::Node *,int> mapp3;
10642       for(std::size_t j=0;j<divs.size();j++)
10643         {
10644           int id=divs[j];
10645           INTERP_KERNEL::Node *tmp=0;
10646           if(id<offset1)
10647             tmp=new INTERP_KERNEL::Node(cooBis[2*id],cooBis[2*id+1]);
10648           else if(id<offset2)
10649             tmp=new INTERP_KERNEL::Node(coo[2*(id-offset1)],coo[2*(id-offset1)+1]);//if it happens, bad news mesh 'm2' is non conform.
10650           else
10651             tmp=new INTERP_KERNEL::Node(addCoo[2*(id-offset2)],addCoo[2*(id-offset2)+1]);
10652           addNodes[j]=tmp;
10653           mapp3[tmp]=id;
10654         }
10655       e->sortIdsAbs(addNodes,mapp22,mapp3,intersectEdge[i]);
10656       for(std::vector<INTERP_KERNEL::Node *>::const_iterator it=addNodes.begin();it!=addNodes.end();it++)
10657         (*it)->decrRef();
10658       e->decrRef();
10659     }
10660 }
10661
10662 /*!
10663  * 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).
10664  * 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
10665  * with a plane. The result will be put in 'cut3DSuf' out parameter.
10666  * \param [in] cut3DCurve  input paramter that gives for each 3DCurve cell if it owns fully to the plane or partially.
10667  * \param [out] nodesOnPlane, returns all the nodes that are on the plane.
10668  * \param [in] nodal3DSurf is the nodal connectivity of 3D surf mesh.
10669  * \param [in] nodalIndx3DSurf is the nodal connectivity index of 3D surf mesh.
10670  * \param [in] nodal3DCurve is the nodal connectivity of 3D curve mesh.
10671  * \param [in] nodal3DIndxCurve is the nodal connectivity index of 3D curve mesh.
10672  * \param [in] desc is the descending connectivity 3DSurf->3DCurve
10673  * \param [in] descIndx is the descending connectivity index 3DSurf->3DCurve
10674  * \param [out] cut3DSuf input/output param.
10675  */
10676 void MEDCouplingUMesh::AssemblyForSplitFrom3DCurve(const std::vector<int>& cut3DCurve, std::vector<int>& nodesOnPlane, const int *nodal3DSurf, const int *nodalIndx3DSurf,
10677                                                    const int *nodal3DCurve, const int *nodalIndx3DCurve,
10678                                                    const int *desc, const int *descIndx, 
10679                                                    std::vector< std::pair<int,int> >& cut3DSurf)
10680 {
10681   std::set<int> nodesOnP(nodesOnPlane.begin(),nodesOnPlane.end());
10682   int nbOf3DSurfCell=(int)cut3DSurf.size();
10683   for(int i=0;i<nbOf3DSurfCell;i++)
10684     {
10685       std::vector<int> res;
10686       int offset=descIndx[i];
10687       int nbOfSeg=descIndx[i+1]-offset;
10688       for(int j=0;j<nbOfSeg;j++)
10689         {
10690           int edgeId=desc[offset+j];
10691           int status=cut3DCurve[edgeId];
10692           if(status!=-2)
10693             {
10694               if(status>-1)
10695                 res.push_back(status);
10696               else
10697                 {
10698                   res.push_back(nodal3DCurve[nodalIndx3DCurve[edgeId]+1]);
10699                   res.push_back(nodal3DCurve[nodalIndx3DCurve[edgeId]+2]);
10700                 }
10701             }
10702         }
10703       switch(res.size())
10704       {
10705         case 2:
10706           {
10707             cut3DSurf[i].first=res[0]; cut3DSurf[i].second=res[1];
10708             break;
10709           }
10710         case 1:
10711         case 0:
10712           {
10713             std::set<int> s1(nodal3DSurf+nodalIndx3DSurf[i]+1,nodal3DSurf+nodalIndx3DSurf[i+1]);
10714             std::set_intersection(nodesOnP.begin(),nodesOnP.end(),s1.begin(),s1.end(),std::back_insert_iterator< std::vector<int> >(res));
10715             if(res.size()==2)
10716               {
10717                 cut3DSurf[i].first=res[0]; cut3DSurf[i].second=res[1];
10718               }
10719             else
10720               {
10721                 cut3DSurf[i].first=-1; cut3DSurf[i].second=-1;
10722               }
10723             break;
10724           }
10725         default:
10726           {// case when plane is on a multi colinear edge of a polyhedron
10727             if((int)res.size()==2*nbOfSeg)
10728               {
10729                 cut3DSurf[i].first=-2; cut3DSurf[i].second=i;
10730               }
10731             else
10732               throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AssemblyPointsFrom3DCurve : unexpected situation !");
10733           }
10734       }
10735     }
10736 }
10737
10738 /*!
10739  * \a this is expected to be a mesh with spaceDim==3 and meshDim==3. If not an exception will be thrown.
10740  * 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).
10741  * 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
10742  * with a plane. The result will be put in 'nodalRes' 'nodalResIndx' and 'cellIds' out parameters.
10743  * \param cut3DSurf  input paramter that gives for each 3DSurf its intersection with plane (result of MEDCouplingUMesh::AssemblyForSplitFrom3DCurve).
10744  * \param desc is the descending connectivity 3D->3DSurf
10745  * \param descIndx is the descending connectivity index 3D->3DSurf
10746  */
10747 void MEDCouplingUMesh::assemblyForSplitFrom3DSurf(const std::vector< std::pair<int,int> >& cut3DSurf,
10748                                                   const int *desc, const int *descIndx,
10749                                                   DataArrayInt *nodalRes, DataArrayInt *nodalResIndx, DataArrayInt *cellIds) const
10750 {
10751   checkFullyDefined();
10752   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
10753     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::assemblyForSplitFrom3DSurf works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
10754   const int *nodal3D=_nodal_connec->getConstPointer();
10755   const int *nodalIndx3D=_nodal_connec_index->getConstPointer();
10756   int nbOfCells=getNumberOfCells();
10757   for(int i=0;i<nbOfCells;i++)
10758     {
10759       std::map<int, std::set<int> > m;
10760       int offset=descIndx[i];
10761       int nbOfFaces=descIndx[i+1]-offset;
10762       int start=-1;
10763       int end=-1;
10764       for(int j=0;j<nbOfFaces;j++)
10765         {
10766           const std::pair<int,int>& p=cut3DSurf[desc[offset+j]];
10767           if(p.first!=-1 && p.second!=-1)
10768             {
10769               if(p.first!=-2)
10770                 {
10771                   start=p.first; end=p.second;
10772                   m[p.first].insert(p.second);
10773                   m[p.second].insert(p.first);
10774                 }
10775               else
10776                 {
10777                   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)nodal3D[nodalIndx3D[i]]);
10778                   int sz=nodalIndx3D[i+1]-nodalIndx3D[i]-1;
10779                   INTERP_KERNEL::AutoPtr<int> tmp=new int[sz];
10780                   INTERP_KERNEL::NormalizedCellType cmsId;
10781                   unsigned nbOfNodesSon=cm.fillSonCellNodalConnectivity2(j,nodal3D+nodalIndx3D[i]+1,sz,tmp,cmsId);
10782                   start=tmp[0]; end=tmp[nbOfNodesSon-1];
10783                   for(unsigned k=0;k<nbOfNodesSon;k++)
10784                     {
10785                       m[tmp[k]].insert(tmp[(k+1)%nbOfNodesSon]);
10786                       m[tmp[(k+1)%nbOfNodesSon]].insert(tmp[k]);
10787                     }
10788                 }
10789             }
10790         }
10791       if(m.empty())
10792         continue;
10793       std::vector<int> conn(1,(int)INTERP_KERNEL::NORM_POLYGON);
10794       int prev=end;
10795       while(end!=start)
10796         {
10797           std::map<int, std::set<int> >::const_iterator it=m.find(start);
10798           const std::set<int>& s=(*it).second;
10799           std::set<int> s2; s2.insert(prev);
10800           std::set<int> s3;
10801           std::set_difference(s.begin(),s.end(),s2.begin(),s2.end(),inserter(s3,s3.begin()));
10802           if(s3.size()==1)
10803             {
10804               int val=*s3.begin();
10805               conn.push_back(start);
10806               prev=start;
10807               start=val;
10808             }
10809           else
10810             start=end;
10811         }
10812       conn.push_back(end);
10813       if(conn.size()>3)
10814         {
10815           nodalRes->insertAtTheEnd(conn.begin(),conn.end());
10816           nodalResIndx->pushBackSilent(nodalRes->getNumberOfTuples());
10817           cellIds->pushBackSilent(i);
10818         }
10819     }
10820 }
10821
10822 /*!
10823  * 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
10824  * 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
10825  * the geometric cell type set to INTERP_KERNEL::NORM_POLYGON.
10826  * 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
10827  * 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.
10828  * 
10829  * \return false if the input connectivity represents already the convex hull, true if the input cell needs to be reordered.
10830  */
10831 bool MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis(const double *coords, const int *nodalConnBg, const int *nodalConnEnd, DataArrayInt *nodalConnecOut)
10832 {
10833   std::size_t sz=std::distance(nodalConnBg,nodalConnEnd);
10834   if(sz>=4)
10835     {
10836       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)*nodalConnBg);
10837       if(cm.getDimension()==2)
10838         {
10839           const int *node=nodalConnBg+1;
10840           int startNode=*node++;
10841           double refX=coords[2*startNode];
10842           for(;node!=nodalConnEnd;node++)
10843             {
10844               if(coords[2*(*node)]<refX)
10845                 {
10846                   startNode=*node;
10847                   refX=coords[2*startNode];
10848                 }
10849             }
10850           std::vector<int> tmpOut; tmpOut.reserve(sz); tmpOut.push_back(startNode);
10851           refX=1e300;
10852           double tmp1;
10853           double tmp2[2];
10854           double angle0=-M_PI/2;
10855           //
10856           int nextNode=-1;
10857           int prevNode=-1;
10858           double resRef;
10859           double angleNext=0.;
10860           while(nextNode!=startNode)
10861             {
10862               nextNode=-1;
10863               resRef=1e300;
10864               for(node=nodalConnBg+1;node!=nodalConnEnd;node++)
10865                 {
10866                   if(*node!=tmpOut.back() && *node!=prevNode)
10867                     {
10868                       tmp2[0]=coords[2*(*node)]-coords[2*tmpOut.back()]; tmp2[1]=coords[2*(*node)+1]-coords[2*tmpOut.back()+1];
10869                       double angleM=INTERP_KERNEL::EdgeArcCircle::GetAbsoluteAngle(tmp2,tmp1);
10870                       double res;
10871                       if(angleM<=angle0)
10872                         res=angle0-angleM;
10873                       else
10874                         res=angle0-angleM+2.*M_PI;
10875                       if(res<resRef)
10876                         {
10877                           nextNode=*node;
10878                           resRef=res;
10879                           angleNext=angleM;
10880                         }
10881                     }
10882                 }
10883               if(nextNode!=startNode)
10884                 {
10885                   angle0=angleNext-M_PI;
10886                   if(angle0<-M_PI)
10887                     angle0+=2*M_PI;
10888                   prevNode=tmpOut.back();
10889                   tmpOut.push_back(nextNode);
10890                 }
10891             }
10892           std::vector<int> tmp3(2*(sz-1));
10893           std::vector<int>::iterator it=std::copy(nodalConnBg+1,nodalConnEnd,tmp3.begin());
10894           std::copy(nodalConnBg+1,nodalConnEnd,it);
10895           if(std::search(tmp3.begin(),tmp3.end(),tmpOut.begin(),tmpOut.end())!=tmp3.end())
10896             {
10897               nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
10898               return false;
10899             }
10900           if(std::search(tmp3.rbegin(),tmp3.rend(),tmpOut.begin(),tmpOut.end())!=tmp3.rend())
10901             {
10902               nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
10903               return false;
10904             }
10905           else
10906             {
10907               nodalConnecOut->pushBackSilent((int)INTERP_KERNEL::NORM_POLYGON);
10908               nodalConnecOut->insertAtTheEnd(tmpOut.begin(),tmpOut.end());
10909               return true;
10910             }
10911         }
10912       else
10913         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
10914     }
10915   else
10916     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
10917 }
10918
10919 /*!
10920  * This method works on an input pair (\b arr, \b arrIndx) where \b arr indexes is in \b arrIndx.
10921  * 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.
10922  * 
10923  * \param [in] idsToRemoveBg begin of set of ids to remove in \b arr (included)
10924  * \param [in] idsToRemoveEnd end of set of ids to remove in \b arr (excluded)
10925  * \param [in,out] arr array in which the remove operation will be done.
10926  * \param [in,out] arrIndx array in the remove operation will modify
10927  * \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])
10928  * \return true if \b arr and \b arrIndx have been modified, false if not.
10929  */
10930 bool MEDCouplingUMesh::RemoveIdsFromIndexedArrays(const int *idsToRemoveBg, const int *idsToRemoveEnd, DataArrayInt *arr, DataArrayInt *arrIndx, int offsetForRemoval)
10931 {
10932   if(!arrIndx || !arr)
10933     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::RemoveIdsFromIndexedArrays : some input arrays are empty !");
10934   if(offsetForRemoval<0)
10935     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::RemoveIdsFromIndexedArrays : offsetForRemoval should be >=0 !");
10936   std::set<int> s(idsToRemoveBg,idsToRemoveEnd);
10937   int nbOfGrps=arrIndx->getNumberOfTuples()-1;
10938   int *arrIPtr=arrIndx->getPointer();
10939   *arrIPtr++=0;
10940   int previousArrI=0;
10941   const int *arrPtr=arr->getConstPointer();
10942   std::vector<int> arrOut;//no utility to switch to DataArrayInt because copy always needed
10943   for(int i=0;i<nbOfGrps;i++,arrIPtr++)
10944     {
10945       if(*arrIPtr-previousArrI>offsetForRemoval)
10946         {
10947           for(const int *work=arrPtr+previousArrI+offsetForRemoval;work!=arrPtr+*arrIPtr;work++)
10948             {
10949               if(s.find(*work)==s.end())
10950                 arrOut.push_back(*work);
10951             }
10952         }
10953       previousArrI=*arrIPtr;
10954       *arrIPtr=(int)arrOut.size();
10955     }
10956   if(arr->getNumberOfTuples()==(int)arrOut.size())
10957     return false;
10958   arr->alloc((int)arrOut.size(),1);
10959   std::copy(arrOut.begin(),arrOut.end(),arr->getPointer());
10960   return true;
10961 }
10962
10963 /*!
10964  * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn
10965  * (\ref numbering-indirect).
10966  * This method returns the result of the extraction ( specified by a set of ids in [\b idsOfSelectBg , \b idsOfSelectEnd ) ).
10967  * The selection of extraction is done standardly in new2old format.
10968  * This method returns indexed arrays (\ref numbering-indirect) using 2 arrays (arrOut,arrIndexOut).
10969  *
10970  * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
10971  * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
10972  * \param [in] arrIn arr origin array from which the extraction will be done.
10973  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
10974  * \param [out] arrOut the resulting array
10975  * \param [out] arrIndexOut the index array of the resulting array \b arrOut
10976  * \sa MEDCouplingUMesh::ExtractFromIndexedArraysSlice
10977  */
10978 void MEDCouplingUMesh::ExtractFromIndexedArrays(const int *idsOfSelectBg, const int *idsOfSelectEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
10979                                                 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
10980 {
10981   if(!arrIn || !arrIndxIn)
10982     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : input pointer is NULL !");
10983   arrIn->checkAllocated(); arrIndxIn->checkAllocated();
10984   if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1)
10985     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : input arrays must have exactly one component !");
10986   std::size_t sz=std::distance(idsOfSelectBg,idsOfSelectEnd);
10987   const int *arrInPtr=arrIn->getConstPointer();
10988   const int *arrIndxPtr=arrIndxIn->getConstPointer();
10989   int nbOfGrps=arrIndxIn->getNumberOfTuples()-1;
10990   if(nbOfGrps<0)
10991     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : The format of \"arrIndxIn\" is invalid ! Its nb of tuples should be >=1 !");
10992   int maxSizeOfArr=arrIn->getNumberOfTuples();
10993   MCAuto<DataArrayInt> arro=DataArrayInt::New();
10994   MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
10995   arrIo->alloc((int)(sz+1),1);
10996   const int *idsIt=idsOfSelectBg;
10997   int *work=arrIo->getPointer();
10998   *work++=0;
10999   int lgth=0;
11000   for(std::size_t i=0;i<sz;i++,work++,idsIt++)
11001     {
11002       if(*idsIt>=0 && *idsIt<nbOfGrps)
11003         lgth+=arrIndxPtr[*idsIt+1]-arrIndxPtr[*idsIt];
11004       else
11005         {
11006           std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " ! Must be in [0," << nbOfGrps << ") !";
11007           throw INTERP_KERNEL::Exception(oss.str().c_str());
11008         }
11009       if(lgth>=work[-1])
11010         *work=lgth;
11011       else
11012         {
11013           std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " and at this pos arrIndxIn[" << *idsIt;
11014           oss << "+1]-arrIndxIn[" << *idsIt << "] < 0 ! The input index array is bugged !";
11015           throw INTERP_KERNEL::Exception(oss.str().c_str());
11016         }
11017     }
11018   arro->alloc(lgth,1);
11019   work=arro->getPointer();
11020   idsIt=idsOfSelectBg;
11021   for(std::size_t i=0;i<sz;i++,idsIt++)
11022     {
11023       if(arrIndxPtr[*idsIt]>=0 && arrIndxPtr[*idsIt+1]<=maxSizeOfArr)
11024         work=std::copy(arrInPtr+arrIndxPtr[*idsIt],arrInPtr+arrIndxPtr[*idsIt+1],work);
11025       else
11026         {
11027           std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " arrIndx[" << *idsIt << "] must be >= 0 and arrIndx[";
11028           oss << *idsIt << "+1] <= " << maxSizeOfArr << " (the size of arrIn)!";
11029           throw INTERP_KERNEL::Exception(oss.str().c_str());
11030         }
11031     }
11032   arrOut=arro.retn();
11033   arrIndexOut=arrIo.retn();
11034 }
11035
11036 /*!
11037  * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn
11038  * (\ref numbering-indirect).
11039  * 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 ).
11040  * The selection of extraction is done standardly in new2old format.
11041  * This method returns indexed arrays (\ref numbering-indirect) using 2 arrays (arrOut,arrIndexOut).
11042  *
11043  * \param [in] idsOfSelectStart begin of set of ids of the input extraction (included)
11044  * \param [in] idsOfSelectStop end of set of ids of the input extraction (excluded)
11045  * \param [in] idsOfSelectStep
11046  * \param [in] arrIn arr origin array from which the extraction will be done.
11047  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11048  * \param [out] arrOut the resulting array
11049  * \param [out] arrIndexOut the index array of the resulting array \b arrOut
11050  * \sa MEDCouplingUMesh::ExtractFromIndexedArrays
11051  */
11052 void MEDCouplingUMesh::ExtractFromIndexedArraysSlice(int idsOfSelectStart, int idsOfSelectStop, int idsOfSelectStep, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
11053                                                  DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
11054 {
11055   if(!arrIn || !arrIndxIn)
11056     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : input pointer is NULL !");
11057   arrIn->checkAllocated(); arrIndxIn->checkAllocated();
11058   if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1)
11059     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : input arrays must have exactly one component !");
11060   int sz=DataArrayInt::GetNumberOfItemGivenBESRelative(idsOfSelectStart,idsOfSelectStop,idsOfSelectStep,"MEDCouplingUMesh::ExtractFromIndexedArraysSlice : Input slice ");
11061   const int *arrInPtr=arrIn->getConstPointer();
11062   const int *arrIndxPtr=arrIndxIn->getConstPointer();
11063   int nbOfGrps=arrIndxIn->getNumberOfTuples()-1;
11064   if(nbOfGrps<0)
11065     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : The format of \"arrIndxIn\" is invalid ! Its nb of tuples should be >=1 !");
11066   int maxSizeOfArr=arrIn->getNumberOfTuples();
11067   MCAuto<DataArrayInt> arro=DataArrayInt::New();
11068   MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
11069   arrIo->alloc((int)(sz+1),1);
11070   int idsIt=idsOfSelectStart;
11071   int *work=arrIo->getPointer();
11072   *work++=0;
11073   int lgth=0;
11074   for(int i=0;i<sz;i++,work++,idsIt+=idsOfSelectStep)
11075     {
11076       if(idsIt>=0 && idsIt<nbOfGrps)
11077         lgth+=arrIndxPtr[idsIt+1]-arrIndxPtr[idsIt];
11078       else
11079         {
11080           std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " ! Must be in [0," << nbOfGrps << ") !";
11081           throw INTERP_KERNEL::Exception(oss.str().c_str());
11082         }
11083       if(lgth>=work[-1])
11084         *work=lgth;
11085       else
11086         {
11087           std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " and at this pos arrIndxIn[" << idsIt;
11088           oss << "+1]-arrIndxIn[" << idsIt << "] < 0 ! The input index array is bugged !";
11089           throw INTERP_KERNEL::Exception(oss.str().c_str());
11090         }
11091     }
11092   arro->alloc(lgth,1);
11093   work=arro->getPointer();
11094   idsIt=idsOfSelectStart;
11095   for(int i=0;i<sz;i++,idsIt+=idsOfSelectStep)
11096     {
11097       if(arrIndxPtr[idsIt]>=0 && arrIndxPtr[idsIt+1]<=maxSizeOfArr)
11098         work=std::copy(arrInPtr+arrIndxPtr[idsIt],arrInPtr+arrIndxPtr[idsIt+1],work);
11099       else
11100         {
11101           std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " arrIndx[" << idsIt << "] must be >= 0 and arrIndx[";
11102           oss << idsIt << "+1] <= " << maxSizeOfArr << " (the size of arrIn)!";
11103           throw INTERP_KERNEL::Exception(oss.str().c_str());
11104         }
11105     }
11106   arrOut=arro.retn();
11107   arrIndexOut=arrIo.retn();
11108 }
11109
11110 /*!
11111  * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11112  * 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
11113  * cellIds \b in [ \b idsOfSelectBg , \b idsOfSelectEnd ) a copy coming from the corresponding values in input pair (\b srcArr, \b srcArrIndex).
11114  * This method is an generalization of MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx that performs the same thing but by without building explicitely a result output arrays.
11115  *
11116  * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
11117  * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
11118  * \param [in] arrIn arr origin array from which the extraction will be done.
11119  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11120  * \param [in] srcArr input array that will be used as source of copy for ids in [ \b idsOfSelectBg, \b idsOfSelectEnd )
11121  * \param [in] srcArrIndex index array of \b srcArr
11122  * \param [out] arrOut the resulting array
11123  * \param [out] arrIndexOut the index array of the resulting array \b arrOut
11124  * 
11125  * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx
11126  */
11127 void MEDCouplingUMesh::SetPartOfIndexedArrays(const int *idsOfSelectBg, const int *idsOfSelectEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
11128                                               const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex,
11129                                               DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
11130 {
11131   if(arrIn==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11132     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArrays : presence of null pointer in input parameter !");
11133   MCAuto<DataArrayInt> arro=DataArrayInt::New();
11134   MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
11135   int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11136   std::vector<bool> v(nbOfTuples,true);
11137   int offset=0;
11138   const int *arrIndxInPtr=arrIndxIn->getConstPointer();
11139   const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
11140   for(const int *it=idsOfSelectBg;it!=idsOfSelectEnd;it++,srcArrIndexPtr++)
11141     {
11142       if(*it>=0 && *it<nbOfTuples)
11143         {
11144           v[*it]=false;
11145           offset+=(srcArrIndexPtr[1]-srcArrIndexPtr[0])-(arrIndxInPtr[*it+1]-arrIndxInPtr[*it]);
11146         }
11147       else
11148         {
11149           std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArrays : On pos #" << std::distance(idsOfSelectBg,it) << " value is " << *it << " not in [0," << nbOfTuples << ") !";
11150           throw INTERP_KERNEL::Exception(oss.str().c_str());
11151         }
11152     }
11153   srcArrIndexPtr=srcArrIndex->getConstPointer();
11154   arrIo->alloc(nbOfTuples+1,1);
11155   arro->alloc(arrIn->getNumberOfTuples()+offset,1);
11156   const int *arrInPtr=arrIn->getConstPointer();
11157   const int *srcArrPtr=srcArr->getConstPointer();
11158   int *arrIoPtr=arrIo->getPointer(); *arrIoPtr++=0;
11159   int *arroPtr=arro->getPointer();
11160   for(int ii=0;ii<nbOfTuples;ii++,arrIoPtr++)
11161     {
11162       if(v[ii])
11163         {
11164           arroPtr=std::copy(arrInPtr+arrIndxInPtr[ii],arrInPtr+arrIndxInPtr[ii+1],arroPtr);
11165           *arrIoPtr=arrIoPtr[-1]+(arrIndxInPtr[ii+1]-arrIndxInPtr[ii]);
11166         }
11167       else
11168         {
11169           std::size_t pos=std::distance(idsOfSelectBg,std::find(idsOfSelectBg,idsOfSelectEnd,ii));
11170           arroPtr=std::copy(srcArrPtr+srcArrIndexPtr[pos],srcArrPtr+srcArrIndexPtr[pos+1],arroPtr);
11171           *arrIoPtr=arrIoPtr[-1]+(srcArrIndexPtr[pos+1]-srcArrIndexPtr[pos]);
11172         }
11173     }
11174   arrOut=arro.retn();
11175   arrIndexOut=arrIo.retn();
11176 }
11177
11178 /*!
11179  * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11180  * This method is an specialization of MEDCouplingUMesh::SetPartOfIndexedArrays in the case of assignement do not modify the index in \b arrIndxIn.
11181  *
11182  * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
11183  * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
11184  * \param [in,out] arrInOut arr origin array from which the extraction will be done.
11185  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11186  * \param [in] srcArr input array that will be used as source of copy for ids in [ \b idsOfSelectBg , \b idsOfSelectEnd )
11187  * \param [in] srcArrIndex index array of \b srcArr
11188  * 
11189  * \sa MEDCouplingUMesh::SetPartOfIndexedArrays
11190  */
11191 void MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx(const int *idsOfSelectBg, const int *idsOfSelectEnd, DataArrayInt *arrInOut, const DataArrayInt *arrIndxIn,
11192                                                      const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex)
11193 {
11194   if(arrInOut==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11195     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx : presence of null pointer in input parameter !");
11196   int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11197   const int *arrIndxInPtr=arrIndxIn->getConstPointer();
11198   const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
11199   int *arrInOutPtr=arrInOut->getPointer();
11200   const int *srcArrPtr=srcArr->getConstPointer();
11201   for(const int *it=idsOfSelectBg;it!=idsOfSelectEnd;it++,srcArrIndexPtr++)
11202     {
11203       if(*it>=0 && *it<nbOfTuples)
11204         {
11205           if(srcArrIndexPtr[1]-srcArrIndexPtr[0]==arrIndxInPtr[*it+1]-arrIndxInPtr[*it])
11206             std::copy(srcArrPtr+srcArrIndexPtr[0],srcArrPtr+srcArrIndexPtr[1],arrInOutPtr+arrIndxInPtr[*it]);
11207           else
11208             {
11209               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] !";
11210               throw INTERP_KERNEL::Exception(oss.str().c_str());
11211             }
11212         }
11213       else
11214         {
11215           std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx : On pos #" << std::distance(idsOfSelectBg,it) << " value is " << *it << " not in [0," << nbOfTuples << ") !";
11216           throw INTERP_KERNEL::Exception(oss.str().c_str());
11217         }
11218     }
11219 }
11220
11221 /*!
11222  * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
11223  * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
11224  * 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]].
11225  * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
11226  * A negative value in \b arrIn means that it is ignored.
11227  * 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.
11228  * 
11229  * \param [in] arrIn arr origin array from which the extraction will be done.
11230  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11231  * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
11232  * \sa MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed, MEDCouplingUMesh::partitionBySpreadZone
11233  */
11234 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGradually(const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn)
11235 {
11236   int seed=0,nbOfDepthPeelingPerformed=0;
11237   return ComputeSpreadZoneGraduallyFromSeed(&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfDepthPeelingPerformed);
11238 }
11239
11240 /*!
11241  * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
11242  * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
11243  * 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]].
11244  * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
11245  * A negative value in \b arrIn means that it is ignored.
11246  * 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.
11247  * \param [in] seedBg the begin pointer (included) of an array containing the seed of the search zone
11248  * \param [in] seedEnd the end pointer (not included) of an array containing the seed of the search zone
11249  * \param [in] arrIn arr origin array from which the extraction will be done.
11250  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11251  * \param [in] nbOfDepthPeeling the max number of peels requested in search. By default -1, that is to say, no limit.
11252  * \param [out] nbOfDepthPeelingPerformed the number of peels effectively performed. May be different from \a nbOfDepthPeeling
11253  * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
11254  * \sa MEDCouplingUMesh::partitionBySpreadZone
11255  */
11256 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(const int *seedBg, const int *seedEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn, int nbOfDepthPeeling, int& nbOfDepthPeelingPerformed)
11257 {
11258   nbOfDepthPeelingPerformed=0;
11259   if(!arrIndxIn)
11260     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed : arrIndxIn input pointer is NULL !");
11261   int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11262   if(nbOfTuples<=0)
11263     {
11264       DataArrayInt *ret=DataArrayInt::New(); ret->alloc(0,1);
11265       return ret;
11266     }
11267   //
11268   std::vector<bool> fetched(nbOfTuples,false);
11269   return ComputeSpreadZoneGraduallyFromSeedAlg(fetched,seedBg,seedEnd,arrIn,arrIndxIn,nbOfDepthPeeling,nbOfDepthPeelingPerformed);
11270 }
11271
11272 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeedAlg(std::vector<bool>& fetched, const int *seedBg, const int *seedEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn, int nbOfDepthPeeling, int& nbOfDepthPeelingPerformed)
11273 {
11274   nbOfDepthPeelingPerformed=0;
11275   if(!seedBg || !seedEnd || !arrIn || !arrIndxIn)
11276     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeedAlg : some input pointer is NULL !");
11277   int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11278   std::vector<bool> fetched2(nbOfTuples,false);
11279   int i=0;
11280   for(const int *seedElt=seedBg;seedElt!=seedEnd;seedElt++,i++)
11281     {
11282       if(*seedElt>=0 && *seedElt<nbOfTuples)
11283         { fetched[*seedElt]=true; fetched2[*seedElt]=true; }
11284       else
11285         { std::ostringstream oss; oss << "MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeedAlg : At pos #" << i << " of seeds value is " << *seedElt << "! Should be in [0," << nbOfTuples << ") !"; throw INTERP_KERNEL::Exception(oss.str().c_str()); }
11286     }
11287   const int *arrInPtr=arrIn->getConstPointer();
11288   const int *arrIndxPtr=arrIndxIn->getConstPointer();
11289   int targetNbOfDepthPeeling=nbOfDepthPeeling!=-1?nbOfDepthPeeling:std::numeric_limits<int>::max();
11290   std::vector<int> idsToFetch1(seedBg,seedEnd);
11291   std::vector<int> idsToFetch2;
11292   std::vector<int> *idsToFetch=&idsToFetch1;
11293   std::vector<int> *idsToFetchOther=&idsToFetch2;
11294   while(!idsToFetch->empty() && nbOfDepthPeelingPerformed<targetNbOfDepthPeeling)
11295     {
11296       for(std::vector<int>::const_iterator it=idsToFetch->begin();it!=idsToFetch->end();it++)
11297         for(const int *it2=arrInPtr+arrIndxPtr[*it];it2!=arrInPtr+arrIndxPtr[*it+1];it2++)
11298           if(!fetched[*it2])
11299             { fetched[*it2]=true; fetched2[*it2]=true; idsToFetchOther->push_back(*it2); }
11300       std::swap(idsToFetch,idsToFetchOther);
11301       idsToFetchOther->clear();
11302       nbOfDepthPeelingPerformed++;
11303     }
11304   int lgth=(int)std::count(fetched2.begin(),fetched2.end(),true);
11305   i=0;
11306   MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(lgth,1);
11307   int *retPtr=ret->getPointer();
11308   for(std::vector<bool>::const_iterator it=fetched2.begin();it!=fetched2.end();it++,i++)
11309     if(*it)
11310       *retPtr++=i;
11311   return ret.retn();
11312 }
11313
11314 /*!
11315  * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11316  * 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
11317  * cellIds \b in [\b idsOfSelectBg, \b idsOfSelectEnd) a copy coming from the corresponding values in input pair (\b srcArr, \b srcArrIndex).
11318  * This method is an generalization of MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx that performs the same thing but by without building explicitely a result output arrays.
11319  *
11320  * \param [in] start begin of set of ids of the input extraction (included)
11321  * \param [in] end end of set of ids of the input extraction (excluded)
11322  * \param [in] step step of the set of ids in range mode.
11323  * \param [in] arrIn arr origin array from which the extraction will be done.
11324  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11325  * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd)
11326  * \param [in] srcArrIndex index array of \b srcArr
11327  * \param [out] arrOut the resulting array
11328  * \param [out] arrIndexOut the index array of the resulting array \b arrOut
11329  * 
11330  * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx MEDCouplingUMesh::SetPartOfIndexedArrays
11331  */
11332 void MEDCouplingUMesh::SetPartOfIndexedArraysSlice(int start, int end, int step, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
11333                                                const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex,
11334                                                DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
11335 {
11336   if(arrIn==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11337     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSlice : presence of null pointer in input parameter !");
11338   MCAuto<DataArrayInt> arro=DataArrayInt::New();
11339   MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
11340   int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11341   int offset=0;
11342   const int *arrIndxInPtr=arrIndxIn->getConstPointer();
11343   const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
11344   int nbOfElemsToSet=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::SetPartOfIndexedArraysSlice : ");
11345   int it=start;
11346   for(int i=0;i<nbOfElemsToSet;i++,srcArrIndexPtr++,it+=step)
11347     {
11348       if(it>=0 && it<nbOfTuples)
11349         offset+=(srcArrIndexPtr[1]-srcArrIndexPtr[0])-(arrIndxInPtr[it+1]-arrIndxInPtr[it]);
11350       else
11351         {
11352           std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSlice : On pos #" << i << " value is " << it << " not in [0," << nbOfTuples << ") !";
11353           throw INTERP_KERNEL::Exception(oss.str().c_str());
11354         }
11355     }
11356   srcArrIndexPtr=srcArrIndex->getConstPointer();
11357   arrIo->alloc(nbOfTuples+1,1);
11358   arro->alloc(arrIn->getNumberOfTuples()+offset,1);
11359   const int *arrInPtr=arrIn->getConstPointer();
11360   const int *srcArrPtr=srcArr->getConstPointer();
11361   int *arrIoPtr=arrIo->getPointer(); *arrIoPtr++=0;
11362   int *arroPtr=arro->getPointer();
11363   for(int ii=0;ii<nbOfTuples;ii++,arrIoPtr++)
11364     {
11365       int pos=DataArray::GetPosOfItemGivenBESRelativeNoThrow(ii,start,end,step);
11366       if(pos<0)
11367         {
11368           arroPtr=std::copy(arrInPtr+arrIndxInPtr[ii],arrInPtr+arrIndxInPtr[ii+1],arroPtr);
11369           *arrIoPtr=arrIoPtr[-1]+(arrIndxInPtr[ii+1]-arrIndxInPtr[ii]);
11370         }
11371       else
11372         {
11373           arroPtr=std::copy(srcArrPtr+srcArrIndexPtr[pos],srcArrPtr+srcArrIndexPtr[pos+1],arroPtr);
11374           *arrIoPtr=arrIoPtr[-1]+(srcArrIndexPtr[pos+1]-srcArrIndexPtr[pos]);
11375         }
11376     }
11377   arrOut=arro.retn();
11378   arrIndexOut=arrIo.retn();
11379 }
11380
11381 /*!
11382  * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11383  * This method is an specialization of MEDCouplingUMesh::SetPartOfIndexedArrays in the case of assignement do not modify the index in \b arrIndxIn.
11384  *
11385  * \param [in] start begin of set of ids of the input extraction (included)
11386  * \param [in] end end of set of ids of the input extraction (excluded)
11387  * \param [in] step step of the set of ids in range mode.
11388  * \param [in,out] arrInOut arr origin array from which the extraction will be done.
11389  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11390  * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd)
11391  * \param [in] srcArrIndex index array of \b srcArr
11392  * 
11393  * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSlice MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx
11394  */
11395 void MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice(int start, int end, int step, DataArrayInt *arrInOut, const DataArrayInt *arrIndxIn,
11396                                                       const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex)
11397 {
11398   if(arrInOut==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11399     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : presence of null pointer in input parameter !");
11400   int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11401   const int *arrIndxInPtr=arrIndxIn->getConstPointer();
11402   const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
11403   int *arrInOutPtr=arrInOut->getPointer();
11404   const int *srcArrPtr=srcArr->getConstPointer();
11405   int nbOfElemsToSet=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : ");
11406   int it=start;
11407   for(int i=0;i<nbOfElemsToSet;i++,srcArrIndexPtr++,it+=step)
11408     {
11409       if(it>=0 && it<nbOfTuples)
11410         {
11411           if(srcArrIndexPtr[1]-srcArrIndexPtr[0]==arrIndxInPtr[it+1]-arrIndxInPtr[it])
11412             std::copy(srcArrPtr+srcArrIndexPtr[0],srcArrPtr+srcArrIndexPtr[1],arrInOutPtr+arrIndxInPtr[it]);
11413           else
11414             {
11415               std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : On pos #" << i << " id (idsOfSelectBg[" << i << "]) is " << it << " arrIndxIn[id+1]-arrIndxIn[id]!=srcArrIndex[pos+1]-srcArrIndex[pos] !";
11416               throw INTERP_KERNEL::Exception(oss.str().c_str());
11417             }
11418         }
11419       else
11420         {
11421           std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : On pos #" << i << " value is " << it << " not in [0," << nbOfTuples << ") !";
11422           throw INTERP_KERNEL::Exception(oss.str().c_str());
11423         }
11424     }
11425 }
11426
11427 /*!
11428  * \b this is expected to be a mesh fully defined whose spaceDim==meshDim.
11429  * It returns a new allocated mesh having the same mesh dimension and lying on same coordinates.
11430  * The returned mesh contains as poly cells as number of contiguous zone (regarding connectivity).
11431  * A spread contiguous zone is built using poly cells (polyhedra in 3D, polygons in 2D and polyline in 1D).
11432  * The sum of measure field of returned mesh is equal to the sum of measure field of this.
11433  * 
11434  * \return a newly allocated mesh lying on the same coords than \b this with same meshdimension than \b this.
11435  */
11436 MEDCouplingUMesh *MEDCouplingUMesh::buildSpreadZonesWithPoly() const
11437 {
11438   checkFullyDefined();
11439   int mdim=getMeshDimension();
11440   int spaceDim=getSpaceDimension();
11441   if(mdim!=spaceDim)
11442     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension and spacedimension do not match !");
11443   std::vector<DataArrayInt *> partition=partitionBySpreadZone();
11444   std::vector< MCAuto<DataArrayInt> > partitionAuto; partitionAuto.reserve(partition.size());
11445   std::copy(partition.begin(),partition.end(),std::back_insert_iterator<std::vector< MCAuto<DataArrayInt> > >(partitionAuto));
11446   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
11447   ret->setCoords(getCoords());
11448   ret->allocateCells((int)partition.size());
11449   //
11450   for(std::vector<DataArrayInt *>::const_iterator it=partition.begin();it!=partition.end();it++)
11451     {
11452       MCAuto<MEDCouplingUMesh> tmp=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf((*it)->begin(),(*it)->end(),true));
11453       MCAuto<DataArrayInt> cell;
11454       switch(mdim)
11455       {
11456         case 2:
11457           cell=tmp->buildUnionOf2DMesh();
11458           break;
11459         case 3:
11460           cell=tmp->buildUnionOf3DMesh();
11461           break;
11462         default:
11463           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension supported are [2,3] ! Not implemented yet for others !");
11464       }
11465
11466       ret->insertNextCell((INTERP_KERNEL::NormalizedCellType)cell->getIJSafe(0,0),cell->getNumberOfTuples()-1,cell->getConstPointer()+1);
11467     }
11468   //
11469   ret->finishInsertingCells();
11470   return ret.retn();
11471 }
11472
11473 /*!
11474  * This method partitions \b this into contiguous zone.
11475  * This method only needs a well defined connectivity. Coordinates are not considered here.
11476  * This method returns a vector of \b newly allocated arrays that the caller has to deal with.
11477  */
11478 std::vector<DataArrayInt *> MEDCouplingUMesh::partitionBySpreadZone() const
11479 {
11480   int nbOfCellsCur=getNumberOfCells();
11481   std::vector<DataArrayInt *> ret;
11482   if(nbOfCellsCur<=0)
11483     return ret;
11484   DataArrayInt *neigh=0,*neighI=0;
11485   computeNeighborsOfCells(neigh,neighI);
11486   MCAuto<DataArrayInt> neighAuto(neigh),neighIAuto(neighI);
11487   std::vector<bool> fetchedCells(nbOfCellsCur,false);
11488   std::vector< MCAuto<DataArrayInt> > ret2;
11489   int seed=0;
11490   while(seed<nbOfCellsCur)
11491     {
11492       int nbOfPeelPerformed=0;
11493       ret2.push_back(ComputeSpreadZoneGraduallyFromSeedAlg(fetchedCells,&seed,&seed+1,neigh,neighI,-1,nbOfPeelPerformed));
11494       seed=(int)std::distance(fetchedCells.begin(),std::find(fetchedCells.begin()+seed,fetchedCells.end(),false));
11495     }
11496   for(std::vector< MCAuto<DataArrayInt> >::iterator it=ret2.begin();it!=ret2.end();it++)
11497     ret.push_back((*it).retn());
11498   return ret;
11499 }
11500
11501 /*!
11502  * This method returns given a distribution of cell type (returned for example by MEDCouplingUMesh::getDistributionOfTypes method and customized after) a
11503  * newly allocated DataArrayInt instance with 2 components ready to be interpreted as input of DataArrayInt::findRangeIdForEachTuple method.
11504  *
11505  * \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.
11506  * \return a newly allocated DataArrayInt to be managed by the caller.
11507  * \throw In case of \a code has not the right format (typically of size 3*n)
11508  */
11509 DataArrayInt *MEDCouplingUMesh::ComputeRangesFromTypeDistribution(const std::vector<int>& code)
11510 {
11511   MCAuto<DataArrayInt> ret=DataArrayInt::New();
11512   std::size_t nb=code.size()/3;
11513   if(code.size()%3!=0)
11514     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeRangesFromTypeDistribution : invalid input code !");
11515   ret->alloc((int)nb,2);
11516   int *retPtr=ret->getPointer();
11517   for(std::size_t i=0;i<nb;i++,retPtr+=2)
11518     {
11519       retPtr[0]=code[3*i+2];
11520       retPtr[1]=code[3*i+2]+code[3*i+1];
11521     }
11522   return ret.retn();
11523 }
11524
11525 /*!
11526  * This method expects that \a this a 3D mesh (spaceDim=3 and meshDim=3) with all coordinates and connectivities set.
11527  * All cells in \a this are expected to be linear 3D cells.
11528  * This method will split **all** 3D cells in \a this into INTERP_KERNEL::NORM_TETRA4 cells and put them in the returned mesh.
11529  * It leads to an increase to number of cells.
11530  * This method contrary to MEDCouplingUMesh::simplexize can append coordinates in \a this to perform its work.
11531  * The \a nbOfAdditionalPoints returned value informs about it. If > 0, the coordinates array in returned mesh will have \a nbOfAdditionalPoints 
11532  * more tuples (nodes) than in \a this. Anyway, all the nodes in \a this (with the same order) will be in the returned mesh.
11533  *
11534  * \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.
11535  *                      For all other cells, the splitting policy will be ignored. See INTERP_KERNEL::SplittingPolicy for the images.
11536  * \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. 
11537  * \param [out] n2oCells - A new instance of DataArrayInt holding, for each new cell,
11538  *          an id of old cell producing it. The caller is to delete this array using
11539  *         decrRef() as it is no more needed.
11540  * \return MEDCoupling1SGTUMesh * - the mesh containing only INTERP_KERNEL::NORM_TETRA4 cells.
11541  *
11542  * \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
11543  * the policy PLANAR_FACE_6 should be used on a mesh sorted with MEDCoupling1SGTUMesh::sortHexa8EachOther.
11544  * 
11545  * \throw If \a this is not a 3D mesh (spaceDim==3 and meshDim==3).
11546  * \throw If \a this is not fully constituted with linear 3D cells.
11547  * \sa MEDCouplingUMesh::simplexize, MEDCoupling1SGTUMesh::sortHexa8EachOther
11548  */
11549 MEDCoupling1SGTUMesh *MEDCouplingUMesh::tetrahedrize(int policy, DataArrayInt *& n2oCells, int& nbOfAdditionalPoints) const
11550 {
11551   INTERP_KERNEL::SplittingPolicy pol((INTERP_KERNEL::SplittingPolicy)policy);
11552   checkConnectivityFullyDefined();
11553   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
11554     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tetrahedrize : only available for mesh with meshdim == 3 and spacedim == 3 !");
11555   int nbOfCells(getNumberOfCells()),nbNodes(getNumberOfNodes());
11556   MCAuto<MEDCoupling1SGTUMesh> ret0(MEDCoupling1SGTUMesh::New(getName(),INTERP_KERNEL::NORM_TETRA4));
11557   MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(nbOfCells,1);
11558   int *retPt(ret->getPointer());
11559   MCAuto<DataArrayInt> newConn(DataArrayInt::New()); newConn->alloc(0,1);
11560   MCAuto<DataArrayDouble> addPts(DataArrayDouble::New()); addPts->alloc(0,1);
11561   const int *oldc(_nodal_connec->begin());
11562   const int *oldci(_nodal_connec_index->begin());
11563   const double *coords(_coords->begin());
11564   for(int i=0;i<nbOfCells;i++,oldci++,retPt++)
11565     {
11566       std::vector<int> a; std::vector<double> b;
11567       INTERP_KERNEL::SplitIntoTetras(pol,(INTERP_KERNEL::NormalizedCellType)oldc[oldci[0]],oldc+oldci[0]+1,oldc+oldci[1],coords,a,b);
11568       std::size_t nbOfTet(a.size()/4); *retPt=(int)nbOfTet;
11569       const int *aa(&a[0]);
11570       if(!b.empty())
11571         {
11572           for(std::vector<int>::iterator it=a.begin();it!=a.end();it++)
11573             if(*it<0)
11574               *it=(-(*(it))-1+nbNodes);
11575           addPts->insertAtTheEnd(b.begin(),b.end());
11576           nbNodes+=(int)b.size()/3;
11577         }
11578       for(std::size_t j=0;j<nbOfTet;j++,aa+=4)
11579         newConn->insertAtTheEnd(aa,aa+4);
11580     }
11581   if(!addPts->empty())
11582     {
11583       addPts->rearrange(3);
11584       nbOfAdditionalPoints=addPts->getNumberOfTuples();
11585       addPts=DataArrayDouble::Aggregate(getCoords(),addPts);
11586       ret0->setCoords(addPts);
11587     }
11588   else
11589     {
11590       nbOfAdditionalPoints=0;
11591       ret0->setCoords(getCoords());
11592     }
11593   ret0->setNodalConnectivity(newConn);
11594   //
11595   ret->computeOffsetsFull();
11596   n2oCells=ret->buildExplicitArrOfSliceOnScaledArr(0,nbOfCells,1);
11597   return ret0.retn();
11598 }
11599
11600 /*!
11601  * 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). 
11602  *
11603  * \sa MEDCouplingUMesh::split2DCells
11604  */
11605 void MEDCouplingUMesh::split2DCellsLinear(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI)
11606 {
11607   checkConnectivityFullyDefined();
11608   int ncells(getNumberOfCells()),lgthToReach(getNodalConnectivityArrayLen()+subNodesInSeg->getNumberOfTuples());
11609   MCAuto<DataArrayInt> c(DataArrayInt::New()); c->alloc((std::size_t)lgthToReach);
11610   const int *subPtr(subNodesInSeg->begin()),*subIPtr(subNodesInSegI->begin()),*descPtr(desc->begin()),*descIPtr(descI->begin()),*oldConn(getNodalConnectivity()->begin());
11611   int *cPtr(c->getPointer()),*ciPtr(getNodalConnectivityIndex()->getPointer());
11612   int prevPosOfCi(ciPtr[0]);
11613   for(int i=0;i<ncells;i++,ciPtr++,descIPtr++)
11614     {
11615       int offset(descIPtr[0]),sz(descIPtr[1]-descIPtr[0]),deltaSz(0);
11616       *cPtr++=(int)INTERP_KERNEL::NORM_POLYGON; *cPtr++=oldConn[prevPosOfCi+1];
11617       for(int j=0;j<sz;j++)
11618         {
11619           int offset2(subIPtr[descPtr[offset+j]]),sz2(subIPtr[descPtr[offset+j]+1]-subIPtr[descPtr[offset+j]]);
11620           for(int k=0;k<sz2;k++)
11621             *cPtr++=subPtr[offset2+k];
11622           if(j!=sz-1)
11623             *cPtr++=oldConn[prevPosOfCi+j+2];
11624           deltaSz+=sz2;
11625         }
11626       prevPosOfCi=ciPtr[1];
11627       ciPtr[1]=ciPtr[0]+1+sz+deltaSz;//sz==old nb of nodes because (nb of subedges=nb of nodes for polygons)
11628     }
11629   if(c->end()!=cPtr)
11630     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCellsLinear : Some of edges to be split are orphan !");
11631   _nodal_connec->decrRef();
11632   _nodal_connec=c.retn(); _types.clear(); _types.insert(INTERP_KERNEL::NORM_POLYGON);
11633 }
11634
11635 int InternalAddPoint(const INTERP_KERNEL::Edge *e, int id, const double *coo, int startId, int endId, DataArrayDouble& addCoo, int& nodesCnter)
11636 {
11637   if(id!=-1)
11638     return id;
11639   else
11640     {
11641       int ret(nodesCnter++);
11642       double newPt[2];
11643       e->getMiddleOfPoints(coo+2*startId,coo+2*endId,newPt);
11644       addCoo.insertAtTheEnd(newPt,newPt+2);
11645       return ret;
11646     }
11647 }
11648
11649 int InternalAddPointOriented(const INTERP_KERNEL::Edge *e, int id, const double *coo, int startId, int endId, DataArrayDouble& addCoo, int& nodesCnter)
11650 {
11651   if(id!=-1)
11652     return id;
11653   else
11654     {
11655       int ret(nodesCnter++);
11656       double newPt[2];
11657       e->getMiddleOfPointsOriented(coo+2*startId,coo+2*endId,newPt);
11658       addCoo.insertAtTheEnd(newPt,newPt+2);
11659       return ret;
11660     }
11661 }
11662
11663
11664 /// @cond INTERNAL
11665
11666 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)
11667 {
11668   int tmp[3];
11669   int trueStart(start>=0?start:nbOfEdges+start);
11670   tmp[0]=linOrArc?(int)INTERP_KERNEL::NORM_QPOLYG:(int)INTERP_KERNEL::NORM_POLYGON; tmp[1]=connBg[trueStart]; tmp[2]=connBg[stp];
11671   newConnOfCell->insertAtTheEnd(tmp,tmp+3);
11672   if(linOrArc)
11673     {
11674       if(stp-start>1)
11675         {
11676           int tmp2(0),tmp3(appendedCoords->getNumberOfTuples()/2);
11677           InternalAddPointOriented(e,-1,coords,tmp[1],tmp[2],*appendedCoords,tmp2);
11678           middles.push_back(tmp3+offset);
11679         }
11680       else
11681         middles.push_back(connBg[trueStart+nbOfEdges]);
11682     }
11683 }
11684
11685 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)
11686 {
11687   int tmpSrt(newConnOfCell->back()),tmpEnd(connBg[stp]);
11688   newConnOfCell->pushBackSilent(tmpEnd);
11689   if(linOrArc)
11690     {
11691       if(stp-start>1)
11692         {
11693           int tmp2(0),tmp3(appendedCoords->getNumberOfTuples()/2);
11694           InternalAddPointOriented(e,-1,coords,tmpSrt,tmpEnd,*appendedCoords,tmp2);
11695           middles.push_back(tmp3+offset);
11696         }
11697       else
11698         middles.push_back(connBg[start+nbOfEdges]);
11699     }
11700 }
11701
11702 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)
11703 {
11704   // only the quadratic point to deal with:
11705   if(linOrArc)
11706     {
11707       if(stp-start>1)
11708         {
11709           int tmpSrt(connBg[start]),tmpEnd(connBg[stp]);
11710           int tmp2(0),tmp3(appendedCoords->getNumberOfTuples()/2);
11711           InternalAddPointOriented(e,-1,coords,tmpSrt,tmpEnd,*appendedCoords,tmp2);
11712           middles.push_back(tmp3+offset);
11713         }
11714       else
11715         middles.push_back(connBg[start+nbOfEdges]);
11716     }
11717 }
11718
11719 /// @endcond
11720
11721 /*!
11722  * 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 ) .
11723  * \a appendedCoords is a DataArrayDouble instance with number of components equal to one (even if the items are pushed by pair).
11724  */
11725 bool MEDCouplingUMesh::Colinearize2DCell(const double *coords, const int *connBg, const int *connEnd, int offset, DataArrayInt *newConnOfCell, DataArrayDouble *appendedCoords)
11726 {
11727   std::size_t sz(std::distance(connBg,connEnd));
11728   if(sz<3)//3 because 2+1(for the cell type) and 2 is the minimal number of edges of 2D cell.
11729     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Colinearize2DCell : the input cell has invalid format !");
11730   sz--;
11731   INTERP_KERNEL::AutoPtr<int> tmpConn(new int[sz]);
11732   const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connBg[0]));
11733   unsigned nbs(cm.getNumberOfSons2(connBg+1,sz));
11734   unsigned nbOfHit(0); // number of fusions operated
11735   int posBaseElt(0),posEndElt(0),nbOfTurn(0);
11736   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
11737   INTERP_KERNEL::NormalizedCellType typeOfSon;
11738   std::vector<int> middles;
11739   bool ret(false);
11740   for(;(nbOfTurn+nbOfHit)<nbs;nbOfTurn++)
11741     {
11742       cm.fillSonCellNodalConnectivity2(posBaseElt,connBg+1,sz,tmpConn,typeOfSon);
11743       std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
11744       INTERP_KERNEL::Edge *e(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpConn,coords,m));
11745       posEndElt = posBaseElt+1;
11746
11747       // Look backward first: are the final edges of the cells colinear with the first ones?
11748       // This initializes posBaseElt.
11749       if(nbOfTurn==0)
11750         {
11751           for(unsigned i=1;i<nbs && nbOfHit<maxNbOfHit;i++) // 2nd condition is to avoid ending with a cell wih one single edge
11752             {
11753               cm.fillSonCellNodalConnectivity2(nbs-i,connBg+1,sz,tmpConn,typeOfSon);
11754               INTERP_KERNEL::Edge *eCand(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpConn,coords,m));
11755               INTERP_KERNEL::EdgeIntersector *eint(INTERP_KERNEL::Edge::BuildIntersectorWith(e,eCand));
11756               bool isColinear=eint->areColinears();
11757               if(isColinear)
11758                 {
11759                   nbOfHit++;
11760                   posBaseElt--;
11761                   ret=true;
11762                 }
11763               delete eint;
11764               eCand->decrRef();
11765               if(!isColinear)
11766                 break;
11767             }
11768         }
11769       // Now move forward:
11770       const unsigned fwdStart = (nbOfTurn == 0 ? 0 : posBaseElt);  // the first element to be inspected going forward
11771       for(unsigned j=fwdStart+1;j<nbs && nbOfHit<maxNbOfHit;j++)  // 2nd condition is to avoid ending with a cell wih one single edge
11772         {
11773           cm.fillSonCellNodalConnectivity2((int)j,connBg+1,sz,tmpConn,typeOfSon); // get edge #j's connectivity
11774           INTERP_KERNEL::Edge *eCand(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpConn,coords,m));
11775           INTERP_KERNEL::EdgeIntersector *eint(INTERP_KERNEL::Edge::BuildIntersectorWith(e,eCand));
11776           bool isColinear(eint->areColinears());
11777           if(isColinear)
11778             {
11779               nbOfHit++;
11780               posEndElt++;
11781               ret=true;
11782             }
11783           delete eint;
11784           eCand->decrRef();
11785           if(!isColinear)
11786               break;
11787         }
11788       //push [posBaseElt,posEndElt) in newConnOfCell using e
11789       // 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!
11790       if(nbOfTurn==0)
11791         // at the begining of the connectivity (insert type)
11792         EnterTheResultOf2DCellFirst(e,posBaseElt,posEndElt,(int)nbs,cm.isQuadratic(),coords,connBg+1,offset,newConnOfCell,appendedCoords,middles);
11793       else if((nbOfHit+nbOfTurn) != (nbs-1))
11794         // in the middle
11795         EnterTheResultOf2DCellMiddle(e,posBaseElt,posEndElt,(int)nbs,cm.isQuadratic(),coords,connBg+1,offset,newConnOfCell,appendedCoords,middles);
11796       if ((nbOfHit+nbOfTurn) == (nbs-1))
11797         // at the end (only quad points to deal with)
11798         EnterTheResultOf2DCellEnd(e,posBaseElt,posEndElt,(int)nbs,cm.isQuadratic(),coords,connBg+1,offset,newConnOfCell,appendedCoords,middles);
11799       posBaseElt=posEndElt;
11800       e->decrRef();
11801     }
11802   if(!middles.empty())
11803     newConnOfCell->insertAtTheEnd(middles.begin(),middles.end());
11804   return ret;
11805 }
11806
11807 /*!
11808  * It is the quadratic part of MEDCouplingUMesh::split2DCells. Here some additionnal nodes can be added at the end of coordinates array object.
11809  *
11810  * \return  int - the number of new nodes created.
11811  * \sa MEDCouplingUMesh::split2DCells
11812  */
11813 int MEDCouplingUMesh::split2DCellsQuadratic(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI, const DataArrayInt *mid, const DataArrayInt *midI)
11814 {
11815   checkConsistencyLight();
11816   int ncells(getNumberOfCells()),lgthToReach(getNodalConnectivityArrayLen()+2*subNodesInSeg->getNumberOfTuples()),nodesCnt(getNumberOfNodes());
11817   MCAuto<DataArrayInt> c(DataArrayInt::New()); c->alloc((std::size_t)lgthToReach);
11818   MCAuto<DataArrayDouble> addCoo(DataArrayDouble::New()); addCoo->alloc(0,1);
11819   const int *subPtr(subNodesInSeg->begin()),*subIPtr(subNodesInSegI->begin()),*descPtr(desc->begin()),*descIPtr(descI->begin()),*oldConn(getNodalConnectivity()->begin());
11820   const int *midPtr(mid->begin()),*midIPtr(midI->begin());
11821   const double *oldCoordsPtr(getCoords()->begin());
11822   int *cPtr(c->getPointer()),*ciPtr(getNodalConnectivityIndex()->getPointer());
11823   int prevPosOfCi(ciPtr[0]);
11824   for(int i=0;i<ncells;i++,ciPtr++,descIPtr++)
11825     {
11826       int offset(descIPtr[0]),sz(descIPtr[1]-descIPtr[0]),deltaSz(sz);
11827       for(int j=0;j<sz;j++)
11828         { int sz2(subIPtr[descPtr[offset+j]+1]-subIPtr[descPtr[offset+j]]); deltaSz+=sz2; }
11829       *cPtr++=(int)INTERP_KERNEL::NORM_QPOLYG; cPtr[0]=oldConn[prevPosOfCi+1];
11830       for(int j=0;j<sz;j++)//loop over subedges of oldConn
11831         {
11832           int offset2(subIPtr[descPtr[offset+j]]),sz2(subIPtr[descPtr[offset+j]+1]-subIPtr[descPtr[offset+j]]),offset3(midIPtr[descPtr[offset+j]]);
11833           if(sz2==0)
11834             {
11835               if(j<sz-1)
11836                 cPtr[1]=oldConn[prevPosOfCi+2+j];
11837               cPtr[deltaSz]=oldConn[prevPosOfCi+1+j+sz]; cPtr++;
11838               continue;
11839             }
11840           std::vector<INTERP_KERNEL::Node *> ns(3);
11841           ns[0]=new INTERP_KERNEL::Node(oldCoordsPtr[2*oldConn[prevPosOfCi+1+j]],oldCoordsPtr[2*oldConn[prevPosOfCi+1+j]+1]);
11842           ns[1]=new INTERP_KERNEL::Node(oldCoordsPtr[2*oldConn[prevPosOfCi+1+(1+j)%sz]],oldCoordsPtr[2*oldConn[prevPosOfCi+1+(1+j)%sz]+1]);
11843           ns[2]=new INTERP_KERNEL::Node(oldCoordsPtr[2*oldConn[prevPosOfCi+1+sz+j]],oldCoordsPtr[2*oldConn[prevPosOfCi+1+sz+j]+1]);
11844           MCAuto<INTERP_KERNEL::Edge> e(INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(ns));
11845           for(int k=0;k<sz2;k++)//loop over subsplit of current subedge
11846             {
11847               cPtr[1]=subPtr[offset2+k];
11848               cPtr[deltaSz]=InternalAddPoint(e,midPtr[offset3+k],oldCoordsPtr,cPtr[0],cPtr[1],*addCoo,nodesCnt); cPtr++;
11849             }
11850           int tmpEnd(oldConn[prevPosOfCi+1+(j+1)%sz]);
11851           if(j!=sz-1)
11852             { cPtr[1]=tmpEnd; }
11853           cPtr[deltaSz]=InternalAddPoint(e,midPtr[offset3+sz2],oldCoordsPtr,cPtr[0],tmpEnd,*addCoo,nodesCnt); cPtr++;
11854         }
11855       prevPosOfCi=ciPtr[1]; cPtr+=deltaSz;
11856       ciPtr[1]=ciPtr[0]+1+2*deltaSz;//sz==old nb of nodes because (nb of subedges=nb of nodes for polygons)
11857     }
11858   if(c->end()!=cPtr)
11859     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCellsQuadratic : Some of edges to be split are orphan !");
11860   _nodal_connec->decrRef();
11861   _nodal_connec=c.retn(); _types.clear(); _types.insert(INTERP_KERNEL::NORM_QPOLYG);
11862   addCoo->rearrange(2);
11863   MCAuto<DataArrayDouble> coo(DataArrayDouble::Aggregate(getCoords(),addCoo));//info are copied from getCoords() by using Aggregate
11864   setCoords(coo);
11865   return addCoo->getNumberOfTuples();
11866 }
11867
11868 void MEDCouplingUMesh::ComputeAllTypesInternal(std::set<INTERP_KERNEL::NormalizedCellType>& types, const DataArrayInt *nodalConnec, const DataArrayInt *nodalConnecIndex)
11869 {
11870   if(nodalConnec && nodalConnecIndex)
11871     {
11872       types.clear();
11873       const int *conn(nodalConnec->getConstPointer()),*connIndex(nodalConnecIndex->getConstPointer());
11874       int nbOfElem(nodalConnecIndex->getNbOfElems()-1);
11875       if(nbOfElem>0)
11876         for(const int *pt=connIndex;pt!=connIndex+nbOfElem;pt++)
11877           types.insert((INTERP_KERNEL::NormalizedCellType)conn[*pt]);
11878     }
11879 }
11880
11881 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),
11882     _own_cell(true),_cell_id(-1),_nb_cell(0)
11883 {
11884   if(mesh)
11885     {
11886       mesh->incrRef();
11887       _nb_cell=mesh->getNumberOfCells();
11888     }
11889 }
11890
11891 MEDCouplingUMeshCellIterator::~MEDCouplingUMeshCellIterator()
11892 {
11893   if(_mesh)
11894     _mesh->decrRef();
11895   if(_own_cell)
11896     delete _cell;
11897 }
11898
11899 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh, MEDCouplingUMeshCell *itc, int bg, int end):_mesh(mesh),_cell(itc),
11900     _own_cell(false),_cell_id(bg-1),
11901     _nb_cell(end)
11902 {
11903   if(mesh)
11904     mesh->incrRef();
11905 }
11906
11907 MEDCouplingUMeshCell *MEDCouplingUMeshCellIterator::nextt()
11908 {
11909   _cell_id++;
11910   if(_cell_id<_nb_cell)
11911     {
11912       _cell->next();
11913       return _cell;
11914     }
11915   else
11916     return 0;
11917 }
11918
11919 MEDCouplingUMeshCellByTypeEntry::MEDCouplingUMeshCellByTypeEntry(MEDCouplingUMesh *mesh):_mesh(mesh)
11920 {
11921   if(_mesh)
11922     _mesh->incrRef();
11923 }
11924
11925 MEDCouplingUMeshCellByTypeIterator *MEDCouplingUMeshCellByTypeEntry::iterator()
11926 {
11927   return new MEDCouplingUMeshCellByTypeIterator(_mesh);
11928 }
11929
11930 MEDCouplingUMeshCellByTypeEntry::~MEDCouplingUMeshCellByTypeEntry()
11931 {
11932   if(_mesh)
11933     _mesh->decrRef();
11934 }
11935
11936 MEDCouplingUMeshCellEntry::MEDCouplingUMeshCellEntry(MEDCouplingUMesh *mesh,  INTERP_KERNEL::NormalizedCellType type, MEDCouplingUMeshCell *itc, int bg, int end):_mesh(mesh),_type(type),
11937     _itc(itc),
11938     _bg(bg),_end(end)
11939 {
11940   if(_mesh)
11941     _mesh->incrRef();
11942 }
11943
11944 MEDCouplingUMeshCellEntry::~MEDCouplingUMeshCellEntry()
11945 {
11946   if(_mesh)
11947     _mesh->decrRef();
11948 }
11949
11950 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCellEntry::getType() const
11951 {
11952   return _type;
11953 }
11954
11955 int MEDCouplingUMeshCellEntry::getNumberOfElems() const
11956 {
11957   return _end-_bg;
11958 }
11959
11960 MEDCouplingUMeshCellIterator *MEDCouplingUMeshCellEntry::iterator()
11961 {
11962   return new MEDCouplingUMeshCellIterator(_mesh,_itc,_bg,_end);
11963 }
11964
11965 MEDCouplingUMeshCellByTypeIterator::MEDCouplingUMeshCellByTypeIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),_cell_id(0),_nb_cell(0)
11966 {
11967   if(mesh)
11968     {
11969       mesh->incrRef();
11970       _nb_cell=mesh->getNumberOfCells();
11971     }
11972 }
11973
11974 MEDCouplingUMeshCellByTypeIterator::~MEDCouplingUMeshCellByTypeIterator()
11975 {
11976   if(_mesh)
11977     _mesh->decrRef();
11978   delete _cell;
11979 }
11980
11981 MEDCouplingUMeshCellEntry *MEDCouplingUMeshCellByTypeIterator::nextt()
11982 {
11983   const int *c=_mesh->getNodalConnectivity()->getConstPointer();
11984   const int *ci=_mesh->getNodalConnectivityIndex()->getConstPointer();
11985   if(_cell_id<_nb_cell)
11986     {
11987       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[_cell_id]];
11988       int nbOfElems=(int)std::distance(ci+_cell_id,std::find_if(ci+_cell_id,ci+_nb_cell,MEDCouplingImpl::ConnReader(c,type)));
11989       int startId=_cell_id;
11990       _cell_id+=nbOfElems;
11991       return new MEDCouplingUMeshCellEntry(_mesh,type,_cell,startId,_cell_id);
11992     }
11993   else
11994     return 0;
11995 }
11996
11997 MEDCouplingUMeshCell::MEDCouplingUMeshCell(MEDCouplingUMesh *mesh):_conn(0),_conn_indx(0),_conn_lgth(NOTICABLE_FIRST_VAL)
11998 {
11999   if(mesh)
12000     {
12001       _conn=mesh->getNodalConnectivity()->getPointer();
12002       _conn_indx=mesh->getNodalConnectivityIndex()->getPointer();
12003     }
12004 }
12005
12006 void MEDCouplingUMeshCell::next()
12007 {
12008   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
12009     {
12010       _conn+=_conn_lgth;
12011       _conn_indx++;
12012     }
12013   _conn_lgth=_conn_indx[1]-_conn_indx[0];
12014 }
12015
12016 std::string MEDCouplingUMeshCell::repr() const
12017 {
12018   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
12019     {
12020       std::ostringstream oss; oss << "Cell Type " << INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)_conn[0]).getRepr();
12021       oss << " : ";
12022       std::copy(_conn+1,_conn+_conn_lgth,std::ostream_iterator<int>(oss," "));
12023       return oss.str();
12024     }
12025   else
12026     return std::string("MEDCouplingUMeshCell::repr : Invalid pos");
12027 }
12028
12029 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCell::getType() const
12030 {
12031   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
12032     return (INTERP_KERNEL::NormalizedCellType)_conn[0];
12033   else
12034     return INTERP_KERNEL::NORM_ERROR;
12035 }
12036
12037 const int *MEDCouplingUMeshCell::getAllConn(int& lgth) const
12038 {
12039   lgth=_conn_lgth;
12040   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
12041     return _conn;
12042   else
12043     return 0;
12044 }