1 // Copyright (C) 2007-2016 CEA/DEN, EDF R&D
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.
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.
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
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 // Author : Anthony Geay (CEA/DEN)
21 #include "MEDCouplingUMesh.hxx"
22 #include "MEDCoupling1GTUMesh.hxx"
23 #include "MEDCouplingFieldDouble.hxx"
24 #include "MEDCouplingSkyLineArray.hxx"
25 #include "CellModel.hxx"
26 #include "VolSurfUser.txx"
27 #include "InterpolationUtils.hxx"
28 #include "PointLocatorAlgos.txx"
30 #include "BBTreeDst.txx"
31 #include "SplitterTetra.hxx"
32 #include "DiameterCalculator.hxx"
33 #include "DirectedBoundingBox.hxx"
34 #include "InterpKernelMatrixTools.hxx"
35 #include "InterpKernelMeshQuality.hxx"
36 #include "InterpKernelCellSimplify.hxx"
37 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
38 #include "InterpKernelAutoPtr.hxx"
39 #include "InterpKernelGeo2DNode.hxx"
40 #include "InterpKernelGeo2DEdgeLin.hxx"
41 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
42 #include "InterpKernelGeo2DQuadraticPolygon.hxx"
51 using namespace MEDCoupling;
53 double MEDCouplingUMesh::EPS_FOR_POLYH_ORIENTATION=1.e-14;
56 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 };
57 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};
60 MEDCouplingUMesh *MEDCouplingUMesh::New()
62 return new MEDCouplingUMesh;
65 MEDCouplingUMesh *MEDCouplingUMesh::New(const std::string& meshName, int meshDim)
67 MEDCouplingUMesh *ret=new MEDCouplingUMesh;
68 ret->setName(meshName);
69 ret->setMeshDimension(meshDim);
74 * Returns a new MEDCouplingUMesh which is a full copy of \a this one. No data is shared
75 * between \a this and the new mesh.
76 * \return MEDCouplingUMesh * - a new instance of MEDCouplingMesh. The caller is to
77 * delete this mesh using decrRef() as it is no more needed.
79 MEDCouplingUMesh *MEDCouplingUMesh::deepCopy() const
86 * Returns a new MEDCouplingUMesh which is a copy of \a this one.
87 * \param [in] recDeepCpy - if \a true, the copy is deep, else all data arrays of \a
88 * this mesh are shared by the new mesh.
89 * \return MEDCouplingUMesh * - a new instance of MEDCouplingMesh. The caller is to
90 * delete this mesh using decrRef() as it is no more needed.
92 MEDCouplingUMesh *MEDCouplingUMesh::clone(bool recDeepCpy) const
94 return new MEDCouplingUMesh(*this,recDeepCpy);
98 * This method behaves mostly like MEDCouplingUMesh::deepCopy method, except that only nodal connectivity arrays are deeply copied.
99 * The coordinates are shared between \a this and the returned instance.
101 * \return MEDCouplingUMesh * - A new object instance holding the copy of \a this (deep for connectivity, shallow for coordiantes)
102 * \sa MEDCouplingUMesh::deepCopy
104 MEDCouplingUMesh *MEDCouplingUMesh::deepCopyConnectivityOnly() const
106 checkConnectivityFullyDefined();
107 MCAuto<MEDCouplingUMesh> ret=clone(false);
108 MCAuto<DataArrayInt> c(getNodalConnectivity()->deepCopy()),ci(getNodalConnectivityIndex()->deepCopy());
109 ret->setConnectivity(c,ci);
113 void MEDCouplingUMesh::shallowCopyConnectivityFrom(const MEDCouplingPointSet *other)
116 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is null !");
117 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
119 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is not an MEDCouplingUMesh instance !");
120 MEDCouplingUMesh *otherC2=const_cast<MEDCouplingUMesh *>(otherC);//sorry :(
121 setConnectivity(otherC2->getNodalConnectivity(),otherC2->getNodalConnectivityIndex(),true);
124 std::size_t MEDCouplingUMesh::getHeapMemorySizeWithoutChildren() const
126 std::size_t ret(MEDCouplingPointSet::getHeapMemorySizeWithoutChildren());
130 std::vector<const BigMemoryObject *> MEDCouplingUMesh::getDirectChildrenWithNull() const
132 std::vector<const BigMemoryObject *> ret(MEDCouplingPointSet::getDirectChildrenWithNull());
133 ret.push_back(_nodal_connec);
134 ret.push_back(_nodal_connec_index);
138 void MEDCouplingUMesh::updateTime() const
140 MEDCouplingPointSet::updateTime();
143 updateTimeWith(*_nodal_connec);
145 if(_nodal_connec_index)
147 updateTimeWith(*_nodal_connec_index);
151 MEDCouplingUMesh::MEDCouplingUMesh():_mesh_dim(-2),_nodal_connec(0),_nodal_connec_index(0)
156 * Checks if \a this mesh is well defined. If no exception is thrown by this method,
157 * then \a this mesh is most probably is writable, exchangeable and available for most
158 * of algorithms. When a mesh is constructed from scratch, it is a good habit to call
159 * this method to check that all is in order with \a this mesh.
160 * \throw If the mesh dimension is not set.
161 * \throw If the coordinates array is not set (if mesh dimension != -1 ).
162 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
163 * \throw If the connectivity data array has more than one component.
164 * \throw If the connectivity data array has a named component.
165 * \throw If the connectivity index data array has more than one component.
166 * \throw If the connectivity index data array has a named component.
168 void MEDCouplingUMesh::checkConsistencyLight() const
171 throw INTERP_KERNEL::Exception("No mesh dimension specified !");
173 MEDCouplingPointSet::checkConsistencyLight();
174 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
176 if((int)INTERP_KERNEL::CellModel::GetCellModel(*iter).getDimension()!=_mesh_dim)
178 std::ostringstream message;
179 message << "Mesh invalid because dimension is " << _mesh_dim << " and there is presence of cell(s) with type " << (*iter);
180 throw INTERP_KERNEL::Exception(message.str().c_str());
185 if(_nodal_connec->getNumberOfComponents()!=1)
186 throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to be with number of components set to one !");
187 if(_nodal_connec->getInfoOnComponent(0)!="")
188 throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to have no info on its single component !");
192 throw INTERP_KERNEL::Exception("Nodal connectivity array is not defined !");
193 if(_nodal_connec_index)
195 if(_nodal_connec_index->getNumberOfComponents()!=1)
196 throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to be with number of components set to one !");
197 if(_nodal_connec_index->getInfoOnComponent(0)!="")
198 throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to have no info on its single component !");
202 throw INTERP_KERNEL::Exception("Nodal connectivity index array is not defined !");
206 * Checks if \a this mesh is well defined. If no exception is thrown by this method,
207 * then \a this mesh is most probably is writable, exchangeable and available for all
208 * algorithms. <br> In addition to the checks performed by checkConsistencyLight(), this
209 * method thoroughly checks the nodal connectivity.
210 * \param [in] eps - a not used parameter.
211 * \throw If the mesh dimension is not set.
212 * \throw If the coordinates array is not set (if mesh dimension != -1 ).
213 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
214 * \throw If the connectivity data array has more than one component.
215 * \throw If the connectivity data array has a named component.
216 * \throw If the connectivity index data array has more than one component.
217 * \throw If the connectivity index data array has a named component.
218 * \throw If number of nodes defining an element does not correspond to the type of element.
219 * \throw If the nodal connectivity includes an invalid node id.
221 void MEDCouplingUMesh::checkConsistency(double eps) const
223 checkConsistencyLight();
226 int meshDim=getMeshDimension();
227 int nbOfNodes=getNumberOfNodes();
228 int nbOfCells=getNumberOfCells();
229 const int *ptr=_nodal_connec->getConstPointer();
230 const int *ptrI=_nodal_connec_index->getConstPointer();
231 for(int i=0;i<nbOfCells;i++)
233 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)ptr[ptrI[i]]);
234 if((int)cm.getDimension()!=meshDim)
236 std::ostringstream oss;
237 oss << "MEDCouplingUMesh::checkConsistency : cell << #" << i<< " with type Type " << cm.getRepr() << " in 'this' whereas meshdim == " << meshDim << " !";
238 throw INTERP_KERNEL::Exception(oss.str());
240 int nbOfNodesInCell=ptrI[i+1]-ptrI[i]-1;
242 if(nbOfNodesInCell!=(int)cm.getNumberOfNodes())
244 std::ostringstream oss;
245 oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with static Type '" << cm.getRepr() << "' has " << cm.getNumberOfNodes();
246 oss << " nodes whereas in connectivity there is " << nbOfNodesInCell << " nodes ! Looks very bad !";
247 throw INTERP_KERNEL::Exception(oss.str());
249 if(cm.isQuadratic() && cm.isDynamic() && meshDim == 2)
250 if (nbOfNodesInCell % 2 || nbOfNodesInCell < 4)
252 std::ostringstream oss;
253 oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with quadratic type '" << cm.getRepr() << "' has " << nbOfNodesInCell;
254 oss << " nodes. This should be even, and greater or equal than 4!! Looks very bad!";
255 throw INTERP_KERNEL::Exception(oss.str());
257 for(const int *w=ptr+ptrI[i]+1;w!=ptr+ptrI[i+1];w++)
262 if(nodeId>=nbOfNodes)
264 std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " whereas there are only " << nbOfNodes << " nodes in the mesh !";
265 throw INTERP_KERNEL::Exception(oss.str());
270 std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " in connectivity ! sounds bad !";
271 throw INTERP_KERNEL::Exception(oss.str());
275 if((INTERP_KERNEL::NormalizedCellType)(ptr[ptrI[i]])!=INTERP_KERNEL::NORM_POLYHED)
277 std::ostringstream oss; oss << "Cell #" << i << " is built with node #-1 in connectivity ! sounds bad !";
278 throw INTERP_KERNEL::Exception(oss.str());
286 * Sets dimension of \a this mesh. The mesh dimension in general depends on types of
287 * elements contained in the mesh. For more info on the mesh dimension see
288 * \ref MEDCouplingUMeshPage.
289 * \param [in] meshDim - a new mesh dimension.
290 * \throw If \a meshDim is invalid. A valid range is <em> -1 <= meshDim <= 3</em>.
292 void MEDCouplingUMesh::setMeshDimension(int meshDim)
294 if(meshDim<-1 || meshDim>3)
295 throw INTERP_KERNEL::Exception("Invalid meshDim specified ! Must be greater or equal to -1 and lower or equal to 3 !");
301 * Allocates memory to store an estimation of the given number of cells. The closer is the estimation to the number of cells effectively inserted,
302 * the less will the library need to reallocate memory. If the number of cells to be inserted is not known simply put 0 to this parameter.
303 * If a nodal connectivity previouly existed before the call of this method, it will be reset.
305 * \param [in] nbOfCells - estimation of the number of cell \a this mesh will contain.
307 * \if ENABLE_EXAMPLES
308 * \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
309 * \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
312 void MEDCouplingUMesh::allocateCells(int nbOfCells)
315 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::allocateCells : the input number of cells should be >= 0 !");
316 if(_nodal_connec_index)
318 _nodal_connec_index->decrRef();
322 _nodal_connec->decrRef();
324 _nodal_connec_index=DataArrayInt::New();
325 _nodal_connec_index->reserve(nbOfCells+1);
326 _nodal_connec_index->pushBackSilent(0);
327 _nodal_connec=DataArrayInt::New();
328 _nodal_connec->reserve(2*nbOfCells);
334 * Appends a cell to the connectivity array. For deeper understanding what is
335 * happening see \ref MEDCouplingUMeshNodalConnectivity.
336 * \param [in] type - type of cell to add.
337 * \param [in] size - number of nodes constituting this cell.
338 * \param [in] nodalConnOfCell - the connectivity of the cell to add.
340 * \if ENABLE_EXAMPLES
341 * \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
342 * \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
345 void MEDCouplingUMesh::insertNextCell(INTERP_KERNEL::NormalizedCellType type, int size, const int *nodalConnOfCell)
347 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
348 if(_nodal_connec_index==0)
349 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::insertNextCell : nodal connectivity not set ! invoke allocateCells before calling insertNextCell !");
350 if((int)cm.getDimension()==_mesh_dim)
353 if(size!=(int)cm.getNumberOfNodes())
355 std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : Trying to push a " << cm.getRepr() << " cell with a size of " << size;
356 oss << " ! Expecting " << cm.getNumberOfNodes() << " !";
357 throw INTERP_KERNEL::Exception(oss.str());
359 int idx=_nodal_connec_index->back();
361 _nodal_connec_index->pushBackSilent(val);
362 _nodal_connec->writeOnPlace(idx,type,nodalConnOfCell,size);
367 std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : cell type " << cm.getRepr() << " has a dimension " << cm.getDimension();
368 oss << " whereas Mesh Dimension of current UMesh instance is set to " << _mesh_dim << " ! Please invoke \"setMeshDimension\" method before or invoke ";
369 oss << "\"MEDCouplingUMesh::New\" static method with 2 parameters name and meshDimension !";
370 throw INTERP_KERNEL::Exception(oss.str());
375 * Compacts data arrays to release unused memory. This method is to be called after
376 * finishing cell insertion using \a this->insertNextCell().
378 * \if ENABLE_EXAMPLES
379 * \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
380 * \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
383 void MEDCouplingUMesh::finishInsertingCells()
385 _nodal_connec->pack();
386 _nodal_connec_index->pack();
387 _nodal_connec->declareAsNew();
388 _nodal_connec_index->declareAsNew();
393 * Entry point for iteration over cells of this. Warning the returned cell iterator should be deallocated.
394 * Useful for python users.
396 MEDCouplingUMeshCellIterator *MEDCouplingUMesh::cellIterator()
398 return new MEDCouplingUMeshCellIterator(this);
402 * Entry point for iteration over cells groups geo types per geotypes. Warning the returned cell iterator should be deallocated.
403 * If \a this is not so that that cells are grouped by geo types this method will throw an exception.
404 * In this case MEDCouplingUMesh::sortCellsInMEDFileFrmt or MEDCouplingUMesh::rearrange2ConsecutiveCellTypes methods for example can be called before invoking this method.
405 * Useful for python users.
407 MEDCouplingUMeshCellByTypeEntry *MEDCouplingUMesh::cellsByType()
409 if(!checkConsecutiveCellTypes())
410 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::cellsByType : this mesh is not sorted by type !");
411 return new MEDCouplingUMeshCellByTypeEntry(this);
415 * Returns a set of all cell types available in \a this mesh.
416 * \return std::set<INTERP_KERNEL::NormalizedCellType> - the set of cell types.
417 * \warning this method does not throw any exception even if \a this is not defined.
418 * \sa MEDCouplingUMesh::getAllGeoTypesSorted
420 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypes() const
426 * This method returns the sorted list of geometric types in \a this.
427 * Sorted means in the same order than the cells in \a this. A single entry in return vector means the maximal chunk of consecutive cells in \a this
428 * having the same geometric type. So a same geometric type can appear more than once if the cells are not sorted per geometric type.
430 * \throw if connectivity in \a this is not correctly defined.
432 * \sa MEDCouplingMesh::getAllGeoTypes
434 std::vector<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypesSorted() const
436 std::vector<INTERP_KERNEL::NormalizedCellType> ret;
437 checkConnectivityFullyDefined();
438 int nbOfCells(getNumberOfCells());
441 if(getNodalConnectivityArrayLen()<1)
442 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAllGeoTypesSorted : the connectivity in this seems invalid !");
443 const int *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin());
444 ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci++]);
445 for(int i=1;i<nbOfCells;i++,ci++)
446 if(ret.back()!=((INTERP_KERNEL::NormalizedCellType)c[*ci]))
447 ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci]);
452 * This method is a method that compares \a this and \a other.
453 * This method compares \b all attributes, even names and component names.
455 bool MEDCouplingUMesh::isEqualIfNotWhy(const MEDCouplingMesh *other, double prec, std::string& reason) const
458 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isEqualIfNotWhy : input other pointer is null !");
459 std::ostringstream oss; oss.precision(15);
460 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
463 reason="mesh given in input is not castable in MEDCouplingUMesh !";
466 if(!MEDCouplingPointSet::isEqualIfNotWhy(other,prec,reason))
468 if(_mesh_dim!=otherC->_mesh_dim)
470 oss << "umesh dimension mismatch : this mesh dimension=" << _mesh_dim << " other mesh dimension=" << otherC->_mesh_dim;
474 if(_types!=otherC->_types)
476 oss << "umesh geometric type mismatch :\nThis geometric types are :";
477 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
478 { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
479 oss << "\nOther geometric types are :";
480 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=otherC->_types.begin();iter!=otherC->_types.end();iter++)
481 { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
485 if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
486 if(_nodal_connec==0 || otherC->_nodal_connec==0)
488 reason="Only one UMesh between the two this and other has its nodal connectivity DataArrayInt defined !";
491 if(_nodal_connec!=otherC->_nodal_connec)
492 if(!_nodal_connec->isEqualIfNotWhy(*otherC->_nodal_connec,reason))
494 reason.insert(0,"Nodal connectivity DataArrayInt differ : ");
497 if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
498 if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
500 reason="Only one UMesh between the two this and other has its nodal connectivity index DataArrayInt defined !";
503 if(_nodal_connec_index!=otherC->_nodal_connec_index)
504 if(!_nodal_connec_index->isEqualIfNotWhy(*otherC->_nodal_connec_index,reason))
506 reason.insert(0,"Nodal connectivity index DataArrayInt differ : ");
513 * Checks if data arrays of this mesh (node coordinates, nodal
514 * connectivity of cells, etc) of two meshes are same. Textual data like name etc. are
516 * \param [in] other - the mesh to compare with.
517 * \param [in] prec - precision value used to compare node coordinates.
518 * \return bool - \a true if the two meshes are same.
520 bool MEDCouplingUMesh::isEqualWithoutConsideringStr(const MEDCouplingMesh *other, double prec) const
522 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
525 if(!MEDCouplingPointSet::isEqualWithoutConsideringStr(other,prec))
527 if(_mesh_dim!=otherC->_mesh_dim)
529 if(_types!=otherC->_types)
531 if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
532 if(_nodal_connec==0 || otherC->_nodal_connec==0)
534 if(_nodal_connec!=otherC->_nodal_connec)
535 if(!_nodal_connec->isEqualWithoutConsideringStr(*otherC->_nodal_connec))
537 if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
538 if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
540 if(_nodal_connec_index!=otherC->_nodal_connec_index)
541 if(!_nodal_connec_index->isEqualWithoutConsideringStr(*otherC->_nodal_connec_index))
547 * Checks if \a this and \a other meshes are geometrically equivalent with high
548 * probability, else an exception is thrown. The meshes are considered equivalent if
549 * (1) meshes contain the same number of nodes and the same number of elements of the
550 * same types (2) three cells of the two meshes (first, last and middle) are based
551 * on coincident nodes (with a specified precision).
552 * \param [in] other - the mesh to compare with.
553 * \param [in] prec - the precision used to compare nodes of the two meshes.
554 * \throw If the two meshes do not match.
556 void MEDCouplingUMesh::checkFastEquivalWith(const MEDCouplingMesh *other, double prec) const
558 MEDCouplingPointSet::checkFastEquivalWith(other,prec);
559 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
561 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkFastEquivalWith : Two meshes are not not unstructured !");
565 * Returns the reverse nodal connectivity. The reverse nodal connectivity enumerates
566 * cells each node belongs to.
567 * \warning For speed reasons, this method does not check if node ids in the nodal
568 * connectivity correspond to the size of node coordinates array.
569 * \param [in,out] revNodal - an array holding ids of cells sharing each node.
570 * \param [in,out] revNodalIndx - an array, of length \a this->getNumberOfNodes() + 1,
571 * dividing cell ids in \a revNodal into groups each referring to one
572 * node. Its every element (except the last one) is an index pointing to the
573 * first id of a group of cells. For example cells sharing the node #1 are
574 * described by following range of indices:
575 * [ \a revNodalIndx[1], \a revNodalIndx[2] ) and the cell ids are
576 * \a revNodal[ \a revNodalIndx[1] ], \a revNodal[ \a revNodalIndx[1] + 1], ...
577 * Number of cells sharing the *i*-th node is
578 * \a revNodalIndx[ *i*+1 ] - \a revNodalIndx[ *i* ].
579 * \throw If the coordinates array is not set.
580 * \throw If the nodal connectivity of cells is not defined.
582 * \if ENABLE_EXAMPLES
583 * \ref cpp_mcumesh_getReverseNodalConnectivity "Here is a C++ example".<br>
584 * \ref py_mcumesh_getReverseNodalConnectivity "Here is a Python example".
587 void MEDCouplingUMesh::getReverseNodalConnectivity(DataArrayInt *revNodal, DataArrayInt *revNodalIndx) const
590 int nbOfNodes=getNumberOfNodes();
591 int *revNodalIndxPtr=(int *)malloc((nbOfNodes+1)*sizeof(int));
592 revNodalIndx->useArray(revNodalIndxPtr,true,C_DEALLOC,nbOfNodes+1,1);
593 std::fill(revNodalIndxPtr,revNodalIndxPtr+nbOfNodes+1,0);
594 const int *conn=_nodal_connec->getConstPointer();
595 const int *connIndex=_nodal_connec_index->getConstPointer();
596 int nbOfCells=getNumberOfCells();
597 int nbOfEltsInRevNodal=0;
598 for(int eltId=0;eltId<nbOfCells;eltId++)
600 const int *strtNdlConnOfCurCell=conn+connIndex[eltId]+1;
601 const int *endNdlConnOfCurCell=conn+connIndex[eltId+1];
602 for(const int *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
603 if(*iter>=0)//for polyhedrons
605 nbOfEltsInRevNodal++;
606 revNodalIndxPtr[(*iter)+1]++;
609 std::transform(revNodalIndxPtr+1,revNodalIndxPtr+nbOfNodes+1,revNodalIndxPtr,revNodalIndxPtr+1,std::plus<int>());
610 int *revNodalPtr=(int *)malloc((nbOfEltsInRevNodal)*sizeof(int));
611 revNodal->useArray(revNodalPtr,true,C_DEALLOC,nbOfEltsInRevNodal,1);
612 std::fill(revNodalPtr,revNodalPtr+nbOfEltsInRevNodal,-1);
613 for(int eltId=0;eltId<nbOfCells;eltId++)
615 const int *strtNdlConnOfCurCell=conn+connIndex[eltId]+1;
616 const int *endNdlConnOfCurCell=conn+connIndex[eltId+1];
617 for(const int *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
618 if(*iter>=0)//for polyhedrons
619 *std::find_if(revNodalPtr+revNodalIndxPtr[*iter],revNodalPtr+revNodalIndxPtr[*iter+1],std::bind2nd(std::equal_to<int>(),-1))=eltId;
625 int MEDCouplingFastNbrer(int id, unsigned nb, const INTERP_KERNEL::CellModel& cm, bool compute, const int *conn1, const int *conn2)
630 int MEDCouplingOrientationSensitiveNbrer(int id, unsigned nb, const INTERP_KERNEL::CellModel& cm, bool compute, const int *conn1, const int *conn2)
636 if(cm.getOrientationStatus(nb,conn1,conn2))
643 class MinusOneSonsGenerator
646 MinusOneSonsGenerator(const INTERP_KERNEL::CellModel& cm):_cm(cm) { }
647 unsigned getNumberOfSons2(const int *conn, int lgth) const { return _cm.getNumberOfSons2(conn,lgth); }
648 unsigned fillSonCellNodalConnectivity2(int sonId, const int *nodalConn, int lgth, int *sonNodalConn, INTERP_KERNEL::NormalizedCellType& typeOfSon) const { return _cm.fillSonCellNodalConnectivity2(sonId,nodalConn,lgth,sonNodalConn,typeOfSon); }
649 static const int DELTA=1;
651 const INTERP_KERNEL::CellModel& _cm;
654 class MinusOneSonsGeneratorBiQuadratic
657 MinusOneSonsGeneratorBiQuadratic(const INTERP_KERNEL::CellModel& cm):_cm(cm) { }
658 unsigned getNumberOfSons2(const int *conn, int lgth) const { return _cm.getNumberOfSons2(conn,lgth); }
659 unsigned fillSonCellNodalConnectivity2(int sonId, const int *nodalConn, int lgth, int *sonNodalConn, INTERP_KERNEL::NormalizedCellType& typeOfSon) const { return _cm.fillSonCellNodalConnectivity4(sonId,nodalConn,lgth,sonNodalConn,typeOfSon); }
660 static const int DELTA=1;
662 const INTERP_KERNEL::CellModel& _cm;
665 class MinusTwoSonsGenerator
668 MinusTwoSonsGenerator(const INTERP_KERNEL::CellModel& cm):_cm(cm) { }
669 unsigned getNumberOfSons2(const int *conn, int lgth) const { return _cm.getNumberOfEdgesIn3D(conn,lgth); }
670 unsigned fillSonCellNodalConnectivity2(int sonId, const int *nodalConn, int lgth, int *sonNodalConn, INTERP_KERNEL::NormalizedCellType& typeOfSon) const { return _cm.fillSonEdgesNodalConnectivity3D(sonId,nodalConn,lgth,sonNodalConn,typeOfSon); }
671 static const int DELTA=2;
673 const INTERP_KERNEL::CellModel& _cm;
676 class MicroEdgesGenerator2D
679 MicroEdgesGenerator2D(const INTERP_KERNEL::CellModel& cm):_cm(cm) { }
680 unsigned getNumberOfSons2(const int *conn, int lgth) const { return _cm.getNumberOfMicroEdges(); }
681 unsigned fillSonCellNodalConnectivity2(int sonId, const int *nodalConn, int lgth, int *sonNodalConn, INTERP_KERNEL::NormalizedCellType& typeOfSon) const { return _cm.fillMicroEdgeNodalConnectivity(sonId,nodalConn,sonNodalConn,typeOfSon); }
682 static const int DELTA=1;
684 const INTERP_KERNEL::CellModel& _cm;
687 class MicroEdgesGenerator3D
690 MicroEdgesGenerator3D(const INTERP_KERNEL::CellModel& cm):_cm(cm) { }
691 unsigned getNumberOfSons2(const int *conn, int lgth) const { return _cm.getNumberOfMicroEdges(); }
692 unsigned fillSonCellNodalConnectivity2(int sonId, const int *nodalConn, int lgth, int *sonNodalConn, INTERP_KERNEL::NormalizedCellType& typeOfSon) const { return _cm.fillMicroEdgeNodalConnectivity(sonId,nodalConn,sonNodalConn,typeOfSon); }
693 static const int DELTA=2;
695 const INTERP_KERNEL::CellModel& _cm;
701 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
702 * this->getMeshDimension(), that bound cells of \a this mesh. In addition arrays
703 * describing correspondence between cells of \a this and the result meshes are
704 * returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending connectivity,
705 * i.e. enumerate cells of the result mesh bounding each cell of \a this mesh. The
706 * arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
707 * i.e. enumerate cells of \a this mesh bounded by each cell of the result mesh.
708 * \warning For speed reasons, this method does not check if node ids in the nodal
709 * connectivity correspond to the size of node coordinates array.
710 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
711 * to write this mesh to the MED file, its cells must be sorted using
712 * sortCellsInMEDFileFrmt().
713 * \param [in,out] desc - the array containing cell ids of the result mesh bounding
714 * each cell of \a this mesh.
715 * \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
716 * dividing cell ids in \a desc into groups each referring to one
717 * cell of \a this mesh. Its every element (except the last one) is an index
718 * pointing to the first id of a group of cells. For example cells of the
719 * result mesh bounding the cell #1 of \a this mesh are described by following
721 * [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
722 * \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
723 * Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
724 * \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
725 * \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
726 * by each cell of the result mesh.
727 * \param [in,out] revDescIndx - the array, of length one more than number of cells
728 * in the result mesh,
729 * dividing cell ids in \a revDesc into groups each referring to one
730 * cell of the result mesh the same way as \a descIndx divides \a desc.
731 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is to
732 * delete this mesh using decrRef() as it is no more needed.
733 * \throw If the coordinates array is not set.
734 * \throw If the nodal connectivity of cells is node defined.
735 * \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
736 * revDescIndx == NULL.
738 * \if ENABLE_EXAMPLES
739 * \ref cpp_mcumesh_buildDescendingConnectivity "Here is a C++ example".<br>
740 * \ref py_mcumesh_buildDescendingConnectivity "Here is a Python example".
742 * \sa buildDescendingConnectivity2()
744 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
746 return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
750 * \a this has to have a mesh dimension equal to 3. If it is not the case an INTERP_KERNEL::Exception will be thrown.
751 * This behaves exactly as MEDCouplingUMesh::buildDescendingConnectivity does except that this method compute directly the transition from mesh dimension 3 to sub edges (dimension 1)
752 * in one shot. That is to say that this method is equivalent to 2 successive calls to MEDCouplingUMesh::buildDescendingConnectivity.
753 * This method returns 4 arrays and a mesh as MEDCouplingUMesh::buildDescendingConnectivity does.
754 * \sa MEDCouplingUMesh::buildDescendingConnectivity
756 MEDCouplingUMesh *MEDCouplingUMesh::explode3DMeshTo1D(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
759 if(getMeshDimension()!=3)
760 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explode3DMeshTo1D : This has to have a mesh dimension to 3 !");
761 return buildDescendingConnectivityGen<MinusTwoSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
765 * 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.
766 * This method works for both meshes with mesh dimenstion equal to 2 or 3. Dynamical cells are not supported (polygons, polyhedrons...)
768 * \sa explode3DMeshTo1D, buildDescendingConnectiviy
770 MEDCouplingUMesh *MEDCouplingUMesh::explodeMeshIntoMicroEdges(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
773 switch(getMeshDimension())
776 return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
778 return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
780 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explodeMeshIntoMicroEdges : Only 2D and 3D supported !");
785 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
786 * this->getMeshDimension(), that bound cells of \a this mesh. In
787 * addition arrays describing correspondence between cells of \a this and the result
788 * meshes are returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending
789 * connectivity, i.e. enumerate cells of the result mesh bounding each cell of \a this
790 * mesh. This method differs from buildDescendingConnectivity() in that apart
791 * from cell ids, \a desc returns mutual orientation of cells in \a this and the
792 * result meshes. So a positive id means that order of nodes in corresponding cells
793 * of two meshes is same, and a negative id means a reverse order of nodes. Since a
794 * cell with id #0 can't be negative, the array \a desc returns ids in FORTRAN mode,
795 * i.e. cell ids are one-based.
796 * Arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
797 * i.e. enumerate cells of \a this mesh bounded by each cell of the result mesh.
798 * \warning For speed reasons, this method does not check if node ids in the nodal
799 * connectivity correspond to the size of node coordinates array.
800 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
801 * to write this mesh to the MED file, its cells must be sorted using
802 * sortCellsInMEDFileFrmt().
803 * \param [in,out] desc - the array containing cell ids of the result mesh bounding
804 * each cell of \a this mesh.
805 * \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
806 * dividing cell ids in \a desc into groups each referring to one
807 * cell of \a this mesh. Its every element (except the last one) is an index
808 * pointing to the first id of a group of cells. For example cells of the
809 * result mesh bounding the cell #1 of \a this mesh are described by following
811 * [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
812 * \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
813 * Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
814 * \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
815 * \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
816 * by each cell of the result mesh.
817 * \param [in,out] revDescIndx - the array, of length one more than number of cells
818 * in the result mesh,
819 * dividing cell ids in \a revDesc into groups each referring to one
820 * cell of the result mesh the same way as \a descIndx divides \a desc.
821 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This result mesh
822 * shares the node coordinates array with \a this mesh. The caller is to
823 * delete this mesh using decrRef() as it is no more needed.
824 * \throw If the coordinates array is not set.
825 * \throw If the nodal connectivity of cells is node defined.
826 * \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
827 * revDescIndx == NULL.
829 * \if ENABLE_EXAMPLES
830 * \ref cpp_mcumesh_buildDescendingConnectivity2 "Here is a C++ example".<br>
831 * \ref py_mcumesh_buildDescendingConnectivity2 "Here is a Python example".
833 * \sa buildDescendingConnectivity()
835 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity2(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
837 return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingOrientationSensitiveNbrer);
841 * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
842 * For speed reasons no check of this will be done. This method calls
843 * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
844 * This method lists cell by cell in \b this which are its neighbors. To compute the result
845 * only connectivities are considered.
846 * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
847 * The format of return is hence \ref numbering-indirect.
849 * \param [out] neighbors is an array storing all the neighbors of all cells in \b this. This array is newly
850 * allocated and should be dealt by the caller. \b neighborsIndx 2nd output
851 * parameter allows to select the right part in this array (\ref numbering-indirect). The number of tuples
852 * is equal to the last values in \b neighborsIndx.
853 * \param [out] neighborsIndx is an array of size this->getNumberOfCells()+1 newly allocated and should be
854 * dealt by the caller. This arrays allow to use the first output parameter \b neighbors (\ref numbering-indirect).
856 void MEDCouplingUMesh::computeNeighborsOfCells(DataArrayInt *&neighbors, DataArrayInt *&neighborsIndx) const
858 MCAuto<DataArrayInt> desc=DataArrayInt::New();
859 MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
860 MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
861 MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
862 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
864 ComputeNeighborsOfCellsAdv(desc,descIndx,revDesc,revDescIndx,neighbors,neighborsIndx);
867 void MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne(const DataArrayInt *nodeNeigh, const DataArrayInt *nodeNeighI, MCAuto<DataArrayInt>& cellNeigh, MCAuto<DataArrayInt>& cellNeighIndex) const
869 if(!nodeNeigh || !nodeNeighI)
870 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : null pointer !");
871 checkConsistencyLight();
872 nodeNeigh->checkAllocated(); nodeNeighI->checkAllocated();
873 nodeNeigh->checkNbOfComps(1,"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : node neigh");
874 nodeNeighI->checkNbOfComps(1,"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : node neigh index");
875 nodeNeighI->checkNbOfTuples(1+getNumberOfNodes(),"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : invalid length");
876 int nbCells(getNumberOfCells());
877 const int *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin()),*ne(nodeNeigh->begin()),*nei(nodeNeighI->begin());
878 cellNeigh=DataArrayInt::New(); cellNeigh->alloc(0,1); cellNeighIndex=DataArrayInt::New(); cellNeighIndex->alloc(1,1); cellNeighIndex->setIJ(0,0,0);
879 for(int i=0;i<nbCells;i++)
882 for(const int *it=c+ci[i]+1;it!=c+ci[i+1];it++)
884 s.insert(ne+nei[*it],ne+nei[*it+1]);
886 cellNeigh->insertAtTheEnd(s.begin(),s.end());
887 cellNeighIndex->pushBackSilent(cellNeigh->getNumberOfTuples());
892 * This method is called by MEDCouplingUMesh::computeNeighborsOfCells. This methods performs the algorithm
893 * of MEDCouplingUMesh::computeNeighborsOfCells.
894 * This method is useful for users that want to reduce along a criterion the set of neighbours cell. This is
895 * typically the case to extract a set a neighbours,
896 * excluding a set of meshdim-1 cells in input descending connectivity.
897 * Typically \b desc, \b descIndx, \b revDesc and \b revDescIndx (\ref numbering-indirect) input params are
898 * the result of MEDCouplingUMesh::buildDescendingConnectivity.
899 * This method lists cell by cell in \b this which are its neighbors. To compute the result only connectivities
901 * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
903 * \param [in] desc descending connectivity array.
904 * \param [in] descIndx descending connectivity index array used to walk through \b desc (\ref numbering-indirect).
905 * \param [in] revDesc reverse descending connectivity array.
906 * \param [in] revDescIndx reverse descending connectivity index array used to walk through \b revDesc (\ref numbering-indirect).
907 * \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
908 * parameter allows to select the right part in this array. The number of tuples is equal to the last values in \b neighborsIndx.
909 * \param [out] neighborsIndx is an array of size this->getNumberOfCells()+1 newly allocated and should be dealt by the caller. This arrays allow to use the first output parameter \b neighbors.
911 void MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(const DataArrayInt *desc, const DataArrayInt *descIndx, const DataArrayInt *revDesc, const DataArrayInt *revDescIndx,
912 DataArrayInt *&neighbors, DataArrayInt *&neighborsIndx)
914 if(!desc || !descIndx || !revDesc || !revDescIndx)
915 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeNeighborsOfCellsAdv some input array is empty !");
916 const int *descPtr=desc->getConstPointer();
917 const int *descIPtr=descIndx->getConstPointer();
918 const int *revDescPtr=revDesc->getConstPointer();
919 const int *revDescIPtr=revDescIndx->getConstPointer();
921 int nbCells=descIndx->getNumberOfTuples()-1;
922 MCAuto<DataArrayInt> out0=DataArrayInt::New();
923 MCAuto<DataArrayInt> out1=DataArrayInt::New(); out1->alloc(nbCells+1,1);
924 int *out1Ptr=out1->getPointer();
926 out0->reserve(desc->getNumberOfTuples());
927 for(int i=0;i<nbCells;i++,descIPtr++,out1Ptr++)
929 for(const int *w1=descPtr+descIPtr[0];w1!=descPtr+descIPtr[1];w1++)
931 std::set<int> s(revDescPtr+revDescIPtr[*w1],revDescPtr+revDescIPtr[(*w1)+1]);
933 out0->insertAtTheEnd(s.begin(),s.end());
935 *out1Ptr=out0->getNumberOfTuples();
937 neighbors=out0.retn();
938 neighborsIndx=out1.retn();
942 * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
943 * For speed reasons no check of this will be done. This method calls
944 * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
945 * This method lists node by node in \b this which are its neighbors. To compute the result
946 * only connectivities are considered.
947 * The neighbor nodes of node having id 'nodeId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
949 * \param [out] neighbors is an array storing all the neighbors of all nodes in \b this. This array
950 * is newly allocated and should be dealt by the caller. \b neighborsIndx 2nd output
951 * parameter allows to select the right part in this array (\ref numbering-indirect).
952 * The number of tuples is equal to the last values in \b neighborsIndx.
953 * \param [out] neighborsIdx is an array of size this->getNumberOfCells()+1 newly allocated and should
954 * be dealt by the caller. This arrays allow to use the first output parameter \b neighbors.
956 void MEDCouplingUMesh::computeNeighborsOfNodes(DataArrayInt *&neighbors, DataArrayInt *&neighborsIdx) const
959 int mdim(getMeshDimension()),nbNodes(getNumberOfNodes());
960 MCAuto<DataArrayInt> desc(DataArrayInt::New()),descIndx(DataArrayInt::New()),revDesc(DataArrayInt::New()),revDescIndx(DataArrayInt::New());
961 MCAuto<MEDCouplingUMesh> mesh1D;
966 mesh1D=explode3DMeshTo1D(desc,descIndx,revDesc,revDescIndx);
971 mesh1D=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
976 mesh1D=const_cast<MEDCouplingUMesh *>(this);
982 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2,1] !");
985 desc=DataArrayInt::New(); descIndx=DataArrayInt::New(); revDesc=0; revDescIndx=0;
986 mesh1D->getReverseNodalConnectivity(desc,descIndx);
987 MCAuto<DataArrayInt> ret0(DataArrayInt::New());
988 ret0->alloc(desc->getNumberOfTuples(),1);
989 int *r0Pt(ret0->getPointer());
990 const int *c1DPtr(mesh1D->getNodalConnectivity()->begin()),*rn(desc->begin()),*rni(descIndx->begin());
991 for(int i=0;i<nbNodes;i++,rni++)
993 for(const int *oneDCellIt=rn+rni[0];oneDCellIt!=rn+rni[1];oneDCellIt++)
994 *r0Pt++=c1DPtr[3*(*oneDCellIt)+1]==i?c1DPtr[3*(*oneDCellIt)+2]:c1DPtr[3*(*oneDCellIt)+1];
996 neighbors=ret0.retn();
997 neighborsIdx=descIndx.retn();
1003 * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
1004 * For speed reasons no check of this will be done.
1006 template<class SonsGenerator>
1007 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivityGen(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx, DimM1DescNbrer nbrer) const
1009 if(!desc || !descIndx || !revDesc || !revDescIndx)
1010 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildDescendingConnectivityGen : present of a null pointer in input !");
1011 checkConnectivityFullyDefined();
1012 int nbOfCells=getNumberOfCells();
1013 int nbOfNodes=getNumberOfNodes();
1014 MCAuto<DataArrayInt> revNodalIndx=DataArrayInt::New(); revNodalIndx->alloc(nbOfNodes+1,1); revNodalIndx->fillWithZero();
1015 int *revNodalIndxPtr=revNodalIndx->getPointer();
1016 const int *conn=_nodal_connec->getConstPointer();
1017 const int *connIndex=_nodal_connec_index->getConstPointer();
1018 std::string name="Mesh constituent of "; name+=getName();
1019 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(name,getMeshDimension()-SonsGenerator::DELTA);
1020 ret->setCoords(getCoords());
1021 ret->allocateCells(2*nbOfCells);
1022 descIndx->alloc(nbOfCells+1,1);
1023 MCAuto<DataArrayInt> revDesc2(DataArrayInt::New()); revDesc2->reserve(2*nbOfCells);
1024 int *descIndxPtr=descIndx->getPointer(); *descIndxPtr++=0;
1025 for(int eltId=0;eltId<nbOfCells;eltId++,descIndxPtr++)
1027 int pos=connIndex[eltId];
1028 int posP1=connIndex[eltId+1];
1029 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[pos]);
1030 SonsGenerator sg(cm);
1031 unsigned nbOfSons=sg.getNumberOfSons2(conn+pos+1,posP1-pos-1);
1032 INTERP_KERNEL::AutoPtr<int> tmp=new int[posP1-pos];
1033 for(unsigned i=0;i<nbOfSons;i++)
1035 INTERP_KERNEL::NormalizedCellType cmsId;
1036 unsigned nbOfNodesSon=sg.fillSonCellNodalConnectivity2(i,conn+pos+1,posP1-pos-1,tmp,cmsId);
1037 for(unsigned k=0;k<nbOfNodesSon;k++)
1039 revNodalIndxPtr[tmp[k]+1]++;
1040 ret->insertNextCell(cmsId,nbOfNodesSon,tmp);
1041 revDesc2->pushBackSilent(eltId);
1043 descIndxPtr[0]=descIndxPtr[-1]+(int)nbOfSons;
1045 int nbOfCellsM1=ret->getNumberOfCells();
1046 std::transform(revNodalIndxPtr+1,revNodalIndxPtr+nbOfNodes+1,revNodalIndxPtr,revNodalIndxPtr+1,std::plus<int>());
1047 MCAuto<DataArrayInt> revNodal=DataArrayInt::New(); revNodal->alloc(revNodalIndx->back(),1);
1048 std::fill(revNodal->getPointer(),revNodal->getPointer()+revNodalIndx->back(),-1);
1049 int *revNodalPtr=revNodal->getPointer();
1050 const int *connM1=ret->getNodalConnectivity()->getConstPointer();
1051 const int *connIndexM1=ret->getNodalConnectivityIndex()->getConstPointer();
1052 for(int eltId=0;eltId<nbOfCellsM1;eltId++)
1054 const int *strtNdlConnOfCurCell=connM1+connIndexM1[eltId]+1;
1055 const int *endNdlConnOfCurCell=connM1+connIndexM1[eltId+1];
1056 for(const int *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
1057 if(*iter>=0)//for polyhedrons
1058 *std::find_if(revNodalPtr+revNodalIndxPtr[*iter],revNodalPtr+revNodalIndxPtr[*iter+1],std::bind2nd(std::equal_to<int>(),-1))=eltId;
1061 DataArrayInt *commonCells=0,*commonCellsI=0;
1062 FindCommonCellsAlg(3,0,ret->getNodalConnectivity(),ret->getNodalConnectivityIndex(),revNodal,revNodalIndx,commonCells,commonCellsI);
1063 MCAuto<DataArrayInt> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1064 const int *commonCellsPtr(commonCells->getConstPointer()),*commonCellsIPtr(commonCellsI->getConstPointer());
1065 int newNbOfCellsM1=-1;
1066 MCAuto<DataArrayInt> o2nM1=DataArrayInt::ConvertIndexArrayToO2N(nbOfCellsM1,commonCells->begin(),
1067 commonCellsI->begin(),commonCellsI->end(),newNbOfCellsM1);
1068 std::vector<bool> isImpacted(nbOfCellsM1,false);
1069 for(const int *work=commonCellsI->begin();work!=commonCellsI->end()-1;work++)
1070 for(int work2=work[0];work2!=work[1];work2++)
1071 isImpacted[commonCellsPtr[work2]]=true;
1072 const int *o2nM1Ptr=o2nM1->getConstPointer();
1073 MCAuto<DataArrayInt> n2oM1=o2nM1->invertArrayO2N2N2OBis(newNbOfCellsM1);
1074 const int *n2oM1Ptr=n2oM1->getConstPointer();
1075 MCAuto<MEDCouplingUMesh> ret2=static_cast<MEDCouplingUMesh *>(ret->buildPartOfMySelf(n2oM1->begin(),n2oM1->end(),true));
1076 ret2->copyTinyInfoFrom(this);
1077 desc->alloc(descIndx->back(),1);
1078 int *descPtr=desc->getPointer();
1079 const INTERP_KERNEL::CellModel& cmsDft=INTERP_KERNEL::CellModel::GetCellModel(INTERP_KERNEL::NORM_POINT1);
1080 for(int i=0;i<nbOfCellsM1;i++,descPtr++)
1083 *descPtr=nbrer(o2nM1Ptr[i],0,cmsDft,false,0,0);
1086 if(i!=n2oM1Ptr[o2nM1Ptr[i]])
1088 const INTERP_KERNEL::CellModel& cms=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connM1[connIndexM1[i]]);
1089 *descPtr=nbrer(o2nM1Ptr[i],connIndexM1[i+1]-connIndexM1[i]-1,cms,true,connM1+connIndexM1[n2oM1Ptr[o2nM1Ptr[i]]]+1,connM1+connIndexM1[i]+1);
1092 *descPtr=nbrer(o2nM1Ptr[i],0,cmsDft,false,0,0);
1095 revDesc->reserve(newNbOfCellsM1);
1096 revDescIndx->alloc(newNbOfCellsM1+1,1);
1097 int *revDescIndxPtr=revDescIndx->getPointer(); *revDescIndxPtr++=0;
1098 const int *revDesc2Ptr=revDesc2->getConstPointer();
1099 for(int i=0;i<newNbOfCellsM1;i++,revDescIndxPtr++)
1101 int oldCellIdM1=n2oM1Ptr[i];
1102 if(!isImpacted[oldCellIdM1])
1104 revDesc->pushBackSilent(revDesc2Ptr[oldCellIdM1]);
1105 revDescIndxPtr[0]=revDescIndxPtr[-1]+1;
1109 for(int j=commonCellsIPtr[0];j<commonCellsIPtr[1];j++)
1110 revDesc->pushBackSilent(revDesc2Ptr[commonCellsPtr[j]]);
1111 revDescIndxPtr[0]=revDescIndxPtr[-1]+commonCellsIPtr[1]-commonCellsIPtr[0];
1119 struct MEDCouplingAccVisit
1121 MEDCouplingAccVisit():_new_nb_of_nodes(0) { }
1122 int operator()(int val) { if(val!=-1) return _new_nb_of_nodes++; else return -1; }
1123 int _new_nb_of_nodes;
1129 * Converts specified cells to either polygons (if \a this is a 2D mesh) or
1130 * polyhedrons (if \a this is a 3D mesh). The cells to convert are specified by an
1131 * array of cell ids. Pay attention that after conversion all algorithms work slower
1132 * with \a this mesh than before conversion. <br> If an exception is thrown during the
1133 * conversion due presence of invalid ids in the array of cells to convert, as a
1134 * result \a this mesh contains some already converted elements. In this case the 2D
1135 * mesh remains valid but 3D mesh becomes \b inconsistent!
1136 * \warning This method can significantly modify the order of geometric types in \a this,
1137 * hence, to write this mesh to the MED file, its cells must be sorted using
1138 * sortCellsInMEDFileFrmt().
1139 * \param [in] cellIdsToConvertBg - the array holding ids of cells to convert.
1140 * \param [in] cellIdsToConvertEnd - a pointer to the last-plus-one-th element of \a
1141 * cellIdsToConvertBg.
1142 * \throw If the coordinates array is not set.
1143 * \throw If the nodal connectivity of cells is node defined.
1144 * \throw If dimension of \a this mesh is not either 2 or 3.
1146 * \if ENABLE_EXAMPLES
1147 * \ref cpp_mcumesh_convertToPolyTypes "Here is a C++ example".<br>
1148 * \ref py_mcumesh_convertToPolyTypes "Here is a Python example".
1151 void MEDCouplingUMesh::convertToPolyTypes(const int *cellIdsToConvertBg, const int *cellIdsToConvertEnd)
1153 checkFullyDefined();
1154 int dim=getMeshDimension();
1156 throw INTERP_KERNEL::Exception("Invalid mesh dimension : must be 2 or 3 !");
1157 int nbOfCells(getNumberOfCells());
1160 const int *connIndex=_nodal_connec_index->getConstPointer();
1161 int *conn=_nodal_connec->getPointer();
1162 for(const int *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1164 if(*iter>=0 && *iter<nbOfCells)
1166 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*iter]]);
1167 if(!cm.isQuadratic())
1168 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_POLYGON;
1170 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_QPOLYG;
1174 std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1175 oss << " in range [0," << nbOfCells << ") !";
1176 throw INTERP_KERNEL::Exception(oss.str());
1182 int *connIndex(_nodal_connec_index->getPointer());
1183 const int *connOld(_nodal_connec->getConstPointer());
1184 MCAuto<DataArrayInt> connNew(DataArrayInt::New()),connNewI(DataArrayInt::New()); connNew->alloc(0,1); connNewI->alloc(1,1); connNewI->setIJ(0,0,0);
1185 std::vector<bool> toBeDone(nbOfCells,false);
1186 for(const int *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1188 if(*iter>=0 && *iter<nbOfCells)
1189 toBeDone[*iter]=true;
1192 std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1193 oss << " in range [0," << nbOfCells << ") !";
1194 throw INTERP_KERNEL::Exception(oss.str());
1197 for(int cellId=0;cellId<nbOfCells;cellId++)
1199 int pos(connIndex[cellId]),posP1(connIndex[cellId+1]);
1200 int lgthOld(posP1-pos-1);
1201 if(toBeDone[cellId])
1203 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connOld[pos]);
1204 unsigned nbOfFaces(cm.getNumberOfSons2(connOld+pos+1,lgthOld));
1205 int *tmp(new int[nbOfFaces*lgthOld+1]);
1206 int *work=tmp; *work++=INTERP_KERNEL::NORM_POLYHED;
1207 for(unsigned j=0;j<nbOfFaces;j++)
1209 INTERP_KERNEL::NormalizedCellType type;
1210 unsigned offset=cm.fillSonCellNodalConnectivity2(j,connOld+pos+1,lgthOld,work,type);
1214 std::size_t newLgth(std::distance(tmp,work)-1);//-1 for last -1
1215 connNew->pushBackValsSilent(tmp,tmp+newLgth);
1216 connNewI->pushBackSilent(connNewI->back()+(int)newLgth);
1221 connNew->pushBackValsSilent(connOld+pos,connOld+posP1);
1222 connNewI->pushBackSilent(connNewI->back()+posP1-pos);
1225 setConnectivity(connNew,connNewI,false);//false because computeTypes called just behind.
1231 * Converts all cells to either polygons (if \a this is a 2D mesh) or
1232 * polyhedrons (if \a this is a 3D mesh).
1233 * \warning As this method is purely for user-friendliness and no optimization is
1234 * done to avoid construction of a useless vector, this method can be costly
1236 * \throw If the coordinates array is not set.
1237 * \throw If the nodal connectivity of cells is node defined.
1238 * \throw If dimension of \a this mesh is not either 2 or 3.
1240 void MEDCouplingUMesh::convertAllToPoly()
1242 int nbOfCells=getNumberOfCells();
1243 std::vector<int> cellIds(nbOfCells);
1244 for(int i=0;i<nbOfCells;i++)
1246 convertToPolyTypes(&cellIds[0],&cellIds[0]+cellIds.size());
1250 * Fixes nodal connectivity of invalid cells of type NORM_POLYHED. This method
1251 * expects that all NORM_POLYHED cells have connectivity similar to that of prismatic
1252 * volumes like NORM_HEXA8, NORM_PENTA6 etc., i.e. the first half of nodes describes a
1253 * base facet of the volume and the second half of nodes describes an opposite facet
1254 * having the same number of nodes as the base one. This method converts such
1255 * connectivity to a valid polyhedral format where connectivity of each facet is
1256 * explicitly described and connectivity of facets are separated by -1. If \a this mesh
1257 * contains a NORM_POLYHED cell with a valid connectivity, or an invalid connectivity is
1258 * not as expected, an exception is thrown and the mesh remains unchanged. Care of
1259 * a correct orientation of the first facet of a polyhedron, else orientation of a
1260 * corrected cell is reverse.<br>
1261 * This method is useful to build an extruded unstructured mesh with polyhedrons as
1262 * it releases the user from boring description of polyhedra connectivity in the valid
1264 * \throw If \a this->getMeshDimension() != 3.
1265 * \throw If \a this->getSpaceDimension() != 3.
1266 * \throw If the nodal connectivity of cells is not defined.
1267 * \throw If the coordinates array is not set.
1268 * \throw If \a this mesh contains polyhedrons with the valid connectivity.
1269 * \throw If \a this mesh contains polyhedrons with odd number of nodes.
1271 * \if ENABLE_EXAMPLES
1272 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
1273 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
1276 void MEDCouplingUMesh::convertExtrudedPolyhedra()
1278 checkFullyDefined();
1279 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1280 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertExtrudedPolyhedra works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
1281 int nbOfCells=getNumberOfCells();
1282 MCAuto<DataArrayInt> newCi=DataArrayInt::New();
1283 newCi->alloc(nbOfCells+1,1);
1284 int *newci=newCi->getPointer();
1285 const int *ci=_nodal_connec_index->getConstPointer();
1286 const int *c=_nodal_connec->getConstPointer();
1288 for(int i=0;i<nbOfCells;i++)
1290 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1291 if(type==INTERP_KERNEL::NORM_POLYHED)
1293 if(std::count(c+ci[i]+1,c+ci[i+1],-1)!=0)
1295 std::ostringstream oss; oss << "MEDCouplingUMesh::convertExtrudedPolyhedra : cell # " << i << " is a polhedron BUT it has NOT exactly 1 face !";
1296 throw INTERP_KERNEL::Exception(oss.str());
1298 std::size_t n2=std::distance(c+ci[i]+1,c+ci[i+1]);
1301 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 !";
1302 throw INTERP_KERNEL::Exception(oss.str());
1305 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)
1308 newci[i+1]=(ci[i+1]-ci[i])+newci[i];
1310 MCAuto<DataArrayInt> newC=DataArrayInt::New();
1311 newC->alloc(newci[nbOfCells],1);
1312 int *newc=newC->getPointer();
1313 for(int i=0;i<nbOfCells;i++)
1315 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1316 if(type==INTERP_KERNEL::NORM_POLYHED)
1318 std::size_t n1=std::distance(c+ci[i]+1,c+ci[i+1])/2;
1319 newc=std::copy(c+ci[i],c+ci[i]+n1+1,newc);
1321 for(std::size_t j=0;j<n1;j++)
1323 newc[j]=c[ci[i]+1+n1+(n1-j)%n1];
1325 newc[n1+5*j+1]=c[ci[i]+1+j];
1326 newc[n1+5*j+2]=c[ci[i]+1+j+n1];
1327 newc[n1+5*j+3]=c[ci[i]+1+(j+1)%n1+n1];
1328 newc[n1+5*j+4]=c[ci[i]+1+(j+1)%n1];
1333 newc=std::copy(c+ci[i],c+ci[i+1],newc);
1335 _nodal_connec_index->decrRef(); _nodal_connec_index=newCi.retn();
1336 _nodal_connec->decrRef(); _nodal_connec=newC.retn();
1341 * Converts all polygons (if \a this is a 2D mesh) or polyhedrons (if \a this is a 3D
1342 * mesh) to cells of classical types. This method is opposite to convertToPolyTypes().
1343 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
1344 * to write this mesh to the MED file, its cells must be sorted using
1345 * sortCellsInMEDFileFrmt().
1346 * \warning Cells (and most notably polyhedrons) must be correctly oriented for this to work
1347 * properly. See orientCorrectlyPolyhedrons() and arePolyhedronsNotCorrectlyOriented().
1348 * \return \c true if at least one cell has been converted, \c false else. In the
1349 * last case the nodal connectivity remains unchanged.
1350 * \throw If the coordinates array is not set.
1351 * \throw If the nodal connectivity of cells is not defined.
1352 * \throw If \a this->getMeshDimension() < 0.
1354 bool MEDCouplingUMesh::unPolyze()
1356 checkFullyDefined();
1357 int mdim=getMeshDimension();
1359 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::unPolyze works on umeshes with meshdim equals to 0, 1 2 or 3 !");
1362 int nbOfCells=getNumberOfCells();
1365 int initMeshLgth=getNodalConnectivityArrayLen();
1366 int *conn=_nodal_connec->getPointer();
1367 int *index=_nodal_connec_index->getPointer();
1372 for(int i=0;i<nbOfCells;i++)
1374 lgthOfCurCell=index[i+1]-posOfCurCell;
1375 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
1376 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
1377 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::NORM_ERROR;
1381 switch(cm.getDimension())
1385 INTERP_KERNEL::AutoPtr<int> tmp=new int[lgthOfCurCell-1];
1386 std::copy(conn+posOfCurCell+1,conn+posOfCurCell+lgthOfCurCell,(int *)tmp);
1387 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly2D(cm.isQuadratic(),tmp,lgthOfCurCell-1,conn+newPos+1,newLgth);
1392 int nbOfFaces,lgthOfPolyhConn;
1393 INTERP_KERNEL::AutoPtr<int> zipFullReprOfPolyh=INTERP_KERNEL::CellSimplify::getFullPolyh3DCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,nbOfFaces,lgthOfPolyhConn);
1394 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly3D(zipFullReprOfPolyh,nbOfFaces,lgthOfPolyhConn,conn+newPos+1,newLgth);
1399 newType=(lgthOfCurCell==3)?INTERP_KERNEL::NORM_SEG2:INTERP_KERNEL::NORM_POLYL;
1403 ret=ret || (newType!=type);
1404 conn[newPos]=newType;
1406 posOfCurCell=index[i+1];
1411 std::copy(conn+posOfCurCell,conn+posOfCurCell+lgthOfCurCell,conn+newPos);
1412 newPos+=lgthOfCurCell;
1413 posOfCurCell+=lgthOfCurCell;
1417 if(newPos!=initMeshLgth)
1418 _nodal_connec->reAlloc(newPos);
1425 * This method expects that spaceDimension is equal to 3 and meshDimension equal to 3.
1426 * This method performs operation only on polyhedrons in \b this. If no polyhedrons exists in \b this, \b this remains unchanged.
1427 * This method allows to merge if any coplanar 3DSurf cells that may appear in some polyhedrons cells.
1429 * \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
1432 void MEDCouplingUMesh::simplifyPolyhedra(double eps)
1434 checkFullyDefined();
1435 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1436 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplifyPolyhedra : works on meshdimension 3 and spaceDimension 3 !");
1437 MCAuto<DataArrayDouble> coords=getCoords()->deepCopy();
1438 coords->recenterForMaxPrecision(eps);
1440 int nbOfCells=getNumberOfCells();
1441 const int *conn=_nodal_connec->getConstPointer();
1442 const int *index=_nodal_connec_index->getConstPointer();
1443 MCAuto<DataArrayInt> connINew=DataArrayInt::New();
1444 connINew->alloc(nbOfCells+1,1);
1445 int *connINewPtr=connINew->getPointer(); *connINewPtr++=0;
1446 MCAuto<DataArrayInt> connNew=DataArrayInt::New(); connNew->alloc(0,1);
1448 for(int i=0;i<nbOfCells;i++,connINewPtr++)
1450 if(conn[index[i]]==(int)INTERP_KERNEL::NORM_POLYHED)
1452 SimplifyPolyhedronCell(eps,coords,conn+index[i],conn+index[i+1],connNew);
1456 connNew->insertAtTheEnd(conn+index[i],conn+index[i+1]);
1457 *connINewPtr=connNew->getNumberOfTuples();
1460 setConnectivity(connNew,connINew,false);
1464 * This method returns all node ids used in the connectivity of \b this. The data array returned has to be dealt by the caller.
1465 * The returned node ids are sorted ascendingly. This method is close to MEDCouplingUMesh::getNodeIdsInUse except
1466 * the format of the returned DataArrayInt instance.
1468 * \return a newly allocated DataArrayInt sorted ascendingly of fetched node ids.
1469 * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1471 DataArrayInt *MEDCouplingUMesh::computeFetchedNodeIds() const
1473 checkConnectivityFullyDefined();
1474 const int *maxEltPt(std::max_element(_nodal_connec->begin(),_nodal_connec->end()));
1475 int maxElt(maxEltPt==_nodal_connec->end()?0:std::abs(*maxEltPt)+1);
1476 std::vector<bool> retS(maxElt,false);
1477 computeNodeIdsAlg(retS);
1478 return DataArrayInt::BuildListOfSwitchedOn(retS);
1482 * \param [in,out] nodeIdsInUse an array of size typically equal to nbOfNodes.
1483 * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1485 void MEDCouplingUMesh::computeNodeIdsAlg(std::vector<bool>& nodeIdsInUse) const
1487 int nbOfNodes((int)nodeIdsInUse.size()),nbOfCells(getNumberOfCells());
1488 const int *connIndex(_nodal_connec_index->getConstPointer()),*conn(_nodal_connec->getConstPointer());
1489 for(int i=0;i<nbOfCells;i++)
1490 for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1493 if(conn[j]<nbOfNodes)
1494 nodeIdsInUse[conn[j]]=true;
1497 std::ostringstream oss; oss << "MEDCouplingUMesh::computeNodeIdsAlg : In cell #" << i << " presence of node id " << conn[j] << " not in [0," << nbOfNodes << ") !";
1498 throw INTERP_KERNEL::Exception(oss.str());
1504 * Finds nodes not used in any cell and returns an array giving a new id to every node
1505 * by excluding the unused nodes, for which the array holds -1. The result array is
1506 * a mapping in "Old to New" mode.
1507 * \param [out] nbrOfNodesInUse - number of node ids present in the nodal connectivity.
1508 * \return DataArrayInt * - a new instance of DataArrayInt. Its length is \a
1509 * this->getNumberOfNodes(). It holds for each node of \a this mesh either -1
1510 * if the node is unused or a new id else. The caller is to delete this
1511 * array using decrRef() as it is no more needed.
1512 * \throw If the coordinates array is not set.
1513 * \throw If the nodal connectivity of cells is not defined.
1514 * \throw If the nodal connectivity includes an invalid id.
1516 * \if ENABLE_EXAMPLES
1517 * \ref cpp_mcumesh_getNodeIdsInUse "Here is a C++ example".<br>
1518 * \ref py_mcumesh_getNodeIdsInUse "Here is a Python example".
1520 * \sa computeFetchedNodeIds, computeNodeIdsAlg()
1522 DataArrayInt *MEDCouplingUMesh::getNodeIdsInUse(int& nbrOfNodesInUse) const
1525 int nbOfNodes(getNumberOfNodes());
1526 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1527 ret->alloc(nbOfNodes,1);
1528 int *traducer=ret->getPointer();
1529 std::fill(traducer,traducer+nbOfNodes,-1);
1530 int nbOfCells=getNumberOfCells();
1531 const int *connIndex=_nodal_connec_index->getConstPointer();
1532 const int *conn=_nodal_connec->getConstPointer();
1533 for(int i=0;i<nbOfCells;i++)
1534 for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1537 if(conn[j]<nbOfNodes)
1538 traducer[conn[j]]=1;
1541 std::ostringstream oss; oss << "MEDCouplingUMesh::getNodeIdsInUse : In cell #" << i << " presence of node id " << conn[j] << " not in [0," << nbOfNodes << ") !";
1542 throw INTERP_KERNEL::Exception(oss.str());
1545 nbrOfNodesInUse=(int)std::count(traducer,traducer+nbOfNodes,1);
1546 std::transform(traducer,traducer+nbOfNodes,traducer,MEDCouplingAccVisit());
1551 * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1552 * For each cell in \b this the number of nodes constituting cell is computed.
1553 * For each polyhedron cell, the sum of the number of nodes of each face constituting polyhedron cell is returned.
1554 * So for pohyhedrons some nodes can be counted several times in the returned result.
1556 * \return a newly allocated array
1557 * \sa MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell
1559 DataArrayInt *MEDCouplingUMesh::computeNbOfNodesPerCell() const
1561 checkConnectivityFullyDefined();
1562 int nbOfCells=getNumberOfCells();
1563 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1564 ret->alloc(nbOfCells,1);
1565 int *retPtr=ret->getPointer();
1566 const int *conn=getNodalConnectivity()->getConstPointer();
1567 const int *connI=getNodalConnectivityIndex()->getConstPointer();
1568 for(int i=0;i<nbOfCells;i++,retPtr++)
1570 if(conn[connI[i]]!=(int)INTERP_KERNEL::NORM_POLYHED)
1571 *retPtr=connI[i+1]-connI[i]-1;
1573 *retPtr=connI[i+1]-connI[i]-1-std::count(conn+connI[i]+1,conn+connI[i+1],-1);
1579 * This method computes effective number of nodes per cell. That is to say nodes appearing several times in nodal connectivity of a cell,
1580 * will be counted only once here whereas it will be counted several times in MEDCouplingUMesh::computeNbOfNodesPerCell method.
1582 * \return DataArrayInt * - new object to be deallocated by the caller.
1583 * \sa MEDCouplingUMesh::computeNbOfNodesPerCell
1585 DataArrayInt *MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell() const
1587 checkConnectivityFullyDefined();
1588 int nbOfCells=getNumberOfCells();
1589 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1590 ret->alloc(nbOfCells,1);
1591 int *retPtr=ret->getPointer();
1592 const int *conn=getNodalConnectivity()->getConstPointer();
1593 const int *connI=getNodalConnectivityIndex()->getConstPointer();
1594 for(int i=0;i<nbOfCells;i++,retPtr++)
1596 std::set<int> s(conn+connI[i]+1,conn+connI[i+1]);
1597 if(conn[connI[i]]!=(int)INTERP_KERNEL::NORM_POLYHED)
1598 *retPtr=(int)s.size();
1602 *retPtr=(int)s.size();
1609 * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1610 * For each cell in \b this the number of faces constituting (entity of dimension this->getMeshDimension()-1) cell is computed.
1612 * \return a newly allocated array
1614 DataArrayInt *MEDCouplingUMesh::computeNbOfFacesPerCell() const
1616 checkConnectivityFullyDefined();
1617 int nbOfCells=getNumberOfCells();
1618 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1619 ret->alloc(nbOfCells,1);
1620 int *retPtr=ret->getPointer();
1621 const int *conn=getNodalConnectivity()->getConstPointer();
1622 const int *connI=getNodalConnectivityIndex()->getConstPointer();
1623 for(int i=0;i<nbOfCells;i++,retPtr++,connI++)
1625 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]);
1626 *retPtr=cm.getNumberOfSons2(conn+connI[0]+1,connI[1]-connI[0]-1);
1632 * Removes unused nodes (the node coordinates array is shorten) and returns an array
1633 * mapping between new and old node ids in "Old to New" mode. -1 values in the returned
1634 * array mean that the corresponding old node is no more used.
1635 * \return DataArrayInt * - a new instance of DataArrayInt of length \a
1636 * this->getNumberOfNodes() before call of this method. The caller is to
1637 * delete this array using decrRef() as it is no more needed.
1638 * \throw If the coordinates array is not set.
1639 * \throw If the nodal connectivity of cells is not defined.
1640 * \throw If the nodal connectivity includes an invalid id.
1641 * \sa areAllNodesFetched
1643 * \if ENABLE_EXAMPLES
1644 * \ref cpp_mcumesh_zipCoordsTraducer "Here is a C++ example".<br>
1645 * \ref py_mcumesh_zipCoordsTraducer "Here is a Python example".
1648 DataArrayInt *MEDCouplingUMesh::zipCoordsTraducer()
1650 return MEDCouplingPointSet::zipCoordsTraducer();
1654 * This method stands if 'cell1' and 'cell2' are equals regarding 'compType' policy.
1655 * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1657 int MEDCouplingUMesh::AreCellsEqual(const int *conn, const int *connI, int cell1, int cell2, int compType)
1662 return AreCellsEqualPolicy0(conn,connI,cell1,cell2);
1664 return AreCellsEqualPolicy1(conn,connI,cell1,cell2);
1666 return AreCellsEqualPolicy2(conn,connI,cell1,cell2);
1668 return AreCellsEqualPolicy2NoType(conn,connI,cell1,cell2);
1670 return AreCellsEqualPolicy7(conn,connI,cell1,cell2);
1672 throw INTERP_KERNEL::Exception("Unknown comparison asked ! Must be in 0,1,2,3 or 7.");
1676 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 0.
1678 int MEDCouplingUMesh::AreCellsEqualPolicy0(const int *conn, const int *connI, int cell1, int cell2)
1680 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1681 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;
1686 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 1.
1688 int MEDCouplingUMesh::AreCellsEqualPolicy1(const int *conn, const int *connI, int cell1, int cell2)
1690 int sz=connI[cell1+1]-connI[cell1];
1691 if(sz==connI[cell2+1]-connI[cell2])
1693 if(conn[connI[cell1]]==conn[connI[cell2]])
1695 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1696 unsigned dim=cm.getDimension();
1702 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz1];
1703 int *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(int *)tmp);
1704 std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1705 work=std::search((int *)tmp,(int *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1706 return work!=tmp+sz1?1:0;
1709 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;//case of SEG2 and SEG3
1712 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy1 : not implemented yet for meshdim == 3 !");
1719 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 2.
1721 int MEDCouplingUMesh::AreCellsEqualPolicy2(const int *conn, const int *connI, int cell1, int cell2)
1723 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1725 if(conn[connI[cell1]]==conn[connI[cell2]])
1727 std::set<int> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1728 std::set<int> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1736 * This method is less restrictive than AreCellsEqualPolicy2. Here the geometric type is absolutely not taken into account !
1738 int MEDCouplingUMesh::AreCellsEqualPolicy2NoType(const int *conn, const int *connI, int cell1, int cell2)
1740 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1742 std::set<int> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1743 std::set<int> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1750 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 7.
1752 int MEDCouplingUMesh::AreCellsEqualPolicy7(const int *conn, const int *connI, int cell1, int cell2)
1754 int sz=connI[cell1+1]-connI[cell1];
1755 if(sz==connI[cell2+1]-connI[cell2])
1757 if(conn[connI[cell1]]==conn[connI[cell2]])
1759 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1760 unsigned dim=cm.getDimension();
1766 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz1];
1767 int *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(int *)tmp);
1768 std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1769 work=std::search((int *)tmp,(int *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1774 std::reverse_iterator<int *> it1((int *)tmp+sz1);
1775 std::reverse_iterator<int *> it2((int *)tmp);
1776 if(std::search(it1,it2,conn+connI[cell2]+1,conn+connI[cell2+1])!=it2)
1782 return work!=tmp+sz1?1:0;
1785 {//case of SEG2 and SEG3
1786 if(std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1))
1788 if(!cm.isQuadratic())
1790 std::reverse_iterator<const int *> it1(conn+connI[cell1+1]);
1791 std::reverse_iterator<const int *> it2(conn+connI[cell1]+1);
1792 if(std::equal(it1,it2,conn+connI[cell2]+1))
1798 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])
1805 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy7 : not implemented yet for meshdim == 3 !");
1812 * This method find in candidate pool defined by 'candidates' the cells equal following the polycy 'compType'.
1813 * If any true is returned and the results will be put at the end of 'result' output parameter. If not false is returned
1814 * and result remains unchanged.
1815 * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1816 * If in 'candidates' pool -1 value is considered as an empty value.
1817 * WARNING this method returns only ONE set of result !
1819 bool MEDCouplingUMesh::AreCellsEqualInPool(const std::vector<int>& candidates, int compType, const int *conn, const int *connI, DataArrayInt *result)
1821 if(candidates.size()<1)
1824 std::vector<int>::const_iterator iter=candidates.begin();
1825 int start=(*iter++);
1826 for(;iter!=candidates.end();iter++)
1828 int status=AreCellsEqual(conn,connI,start,*iter,compType);
1833 result->pushBackSilent(start);
1837 result->pushBackSilent(*iter);
1839 result->pushBackSilent(status==2?(*iter+1):-(*iter+1));
1846 * This method find cells that are equal (regarding \a compType) in \a this. The comparison is specified
1848 * This method keeps the coordiantes of \a this. This method is time consuming.
1850 * \param [in] compType input specifying the technique used to compare cells each other.
1851 * - 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.
1852 * - 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)
1853 * and their type equal. For 1D mesh the policy 1 is equivalent to 0.
1854 * - 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
1855 * can be used for users not sensitive to orientation of cell
1856 * \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.
1857 * \param [out] commonCellsArr common cells ids (\ref numbering-indirect)
1858 * \param [out] commonCellsIArr common cells ids (\ref numbering-indirect)
1859 * \return the correspondance array old to new in a newly allocated array.
1862 void MEDCouplingUMesh::findCommonCells(int compType, int startCellId, DataArrayInt *& commonCellsArr, DataArrayInt *& commonCellsIArr) const
1864 MCAuto<DataArrayInt> revNodal=DataArrayInt::New(),revNodalI=DataArrayInt::New();
1865 getReverseNodalConnectivity(revNodal,revNodalI);
1866 FindCommonCellsAlg(compType,startCellId,_nodal_connec,_nodal_connec_index,revNodal,revNodalI,commonCellsArr,commonCellsIArr);
1869 void MEDCouplingUMesh::FindCommonCellsAlg(int compType, int startCellId, const DataArrayInt *nodal, const DataArrayInt *nodalI, const DataArrayInt *revNodal, const DataArrayInt *revNodalI,
1870 DataArrayInt *& commonCellsArr, DataArrayInt *& commonCellsIArr)
1872 MCAuto<DataArrayInt> commonCells=DataArrayInt::New(),commonCellsI=DataArrayInt::New(); commonCells->alloc(0,1);
1873 int nbOfCells=nodalI->getNumberOfTuples()-1;
1874 commonCellsI->reserve(1); commonCellsI->pushBackSilent(0);
1875 const int *revNodalPtr=revNodal->getConstPointer(),*revNodalIPtr=revNodalI->getConstPointer();
1876 const int *connPtr=nodal->getConstPointer(),*connIPtr=nodalI->getConstPointer();
1877 std::vector<bool> isFetched(nbOfCells,false);
1880 for(int i=0;i<nbOfCells;i++)
1884 const int *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind2nd(std::not_equal_to<int>(),-1));
1885 std::vector<int> v,v2;
1886 if(connOfNode!=connPtr+connIPtr[i+1])
1888 const int *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1889 v2.insert(v2.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1]);
1892 for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1896 const int *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1897 std::vector<int>::iterator it=std::set_intersection(v.begin(),v.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1898 v2.resize(std::distance(v2.begin(),it));
1902 if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1904 int pos=commonCellsI->back();
1905 commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1906 for(const int *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1907 isFetched[*it]=true;
1915 for(int i=startCellId;i<nbOfCells;i++)
1919 const int *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind2nd(std::not_equal_to<int>(),-1));
1920 std::vector<int> v,v2;
1921 if(connOfNode!=connPtr+connIPtr[i+1])
1923 v2.insert(v2.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1]);
1926 for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1930 std::vector<int>::iterator it=std::set_intersection(v.begin(),v.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1931 v2.resize(std::distance(v2.begin(),it));
1935 if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1937 int pos=commonCellsI->back();
1938 commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1939 for(const int *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1940 isFetched[*it]=true;
1946 commonCellsArr=commonCells.retn();
1947 commonCellsIArr=commonCellsI.retn();
1951 * Checks if \a this mesh includes all cells of an \a other mesh, and returns an array
1952 * giving for each cell of the \a other an id of a cell in \a this mesh. A value larger
1953 * than \a this->getNumberOfCells() in the returned array means that there is no
1954 * corresponding cell in \a this mesh.
1955 * It is expected that \a this and \a other meshes share the same node coordinates
1956 * array, if it is not so an exception is thrown.
1957 * \param [in] other - the mesh to compare with.
1958 * \param [in] compType - specifies a cell comparison technique. For meaning of its
1959 * valid values [0,1,2], see zipConnectivityTraducer().
1960 * \param [out] arr - a new instance of DataArrayInt returning correspondence
1961 * between cells of the two meshes. It contains \a other->getNumberOfCells()
1962 * values. The caller is to delete this array using
1963 * decrRef() as it is no more needed.
1964 * \return bool - \c true if all cells of \a other mesh are present in the \a this
1967 * \if ENABLE_EXAMPLES
1968 * \ref cpp_mcumesh_areCellsIncludedIn "Here is a C++ example".<br>
1969 * \ref py_mcumesh_areCellsIncludedIn "Here is a Python example".
1971 * \sa checkDeepEquivalOnSameNodesWith()
1972 * \sa checkGeoEquivalWith()
1974 bool MEDCouplingUMesh::areCellsIncludedIn(const MEDCouplingUMesh *other, int compType, DataArrayInt *& arr) const
1976 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1977 int nbOfCells=getNumberOfCells();
1978 static const int possibleCompType[]={0,1,2};
1979 if(std::find(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),compType)==possibleCompType+sizeof(possibleCompType)/sizeof(int))
1981 std::ostringstream oss; oss << "MEDCouplingUMesh::areCellsIncludedIn : only following policies are possible : ";
1982 std::copy(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),std::ostream_iterator<int>(oss," "));
1984 throw INTERP_KERNEL::Exception(oss.str());
1986 MCAuto<DataArrayInt> o2n=mesh->zipConnectivityTraducer(compType,nbOfCells);
1987 arr=o2n->subArray(nbOfCells);
1988 arr->setName(other->getName());
1990 if(other->getNumberOfCells()==0)
1992 return arr->getMaxValue(tmp)<nbOfCells;
1996 * This method makes the assumption that \a this and \a other share the same coords. If not an exception will be thrown !
1997 * This method tries to determine if \b other is fully included in \b this.
1998 * The main difference is that this method is not expected to throw exception.
1999 * This method has two outputs :
2001 * \param other other mesh
2002 * \param arr is an output parameter that returns a \b newly created instance. This array is of size 'other->getNumberOfCells()'.
2003 * \return If \a other is fully included in 'this 'true is returned. If not false is returned.
2005 bool MEDCouplingUMesh::areCellsIncludedInPolicy7(const MEDCouplingUMesh *other, DataArrayInt *& arr) const
2007 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
2008 DataArrayInt *commonCells=0,*commonCellsI=0;
2009 int thisNbCells=getNumberOfCells();
2010 mesh->findCommonCells(7,thisNbCells,commonCells,commonCellsI);
2011 MCAuto<DataArrayInt> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
2012 const int *commonCellsPtr=commonCells->getConstPointer(),*commonCellsIPtr=commonCellsI->getConstPointer();
2013 int otherNbCells=other->getNumberOfCells();
2014 MCAuto<DataArrayInt> arr2=DataArrayInt::New();
2015 arr2->alloc(otherNbCells,1);
2016 arr2->fillWithZero();
2017 int *arr2Ptr=arr2->getPointer();
2018 int nbOfCommon=commonCellsI->getNumberOfTuples()-1;
2019 for(int i=0;i<nbOfCommon;i++)
2021 int start=commonCellsPtr[commonCellsIPtr[i]];
2022 if(start<thisNbCells)
2024 for(int j=commonCellsIPtr[i]+1;j!=commonCellsIPtr[i+1];j++)
2026 int sig=commonCellsPtr[j]>0?1:-1;
2027 int val=std::abs(commonCellsPtr[j])-1;
2028 if(val>=thisNbCells)
2029 arr2Ptr[val-thisNbCells]=sig*(start+1);
2033 arr2->setName(other->getName());
2034 if(arr2->presenceOfValue(0))
2040 MEDCouplingUMesh *MEDCouplingUMesh::mergeMyselfWithOnSameCoords(const MEDCouplingPointSet *other) const
2043 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : input other is null !");
2044 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
2046 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : the input other mesh is not of type unstructured !");
2047 std::vector<const MEDCouplingUMesh *> ms(2);
2050 return MergeUMeshesOnSameCoords(ms);
2054 * Build a sub part of \b this lying or not on the same coordinates than \b this (regarding value of \b keepCoords).
2055 * By default coordinates are kept. This method is close to MEDCouplingUMesh::buildPartOfMySelf except that here input
2056 * cellIds is not given explicitely but by a range python like.
2061 * \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.
2062 * \return a newly allocated
2064 * \warning This method modifies can generate an unstructured mesh whose cells are not sorted by geometric type order.
2065 * In view of the MED file writing, a renumbering of cells of returned unstructured mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
2067 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfSlice(int start, int end, int step, bool keepCoords) const
2069 if(getMeshDimension()!=-1)
2070 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelfSlice(start,end,step,keepCoords));
2073 int newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfSlice for -1 dimension mesh ");
2075 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
2077 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
2079 return const_cast<MEDCouplingUMesh *>(this);
2084 * Creates a new MEDCouplingUMesh containing specified cells of \a this mesh.
2085 * The result mesh shares or not the node coordinates array with \a this mesh depending
2086 * on \a keepCoords parameter.
2087 * \warning Cells of the result mesh can be \b not sorted by geometric type, hence,
2088 * to write this mesh to the MED file, its cells must be sorted using
2089 * sortCellsInMEDFileFrmt().
2090 * \param [in] begin - an array of cell ids to include to the new mesh.
2091 * \param [in] end - a pointer to last-plus-one-th element of \a begin.
2092 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2093 * array of \a this mesh, else "free" nodes are removed from the result mesh
2094 * by calling zipCoords().
2095 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2096 * to delete this mesh using decrRef() as it is no more needed.
2097 * \throw If the coordinates array is not set.
2098 * \throw If the nodal connectivity of cells is not defined.
2099 * \throw If any cell id in the array \a begin is not valid.
2101 * \if ENABLE_EXAMPLES
2102 * \ref cpp_mcumesh_buildPartOfMySelf "Here is a C++ example".<br>
2103 * \ref py_mcumesh_buildPartOfMySelf "Here is a Python example".
2106 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelf(const int *begin, const int *end, bool keepCoords) const
2108 if(getMeshDimension()!=-1)
2109 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelf(begin,end,keepCoords));
2113 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
2115 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
2117 return const_cast<MEDCouplingUMesh *>(this);
2122 * This method operates only on nodal connectivity on \b this. Coordinates of \b this is completely ignored here.
2124 * 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.
2125 * Size of [ \b cellIdsBg, \b cellIdsEnd ) ) must be equal to the number of cells of otherOnSameCoordsThanThis.
2126 * The number of cells of \b this will remain the same with this method.
2128 * \param [in] cellIdsBg begin of cell ids (included) of cells in this to assign
2129 * \param [in] cellIdsEnd end of cell ids (excluded) of cells in this to assign
2130 * \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 ).
2131 * Coordinate pointer of \b this and those of \b otherOnSameCoordsThanThis must be the same
2133 void MEDCouplingUMesh::setPartOfMySelf(const int *cellIdsBg, const int *cellIdsEnd, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2135 checkConnectivityFullyDefined();
2136 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2137 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2138 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelf : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2139 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2141 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2142 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2143 throw INTERP_KERNEL::Exception(oss.str());
2145 int nbOfCellsToModify=(int)std::distance(cellIdsBg,cellIdsEnd);
2146 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2148 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2149 throw INTERP_KERNEL::Exception(oss.str());
2151 int nbOfCells=getNumberOfCells();
2152 bool easyAssign=true;
2153 const int *connI=_nodal_connec_index->getConstPointer();
2154 const int *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2155 for(const int *it=cellIdsBg;it!=cellIdsEnd && easyAssign;it++,connIOther++)
2157 if(*it>=0 && *it<nbOfCells)
2159 easyAssign=(connIOther[1]-connIOther[0])==(connI[*it+1]-connI[*it]);
2163 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : On pos #" << std::distance(cellIdsBg,it) << " id is equal to " << *it << " which is not in [0," << nbOfCells << ") !";
2164 throw INTERP_KERNEL::Exception(oss.str());
2169 MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2174 DataArrayInt *arrOut=0,*arrIOut=0;
2175 MEDCouplingUMesh::SetPartOfIndexedArrays(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2177 MCAuto<DataArrayInt> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2178 setConnectivity(arrOut,arrIOut,true);
2182 void MEDCouplingUMesh::setPartOfMySelfSlice(int start, int end, int step, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2184 checkConnectivityFullyDefined();
2185 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2186 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2187 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelfSlice : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2188 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2190 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2191 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2192 throw INTERP_KERNEL::Exception(oss.str());
2194 int nbOfCellsToModify=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::setPartOfMySelfSlice : ");
2195 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2197 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2198 throw INTERP_KERNEL::Exception(oss.str());
2200 int nbOfCells=getNumberOfCells();
2201 bool easyAssign=true;
2202 const int *connI=_nodal_connec_index->getConstPointer();
2203 const int *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2205 for(int i=0;i<nbOfCellsToModify && easyAssign;i++,it+=step,connIOther++)
2207 if(it>=0 && it<nbOfCells)
2209 easyAssign=(connIOther[1]-connIOther[0])==(connI[it+1]-connI[it]);
2213 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : On pos #" << i << " id is equal to " << it << " which is not in [0," << nbOfCells << ") !";
2214 throw INTERP_KERNEL::Exception(oss.str());
2219 MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2224 DataArrayInt *arrOut=0,*arrIOut=0;
2225 MEDCouplingUMesh::SetPartOfIndexedArraysSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2227 MCAuto<DataArrayInt> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2228 setConnectivity(arrOut,arrIOut,true);
2233 * Keeps from \a this only cells which constituing point id are in the ids specified by [ \a begin,\a end ).
2234 * The resulting cell ids are stored at the end of the 'cellIdsKept' parameter.
2235 * Parameter \a fullyIn specifies if a cell that has part of its nodes in ids array is kept or not.
2236 * If \a fullyIn is true only cells whose ids are \b fully contained in [ \a begin,\a end ) tab will be kept.
2238 * \param [in] begin input start of array of node ids.
2239 * \param [in] end input end of array of node ids.
2240 * \param [in] fullyIn input that specifies if all node ids must be in [ \a begin,\a end ) array to consider cell to be in.
2241 * \param [in,out] cellIdsKeptArr array where all candidate cell ids are put at the end.
2243 void MEDCouplingUMesh::fillCellIdsToKeepFromNodeIds(const int *begin, const int *end, bool fullyIn, DataArrayInt *&cellIdsKeptArr) const
2245 MCAuto<DataArrayInt> cellIdsKept=DataArrayInt::New(); cellIdsKept->alloc(0,1);
2246 checkConnectivityFullyDefined();
2248 int sz=getNodalConnectivity()->getMaxValue(tmp); sz=std::max(sz,0)+1;
2249 std::vector<bool> fastFinder(sz,false);
2250 for(const int *work=begin;work!=end;work++)
2251 if(*work>=0 && *work<sz)
2252 fastFinder[*work]=true;
2253 int nbOfCells=getNumberOfCells();
2254 const int *conn=getNodalConnectivity()->getConstPointer();
2255 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2256 for(int i=0;i<nbOfCells;i++)
2258 int ref=0,nbOfHit=0;
2259 for(const int *work2=conn+connIndex[i]+1;work2!=conn+connIndex[i+1];work2++)
2263 if(fastFinder[*work2])
2266 if((ref==nbOfHit && fullyIn) || (nbOfHit!=0 && !fullyIn))
2267 cellIdsKept->pushBackSilent(i);
2269 cellIdsKeptArr=cellIdsKept.retn();
2273 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2274 * this->getMeshDimension(), that bound some cells of \a this mesh.
2275 * The cells of lower dimension to include to the result mesh are selected basing on
2276 * specified node ids and the value of \a fullyIn parameter. If \a fullyIn ==\c true, a
2277 * cell is copied if its all nodes are in the array \a begin of node ids. If \a fullyIn
2278 * ==\c false, a cell is copied if any its node is in the array of node ids. The
2279 * created mesh shares the node coordinates array with \a this mesh.
2280 * \param [in] begin - the array of node ids.
2281 * \param [in] end - a pointer to the (last+1)-th element of \a begin.
2282 * \param [in] fullyIn - if \c true, then cells whose all nodes are in the
2283 * array \a begin are added, else cells whose any node is in the
2284 * array \a begin are added.
2285 * \return MEDCouplingUMesh * - new instance of MEDCouplingUMesh. The caller is
2286 * to delete this mesh using decrRef() as it is no more needed.
2287 * \throw If the coordinates array is not set.
2288 * \throw If the nodal connectivity of cells is not defined.
2289 * \throw If any node id in \a begin is not valid.
2291 * \if ENABLE_EXAMPLES
2292 * \ref cpp_mcumesh_buildFacePartOfMySelfNode "Here is a C++ example".<br>
2293 * \ref py_mcumesh_buildFacePartOfMySelfNode "Here is a Python example".
2296 MEDCouplingUMesh *MEDCouplingUMesh::buildFacePartOfMySelfNode(const int *begin, const int *end, bool fullyIn) const
2298 MCAuto<DataArrayInt> desc,descIndx,revDesc,revDescIndx;
2299 desc=DataArrayInt::New(); descIndx=DataArrayInt::New(); revDesc=DataArrayInt::New(); revDescIndx=DataArrayInt::New();
2300 MCAuto<MEDCouplingUMesh> subMesh=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2301 desc=0; descIndx=0; revDesc=0; revDescIndx=0;
2302 return static_cast<MEDCouplingUMesh*>(subMesh->buildPartOfMySelfNode(begin,end,fullyIn));
2306 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2307 * this->getMeshDimension(), which bound only one cell of \a this mesh.
2308 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2309 * array of \a this mesh, else "free" nodes are removed from the result mesh
2310 * by calling zipCoords().
2311 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2312 * to delete this mesh using decrRef() as it is no more needed.
2313 * \throw If the coordinates array is not set.
2314 * \throw If the nodal connectivity of cells is not defined.
2316 * \if ENABLE_EXAMPLES
2317 * \ref cpp_mcumesh_buildBoundaryMesh "Here is a C++ example".<br>
2318 * \ref py_mcumesh_buildBoundaryMesh "Here is a Python example".
2321 MEDCouplingUMesh *MEDCouplingUMesh::buildBoundaryMesh(bool keepCoords) const
2323 DataArrayInt *desc=DataArrayInt::New();
2324 DataArrayInt *descIndx=DataArrayInt::New();
2325 DataArrayInt *revDesc=DataArrayInt::New();
2326 DataArrayInt *revDescIndx=DataArrayInt::New();
2328 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2331 descIndx->decrRef();
2332 int nbOfCells=meshDM1->getNumberOfCells();
2333 const int *revDescIndxC=revDescIndx->getConstPointer();
2334 std::vector<int> boundaryCells;
2335 for(int i=0;i<nbOfCells;i++)
2336 if(revDescIndxC[i+1]-revDescIndxC[i]==1)
2337 boundaryCells.push_back(i);
2338 revDescIndx->decrRef();
2339 MEDCouplingUMesh *ret=meshDM1->buildPartOfMySelf(&boundaryCells[0],&boundaryCells[0]+boundaryCells.size(),keepCoords);
2344 * This method returns a newly created DataArrayInt instance containing ids of cells located in boundary.
2345 * A cell is detected to be on boundary if it contains one or more than one face having only one father.
2346 * This method makes the assumption that \a this is fully defined (coords,connectivity). If not an exception will be thrown.
2348 DataArrayInt *MEDCouplingUMesh::findCellIdsOnBoundary() const
2350 checkFullyDefined();
2351 MCAuto<DataArrayInt> desc=DataArrayInt::New();
2352 MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
2353 MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
2354 MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
2356 buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx)->decrRef();
2357 desc=(DataArrayInt*)0; descIndx=(DataArrayInt*)0;
2359 MCAuto<DataArrayInt> tmp=revDescIndx->deltaShiftIndex();
2360 MCAuto<DataArrayInt> faceIds=tmp->findIdsEqual(1); tmp=(DataArrayInt*)0;
2361 const int *revDescPtr=revDesc->getConstPointer();
2362 const int *revDescIndxPtr=revDescIndx->getConstPointer();
2363 int nbOfCells=getNumberOfCells();
2364 std::vector<bool> ret1(nbOfCells,false);
2366 for(const int *pt=faceIds->begin();pt!=faceIds->end();pt++)
2367 if(!ret1[revDescPtr[revDescIndxPtr[*pt]]])
2368 { ret1[revDescPtr[revDescIndxPtr[*pt]]]=true; sz++; }
2370 DataArrayInt *ret2=DataArrayInt::New();
2372 int *ret2Ptr=ret2->getPointer();
2374 for(std::vector<bool>::const_iterator it=ret1.begin();it!=ret1.end();it++,sz++)
2377 ret2->setName("BoundaryCells");
2382 * This method finds in \b this the cell ids that lie on mesh \b otherDimM1OnSameCoords.
2383 * \b this and \b otherDimM1OnSameCoords have to lie on the same coordinate array pointer. The coherency of that coords array with connectivity
2384 * of \b this and \b otherDimM1OnSameCoords is not important here because this method works only on connectivity.
2385 * this->getMeshDimension() - 1 must be equal to otherDimM1OnSameCoords.getMeshDimension()
2387 * s0 is the cell ids set in \b this lying on at least one node in the fetched nodes in \b otherDimM1OnSameCoords.
2388 * 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
2389 * equals a cell in \b otherDimM1OnSameCoords.
2391 * \throw if \b otherDimM1OnSameCoords is not part of constituent of \b this, or if coordinate pointer of \b this and \b otherDimM1OnSameCoords
2392 * are not same, or if this->getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension()
2394 * \param [in] otherDimM1OnSameCoords
2395 * \param [out] cellIdsRk0 a newly allocated array containing the cell ids of s0 (which are cell ids of \b this) in the above algorithm.
2396 * \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
2397 * cellIdsRk1->transformWithIndArr(cellIdsRk0->begin(),cellIdsRk0->end());
2399 void MEDCouplingUMesh::findCellIdsLyingOn(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayInt *&cellIdsRk0, DataArrayInt *&cellIdsRk1) const
2401 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2402 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : coordinates pointer are not the same ! Use tryToShareSameCoords method !");
2403 checkConnectivityFullyDefined();
2404 otherDimM1OnSameCoords.checkConnectivityFullyDefined();
2405 if(getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension())
2406 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : invalid mesh dimension of input mesh regarding meshdimesion of this !");
2407 MCAuto<DataArrayInt> fetchedNodeIds1=otherDimM1OnSameCoords.computeFetchedNodeIds();
2408 MCAuto<DataArrayInt> s0arr=getCellIdsLyingOnNodes(fetchedNodeIds1->begin(),fetchedNodeIds1->end(),false);
2409 MCAuto<MEDCouplingUMesh> thisPart=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(s0arr->begin(),s0arr->end(),true));
2410 MCAuto<DataArrayInt> descThisPart=DataArrayInt::New(),descIThisPart=DataArrayInt::New(),revDescThisPart=DataArrayInt::New(),revDescIThisPart=DataArrayInt::New();
2411 MCAuto<MEDCouplingUMesh> thisPartConsti=thisPart->buildDescendingConnectivity(descThisPart,descIThisPart,revDescThisPart,revDescIThisPart);
2412 const int *revDescThisPartPtr=revDescThisPart->getConstPointer(),*revDescIThisPartPtr=revDescIThisPart->getConstPointer();
2413 DataArrayInt *idsOtherInConsti=0;
2414 bool b=thisPartConsti->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsOtherInConsti);
2415 MCAuto<DataArrayInt> idsOtherInConstiAuto(idsOtherInConsti);
2417 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : the given mdim-1 mesh in other is not a constituent of this !");
2419 for(const int *idOther=idsOtherInConsti->begin();idOther!=idsOtherInConsti->end();idOther++)
2420 s1.insert(revDescThisPartPtr+revDescIThisPartPtr[*idOther],revDescThisPartPtr+revDescIThisPartPtr[*idOther+1]);
2421 MCAuto<DataArrayInt> s1arr_renum1=DataArrayInt::New(); s1arr_renum1->alloc((int)s1.size(),1); std::copy(s1.begin(),s1.end(),s1arr_renum1->getPointer());
2422 s1arr_renum1->sort();
2423 cellIdsRk0=s0arr.retn();
2424 //cellIdsRk1=s_renum1.retn();
2425 cellIdsRk1=s1arr_renum1.retn();
2429 * 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
2430 * returned. This subpart of meshdim-1 mesh is built using meshdim-1 cells in it shared only one cell in \b this.
2432 * \return a newly allocated mesh lying on the same coordinates than \b this. The caller has to deal with returned mesh.
2434 MEDCouplingUMesh *MEDCouplingUMesh::computeSkin() const
2436 MCAuto<DataArrayInt> desc=DataArrayInt::New();
2437 MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
2438 MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
2439 MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
2441 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2442 revDesc=0; desc=0; descIndx=0;
2443 MCAuto<DataArrayInt> revDescIndx2=revDescIndx->deltaShiftIndex();
2444 MCAuto<DataArrayInt> part=revDescIndx2->findIdsEqual(1);
2445 return static_cast<MEDCouplingUMesh *>(meshDM1->buildPartOfMySelf(part->begin(),part->end(),true));
2449 * Finds nodes lying on the boundary of \a this mesh.
2450 * \return DataArrayInt * - a new instance of DataArrayInt holding ids of found
2451 * nodes. The caller is to delete this array using decrRef() as it is no
2453 * \throw If the coordinates array is not set.
2454 * \throw If the nodal connectivity of cells is node defined.
2456 * \if ENABLE_EXAMPLES
2457 * \ref cpp_mcumesh_findBoundaryNodes "Here is a C++ example".<br>
2458 * \ref py_mcumesh_findBoundaryNodes "Here is a Python example".
2461 DataArrayInt *MEDCouplingUMesh::findBoundaryNodes() const
2463 MCAuto<MEDCouplingUMesh> skin=computeSkin();
2464 return skin->computeFetchedNodeIds();
2467 MEDCouplingUMesh *MEDCouplingUMesh::buildUnstructured() const
2470 return const_cast<MEDCouplingUMesh *>(this);
2474 * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2475 * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2476 * 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.
2477 * 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.
2478 * When the set of node ids \b nodeIdsToDuplicate is computed, cell ids in \b this is searched so that their connectivity includes at least 1 node in \b nodeIdsToDuplicate.
2480 * \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
2481 * parameter is altered during the call.
2482 * \param [out] nodeIdsToDuplicate node ids needed to be duplicated following the algorithm explain above.
2483 * \param [out] cellIdsNeededToBeRenum cell ids in \b this in which the renumber of nodes should be performed.
2484 * \param [out] cellIdsNotModified cell ids int \b this that lies on \b otherDimM1OnSameCoords mesh whose connectivity do \b not need to be modified as it is the case for \b cellIdsNeededToBeRenum.
2486 * \warning This method modifies param \b otherDimM1OnSameCoords (for speed reasons).
2488 void MEDCouplingUMesh::findNodesToDuplicate(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayInt *& nodeIdsToDuplicate,
2489 DataArrayInt *& cellIdsNeededToBeRenum, DataArrayInt *& cellIdsNotModified) const
2491 typedef MCAuto<DataArrayInt> DAInt;
2492 typedef MCAuto<MEDCouplingUMesh> MCUMesh;
2494 checkFullyDefined();
2495 otherDimM1OnSameCoords.checkFullyDefined();
2496 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2497 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : meshes do not share the same coords array !");
2498 if(otherDimM1OnSameCoords.getMeshDimension()!=getMeshDimension()-1)
2499 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the mesh given in other parameter must have this->getMeshDimension()-1 !");
2501 // Checking star-shaped M1 group:
2502 DAInt dt0=DataArrayInt::New(),dit0=DataArrayInt::New(),rdt0=DataArrayInt::New(),rdit0=DataArrayInt::New();
2503 MCUMesh meshM2 = otherDimM1OnSameCoords.buildDescendingConnectivity(dt0, dit0, rdt0, rdit0);
2504 DAInt dsi = rdit0->deltaShiftIndex();
2505 DAInt idsTmp0 = dsi->findIdsNotInRange(-1, 3);
2506 if(idsTmp0->getNumberOfTuples())
2507 throw INTERP_KERNEL::Exception("MEDFileUMesh::buildInnerBoundaryAlongM1Group: group is too complex: some points (or edges) have more than two connected segments (or faces)!");
2508 dt0=0; dit0=0; rdt0=0; rdit0=0; idsTmp0=0;
2510 // Get extreme nodes from the group (they won't be duplicated), ie nodes belonging to boundary cells of M1
2511 DAInt xtremIdsM2 = dsi->findIdsEqual(1); dsi = 0;
2512 MCUMesh meshM2Part = static_cast<MEDCouplingUMesh *>(meshM2->buildPartOfMySelf(xtremIdsM2->begin(), xtremIdsM2->end(),true));
2513 DAInt xtrem = meshM2Part->computeFetchedNodeIds();
2514 // Remove from the list points on the boundary of the M0 mesh (those need duplication!)
2515 dt0=DataArrayInt::New(),dit0=DataArrayInt::New(),rdt0=DataArrayInt::New(),rdit0=DataArrayInt::New();
2516 MCUMesh m0desc = buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); dt0=0; dit0=0; rdt0=0;
2517 dsi = rdit0->deltaShiftIndex();
2518 DAInt boundSegs = dsi->findIdsEqual(1); // boundary segs/faces of the M0 mesh
2519 MCUMesh m0descSkin = static_cast<MEDCouplingUMesh *>(m0desc->buildPartOfMySelf(boundSegs->begin(),boundSegs->end(), true));
2520 DAInt fNodes = m0descSkin->computeFetchedNodeIds();
2521 // In 3D, some points on the boundary of M0 still need duplication:
2523 if (getMeshDimension() == 3)
2525 DAInt dnu1=DataArrayInt::New(), dnu2=DataArrayInt::New(), dnu3=DataArrayInt::New(), dnu4=DataArrayInt::New();
2526 MCUMesh m0descSkinDesc = m0descSkin->buildDescendingConnectivity(dnu1, dnu2, dnu3, dnu4);
2527 dnu1=0;dnu2=0;dnu3=0;dnu4=0;
2528 DataArrayInt * corresp=0;
2529 meshM2->areCellsIncludedIn(m0descSkinDesc,2,corresp);
2530 DAInt validIds = corresp->findIdsInRange(0, meshM2->getNumberOfCells());
2532 if (validIds->getNumberOfTuples())
2534 MCUMesh m1IntersecSkin = static_cast<MEDCouplingUMesh *>(m0descSkinDesc->buildPartOfMySelf(validIds->begin(), validIds->end(), true));
2535 DAInt notDuplSkin = m1IntersecSkin->findBoundaryNodes();
2536 DAInt fNodes1 = fNodes->buildSubstraction(notDuplSkin);
2537 notDup = xtrem->buildSubstraction(fNodes1);
2540 notDup = xtrem->buildSubstraction(fNodes);
2543 notDup = xtrem->buildSubstraction(fNodes);
2545 // Now compute cells around group (i.e. cells where we will do the propagation to identify the two sub-sets delimited by the group)
2546 DAInt m1Nodes = otherDimM1OnSameCoords.computeFetchedNodeIds();
2547 DAInt dupl = m1Nodes->buildSubstraction(notDup);
2548 DAInt cellsAroundGroup = getCellIdsLyingOnNodes(dupl->begin(), dupl->end(), false); // false= take cell in, even if not all nodes are in notDup
2551 MCUMesh m0Part2=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(cellsAroundGroup->begin(),cellsAroundGroup->end(),true));
2552 int nCells2 = m0Part2->getNumberOfCells();
2553 DAInt desc00=DataArrayInt::New(),descI00=DataArrayInt::New(),revDesc00=DataArrayInt::New(),revDescI00=DataArrayInt::New();
2554 MCUMesh m01=m0Part2->buildDescendingConnectivity(desc00,descI00,revDesc00,revDescI00);
2556 // Neighbor information of the mesh without considering the crack (serves to count how many connex pieces it is made of)
2557 DataArrayInt *tmp00=0,*tmp11=0;
2558 MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00, tmp00, tmp11);
2559 DAInt neighInit00(tmp00);
2560 DAInt neighIInit00(tmp11);
2561 // Neighbor information of the mesh WITH the crack (some neighbors are removed):
2562 DataArrayInt *idsTmp=0;
2563 bool b=m01->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsTmp);
2565 // In the neighbor information remove the connection between high dimension cells and its low level constituents which are part
2566 // of the frontier given in parameter (i.e. the cells of low dimension from the group delimiting the crack):
2567 MEDCouplingUMesh::RemoveIdsFromIndexedArrays(ids->begin(),ids->end(),desc00,descI00);
2568 DataArrayInt *tmp0=0,*tmp1=0;
2569 // Compute the neighbor of each cell in m0Part2, taking into account the broken link above. Two
2570 // cells on either side of the crack (defined by the mesh of low dimension) are not neighbor anymore.
2571 ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00,tmp0,tmp1);
2572 DAInt neigh00(tmp0);
2573 DAInt neighI00(tmp1);
2575 // For each initial connex part of the sub-mesh (or said differently for each independent crack):
2576 int seed = 0, nIter = 0;
2577 int nIterMax = nCells2+1; // Safety net for the loop
2578 DAInt hitCells = DataArrayInt::New(); hitCells->alloc(nCells2);
2579 hitCells->fillWithValue(-1);
2580 DAInt cellsToModifyConn0_torenum = DataArrayInt::New();
2581 cellsToModifyConn0_torenum->alloc(0,1);
2582 while (nIter < nIterMax)
2584 DAInt t = hitCells->findIdsEqual(-1);
2585 if (!t->getNumberOfTuples())
2587 // Connex zone without the crack (to compute the next seed really)
2589 DAInt connexCheck = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neighInit00,neighIInit00, -1, dnu);
2591 for (int * ptr = connexCheck->getPointer(); cnt < connexCheck->getNumberOfTuples(); ptr++, cnt++)
2592 hitCells->setIJ(*ptr,0,1);
2593 // Connex zone WITH the crack (to identify cells lying on either part of the crack)
2594 DAInt spreadZone = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neigh00,neighI00, -1, dnu);
2595 cellsToModifyConn0_torenum = DataArrayInt::Aggregate(cellsToModifyConn0_torenum, spreadZone, 0);
2596 // Compute next seed, i.e. a cell in another connex part, which was not covered by the previous iterations
2597 DAInt comple = cellsToModifyConn0_torenum->buildComplement(nCells2);
2598 DAInt nonHitCells = hitCells->findIdsEqual(-1);
2599 DAInt intersec = nonHitCells->buildIntersection(comple);
2600 if (intersec->getNumberOfTuples())
2601 { seed = intersec->getIJ(0,0); }
2606 if (nIter >= nIterMax)
2607 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate(): internal error - too many iterations.");
2609 DAInt cellsToModifyConn1_torenum=cellsToModifyConn0_torenum->buildComplement(neighI00->getNumberOfTuples()-1);
2610 cellsToModifyConn0_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2611 cellsToModifyConn1_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2613 cellIdsNeededToBeRenum=cellsToModifyConn0_torenum.retn();
2614 cellIdsNotModified=cellsToModifyConn1_torenum.retn();
2615 nodeIdsToDuplicate=dupl.retn();
2619 * This method operates a modification of the connectivity and coords in \b this.
2620 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2621 * its ids will be modified to id this->getNumberOfNodes()+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2622 * 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
2623 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id this->getNumberOfNodes()+0, node id nodeIdsToDuplicateBg[1] will have id this->getNumberOfNodes()+1,
2624 * node id nodeIdsToDuplicateBg[2] will have id this->getNumberOfNodes()+2...
2626 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2628 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2629 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2631 void MEDCouplingUMesh::duplicateNodes(const int *nodeIdsToDuplicateBg, const int *nodeIdsToDuplicateEnd)
2633 int nbOfNodes=getNumberOfNodes();
2634 duplicateNodesInCoords(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd);
2635 duplicateNodesInConn(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,nbOfNodes);
2639 * This method renumbers only nodal connectivity in \a this. The renumbering is only an offset applied. So this method is a specialization of
2640 * \a renumberNodesInConn. \b WARNING, this method does not check that the resulting node ids in the nodal connectivity is in a valid range !
2642 * \param [in] offset - specifies the offset to be applied on each element of connectivity.
2644 * \sa renumberNodesInConn
2646 void MEDCouplingUMesh::renumberNodesWithOffsetInConn(int offset)
2648 checkConnectivityFullyDefined();
2649 int *conn(getNodalConnectivity()->getPointer());
2650 const int *connIndex(getNodalConnectivityIndex()->getConstPointer());
2651 int nbOfCells(getNumberOfCells());
2652 for(int i=0;i<nbOfCells;i++)
2653 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2655 int& node=conn[iconn];
2656 if(node>=0)//avoid polyhedron separator
2661 _nodal_connec->declareAsNew();
2666 * Same than renumberNodesInConn(const int *) except that here the format of old-to-new traducer is using map instead
2667 * 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
2670 void MEDCouplingUMesh::renumberNodesInConn(const INTERP_KERNEL::HashMap<int,int>& newNodeNumbersO2N)
2672 checkConnectivityFullyDefined();
2673 int *conn(getNodalConnectivity()->getPointer());
2674 const int *connIndex(getNodalConnectivityIndex()->getConstPointer());
2675 int nbOfCells(getNumberOfCells());
2676 for(int i=0;i<nbOfCells;i++)
2677 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2679 int& node=conn[iconn];
2680 if(node>=0)//avoid polyhedron separator
2682 INTERP_KERNEL::HashMap<int,int>::const_iterator it(newNodeNumbersO2N.find(node));
2683 if(it!=newNodeNumbersO2N.end())
2689 std::ostringstream oss; oss << "MEDCouplingUMesh::renumberNodesInConn(map) : presence in connectivity for cell #" << i << " of node #" << node << " : Not in map !";
2690 throw INTERP_KERNEL::Exception(oss.str());
2694 _nodal_connec->declareAsNew();
2699 * Changes ids of nodes within the nodal connectivity arrays according to a permutation
2700 * array in "Old to New" mode. The node coordinates array is \b not changed by this method.
2701 * This method is a generalization of shiftNodeNumbersInConn().
2702 * \warning This method performs no check of validity of new ids. **Use it with care !**
2703 * \param [in] newNodeNumbersO2N - a permutation array, of length \a
2704 * this->getNumberOfNodes(), in "Old to New" mode.
2705 * See \ref numbering for more info on renumbering modes.
2706 * \throw If the nodal connectivity of cells is not defined.
2708 * \if ENABLE_EXAMPLES
2709 * \ref cpp_mcumesh_renumberNodesInConn "Here is a C++ example".<br>
2710 * \ref py_mcumesh_renumberNodesInConn "Here is a Python example".
2713 void MEDCouplingUMesh::renumberNodesInConn(const int *newNodeNumbersO2N)
2715 checkConnectivityFullyDefined();
2716 int *conn=getNodalConnectivity()->getPointer();
2717 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2718 int nbOfCells(getNumberOfCells());
2719 for(int i=0;i<nbOfCells;i++)
2720 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2722 int& node=conn[iconn];
2723 if(node>=0)//avoid polyhedron separator
2725 node=newNodeNumbersO2N[node];
2728 _nodal_connec->declareAsNew();
2733 * This method renumbers nodes \b in \b connectivity \b only \b without \b any \b reference \b to \b coords.
2734 * This method performs no check on the fact that new coordinate ids are valid. \b Use \b it \b with \b care !
2735 * This method is an specialization of \ref MEDCoupling::MEDCouplingUMesh::renumberNodesInConn "renumberNodesInConn method".
2737 * \param [in] delta specifies the shift size applied to nodeId in nodal connectivity in \b this.
2739 void MEDCouplingUMesh::shiftNodeNumbersInConn(int delta)
2741 checkConnectivityFullyDefined();
2742 int *conn=getNodalConnectivity()->getPointer();
2743 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2744 int nbOfCells=getNumberOfCells();
2745 for(int i=0;i<nbOfCells;i++)
2746 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2748 int& node=conn[iconn];
2749 if(node>=0)//avoid polyhedron separator
2754 _nodal_connec->declareAsNew();
2759 * This method operates a modification of the connectivity in \b this.
2760 * 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.
2761 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2762 * its ids will be modified to id offset+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2763 * 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
2764 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id offset+0, node id nodeIdsToDuplicateBg[1] will have id offset+1,
2765 * node id nodeIdsToDuplicateBg[2] will have id offset+2...
2767 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2768 * As an another consequense after the call of this method \b this can be transiently non cohrent.
2770 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2771 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2772 * \param [in] offset the offset applied to all node ids in connectivity that are in [ \a nodeIdsToDuplicateBg, \a nodeIdsToDuplicateEnd ).
2774 void MEDCouplingUMesh::duplicateNodesInConn(const int *nodeIdsToDuplicateBg, const int *nodeIdsToDuplicateEnd, int offset)
2776 checkConnectivityFullyDefined();
2777 std::map<int,int> m;
2779 for(const int *work=nodeIdsToDuplicateBg;work!=nodeIdsToDuplicateEnd;work++,val++)
2781 int *conn=getNodalConnectivity()->getPointer();
2782 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2783 int nbOfCells=getNumberOfCells();
2784 for(int i=0;i<nbOfCells;i++)
2785 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2787 int& node=conn[iconn];
2788 if(node>=0)//avoid polyhedron separator
2790 std::map<int,int>::iterator it=m.find(node);
2799 * This method renumbers cells of \a this using the array specified by [old2NewBg;old2NewBg+getNumberOfCells())
2801 * Contrary to MEDCouplingPointSet::renumberNodes, this method makes a permutation without any fuse of cell.
2802 * After the call of this method the number of cells remains the same as before.
2804 * If 'check' equals true the method will check that any elements in [ \a old2NewBg; \a old2NewEnd ) is unique ; if not
2805 * an INTERP_KERNEL::Exception will be thrown. When 'check' equals true [ \a old2NewBg ; \a old2NewEnd ) is not expected to
2806 * be strictly in [0;this->getNumberOfCells()).
2808 * If 'check' equals false the method will not check the content of [ \a old2NewBg ; \a old2NewEnd ).
2809 * To avoid any throw of SIGSEGV when 'check' equals false, the elements in [ \a old2NewBg ; \a old2NewEnd ) should be unique and
2810 * should be contained in[0;this->getNumberOfCells()).
2812 * \param [in] old2NewBg is expected to be a dynamically allocated pointer of size at least equal to this->getNumberOfCells()
2815 void MEDCouplingUMesh::renumberCells(const int *old2NewBg, bool check)
2817 checkConnectivityFullyDefined();
2818 int nbCells=getNumberOfCells();
2819 const int *array=old2NewBg;
2821 array=DataArrayInt::CheckAndPreparePermutation(old2NewBg,old2NewBg+nbCells);
2823 const int *conn=_nodal_connec->getConstPointer();
2824 const int *connI=_nodal_connec_index->getConstPointer();
2825 MCAuto<DataArrayInt> o2n=DataArrayInt::New(); o2n->useArray(array,false,C_DEALLOC,nbCells,1);
2826 MCAuto<DataArrayInt> n2o=o2n->invertArrayO2N2N2O(nbCells);
2827 const int *n2oPtr=n2o->begin();
2828 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
2829 newConn->alloc(_nodal_connec->getNumberOfTuples(),_nodal_connec->getNumberOfComponents());
2830 newConn->copyStringInfoFrom(*_nodal_connec);
2831 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
2832 newConnI->alloc(_nodal_connec_index->getNumberOfTuples(),_nodal_connec_index->getNumberOfComponents());
2833 newConnI->copyStringInfoFrom(*_nodal_connec_index);
2835 int *newC=newConn->getPointer();
2836 int *newCI=newConnI->getPointer();
2839 for(int i=0;i<nbCells;i++)
2842 int nbOfElts=connI[pos+1]-connI[pos];
2843 newC=std::copy(conn+connI[pos],conn+connI[pos+1],newC);
2848 setConnectivity(newConn,newConnI);
2850 free(const_cast<int *>(array));
2854 * Finds cells whose bounding boxes intersect a given bounding box.
2855 * \param [in] bbox - an array defining the bounding box via coordinates of its
2856 * extremum points in "no interlace" mode, i.e. xMin, xMax, yMin, yMax, zMin,
2858 * \param [in] eps - a factor used to increase size of the bounding box of cell
2859 * before comparing it with \a bbox. This factor is multiplied by the maximal
2860 * extent of the bounding box of cell to produce an addition to this bounding box.
2861 * \return DataArrayInt * - a new instance of DataArrayInt holding ids for found
2862 * cells. The caller is to delete this array using decrRef() as it is no more
2864 * \throw If the coordinates array is not set.
2865 * \throw If the nodal connectivity of cells is not defined.
2867 * \if ENABLE_EXAMPLES
2868 * \ref cpp_mcumesh_getCellsInBoundingBox "Here is a C++ example".<br>
2869 * \ref py_mcumesh_getCellsInBoundingBox "Here is a Python example".
2872 DataArrayInt *MEDCouplingUMesh::getCellsInBoundingBox(const double *bbox, double eps) const
2874 MCAuto<DataArrayInt> elems=DataArrayInt::New(); elems->alloc(0,1);
2875 if(getMeshDimension()==-1)
2877 elems->pushBackSilent(0);
2878 return elems.retn();
2880 int dim=getSpaceDimension();
2881 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2882 const int* conn = getNodalConnectivity()->getConstPointer();
2883 const int* conn_index= getNodalConnectivityIndex()->getConstPointer();
2884 const double* coords = getCoords()->getConstPointer();
2885 int nbOfCells=getNumberOfCells();
2886 for ( int ielem=0; ielem<nbOfCells;ielem++ )
2888 for (int i=0; i<dim; i++)
2890 elem_bb[i*2]=std::numeric_limits<double>::max();
2891 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2894 for (int inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2896 int node= conn[inode];
2897 if(node>=0)//avoid polyhedron separator
2899 for (int idim=0; idim<dim; idim++)
2901 if ( coords[node*dim+idim] < elem_bb[idim*2] )
2903 elem_bb[idim*2] = coords[node*dim+idim] ;
2905 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2907 elem_bb[idim*2+1] = coords[node*dim+idim] ;
2912 if (intersectsBoundingBox(elem_bb, bbox, dim, eps))
2913 elems->pushBackSilent(ielem);
2915 return elems.retn();
2919 * Given a boundary box 'bbox' returns elements 'elems' contained in this 'bbox' or touching 'bbox' (within 'eps' distance).
2920 * Warning 'elems' is incremented during the call so if elems is not empty before call returned elements will be
2921 * added in 'elems' parameter.
2923 DataArrayInt *MEDCouplingUMesh::getCellsInBoundingBox(const INTERP_KERNEL::DirectedBoundingBox& bbox, double eps)
2925 MCAuto<DataArrayInt> elems=DataArrayInt::New(); elems->alloc(0,1);
2926 if(getMeshDimension()==-1)
2928 elems->pushBackSilent(0);
2929 return elems.retn();
2931 int dim=getSpaceDimension();
2932 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2933 const int* conn = getNodalConnectivity()->getConstPointer();
2934 const int* conn_index= getNodalConnectivityIndex()->getConstPointer();
2935 const double* coords = getCoords()->getConstPointer();
2936 int nbOfCells=getNumberOfCells();
2937 for ( int ielem=0; ielem<nbOfCells;ielem++ )
2939 for (int i=0; i<dim; i++)
2941 elem_bb[i*2]=std::numeric_limits<double>::max();
2942 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2945 for (int inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2947 int node= conn[inode];
2948 if(node>=0)//avoid polyhedron separator
2950 for (int idim=0; idim<dim; idim++)
2952 if ( coords[node*dim+idim] < elem_bb[idim*2] )
2954 elem_bb[idim*2] = coords[node*dim+idim] ;
2956 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2958 elem_bb[idim*2+1] = coords[node*dim+idim] ;
2963 if(intersectsBoundingBox(bbox, elem_bb, dim, eps))
2964 elems->pushBackSilent(ielem);
2966 return elems.retn();
2970 * Returns a type of a cell by its id.
2971 * \param [in] cellId - the id of the cell of interest.
2972 * \return INTERP_KERNEL::NormalizedCellType - enumeration item describing the cell type.
2973 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2975 INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::getTypeOfCell(int cellId) const
2977 const int *ptI=_nodal_connec_index->getConstPointer();
2978 const int *pt=_nodal_connec->getConstPointer();
2979 if(cellId>=0 && cellId<(int)_nodal_connec_index->getNbOfElems()-1)
2980 return (INTERP_KERNEL::NormalizedCellType) pt[ptI[cellId]];
2983 std::ostringstream oss; oss << "MEDCouplingUMesh::getTypeOfCell : Requesting type of cell #" << cellId << " but it should be in [0," << _nodal_connec_index->getNbOfElems()-1 << ") !";
2984 throw INTERP_KERNEL::Exception(oss.str());
2989 * This method returns a newly allocated array containing cell ids (ascendingly sorted) whose geometric type are equal to type.
2990 * This method does not throw exception if geometric type \a type is not in \a this.
2991 * This method throws an INTERP_KERNEL::Exception if meshdimension of \b this is not equal to those of \b type.
2992 * The coordinates array is not considered here.
2994 * \param [in] type the geometric type
2995 * \return cell ids in this having geometric type \a type.
2997 DataArrayInt *MEDCouplingUMesh::giveCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
3000 MCAuto<DataArrayInt> ret=DataArrayInt::New();
3002 checkConnectivityFullyDefined();
3003 int nbCells=getNumberOfCells();
3004 int mdim=getMeshDimension();
3005 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
3006 if(mdim!=(int)cm.getDimension())
3007 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::giveCellsWithType : Mismatch between mesh dimension and dimension of the cell !");
3008 const int *ptI=_nodal_connec_index->getConstPointer();
3009 const int *pt=_nodal_connec->getConstPointer();
3010 for(int i=0;i<nbCells;i++)
3012 if((INTERP_KERNEL::NormalizedCellType)pt[ptI[i]]==type)
3013 ret->pushBackSilent(i);
3019 * Returns nb of cells having the geometric type \a type. No throw if no cells in \a this has the geometric type \a type.
3021 int MEDCouplingUMesh::getNumberOfCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
3023 const int *ptI=_nodal_connec_index->getConstPointer();
3024 const int *pt=_nodal_connec->getConstPointer();
3025 int nbOfCells=getNumberOfCells();
3027 for(int i=0;i<nbOfCells;i++)
3028 if((INTERP_KERNEL::NormalizedCellType) pt[ptI[i]]==type)
3034 * Returns the nodal connectivity of a given cell.
3035 * The separator of faces within polyhedron connectivity (-1) is not returned, thus
3036 * all returned node ids can be used in getCoordinatesOfNode().
3037 * \param [in] cellId - an id of the cell of interest.
3038 * \param [in,out] conn - a vector where the node ids are appended. It is not
3039 * cleared before the appending.
3040 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
3042 void MEDCouplingUMesh::getNodeIdsOfCell(int cellId, std::vector<int>& conn) const
3044 const int *ptI=_nodal_connec_index->getConstPointer();
3045 const int *pt=_nodal_connec->getConstPointer();
3046 for(const int *w=pt+ptI[cellId]+1;w!=pt+ptI[cellId+1];w++)
3051 std::string MEDCouplingUMesh::simpleRepr() const
3053 static const char msg0[]="No coordinates specified !";
3054 std::ostringstream ret;
3055 ret << "Unstructured mesh with name : \"" << getName() << "\"\n";
3056 ret << "Description of mesh : \"" << getDescription() << "\"\n";
3058 double tt=getTime(tmpp1,tmpp2);
3059 ret << "Time attached to the mesh [unit] : " << tt << " [" << getTimeUnit() << "]\n";
3060 ret << "Iteration : " << tmpp1 << " Order : " << tmpp2 << "\n";
3062 { ret << "Mesh dimension : " << _mesh_dim << "\nSpace dimension : "; }
3064 { ret << " Mesh dimension has not been set or is invalid !"; }
3067 const int spaceDim=getSpaceDimension();
3068 ret << spaceDim << "\nInfo attached on space dimension : ";
3069 for(int i=0;i<spaceDim;i++)
3070 ret << "\"" << _coords->getInfoOnComponent(i) << "\" ";
3074 ret << msg0 << "\n";
3075 ret << "Number of nodes : ";
3077 ret << getNumberOfNodes() << "\n";
3079 ret << msg0 << "\n";
3080 ret << "Number of cells : ";
3081 if(_nodal_connec!=0 && _nodal_connec_index!=0)
3082 ret << getNumberOfCells() << "\n";
3084 ret << "No connectivity specified !" << "\n";
3085 ret << "Cell types present : ";
3086 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
3088 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter);
3089 ret << cm.getRepr() << " ";
3095 std::string MEDCouplingUMesh::advancedRepr() const
3097 std::ostringstream ret;
3098 ret << simpleRepr();
3099 ret << "\nCoordinates array : \n___________________\n\n";
3101 _coords->reprWithoutNameStream(ret);
3103 ret << "No array set !\n";
3104 ret << "\n\nConnectivity arrays : \n_____________________\n\n";
3105 reprConnectivityOfThisLL(ret);
3110 * This method returns a C++ code that is a dump of \a this.
3111 * This method will throw if this is not fully defined.
3113 std::string MEDCouplingUMesh::cppRepr() const
3115 static const char coordsName[]="coords";
3116 static const char connName[]="conn";
3117 static const char connIName[]="connI";
3118 checkFullyDefined();
3119 std::ostringstream ret; ret << "// coordinates" << std::endl;
3120 _coords->reprCppStream(coordsName,ret); ret << std::endl << "// connectivity" << std::endl;
3121 _nodal_connec->reprCppStream(connName,ret); ret << std::endl;
3122 _nodal_connec_index->reprCppStream(connIName,ret); ret << std::endl;
3123 ret << "MEDCouplingUMesh *mesh=MEDCouplingUMesh::New(\"" << getName() << "\"," << getMeshDimension() << ");" << std::endl;
3124 ret << "mesh->setCoords(" << coordsName << ");" << std::endl;
3125 ret << "mesh->setConnectivity(" << connName << "," << connIName << ",true);" << std::endl;
3126 ret << coordsName << "->decrRef(); " << connName << "->decrRef(); " << connIName << "->decrRef();" << std::endl;
3130 std::string MEDCouplingUMesh::reprConnectivityOfThis() const
3132 std::ostringstream ret;
3133 reprConnectivityOfThisLL(ret);
3138 * This method builds a newly allocated instance (with the same name than \a this) that the caller has the responsability to deal with.
3139 * This method returns an instance with all arrays allocated (connectivity, connectivity index, coordinates)
3140 * but with length of these arrays set to 0. It allows to define an "empty" mesh (with nor cells nor nodes but compliant with
3143 * This method expects that \a this has a mesh dimension set and higher or equal to 0. If not an exception will be thrown.
3144 * 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
3145 * with number of tuples set to 0, if not the array is taken as this in the returned instance.
3147 MEDCouplingUMesh *MEDCouplingUMesh::buildSetInstanceFromThis(int spaceDim) const
3149 int mdim=getMeshDimension();
3151 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSetInstanceFromThis : invalid mesh dimension ! Should be >= 0 !");
3152 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
3153 MCAuto<DataArrayInt> tmp1,tmp2;
3154 bool needToCpyCT=true;
3157 tmp1=DataArrayInt::New(); tmp1->alloc(0,1);
3165 if(!_nodal_connec_index)
3167 tmp2=DataArrayInt::New(); tmp2->alloc(1,1); tmp2->setIJ(0,0,0);
3172 tmp2=_nodal_connec_index;
3175 ret->setConnectivity(tmp1,tmp2,false);
3180 MCAuto<DataArrayDouble> coords=DataArrayDouble::New(); coords->alloc(0,spaceDim);
3181 ret->setCoords(coords);
3184 ret->setCoords(_coords);
3188 void MEDCouplingUMesh::reprConnectivityOfThisLL(std::ostringstream& stream) const
3190 if(_nodal_connec!=0 && _nodal_connec_index!=0)
3192 int nbOfCells=getNumberOfCells();
3193 const int *c=_nodal_connec->getConstPointer();
3194 const int *ci=_nodal_connec_index->getConstPointer();
3195 for(int i=0;i<nbOfCells;i++)
3197 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c[ci[i]]);
3198 stream << "Cell #" << i << " " << cm.getRepr() << " : ";
3199 std::copy(c+ci[i]+1,c+ci[i+1],std::ostream_iterator<int>(stream," "));
3204 stream << "Connectivity not defined !\n";
3207 int MEDCouplingUMesh::getNumberOfNodesInCell(int cellId) const
3209 const int *ptI=_nodal_connec_index->getConstPointer();
3210 const int *pt=_nodal_connec->getConstPointer();
3211 if(pt[ptI[cellId]]!=INTERP_KERNEL::NORM_POLYHED)
3212 return ptI[cellId+1]-ptI[cellId]-1;
3214 return (int)std::count_if(pt+ptI[cellId]+1,pt+ptI[cellId+1],std::bind2nd(std::not_equal_to<int>(),-1));
3218 * Returns types of cells of the specified part of \a this mesh.
3219 * This method avoids computing sub-mesh explicitely to get its types.
3220 * \param [in] begin - an array of cell ids of interest.
3221 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3222 * \return std::set<INTERP_KERNEL::NormalizedCellType> - a set of enumeration items
3223 * describing the cell types.
3224 * \throw If the coordinates array is not set.
3225 * \throw If the nodal connectivity of cells is not defined.
3226 * \sa getAllGeoTypes()
3228 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getTypesOfPart(const int *begin, const int *end) const
3230 checkFullyDefined();
3231 std::set<INTERP_KERNEL::NormalizedCellType> ret;
3232 const int *conn=_nodal_connec->getConstPointer();
3233 const int *connIndex=_nodal_connec_index->getConstPointer();
3234 for(const int *w=begin;w!=end;w++)
3235 ret.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]);
3240 * Defines the nodal connectivity using given connectivity arrays in \ref numbering-indirect format.
3241 * Optionally updates
3242 * a set of types of cells constituting \a this mesh.
3243 * This method is for advanced users having prepared their connectivity before. For
3244 * more info on using this method see \ref MEDCouplingUMeshAdvBuild.
3245 * \param [in] conn - the nodal connectivity array.
3246 * \param [in] connIndex - the nodal connectivity index array.
3247 * \param [in] isComputingTypes - if \c true, the set of types constituting \a this
3250 void MEDCouplingUMesh::setConnectivity(DataArrayInt *conn, DataArrayInt *connIndex, bool isComputingTypes)
3252 DataArrayInt::SetArrayIn(conn,_nodal_connec);
3253 DataArrayInt::SetArrayIn(connIndex,_nodal_connec_index);
3254 if(isComputingTypes)
3260 * Copy constructor. If 'deepCopy' is false \a this is a shallow copy of other.
3261 * If 'deeCpy' is true all arrays (coordinates and connectivities) are deeply copied.
3263 MEDCouplingUMesh::MEDCouplingUMesh(const MEDCouplingUMesh& other, bool deepCopy):MEDCouplingPointSet(other,deepCopy),_mesh_dim(other._mesh_dim),
3264 _nodal_connec(0),_nodal_connec_index(0),
3265 _types(other._types)
3267 if(other._nodal_connec)
3268 _nodal_connec=other._nodal_connec->performCopyOrIncrRef(deepCopy);
3269 if(other._nodal_connec_index)
3270 _nodal_connec_index=other._nodal_connec_index->performCopyOrIncrRef(deepCopy);
3273 MEDCouplingUMesh::~MEDCouplingUMesh()
3276 _nodal_connec->decrRef();
3277 if(_nodal_connec_index)
3278 _nodal_connec_index->decrRef();
3282 * Recomputes a set of cell types of \a this mesh. For more info see
3283 * \ref MEDCouplingUMeshNodalConnectivity.
3285 void MEDCouplingUMesh::computeTypes()
3287 ComputeAllTypesInternal(_types,_nodal_connec,_nodal_connec_index);
3291 * This method checks that all arrays are set. If yes nothing done if no an exception is thrown.
3293 void MEDCouplingUMesh::checkFullyDefined() const
3295 if(!_nodal_connec_index || !_nodal_connec || !_coords)
3296 throw INTERP_KERNEL::Exception("Reverse nodal connectivity computation requires full connectivity and coordinates set in unstructured mesh.");
3300 * This method checks that all connectivity arrays are set. If yes nothing done if no an exception is thrown.
3302 void MEDCouplingUMesh::checkConnectivityFullyDefined() const
3304 if(!_nodal_connec_index || !_nodal_connec)
3305 throw INTERP_KERNEL::Exception("Reverse nodal connectivity computation requires full connectivity set in unstructured mesh.");
3309 * Returns a number of cells constituting \a this mesh.
3310 * \return int - the number of cells in \a this mesh.
3311 * \throw If the nodal connectivity of cells is not defined.
3313 int MEDCouplingUMesh::getNumberOfCells() const
3315 if(_nodal_connec_index)
3316 return _nodal_connec_index->getNumberOfTuples()-1;
3321 throw INTERP_KERNEL::Exception("Unable to get number of cells because no connectivity specified !");
3325 * Returns a dimension of \a this mesh, i.e. a dimension of cells constituting \a this
3326 * mesh. For more info see \ref meshes.
3327 * \return int - the dimension of \a this mesh.
3328 * \throw If the mesh dimension is not defined using setMeshDimension().
3330 int MEDCouplingUMesh::getMeshDimension() const
3333 throw INTERP_KERNEL::Exception("No mesh dimension specified !");
3338 * Returns a length of the nodal connectivity array.
3339 * This method is for test reason. Normally the integer returned is not useable by
3340 * user. For more info see \ref MEDCouplingUMeshNodalConnectivity.
3341 * \return int - the length of the nodal connectivity array.
3343 int MEDCouplingUMesh::getNodalConnectivityArrayLen() const
3345 return _nodal_connec->getNbOfElems();
3349 * First step of serialization process. Used by ParaMEDMEM and MEDCouplingCorba to transfert data between process.
3351 void MEDCouplingUMesh::getTinySerializationInformation(std::vector<double>& tinyInfoD, std::vector<int>& tinyInfo, std::vector<std::string>& littleStrings) const
3353 MEDCouplingPointSet::getTinySerializationInformation(tinyInfoD,tinyInfo,littleStrings);
3354 tinyInfo.push_back(getMeshDimension());
3355 tinyInfo.push_back(getNumberOfCells());
3357 tinyInfo.push_back(getNodalConnectivityArrayLen());
3359 tinyInfo.push_back(-1);
3363 * First step of unserialization process.
3365 bool MEDCouplingUMesh::isEmptyMesh(const std::vector<int>& tinyInfo) const
3367 return tinyInfo[6]<=0;
3371 * Second step of serialization process.
3372 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3375 * \param littleStrings
3377 void MEDCouplingUMesh::resizeForUnserialization(const std::vector<int>& tinyInfo, DataArrayInt *a1, DataArrayDouble *a2, std::vector<std::string>& littleStrings) const
3379 MEDCouplingPointSet::resizeForUnserialization(tinyInfo,a1,a2,littleStrings);
3381 a1->alloc(tinyInfo[7]+tinyInfo[6]+1,1);
3385 * Third and final step of serialization process.
3387 void MEDCouplingUMesh::serialize(DataArrayInt *&a1, DataArrayDouble *&a2) const
3389 MEDCouplingPointSet::serialize(a1,a2);
3390 if(getMeshDimension()>-1)
3392 a1=DataArrayInt::New();
3393 a1->alloc(getNodalConnectivityArrayLen()+getNumberOfCells()+1,1);
3394 int *ptA1=a1->getPointer();
3395 const int *conn=getNodalConnectivity()->getConstPointer();
3396 const int *index=getNodalConnectivityIndex()->getConstPointer();
3397 ptA1=std::copy(index,index+getNumberOfCells()+1,ptA1);
3398 std::copy(conn,conn+getNodalConnectivityArrayLen(),ptA1);
3405 * Second and final unserialization process.
3406 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3408 void MEDCouplingUMesh::unserialization(const std::vector<double>& tinyInfoD, const std::vector<int>& tinyInfo, const DataArrayInt *a1, DataArrayDouble *a2, const std::vector<std::string>& littleStrings)
3410 MEDCouplingPointSet::unserialization(tinyInfoD,tinyInfo,a1,a2,littleStrings);
3411 setMeshDimension(tinyInfo[5]);
3415 const int *recvBuffer=a1->getConstPointer();
3416 MCAuto<DataArrayInt> myConnecIndex=DataArrayInt::New();
3417 myConnecIndex->alloc(tinyInfo[6]+1,1);
3418 std::copy(recvBuffer,recvBuffer+tinyInfo[6]+1,myConnecIndex->getPointer());
3419 MCAuto<DataArrayInt> myConnec=DataArrayInt::New();
3420 myConnec->alloc(tinyInfo[7],1);
3421 std::copy(recvBuffer+tinyInfo[6]+1,recvBuffer+tinyInfo[6]+1+tinyInfo[7],myConnec->getPointer());
3422 setConnectivity(myConnec, myConnecIndex);
3427 * This is the low algorithm of MEDCouplingUMesh::buildPartOfMySelfSlice.
3428 * CellIds are given using range specified by a start an end and step.
3430 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfKeepCoordsSlice(int start, int end, int step) const
3432 checkFullyDefined();
3433 int ncell=getNumberOfCells();
3434 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New();
3435 ret->_mesh_dim=_mesh_dim;
3436 ret->setCoords(_coords);
3437 int newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfKeepCoordsSlice : ");
3438 MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(newNbOfCells+1,1);
3439 int *newConnIPtr=newConnI->getPointer(); *newConnIPtr=0;
3441 const int *conn=_nodal_connec->getConstPointer();
3442 const int *connIndex=_nodal_connec_index->getConstPointer();
3443 for(int i=0;i<newNbOfCells;i++,newConnIPtr++,work+=step)
3445 if(work>=0 && work<ncell)
3447 newConnIPtr[1]=newConnIPtr[0]+connIndex[work+1]-connIndex[work];
3451 std::ostringstream oss; oss << "MEDCouplingUMesh::buildPartOfMySelfKeepCoordsSlice : On pos #" << i << " input cell id =" << work << " should be in [0," << ncell << ") !";
3452 throw INTERP_KERNEL::Exception(oss.str());
3455 MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(newConnIPtr[0],1);
3456 int *newConnPtr=newConn->getPointer();
3457 std::set<INTERP_KERNEL::NormalizedCellType> types;
3459 for(int i=0;i<newNbOfCells;i++,newConnIPtr++,work+=step)
3461 types.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[work]]);
3462 newConnPtr=std::copy(conn+connIndex[work],conn+connIndex[work+1],newConnPtr);
3464 ret->setConnectivity(newConn,newConnI,false);
3466 ret->copyTinyInfoFrom(this);
3471 * This is the low algorithm of MEDCouplingUMesh::buildPartOfMySelf.
3472 * Keeps from \a this only cells which constituing point id are in the ids specified by [ \a begin,\a end ).
3473 * The return newly allocated mesh will share the same coordinates as \a this.
3475 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfKeepCoords(const int *begin, const int *end) const
3477 checkConnectivityFullyDefined();
3478 int ncell=getNumberOfCells();
3479 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New();
3480 ret->_mesh_dim=_mesh_dim;
3481 ret->setCoords(_coords);
3482 std::size_t nbOfElemsRet=std::distance(begin,end);
3483 int *connIndexRet=(int *)malloc((nbOfElemsRet+1)*sizeof(int));
3485 const int *conn=_nodal_connec->getConstPointer();
3486 const int *connIndex=_nodal_connec_index->getConstPointer();
3488 for(const int *work=begin;work!=end;work++,newNbring++)
3490 if(*work>=0 && *work<ncell)
3491 connIndexRet[newNbring+1]=connIndexRet[newNbring]+connIndex[*work+1]-connIndex[*work];
3495 std::ostringstream oss; oss << "MEDCouplingUMesh::buildPartOfMySelfKeepCoords : On pos #" << std::distance(begin,work) << " input cell id =" << *work << " should be in [0," << ncell << ") !";
3496 throw INTERP_KERNEL::Exception(oss.str());
3499 int *connRet=(int *)malloc(connIndexRet[nbOfElemsRet]*sizeof(int));
3500 int *connRetWork=connRet;
3501 std::set<INTERP_KERNEL::NormalizedCellType> types;
3502 for(const int *work=begin;work!=end;work++)
3504 types.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*work]]);
3505 connRetWork=std::copy(conn+connIndex[*work],conn+connIndex[*work+1],connRetWork);
3507 MCAuto<DataArrayInt> connRetArr=DataArrayInt::New();
3508 connRetArr->useArray(connRet,true,C_DEALLOC,connIndexRet[nbOfElemsRet],1);
3509 MCAuto<DataArrayInt> connIndexRetArr=DataArrayInt::New();
3510 connIndexRetArr->useArray(connIndexRet,true,C_DEALLOC,(int)nbOfElemsRet+1,1);
3511 ret->setConnectivity(connRetArr,connIndexRetArr,false);
3513 ret->copyTinyInfoFrom(this);
3518 * Returns a new MEDCouplingFieldDouble containing volumes of cells constituting \a this
3520 * For 1D cells, the returned field contains lengths.<br>
3521 * For 2D cells, the returned field contains areas.<br>
3522 * For 3D cells, the returned field contains volumes.
3523 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3524 * orientation, i.e. the volume is always positive.
3525 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on cells
3526 * and one time . The caller is to delete this field using decrRef() as it is no
3529 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureField(bool isAbs) const
3531 std::string name="MeasureOfMesh_";
3533 int nbelem=getNumberOfCells();
3534 MCAuto<MEDCouplingFieldDouble> field=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3535 field->setName(name);
3536 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3537 array->alloc(nbelem,1);
3538 double *area_vol=array->getPointer();
3539 field->setArray(array) ; array=0;
3540 field->setMesh(const_cast<MEDCouplingUMesh *>(this));
3541 field->synchronizeTimeWithMesh();
3542 if(getMeshDimension()!=-1)
3545 INTERP_KERNEL::NormalizedCellType type;
3546 int dim_space=getSpaceDimension();
3547 const double *coords=getCoords()->getConstPointer();
3548 const int *connec=getNodalConnectivity()->getConstPointer();
3549 const int *connec_index=getNodalConnectivityIndex()->getConstPointer();
3550 for(int iel=0;iel<nbelem;iel++)
3552 ipt=connec_index[iel];
3553 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3554 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);
3557 std::transform(area_vol,area_vol+nbelem,area_vol,std::ptr_fun<double,double>(fabs));
3561 area_vol[0]=std::numeric_limits<double>::max();
3563 return field.retn();
3567 * Returns a new DataArrayDouble containing volumes of specified cells of \a this
3569 * For 1D cells, the returned array contains lengths.<br>
3570 * For 2D cells, the returned array contains areas.<br>
3571 * For 3D cells, the returned array contains volumes.
3572 * This method avoids building explicitly a part of \a this mesh to perform the work.
3573 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3574 * orientation, i.e. the volume is always positive.
3575 * \param [in] begin - an array of cell ids of interest.
3576 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3577 * \return DataArrayDouble * - a new instance of DataArrayDouble. The caller is to
3578 * delete this array using decrRef() as it is no more needed.
3580 * \if ENABLE_EXAMPLES
3581 * \ref cpp_mcumesh_getPartMeasureField "Here is a C++ example".<br>
3582 * \ref py_mcumesh_getPartMeasureField "Here is a Python example".
3584 * \sa getMeasureField()
3586 DataArrayDouble *MEDCouplingUMesh::getPartMeasureField(bool isAbs, const int *begin, const int *end) const
3588 std::string name="PartMeasureOfMesh_";
3590 int nbelem=(int)std::distance(begin,end);
3591 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3592 array->setName(name);
3593 array->alloc(nbelem,1);
3594 double *area_vol=array->getPointer();
3595 if(getMeshDimension()!=-1)
3598 INTERP_KERNEL::NormalizedCellType type;
3599 int dim_space=getSpaceDimension();
3600 const double *coords=getCoords()->getConstPointer();
3601 const int *connec=getNodalConnectivity()->getConstPointer();
3602 const int *connec_index=getNodalConnectivityIndex()->getConstPointer();
3603 for(const int *iel=begin;iel!=end;iel++)
3605 ipt=connec_index[*iel];
3606 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3607 *area_vol++=INTERP_KERNEL::computeVolSurfOfCell2<int,INTERP_KERNEL::ALL_C_MODE>(type,connec+ipt+1,connec_index[*iel+1]-ipt-1,coords,dim_space);
3610 std::transform(array->getPointer(),area_vol,array->getPointer(),std::ptr_fun<double,double>(fabs));
3614 area_vol[0]=std::numeric_limits<double>::max();
3616 return array.retn();
3620 * Returns a new MEDCouplingFieldDouble containing volumes of cells of a dual mesh of
3621 * \a this one. The returned field contains the dual cell volume for each corresponding
3622 * node in \a this mesh. In other words, the field returns the getMeasureField() of
3623 * the dual mesh in P1 sens of \a this.<br>
3624 * For 1D cells, the returned field contains lengths.<br>
3625 * For 2D cells, the returned field contains areas.<br>
3626 * For 3D cells, the returned field contains volumes.
3627 * This method is useful to check "P1*" conservative interpolators.
3628 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3629 * orientation, i.e. the volume is always positive.
3630 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3631 * nodes and one time. The caller is to delete this array using decrRef() as
3632 * it is no more needed.
3634 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureFieldOnNode(bool isAbs) const
3636 MCAuto<MEDCouplingFieldDouble> tmp=getMeasureField(isAbs);
3637 std::string name="MeasureOnNodeOfMesh_";
3639 int nbNodes=getNumberOfNodes();
3640 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_NODES);
3641 double cst=1./((double)getMeshDimension()+1.);
3642 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3643 array->alloc(nbNodes,1);
3644 double *valsToFill=array->getPointer();
3645 std::fill(valsToFill,valsToFill+nbNodes,0.);
3646 const double *values=tmp->getArray()->getConstPointer();
3647 MCAuto<DataArrayInt> da=DataArrayInt::New();
3648 MCAuto<DataArrayInt> daInd=DataArrayInt::New();
3649 getReverseNodalConnectivity(da,daInd);
3650 const int *daPtr=da->getConstPointer();
3651 const int *daIPtr=daInd->getConstPointer();
3652 for(int i=0;i<nbNodes;i++)
3653 for(const int *cell=daPtr+daIPtr[i];cell!=daPtr+daIPtr[i+1];cell++)
3654 valsToFill[i]+=cst*values[*cell];
3656 ret->setArray(array);
3661 * Returns a new MEDCouplingFieldDouble holding normal vectors to cells of \a this
3662 * mesh. The returned normal vectors to each cell have a norm2 equal to 1.
3663 * The computed vectors have <em> this->getMeshDimension()+1 </em> components
3664 * and are normalized.
3665 * <br> \a this can be either
3666 * - a 2D mesh in 2D or 3D space or
3667 * - an 1D mesh in 2D space.
3669 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3670 * cells and one time. The caller is to delete this field using decrRef() as
3671 * it is no more needed.
3672 * \throw If the nodal connectivity of cells is not defined.
3673 * \throw If the coordinates array is not set.
3674 * \throw If the mesh dimension is not set.
3675 * \throw If the mesh and space dimension is not as specified above.
3677 MEDCouplingFieldDouble *MEDCouplingUMesh::buildOrthogonalField() const
3679 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3680 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3681 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3682 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3683 int nbOfCells=getNumberOfCells();
3684 int nbComp=getMeshDimension()+1;
3685 array->alloc(nbOfCells,nbComp);
3686 double *vals=array->getPointer();
3687 const int *connI=_nodal_connec_index->getConstPointer();
3688 const int *conn=_nodal_connec->getConstPointer();
3689 const double *coords=_coords->getConstPointer();
3690 if(getMeshDimension()==2)
3692 if(getSpaceDimension()==3)
3694 MCAuto<DataArrayDouble> loc=computeCellCenterOfMass();
3695 const double *locPtr=loc->getConstPointer();
3696 for(int i=0;i<nbOfCells;i++,vals+=3)
3698 int offset=connI[i];
3699 INTERP_KERNEL::crossprod<3>(locPtr+3*i,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3700 double n=INTERP_KERNEL::norm<3>(vals);
3701 std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3706 MCAuto<MEDCouplingFieldDouble> isAbs=getMeasureField(false);
3707 const double *isAbsPtr=isAbs->getArray()->begin();
3708 for(int i=0;i<nbOfCells;i++,isAbsPtr++)
3709 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=*isAbsPtr>0.?1.:-1.; }
3712 else//meshdimension==1
3715 for(int i=0;i<nbOfCells;i++)
3717 int offset=connI[i];
3718 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3719 double n=INTERP_KERNEL::norm<2>(tmp);
3720 std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3725 ret->setArray(array);
3727 ret->synchronizeTimeWithSupport();
3732 * Returns a new MEDCouplingFieldDouble holding normal vectors to specified cells of
3733 * \a this mesh. The computed vectors have <em> this->getMeshDimension()+1 </em> components
3734 * and are normalized.
3735 * <br> \a this can be either
3736 * - a 2D mesh in 2D or 3D space or
3737 * - an 1D mesh in 2D space.
3739 * This method avoids building explicitly a part of \a this mesh to perform the work.
3740 * \param [in] begin - an array of cell ids of interest.
3741 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3742 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3743 * cells and one time. The caller is to delete this field using decrRef() as
3744 * it is no more needed.
3745 * \throw If the nodal connectivity of cells is not defined.
3746 * \throw If the coordinates array is not set.
3747 * \throw If the mesh dimension is not set.
3748 * \throw If the mesh and space dimension is not as specified above.
3749 * \sa buildOrthogonalField()
3751 * \if ENABLE_EXAMPLES
3752 * \ref cpp_mcumesh_buildPartOrthogonalField "Here is a C++ example".<br>
3753 * \ref py_mcumesh_buildPartOrthogonalField "Here is a Python example".
3756 MEDCouplingFieldDouble *MEDCouplingUMesh::buildPartOrthogonalField(const int *begin, const int *end) const
3758 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3759 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3760 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3761 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3762 std::size_t nbelems=std::distance(begin,end);
3763 int nbComp=getMeshDimension()+1;
3764 array->alloc((int)nbelems,nbComp);
3765 double *vals=array->getPointer();
3766 const int *connI=_nodal_connec_index->getConstPointer();
3767 const int *conn=_nodal_connec->getConstPointer();
3768 const double *coords=_coords->getConstPointer();
3769 if(getMeshDimension()==2)
3771 if(getSpaceDimension()==3)
3773 MCAuto<DataArrayDouble> loc=getPartBarycenterAndOwner(begin,end);
3774 const double *locPtr=loc->getConstPointer();
3775 for(const int *i=begin;i!=end;i++,vals+=3,locPtr+=3)
3777 int offset=connI[*i];
3778 INTERP_KERNEL::crossprod<3>(locPtr,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3779 double n=INTERP_KERNEL::norm<3>(vals);
3780 std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3785 for(std::size_t i=0;i<nbelems;i++)
3786 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=1.; }
3789 else//meshdimension==1
3792 for(const int *i=begin;i!=end;i++)
3794 int offset=connI[*i];
3795 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3796 double n=INTERP_KERNEL::norm<2>(tmp);
3797 std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3802 ret->setArray(array);
3804 ret->synchronizeTimeWithSupport();
3809 * Returns a new MEDCouplingFieldDouble holding a direction vector for each SEG2 in \a
3810 * this 1D mesh. The computed vectors have <em> this->getSpaceDimension() </em> components
3811 * and are \b not normalized.
3812 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3813 * cells and one time. The caller is to delete this field using decrRef() as
3814 * it is no more needed.
3815 * \throw If the nodal connectivity of cells is not defined.
3816 * \throw If the coordinates array is not set.
3817 * \throw If \a this->getMeshDimension() != 1.
3818 * \throw If \a this mesh includes cells of type other than SEG2.
3820 MEDCouplingFieldDouble *MEDCouplingUMesh::buildDirectionVectorField() const
3822 if(getMeshDimension()!=1)
3823 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for buildDirectionVectorField !");
3824 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3825 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for buildDirectionVectorField !");
3826 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3827 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3828 int nbOfCells=getNumberOfCells();
3829 int spaceDim=getSpaceDimension();
3830 array->alloc(nbOfCells,spaceDim);
3831 double *pt=array->getPointer();
3832 const double *coo=getCoords()->getConstPointer();
3833 std::vector<int> conn;
3835 for(int i=0;i<nbOfCells;i++)
3838 getNodeIdsOfCell(i,conn);
3839 pt=std::transform(coo+conn[1]*spaceDim,coo+(conn[1]+1)*spaceDim,coo+conn[0]*spaceDim,pt,std::minus<double>());
3841 ret->setArray(array);
3843 ret->synchronizeTimeWithSupport();
3848 * Creates a 2D mesh by cutting \a this 3D mesh with a plane. In addition to the mesh,
3849 * returns a new DataArrayInt, of length equal to the number of 2D cells in the result
3850 * mesh, holding, for each cell in the result mesh, an id of a 3D cell it comes
3851 * from. If a result face is shared by two 3D cells, then the face in included twice in
3853 * \param [in] origin - 3 components of a point defining location of the plane.
3854 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3855 * must be greater than 1e-6.
3856 * \param [in] eps - half-thickness of the plane.
3857 * \param [out] cellIds - a new instance of DataArrayInt holding ids of 3D cells
3858 * producing correspondent 2D cells. The caller is to delete this array
3859 * using decrRef() as it is no more needed.
3860 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This mesh does
3861 * not share the node coordinates array with \a this mesh. The caller is to
3862 * delete this mesh using decrRef() as it is no more needed.
3863 * \throw If the coordinates array is not set.
3864 * \throw If the nodal connectivity of cells is not defined.
3865 * \throw If \a this->getMeshDimension() != 3 or \a this->getSpaceDimension() != 3.
3866 * \throw If magnitude of \a vec is less than 1e-6.
3867 * \throw If the plane does not intersect any 3D cell of \a this mesh.
3868 * \throw If \a this includes quadratic cells.
3870 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3D(const double *origin, const double *vec, double eps, DataArrayInt *&cellIds) const
3872 checkFullyDefined();
3873 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3874 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3875 MCAuto<DataArrayInt> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3876 if(candidates->empty())
3877 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane considering bounding boxes !");
3878 std::vector<int> nodes;
3879 DataArrayInt *cellIds1D=0;
3880 MCAuto<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3881 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3882 MCAuto<DataArrayInt> desc1=DataArrayInt::New(),desc2=DataArrayInt::New();
3883 MCAuto<DataArrayInt> descIndx1=DataArrayInt::New(),descIndx2=DataArrayInt::New();
3884 MCAuto<DataArrayInt> revDesc1=DataArrayInt::New(),revDesc2=DataArrayInt::New();
3885 MCAuto<DataArrayInt> revDescIndx1=DataArrayInt::New(),revDescIndx2=DataArrayInt::New();
3886 MCAuto<MEDCouplingUMesh> mDesc2=subMesh->buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2);//meshDim==2 spaceDim==3
3887 revDesc2=0; revDescIndx2=0;
3888 MCAuto<MEDCouplingUMesh> mDesc1=mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3889 revDesc1=0; revDescIndx1=0;
3890 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3891 MCAuto<DataArrayInt> cellIds1DTmp(cellIds1D);
3893 std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3894 for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3896 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3897 std::vector< std::pair<int,int> > cut3DSurf(mDesc2->getNumberOfCells());
3898 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->getConstPointer(),mDesc2->getNodalConnectivityIndex()->getConstPointer(),
3899 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3900 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3901 MCAuto<DataArrayInt> conn(DataArrayInt::New()),connI(DataArrayInt::New()),cellIds2(DataArrayInt::New());
3902 connI->pushBackSilent(0); conn->alloc(0,1); cellIds2->alloc(0,1);
3903 subMesh->assemblyForSplitFrom3DSurf(cut3DSurf,desc2->getConstPointer(),descIndx2->getConstPointer(),conn,connI,cellIds2);
3904 if(cellIds2->empty())
3905 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3906 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3D",2);
3907 ret->setCoords(mDesc1->getCoords());
3908 ret->setConnectivity(conn,connI,true);
3909 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3914 * Creates an 1D mesh by cutting \a this 2D mesh in 3D space with a plane. In
3915 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
3916 from. If a result segment is shared by two 2D cells, then the segment in included twice in
3918 * \param [in] origin - 3 components of a point defining location of the plane.
3919 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3920 * must be greater than 1e-6.
3921 * \param [in] eps - half-thickness of the plane.
3922 * \param [out] cellIds - a new instance of DataArrayInt holding ids of faces
3923 * producing correspondent segments. The caller is to delete this array
3924 * using decrRef() as it is no more needed.
3925 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This is an 1D
3926 * mesh in 3D space. This mesh does not share the node coordinates array with
3927 * \a this mesh. The caller is to delete this mesh using decrRef() as it is
3929 * \throw If the coordinates array is not set.
3930 * \throw If the nodal connectivity of cells is not defined.
3931 * \throw If \a this->getMeshDimension() != 2 or \a this->getSpaceDimension() != 3.
3932 * \throw If magnitude of \a vec is less than 1e-6.
3933 * \throw If the plane does not intersect any 2D cell of \a this mesh.
3934 * \throw If \a this includes quadratic cells.
3936 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3DSurf(const double *origin, const double *vec, double eps, DataArrayInt *&cellIds) const
3938 checkFullyDefined();
3939 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
3940 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf works on umeshes with meshdim equal to 2 and spaceDim equal to 3 !");
3941 MCAuto<DataArrayInt> candidates(getCellIdsCrossingPlane(origin,vec,eps));
3942 if(candidates->empty())
3943 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3D surf cells in this intercepts the specified plane considering bounding boxes !");
3944 std::vector<int> nodes;
3945 DataArrayInt *cellIds1D(0);
3946 MCAuto<MEDCouplingUMesh> subMesh(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3947 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3948 MCAuto<DataArrayInt> desc1(DataArrayInt::New()),descIndx1(DataArrayInt::New()),revDesc1(DataArrayInt::New()),revDescIndx1(DataArrayInt::New());
3949 MCAuto<MEDCouplingUMesh> mDesc1(subMesh->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3950 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3951 MCAuto<DataArrayInt> cellIds1DTmp(cellIds1D);
3953 std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3954 for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3956 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3957 int ncellsSub=subMesh->getNumberOfCells();
3958 std::vector< std::pair<int,int> > cut3DSurf(ncellsSub);
3959 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,subMesh->getNodalConnectivity()->getConstPointer(),subMesh->getNodalConnectivityIndex()->getConstPointer(),
3960 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3961 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3962 MCAuto<DataArrayInt> conn(DataArrayInt::New()),connI(DataArrayInt::New()),cellIds2(DataArrayInt::New()); connI->pushBackSilent(0);
3964 const int *nodal=subMesh->getNodalConnectivity()->getConstPointer();
3965 const int *nodalI=subMesh->getNodalConnectivityIndex()->getConstPointer();
3966 for(int i=0;i<ncellsSub;i++)
3968 if(cut3DSurf[i].first!=-1 && cut3DSurf[i].second!=-1)
3970 if(cut3DSurf[i].first!=-2)
3972 conn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG2); conn->pushBackSilent(cut3DSurf[i].first); conn->pushBackSilent(cut3DSurf[i].second);
3973 connI->pushBackSilent(conn->getNumberOfTuples());
3974 cellIds2->pushBackSilent(i);
3978 int cellId3DSurf=cut3DSurf[i].second;
3979 int offset=nodalI[cellId3DSurf]+1;
3980 int nbOfEdges=nodalI[cellId3DSurf+1]-offset;
3981 for(int j=0;j<nbOfEdges;j++)
3983 conn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG2); conn->pushBackSilent(nodal[offset+j]); conn->pushBackSilent(nodal[offset+(j+1)%nbOfEdges]);
3984 connI->pushBackSilent(conn->getNumberOfTuples());
3985 cellIds2->pushBackSilent(cellId3DSurf);
3990 if(cellIds2->empty())
3991 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3DSurf cells in this intercepts the specified plane !");
3992 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3DSurf",1);
3993 ret->setCoords(mDesc1->getCoords());
3994 ret->setConnectivity(conn,connI,true);
3995 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3999 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::clipSingle3DCellByPlane(const double origin[3], const double vec[3], double eps) const
4001 checkFullyDefined();
4002 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
4003 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
4004 if(getNumberOfCells()!=1)
4005 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works only on mesh containing exactly one cell !");
4007 std::vector<int> nodes;
4008 findNodesOnPlane(origin,vec,eps,nodes);
4009 MCAuto<DataArrayInt> desc1(DataArrayInt::New()),desc2(DataArrayInt::New()),descIndx1(DataArrayInt::New()),descIndx2(DataArrayInt::New()),revDesc1(DataArrayInt::New()),revDesc2(DataArrayInt::New()),revDescIndx1(DataArrayInt::New()),revDescIndx2(DataArrayInt::New());
4010 MCAuto<MEDCouplingUMesh> mDesc2(buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2));//meshDim==2 spaceDim==3
4011 revDesc2=0; revDescIndx2=0;
4012 MCAuto<MEDCouplingUMesh> mDesc1(mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
4013 revDesc1=0; revDescIndx1=0;
4014 DataArrayInt *cellIds1D(0);
4015 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
4016 MCAuto<DataArrayInt> cellIds1DTmp(cellIds1D);
4017 std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
4018 for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++)
4020 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
4021 std::vector< std::pair<int,int> > cut3DSurf(mDesc2->getNumberOfCells());
4022 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->begin(),mDesc2->getNodalConnectivityIndex()->begin(),
4023 mDesc1->getNodalConnectivity()->begin(),mDesc1->getNodalConnectivityIndex()->begin(),
4024 desc1->begin(),descIndx1->begin(),cut3DSurf);
4025 MCAuto<DataArrayInt> conn(DataArrayInt::New()),connI(DataArrayInt::New());
4026 connI->pushBackSilent(0); conn->alloc(0,1);
4028 MCAuto<DataArrayInt> cellIds2(DataArrayInt::New()); cellIds2->alloc(0,1);
4029 assemblyForSplitFrom3DSurf(cut3DSurf,desc2->begin(),descIndx2->begin(),conn,connI,cellIds2);
4030 if(cellIds2->empty())
4031 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
4033 std::vector<std::vector<int> > res;
4034 buildSubCellsFromCut(cut3DSurf,desc2->begin(),descIndx2->begin(),mDesc1->getCoords()->begin(),eps,res);
4035 std::size_t sz(res.size());
4036 if(res.size()==mDesc1->getNumberOfCells())
4037 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane : cell is not clipped !");
4038 for(std::size_t i=0;i<sz;i++)
4040 conn->pushBackSilent((int)INTERP_KERNEL::NORM_POLYGON);
4041 conn->insertAtTheEnd(res[i].begin(),res[i].end());
4042 connI->pushBackSilent(conn->getNumberOfTuples());
4044 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
4045 ret->setCoords(mDesc1->getCoords());
4046 ret->setConnectivity(conn,connI,true);
4047 int nbCellsRet(ret->getNumberOfCells());
4049 MCAuto<DataArrayDouble> vec2(DataArrayDouble::New()); vec2->alloc(1,3); std::copy(vec,vec+3,vec2->getPointer());
4050 MCAuto<MEDCouplingFieldDouble> ortho(ret->buildOrthogonalField());
4051 MCAuto<DataArrayDouble> ortho2(ortho->getArray()->selectByTupleIdSafeSlice(0,1,1));
4052 MCAuto<DataArrayDouble> dott(DataArrayDouble::Dot(ortho2,vec2));
4053 MCAuto<DataArrayDouble> ccm(ret->computeCellCenterOfMass());
4054 MCAuto<DataArrayDouble> occm;
4056 MCAuto<DataArrayDouble> pt(DataArrayDouble::New()); pt->alloc(1,3); std::copy(origin,origin+3,pt->getPointer());
4057 occm=DataArrayDouble::Substract(ccm,pt);
4059 vec2=DataArrayDouble::New(); vec2->alloc(nbCellsRet,3);
4060 vec2->setPartOfValuesSimple1(vec[0],0,nbCellsRet,1,0,1,1); vec2->setPartOfValuesSimple1(vec[1],0,nbCellsRet,1,1,2,1); vec2->setPartOfValuesSimple1(vec[2],0,nbCellsRet,1,2,3,1);
4061 MCAuto<DataArrayDouble> dott2(DataArrayDouble::Dot(occm,vec2));
4063 const int *cPtr(ret->getNodalConnectivity()->begin()),*ciPtr(ret->getNodalConnectivityIndex()->begin());
4064 MCAuto<MEDCouplingUMesh> ret2(MEDCouplingUMesh::New("Clip3D",3));
4065 ret2->setCoords(mDesc1->getCoords());
4066 MCAuto<DataArrayInt> conn2(DataArrayInt::New()),conn2I(DataArrayInt::New());
4067 conn2I->pushBackSilent(0); conn2->alloc(0,1);
4068 std::vector<int> cell0(1,(int)INTERP_KERNEL::NORM_POLYHED);
4069 std::vector<int> cell1(1,(int)INTERP_KERNEL::NORM_POLYHED);
4070 if(dott->getIJ(0,0)>0)
4072 cell0.insert(cell0.end(),cPtr+1,cPtr+ciPtr[1]);
4073 std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell1,cell1.end()));
4077 cell1.insert(cell1.end(),cPtr+1,cPtr+ciPtr[1]);
4078 std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell0,cell0.end()));
4080 for(int i=1;i<nbCellsRet;i++)
4082 if(dott2->getIJ(i,0)<0)
4084 if(ciPtr[i+1]-ciPtr[i]>=4)
4086 cell0.push_back(-1);
4087 cell0.insert(cell0.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
4092 if(ciPtr[i+1]-ciPtr[i]>=4)
4094 cell1.push_back(-1);
4095 cell1.insert(cell1.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
4099 conn2->insertAtTheEnd(cell0.begin(),cell0.end());
4100 conn2I->pushBackSilent(conn2->getNumberOfTuples());
4101 conn2->insertAtTheEnd(cell1.begin(),cell1.end());
4102 conn2I->pushBackSilent(conn2->getNumberOfTuples());
4103 ret2->setConnectivity(conn2,conn2I,true);
4104 ret2->checkConsistencyLight();
4105 ret2->writeVTK("ret2.vtu");
4106 ret2->orientCorrectlyPolyhedrons();
4111 * Finds cells whose bounding boxes intersect a given plane.
4112 * \param [in] origin - 3 components of a point defining location of the plane.
4113 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
4114 * must be greater than 1e-6.
4115 * \param [in] eps - half-thickness of the plane.
4116 * \return DataArrayInt * - a new instance of DataArrayInt holding ids of the found
4117 * cells. The caller is to delete this array using decrRef() as it is no more
4119 * \throw If the coordinates array is not set.
4120 * \throw If the nodal connectivity of cells is not defined.
4121 * \throw If \a this->getSpaceDimension() != 3.
4122 * \throw If magnitude of \a vec is less than 1e-6.
4123 * \sa buildSlice3D()
4125 DataArrayInt *MEDCouplingUMesh::getCellIdsCrossingPlane(const double *origin, const double *vec, double eps) const
4127 checkFullyDefined();
4128 if(getSpaceDimension()!=3)
4129 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with spaceDim equal to 3 !");
4130 double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
4132 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellIdsCrossingPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
4134 vec2[0]=vec[1]; vec2[1]=-vec[0]; vec2[2]=0.;//vec2 is the result of cross product of vec with (0,0,1)
4135 double angle=acos(vec[2]/normm);
4136 MCAuto<DataArrayInt> cellIds;
4140 MCAuto<DataArrayDouble> coo=_coords->deepCopy();
4141 double normm2(sqrt(vec2[0]*vec2[0]+vec2[1]*vec2[1]+vec2[2]*vec2[2]));
4142 if(normm2/normm>1e-6)
4143 DataArrayDouble::Rotate3DAlg(origin,vec2,angle,coo->getNumberOfTuples(),coo->getPointer(),coo->getPointer());
4144 MCAuto<MEDCouplingUMesh> mw=clone(false);//false -> shallow copy
4146 mw->getBoundingBox(bbox);
4147 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
4148 cellIds=mw->getCellsInBoundingBox(bbox,eps);
4152 getBoundingBox(bbox);
4153 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
4154 cellIds=getCellsInBoundingBox(bbox,eps);
4156 return cellIds.retn();
4160 * This method checks that \a this is a contiguous mesh. The user is expected to call this method on a mesh with meshdim==1.
4161 * If not an exception will thrown. If this is an empty mesh with no cell an exception will be thrown too.
4162 * No consideration of coordinate is done by this method.
4163 * 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)
4164 * If not false is returned. In case that false is returned a call to MEDCoupling::MEDCouplingUMesh::mergeNodes could be usefull.
4166 bool MEDCouplingUMesh::isContiguous1D() const
4168 if(getMeshDimension()!=1)
4169 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense only for 1D mesh !");
4170 int nbCells=getNumberOfCells();
4172 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense for non empty mesh !");
4173 const int *connI(_nodal_connec_index->begin()),*conn(_nodal_connec->begin());
4174 int ref=conn[connI[0]+2];
4175 for(int i=1;i<nbCells;i++)
4177 if(conn[connI[i]+1]!=ref)
4179 ref=conn[connI[i]+2];
4185 * This method is only callable on mesh with meshdim == 1 containing only SEG2 and spaceDim==3.
4186 * This method projects this on the 3D line defined by (pt,v). This methods first checks that all SEG2 are along v vector.
4187 * \param pt reference point of the line
4188 * \param v normalized director vector of the line
4189 * \param eps max precision before throwing an exception
4190 * \param res output of size this->getNumberOfCells
4192 void MEDCouplingUMesh::project1D(const double *pt, const double *v, double eps, double *res) const
4194 if(getMeshDimension()!=1)
4195 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for project1D !");
4196 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
4197 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for project1D !");
4198 if(getSpaceDimension()!=3)
4199 throw INTERP_KERNEL::Exception("Expected a umesh with spaceDim==3 for project1D !");
4200 MCAuto<MEDCouplingFieldDouble> f=buildDirectionVectorField();
4201 const double *fPtr=f->getArray()->getConstPointer();
4203 for(int i=0;i<getNumberOfCells();i++)
4205 const double *tmp1=fPtr+3*i;
4206 tmp[0]=tmp1[1]*v[2]-tmp1[2]*v[1];
4207 tmp[1]=tmp1[2]*v[0]-tmp1[0]*v[2];
4208 tmp[2]=tmp1[0]*v[1]-tmp1[1]*v[0];
4209 double n1=INTERP_KERNEL::norm<3>(tmp);
4210 n1/=INTERP_KERNEL::norm<3>(tmp1);
4212 throw INTERP_KERNEL::Exception("UMesh::Projection 1D failed !");
4214 const double *coo=getCoords()->getConstPointer();
4215 for(int i=0;i<getNumberOfNodes();i++)
4217 std::transform(coo+i*3,coo+i*3+3,pt,tmp,std::minus<double>());
4218 std::transform(tmp,tmp+3,v,tmp,std::multiplies<double>());
4219 res[i]=std::accumulate(tmp,tmp+3,0.);
4224 * 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.
4225 * \a this is expected to be a mesh so that its space dimension is equal to its
4226 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4227 * Distance from \a ptBg to \a ptEnd is expected to be equal to the space dimension. \a this is also expected to be fully defined (connectivity and coordinates).
4229 * 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
4230 * 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).
4231 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4233 * So this method is more accurate (so, more costly) than simply searching for the closest point in \a this.
4234 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4236 * \param [in] ptBg the start pointer (included) of the coordinates of the point
4237 * \param [in] ptEnd the end pointer (not included) of the coordinates of the point
4238 * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4239 * \return the positive value of the distance.
4240 * \throw if distance from \a ptBg to \a ptEnd is not equal to the space dimension. An exception is also thrown if mesh dimension of \a this is not equal to space
4242 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoints
4244 double MEDCouplingUMesh::distanceToPoint(const double *ptBg, const double *ptEnd, int& cellId) const
4246 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4247 if(meshDim!=spaceDim-1)
4248 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint works only for spaceDim=meshDim+1 !");
4249 if(meshDim!=2 && meshDim!=1)
4250 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint : only mesh dimension 2 and 1 are implemented !");
4251 checkFullyDefined();
4252 if((int)std::distance(ptBg,ptEnd)!=spaceDim)
4253 { 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()); }
4254 DataArrayInt *ret1=0;
4255 MCAuto<DataArrayDouble> pts=DataArrayDouble::New(); pts->useArray(ptBg,false,C_DEALLOC,1,spaceDim);
4256 MCAuto<DataArrayDouble> ret0=distanceToPoints(pts,ret1);
4257 MCAuto<DataArrayInt> ret1Safe(ret1);
4258 cellId=*ret1Safe->begin();
4259 return *ret0->begin();
4263 * This method computes the distance from each point of points serie \a pts (stored in a DataArrayDouble in which each tuple represents a point)
4264 * to \a this and the first \a cellId in \a this corresponding to the returned distance.
4265 * 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
4266 * 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).
4267 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4269 * \a this is expected to be a mesh so that its space dimension is equal to its
4270 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4271 * Number of components of \a pts is expected to be equal to the space dimension. \a this is also expected to be fully defined (connectivity and coordinates).
4273 * So this method is more accurate (so, more costly) than simply searching for each point in \a pts the closest point in \a this.
4274 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4276 * \param [in] pts the list of points in which each tuple represents a point
4277 * \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.
4278 * \return a newly allocated object to be dealed by the caller that tells for each point in \a pts the distance to \a this.
4279 * \throw if number of components of \a pts is not equal to the space dimension.
4280 * \throw if mesh dimension of \a this is not equal to space dimension - 1.
4281 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoint
4283 DataArrayDouble *MEDCouplingUMesh::distanceToPoints(const DataArrayDouble *pts, DataArrayInt *& cellIds) const
4286 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : input points pointer is NULL !");
4287 pts->checkAllocated();
4288 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4289 if(meshDim!=spaceDim-1)
4290 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints works only for spaceDim=meshDim+1 !");
4291 if(meshDim!=2 && meshDim!=1)
4292 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only mesh dimension 2 and 1 are implemented !");
4293 if(pts->getNumberOfComponents()!=spaceDim)
4295 std::ostringstream oss; oss << "MEDCouplingUMesh::distanceToPoints : input pts DataArrayDouble has " << pts->getNumberOfComponents() << " components whereas it should be equal to " << spaceDim << " (mesh spaceDimension) !";
4296 throw INTERP_KERNEL::Exception(oss.str());
4298 checkFullyDefined();
4299 int nbCells=getNumberOfCells();
4301 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : no cells in this !");
4302 int nbOfPts=pts->getNumberOfTuples();
4303 MCAuto<DataArrayDouble> ret0=DataArrayDouble::New(); ret0->alloc(nbOfPts,1);
4304 MCAuto<DataArrayInt> ret1=DataArrayInt::New(); ret1->alloc(nbOfPts,1);
4305 const int *nc=_nodal_connec->begin(),*ncI=_nodal_connec_index->begin(); const double *coords=_coords->begin();
4306 double *ret0Ptr=ret0->getPointer(); int *ret1Ptr=ret1->getPointer(); const double *ptsPtr=pts->begin();
4307 MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree());
4308 const double *bbox(bboxArr->begin());
4313 BBTreeDst<3> myTree(bbox,0,0,nbCells);
4314 for(int i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=3)
4316 double x=std::numeric_limits<double>::max();
4317 std::vector<int> elems;
4318 myTree.getMinDistanceOfMax(ptsPtr,x);
4319 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4320 DistanceToPoint3DSurfAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4326 BBTreeDst<2> myTree(bbox,0,0,nbCells);
4327 for(int i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=2)
4329 double x=std::numeric_limits<double>::max();
4330 std::vector<int> elems;
4331 myTree.getMinDistanceOfMax(ptsPtr,x);
4332 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4333 DistanceToPoint2DCurveAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4338 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only spacedim 2 and 3 supported !");
4340 cellIds=ret1.retn();
4347 * \param [in] pt the start pointer (included) of the coordinates of the point
4348 * \param [in] cellIdsBg the start pointer (included) of cellIds
4349 * \param [in] cellIdsEnd the end pointer (excluded) of cellIds
4350 * \param [in] nc nodal connectivity
4351 * \param [in] ncI nodal connectivity index
4352 * \param [in,out] ret0 the min distance between \a this and the external input point
4353 * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4354 * \sa MEDCouplingUMesh::distanceToPoint, MEDCouplingUMesh::distanceToPoints
4356 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)
4359 ret0=std::numeric_limits<double>::max();
4360 for(const int *zeCell=cellIdsBg;zeCell!=cellIdsEnd;zeCell++)
4362 switch((INTERP_KERNEL::NormalizedCellType)nc[ncI[*zeCell]])
4364 case INTERP_KERNEL::NORM_TRI3:
4366 double tmp=INTERP_KERNEL::DistanceFromPtToTriInSpaceDim3(pt,coords+3*nc[ncI[*zeCell]+1],coords+3*nc[ncI[*zeCell]+2],coords+3*nc[ncI[*zeCell]+3]);
4368 { ret0=tmp; cellId=*zeCell; }
4371 case INTERP_KERNEL::NORM_QUAD4:
4372 case INTERP_KERNEL::NORM_POLYGON:
4374 double tmp=INTERP_KERNEL::DistanceFromPtToPolygonInSpaceDim3(pt,nc+ncI[*zeCell]+1,nc+ncI[*zeCell+1],coords);
4376 { ret0=tmp; cellId=*zeCell; }
4380 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint3DSurfAlg : not managed cell type ! Supporting TRI3, QUAD4 and POLYGON !");
4386 * \param [in] pt the start pointer (included) of the coordinates of the point
4387 * \param [in] cellIdsBg the start pointer (included) of cellIds
4388 * \param [in] cellIdsEnd the end pointer (excluded) of cellIds
4389 * \param [in] nc nodal connectivity
4390 * \param [in] ncI nodal connectivity index
4391 * \param [in,out] ret0 the min distance between \a this and the external input point
4392 * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4393 * \sa MEDCouplingUMesh::distanceToPoint, MEDCouplingUMesh::distanceToPoints
4395 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)
4398 ret0=std::numeric_limits<double>::max();
4399 for(const int *zeCell=cellIdsBg;zeCell!=cellIdsEnd;zeCell++)
4401 switch((INTERP_KERNEL::NormalizedCellType)nc[ncI[*zeCell]])
4403 case INTERP_KERNEL::NORM_SEG2:
4405 std::size_t uselessEntry=0;
4406 double tmp=INTERP_KERNEL::SquareDistanceFromPtToSegInSpaceDim2(pt,coords+2*nc[ncI[*zeCell]+1],coords+2*nc[ncI[*zeCell]+2],uselessEntry);
4409 { ret0=tmp; cellId=*zeCell; }
4413 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint2DCurveAlg : not managed cell type ! Supporting SEG2 !");
4420 * Finds cells in contact with a ball (i.e. a point with precision).
4421 * 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.
4422 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4424 * \warning This method is suitable if the caller intends to evaluate only one
4425 * point, for more points getCellsContainingPoints() is recommended as it is
4427 * \param [in] pos - array of coordinates of the ball central point.
4428 * \param [in] eps - ball radius.
4429 * \return int - a smallest id of cells being in contact with the ball, -1 in case
4430 * if there are no such cells.
4431 * \throw If the coordinates array is not set.
4432 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4434 int MEDCouplingUMesh::getCellContainingPoint(const double *pos, double eps) const
4436 std::vector<int> elts;
4437 getCellsContainingPoint(pos,eps,elts);
4440 return elts.front();
4444 * Finds cells in contact with a ball (i.e. a point with precision).
4445 * 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.
4446 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4447 * \warning This method is suitable if the caller intends to evaluate only one
4448 * point, for more points getCellsContainingPoints() is recommended as it is
4450 * \param [in] pos - array of coordinates of the ball central point.
4451 * \param [in] eps - ball radius.
4452 * \param [out] elts - vector returning ids of the found cells. It is cleared
4453 * before inserting ids.
4454 * \throw If the coordinates array is not set.
4455 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4457 * \if ENABLE_EXAMPLES
4458 * \ref cpp_mcumesh_getCellsContainingPoint "Here is a C++ example".<br>
4459 * \ref py_mcumesh_getCellsContainingPoint "Here is a Python example".
4462 void MEDCouplingUMesh::getCellsContainingPoint(const double *pos, double eps, std::vector<int>& elts) const
4464 MCAuto<DataArrayInt> eltsUg,eltsIndexUg;
4465 getCellsContainingPoints(pos,1,eps,eltsUg,eltsIndexUg);
4466 elts.clear(); elts.insert(elts.end(),eltsUg->begin(),eltsUg->end());
4471 namespace MEDCoupling
4473 template<const int SPACEDIMM>
4477 static const int MY_SPACEDIM=SPACEDIMM;
4478 static const int MY_MESHDIM=8;
4479 typedef int MyConnType;
4480 static const INTERP_KERNEL::NumberingPolicy My_numPol=INTERP_KERNEL::ALL_C_MODE;
4482 // useless, but for windows compilation ...
4483 const double* getCoordinatesPtr() const { return 0; }
4484 const int* getConnectivityPtr() const { return 0; }
4485 const int* getConnectivityIndexPtr() const { return 0; }
4486 INTERP_KERNEL::NormalizedCellType getTypeOfElement(int) const { return (INTERP_KERNEL::NormalizedCellType)0; }
4490 INTERP_KERNEL::Edge *MEDCouplingUMeshBuildQPFromEdge2(INTERP_KERNEL::NormalizedCellType typ, const int *bg, const double *coords2D, std::map< MCAuto<INTERP_KERNEL::Node>,int>& m)
4492 INTERP_KERNEL::Edge *ret(0);
4493 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]));
4494 m[n0]=bg[0]; m[n1]=bg[1];
4497 case INTERP_KERNEL::NORM_SEG2:
4499 ret=new INTERP_KERNEL::EdgeLin(n0,n1);
4502 case INTERP_KERNEL::NORM_SEG3:
4504 INTERP_KERNEL::Node *n2(new INTERP_KERNEL::Node(coords2D[2*bg[2]],coords2D[2*bg[2]+1])); m[n2]=bg[2];
4505 INTERP_KERNEL::EdgeLin *e1(new INTERP_KERNEL::EdgeLin(n0,n2)),*e2(new INTERP_KERNEL::EdgeLin(n2,n1));
4506 INTERP_KERNEL::SegSegIntersector inters(*e1,*e2);
4507 // is the SEG3 degenerated, and thus can be reduced to a SEG2?
4508 bool colinearity(inters.areColinears());
4509 delete e1; delete e2;
4511 { ret=new INTERP_KERNEL::EdgeLin(n0,n1); }
4513 { ret=new INTERP_KERNEL::EdgeArcCircle(n0,n2,n1); }
4517 throw INTERP_KERNEL::Exception("MEDCouplingUMeshBuildQPFromEdge2 : Expecting a mesh with spaceDim==2 and meshDim==1 !");
4522 INTERP_KERNEL::Edge *MEDCouplingUMeshBuildQPFromEdge(INTERP_KERNEL::NormalizedCellType typ, std::map<int, std::pair<INTERP_KERNEL::Node *,bool> >& mapp2, const int *bg)
4524 INTERP_KERNEL::Edge *ret=0;
4527 case INTERP_KERNEL::NORM_SEG2:
4529 ret=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[1]].first);
4532 case INTERP_KERNEL::NORM_SEG3:
4534 INTERP_KERNEL::EdgeLin *e1=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[2]].first);
4535 INTERP_KERNEL::EdgeLin *e2=new INTERP_KERNEL::EdgeLin(mapp2[bg[2]].first,mapp2[bg[1]].first);
4536 INTERP_KERNEL::SegSegIntersector inters(*e1,*e2);
4537 // is the SEG3 degenerated, and thus can be reduced to a SEG2?
4538 bool colinearity=inters.areColinears();
4539 delete e1; delete e2;
4541 ret=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[1]].first);
4543 ret=new INTERP_KERNEL::EdgeArcCircle(mapp2[bg[0]].first,mapp2[bg[2]].first,mapp2[bg[1]].first);
4544 mapp2[bg[2]].second=false;
4548 throw INTERP_KERNEL::Exception("MEDCouplingUMeshBuildQPFromEdge : Expecting a mesh with spaceDim==2 and meshDim==1 !");
4554 * This method creates a sub mesh in Geometric2D DS. The sub mesh is composed by the sub set of cells in 'candidates' taken from
4555 * the global mesh 'mDesc'.
4556 * The input mesh 'mDesc' must be so that mDim==1 and spaceDim==2.
4557 * 'mapp' returns a mapping between local numbering in submesh (represented by a Node*) and the global node numbering in 'mDesc'.
4559 INTERP_KERNEL::QuadraticPolygon *MEDCouplingUMeshBuildQPFromMesh(const MEDCouplingUMesh *mDesc, const std::vector<int>& candidates,
4560 std::map<INTERP_KERNEL::Node *,int>& mapp)
4563 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.
4564 const double *coo=mDesc->getCoords()->getConstPointer();
4565 const int *c=mDesc->getNodalConnectivity()->getConstPointer();
4566 const int *cI=mDesc->getNodalConnectivityIndex()->getConstPointer();
4568 for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
4569 s.insert(c+cI[*it]+1,c+cI[(*it)+1]);
4570 for(std::set<int>::const_iterator it2=s.begin();it2!=s.end();it2++)
4572 INTERP_KERNEL::Node *n=new INTERP_KERNEL::Node(coo[2*(*it2)],coo[2*(*it2)+1]);
4573 mapp2[*it2]=std::pair<INTERP_KERNEL::Node *,bool>(n,true);
4575 INTERP_KERNEL::QuadraticPolygon *ret=new INTERP_KERNEL::QuadraticPolygon;
4576 for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
4578 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[*it]];
4579 ret->pushBack(MEDCouplingUMeshBuildQPFromEdge(typ,mapp2,c+cI[*it]+1));
4581 for(std::map<int, std::pair<INTERP_KERNEL::Node *,bool> >::const_iterator it2=mapp2.begin();it2!=mapp2.end();it2++)
4583 if((*it2).second.second)
4584 mapp[(*it2).second.first]=(*it2).first;
4585 ((*it2).second.first)->decrRef();
4590 INTERP_KERNEL::Node *MEDCouplingUMeshBuildQPNode(int nodeId, const double *coo1, int offset1, const double *coo2, int offset2, const std::vector<double>& addCoo)
4594 int locId=nodeId-offset2;
4595 return new INTERP_KERNEL::Node(addCoo[2*locId],addCoo[2*locId+1]);
4599 int locId=nodeId-offset1;
4600 return new INTERP_KERNEL::Node(coo2[2*locId],coo2[2*locId+1]);
4602 return new INTERP_KERNEL::Node(coo1[2*nodeId],coo1[2*nodeId+1]);
4606 * Construct a mapping between set of Nodes and the standart MEDCoupling connectivity format (c, cI).
4608 void MEDCouplingUMeshBuildQPFromMesh3(const double *coo1, int offset1, const double *coo2, int offset2, const std::vector<double>& addCoo,
4609 const int *desc1Bg, const int *desc1End, const std::vector<std::vector<int> >& intesctEdges1,
4610 /*output*/std::map<INTERP_KERNEL::Node *,int>& mapp, std::map<int,INTERP_KERNEL::Node *>& mappRev)
4612 for(const int *desc1=desc1Bg;desc1!=desc1End;desc1++)
4614 int eltId1=abs(*desc1)-1;
4615 for(std::vector<int>::const_iterator it1=intesctEdges1[eltId1].begin();it1!=intesctEdges1[eltId1].end();it1++)
4617 std::map<int,INTERP_KERNEL::Node *>::const_iterator it=mappRev.find(*it1);
4618 if(it==mappRev.end())
4620 INTERP_KERNEL::Node *node=MEDCouplingUMeshBuildQPNode(*it1,coo1,offset1,coo2,offset2,addCoo);
4631 template<int SPACEDIM>
4632 void MEDCouplingUMesh::getCellsContainingPointsAlg(const double *coords, const double *pos, int nbOfPoints,
4633 double eps, MCAuto<DataArrayInt>& elts, MCAuto<DataArrayInt>& eltsIndex) const
4635 elts=DataArrayInt::New(); eltsIndex=DataArrayInt::New(); eltsIndex->alloc(nbOfPoints+1,1); eltsIndex->setIJ(0,0,0); elts->alloc(0,1);
4636 int *eltsIndexPtr(eltsIndex->getPointer());
4637 MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree(eps));
4638 const double *bbox(bboxArr->begin());
4639 int nbOfCells=getNumberOfCells();
4640 const int *conn=_nodal_connec->getConstPointer();
4641 const int *connI=_nodal_connec_index->getConstPointer();
4642 double bb[2*SPACEDIM];
4643 BBTree<SPACEDIM,int> myTree(&bbox[0],0,0,nbOfCells,-eps);
4644 for(int i=0;i<nbOfPoints;i++)
4646 eltsIndexPtr[i+1]=eltsIndexPtr[i];
4647 for(int j=0;j<SPACEDIM;j++)
4649 bb[2*j]=pos[SPACEDIM*i+j];
4650 bb[2*j+1]=pos[SPACEDIM*i+j];
4652 std::vector<int> candidates;
4653 myTree.getIntersectingElems(bb,candidates);
4654 for(std::vector<int>::const_iterator iter=candidates.begin();iter!=candidates.end();iter++)
4656 int sz(connI[(*iter)+1]-connI[*iter]-1);
4657 INTERP_KERNEL::NormalizedCellType ct((INTERP_KERNEL::NormalizedCellType)conn[connI[*iter]]);
4659 if(ct!=INTERP_KERNEL::NORM_POLYGON && ct!=INTERP_KERNEL::NORM_QPOLYG)
4660 status=INTERP_KERNEL::PointLocatorAlgos<DummyClsMCUG<SPACEDIM> >::isElementContainsPoint(pos+i*SPACEDIM,ct,coords,conn+connI[*iter]+1,sz,eps);
4664 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPointsAlg : not implemented yet for POLYGON and QPOLYGON in spaceDim 3 !");
4665 INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
4666 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
4667 std::vector<INTERP_KERNEL::Node *> nodes(sz);
4668 INTERP_KERNEL::QuadraticPolygon *pol(0);
4669 for(int j=0;j<sz;j++)
4671 int nodeId(conn[connI[*iter]+1+j]);
4672 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*SPACEDIM],coords[nodeId*SPACEDIM+1]);
4674 if(!INTERP_KERNEL::CellModel::GetCellModel(ct).isQuadratic())
4675 pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
4677 pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
4678 INTERP_KERNEL::Node *n(new INTERP_KERNEL::Node(pos[i*SPACEDIM],pos[i*SPACEDIM+1]));
4679 double a(0.),b(0.),c(0.);
4680 a=pol->normalizeMe(b,c); n->applySimilarity(b,c,a);
4681 status=pol->isInOrOut2(n);
4682 delete pol; n->decrRef();
4686 eltsIndexPtr[i+1]++;
4687 elts->pushBackSilent(*iter);
4693 * Finds cells in contact with several balls (i.e. points with precision).
4694 * This method is an extension of getCellContainingPoint() and
4695 * getCellsContainingPoint() for the case of multiple points.
4696 * 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.
4697 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4698 * \param [in] pos - an array of coordinates of points in full interlace mode :
4699 * X0,Y0,Z0,X1,Y1,Z1,... Size of the array must be \a
4700 * this->getSpaceDimension() * \a nbOfPoints
4701 * \param [in] nbOfPoints - number of points to locate within \a this mesh.
4702 * \param [in] eps - radius of balls (i.e. the precision).
4703 * \param [out] elts - vector returning ids of found cells.
4704 * \param [out] eltsIndex - an array, of length \a nbOfPoints + 1,
4705 * dividing cell ids in \a elts into groups each referring to one
4706 * point. Its every element (except the last one) is an index pointing to the
4707 * first id of a group of cells. For example cells in contact with the *i*-th
4708 * point are described by following range of indices:
4709 * [ \a eltsIndex[ *i* ], \a eltsIndex[ *i*+1 ] ) and the cell ids are
4710 * \a elts[ \a eltsIndex[ *i* ]], \a elts[ \a eltsIndex[ *i* ] + 1 ], ...
4711 * Number of cells in contact with the *i*-th point is
4712 * \a eltsIndex[ *i*+1 ] - \a eltsIndex[ *i* ].
4713 * \throw If the coordinates array is not set.
4714 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4716 * \if ENABLE_EXAMPLES
4717 * \ref cpp_mcumesh_getCellsContainingPoints "Here is a C++ example".<br>
4718 * \ref py_mcumesh_getCellsContainingPoints "Here is a Python example".
4721 void MEDCouplingUMesh::getCellsContainingPoints(const double *pos, int nbOfPoints, double eps,
4722 MCAuto<DataArrayInt>& elts, MCAuto<DataArrayInt>& eltsIndex) const
4724 int spaceDim=getSpaceDimension();
4725 int mDim=getMeshDimension();
4730 const double *coords=_coords->getConstPointer();
4731 getCellsContainingPointsAlg<3>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4738 throw INTERP_KERNEL::Exception("For spaceDim==3 only meshDim==3 implemented for getelementscontainingpoints !");
4740 else if(spaceDim==2)
4744 const double *coords=_coords->getConstPointer();
4745 getCellsContainingPointsAlg<2>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4748 throw INTERP_KERNEL::Exception("For spaceDim==2 only meshDim==2 implemented for getelementscontainingpoints !");
4750 else if(spaceDim==1)
4754 const double *coords=_coords->getConstPointer();
4755 getCellsContainingPointsAlg<1>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4758 throw INTERP_KERNEL::Exception("For spaceDim==1 only meshDim==1 implemented for getelementscontainingpoints !");
4761 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPoints : not managed for mdim not in [1,2,3] !");
4765 * Finds butterfly cells in \a this mesh. A 2D cell is considered to be butterfly if at
4766 * least two its edges intersect each other anywhere except their extremities. An
4767 * INTERP_KERNEL::NORM_NORI3 cell can \b not be butterfly.
4768 * \param [in,out] cells - a vector returning ids of the found cells. It is not
4769 * cleared before filling in.
4770 * \param [in] eps - precision.
4771 * \throw If \a this->getMeshDimension() != 2.
4772 * \throw If \a this->getSpaceDimension() != 2 && \a this->getSpaceDimension() != 3.
4774 void MEDCouplingUMesh::checkButterflyCells(std::vector<int>& cells, double eps) const
4776 const char msg[]="Butterfly detection work only for 2D cells with spaceDim==2 or 3!";
4777 if(getMeshDimension()!=2)
4778 throw INTERP_KERNEL::Exception(msg);
4779 int spaceDim=getSpaceDimension();
4780 if(spaceDim!=2 && spaceDim!=3)
4781 throw INTERP_KERNEL::Exception(msg);
4782 const int *conn=_nodal_connec->getConstPointer();
4783 const int *connI=_nodal_connec_index->getConstPointer();
4784 int nbOfCells=getNumberOfCells();
4785 std::vector<double> cell2DinS2;
4786 for(int i=0;i<nbOfCells;i++)
4788 int offset=connI[i];
4789 int nbOfNodesForCell=connI[i+1]-offset-1;
4790 if(nbOfNodesForCell<=3)
4792 bool isQuad=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[offset]).isQuadratic();
4793 project2DCellOnXY(conn+offset+1,conn+connI[i+1],cell2DinS2);
4794 if(isButterfly2DCell(cell2DinS2,isQuad,eps))
4801 * This method is typically requested to unbutterfly 2D linear cells in \b this.
4803 * 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.
4804 * This method works only for linear 2D cells. If there is any of non linear cells (INTERP_KERNEL::NORM_QUAD8 for example) an INTERP_KERNEL::Exception will be thrown too.
4806 * For each 2D linear cell in \b this, this method builds the convex envelop (or the convex hull) of the current cell.
4807 * This convex envelop is computed using Jarvis march algorithm.
4808 * The coordinates and the number of cells of \b this remain unchanged on invocation of this method.
4809 * 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)
4810 * its connectivity will remain unchanged. If the computation leads to a modification of nodal connectivity of a cell its geometric type will be modified to INTERP_KERNEL::NORM_POLYGON.
4812 * \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.
4813 * \sa MEDCouplingUMesh::colinearize2D
4815 DataArrayInt *MEDCouplingUMesh::convexEnvelop2D()
4817 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
4818 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convexEnvelop2D works only for meshDim=2 and spaceDim=2 !");
4819 checkFullyDefined();
4820 const double *coords=getCoords()->getConstPointer();
4821 int nbOfCells=getNumberOfCells();
4822 MCAuto<DataArrayInt> nodalConnecIndexOut=DataArrayInt::New();
4823 nodalConnecIndexOut->alloc(nbOfCells+1,1);
4824 MCAuto<DataArrayInt> nodalConnecOut(DataArrayInt::New());
4825 int *workIndexOut=nodalConnecIndexOut->getPointer();
4827 const int *nodalConnecIn=_nodal_connec->getConstPointer();
4828 const int *nodalConnecIndexIn=_nodal_connec_index->getConstPointer();
4829 std::set<INTERP_KERNEL::NormalizedCellType> types;
4830 MCAuto<DataArrayInt> isChanged(DataArrayInt::New());
4831 isChanged->alloc(0,1);
4832 for(int i=0;i<nbOfCells;i++,workIndexOut++)
4834 int pos=nodalConnecOut->getNumberOfTuples();
4835 if(BuildConvexEnvelopOf2DCellJarvis(coords,nodalConnecIn+nodalConnecIndexIn[i],nodalConnecIn+nodalConnecIndexIn[i+1],nodalConnecOut))
4836 isChanged->pushBackSilent(i);
4837 types.insert((INTERP_KERNEL::NormalizedCellType)nodalConnecOut->getIJ(pos,0));
4838 workIndexOut[1]=nodalConnecOut->getNumberOfTuples();
4840 if(isChanged->empty())
4842 setConnectivity(nodalConnecOut,nodalConnecIndexOut,false);
4844 return isChanged.retn();
4848 * This method is \b NOT const because it can modify \a this.
4849 * \a this is expected to be an unstructured mesh with meshDim==2 and spaceDim==3. If not an exception will be thrown.
4850 * \param mesh1D is an unstructured mesh with MeshDim==1 and spaceDim==3. If not an exception will be thrown.
4851 * \param policy specifies the type of extrusion chosen:
4852 * - \b 0 for translation only (most simple): the cells of the 1D mesh represent the vectors along which the 2D mesh
4853 * will be repeated to build each level
4854 * - \b 1 for translation and rotation: the translation is done as above. For each level, an arc of circle is fitted on
4855 * 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
4856 * along an axis normal to the plane containing the arc, and finally the angle of rotation is defined by the first two points on the
4858 * \return an unstructured mesh with meshDim==3 and spaceDim==3. The returned mesh has the same coords than \a this.
4860 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMesh(const MEDCouplingUMesh *mesh1D, int policy)
4862 checkFullyDefined();
4863 mesh1D->checkFullyDefined();
4864 if(!mesh1D->isContiguous1D())
4865 throw INTERP_KERNEL::Exception("buildExtrudedMesh : 1D mesh passed in parameter is not contiguous !");
4866 if(getSpaceDimension()!=mesh1D->getSpaceDimension())
4867 throw INTERP_KERNEL::Exception("Invalid call to buildExtrudedMesh this and mesh1D must have same space dimension !");
4868 if((getMeshDimension()!=2 || getSpaceDimension()!=3) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
4869 throw INTERP_KERNEL::Exception("Invalid 'this' for buildExtrudedMesh method : must be (meshDim==2 and spaceDim==3) or (meshDim==1 and spaceDim==2) !");
4870 if(mesh1D->getMeshDimension()!=1)
4871 throw INTERP_KERNEL::Exception("Invalid 'mesh1D' for buildExtrudedMesh method : must be meshDim==1 !");
4873 if(isPresenceOfQuadratic())
4875 if(mesh1D->isFullyQuadratic())
4878 throw INTERP_KERNEL::Exception("Invalid 2D mesh and 1D mesh because 2D mesh has quadratic cells and 1D is not fully quadratic !");
4880 int oldNbOfNodes(getNumberOfNodes());
4881 MCAuto<DataArrayDouble> newCoords;
4886 newCoords=fillExtCoordsUsingTranslation(mesh1D,isQuad);
4891 newCoords=fillExtCoordsUsingTranslAndAutoRotation(mesh1D,isQuad);
4895 throw INTERP_KERNEL::Exception("Not implemented extrusion policy : must be in (0) !");
4897 setCoords(newCoords);
4898 MCAuto<MEDCouplingUMesh> ret(buildExtrudedMeshFromThisLowLev(oldNbOfNodes,isQuad));
4904 * This method works on a 3D curve linear mesh that is to say (meshDim==1 and spaceDim==3).
4905 * If it is not the case an exception will be thrown.
4906 * This method is non const because the coordinate of \a this can be appended with some new points issued from
4907 * intersection of plane defined by ('origin','vec').
4908 * This method has one in/out parameter : 'cut3DCurve'.
4909 * Param 'cut3DCurve' is expected to be of size 'this->getNumberOfCells()'. For each i in [0,'this->getNumberOfCells()')
4910 * if cut3DCurve[i]==-2, it means that for cell #i in \a this nothing has been detected previously.
4911 * if cut3DCurve[i]==-1, it means that cell#i has been already detected to be fully part of plane defined by ('origin','vec').
4912 * This method will throw an exception if \a this contains a non linear segment.
4914 void MEDCouplingUMesh::split3DCurveWithPlane(const double *origin, const double *vec, double eps, std::vector<int>& cut3DCurve)
4916 checkFullyDefined();
4917 if(getMeshDimension()!=1 || getSpaceDimension()!=3)
4918 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane works on umeshes with meshdim equal to 1 and spaceDim equal to 3 !");
4919 int ncells=getNumberOfCells();
4920 int nnodes=getNumberOfNodes();
4921 double vec2[3],vec3[3],vec4[3];
4922 double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
4924 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
4925 vec2[0]=vec[0]/normm; vec2[1]=vec[1]/normm; vec2[2]=vec[2]/normm;
4926 const int *conn=_nodal_connec->getConstPointer();
4927 const int *connI=_nodal_connec_index->getConstPointer();
4928 const double *coo=_coords->getConstPointer();
4929 std::vector<double> addCoo;
4930 for(int i=0;i<ncells;i++)
4932 if(conn[connI[i]]==(int)INTERP_KERNEL::NORM_SEG2)
4934 if(cut3DCurve[i]==-2)
4936 int st=conn[connI[i]+1],endd=conn[connI[i]+2];
4937 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];
4938 double normm2=sqrt(vec3[0]*vec3[0]+vec3[1]*vec3[1]+vec3[2]*vec3[2]);
4939 double colin=std::abs((vec3[0]*vec2[0]+vec3[1]*vec2[1]+vec3[2]*vec2[2])/normm2);
4940 if(colin>eps)//if colin<=eps -> current SEG2 is colinear to the input plane
4942 const double *st2=coo+3*st;
4943 vec4[0]=st2[0]-origin[0]; vec4[1]=st2[1]-origin[1]; vec4[2]=st2[2]-origin[2];
4944 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]));
4945 if(pos>eps && pos<1-eps)
4947 int nNode=((int)addCoo.size())/3;
4948 vec4[0]=st2[0]+pos*vec3[0]; vec4[1]=st2[1]+pos*vec3[1]; vec4[2]=st2[2]+pos*vec3[2];
4949 addCoo.insert(addCoo.end(),vec4,vec4+3);
4950 cut3DCurve[i]=nnodes+nNode;
4956 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane : this method is only available for linear cell (NORM_SEG2) !");
4960 int newNbOfNodes=nnodes+((int)addCoo.size())/3;
4961 MCAuto<DataArrayDouble> coo2=DataArrayDouble::New();
4962 coo2->alloc(newNbOfNodes,3);
4963 double *tmp=coo2->getPointer();
4964 tmp=std::copy(_coords->begin(),_coords->end(),tmp);
4965 std::copy(addCoo.begin(),addCoo.end(),tmp);
4966 DataArrayDouble::SetArrayIn(coo2,_coords);
4971 * This method incarnates the policy 0 for MEDCouplingUMesh::buildExtrudedMesh method.
4972 * \param mesh1D is the input 1D mesh used for translation computation.
4973 * \return newCoords new coords filled by this method.
4975 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslation(const MEDCouplingUMesh *mesh1D, bool isQuad) const
4977 int oldNbOfNodes=getNumberOfNodes();
4978 int nbOf1DCells=mesh1D->getNumberOfCells();
4979 int spaceDim=getSpaceDimension();
4980 DataArrayDouble *ret=DataArrayDouble::New();
4981 std::vector<bool> isQuads;
4982 int nbOfLevsInVec=isQuad?2*nbOf1DCells+1:nbOf1DCells+1;
4983 ret->alloc(oldNbOfNodes*nbOfLevsInVec,spaceDim);
4984 double *retPtr=ret->getPointer();
4985 const double *coords=getCoords()->getConstPointer();
4986 double *work=std::copy(coords,coords+spaceDim*oldNbOfNodes,retPtr);
4988 std::vector<double> c;
4992 for(int i=0;i<nbOf1DCells;i++)
4995 mesh1D->getNodeIdsOfCell(i,v);
4997 mesh1D->getCoordinatesOfNode(v[isQuad?2:1],c);
4998 mesh1D->getCoordinatesOfNode(v[0],c);
4999 std::transform(c.begin(),c.begin()+spaceDim,c.begin()+spaceDim,vec,std::minus<double>());
5000 for(int j=0;j<oldNbOfNodes;j++)
5001 work=std::transform(vec,vec+spaceDim,retPtr+spaceDim*(i*oldNbOfNodes+j),work,std::plus<double>());
5005 mesh1D->getCoordinatesOfNode(v[1],c);
5006 mesh1D->getCoordinatesOfNode(v[0],c);
5007 std::transform(c.begin(),c.begin()+spaceDim,c.begin()+spaceDim,vec,std::minus<double>());
5008 for(int j=0;j<oldNbOfNodes;j++)
5009 work=std::transform(vec,vec+spaceDim,retPtr+spaceDim*(i*oldNbOfNodes+j),work,std::plus<double>());
5012 ret->copyStringInfoFrom(*getCoords());
5017 * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method.
5018 * \param mesh1D is the input 1D mesh used for translation and automatic rotation computation.
5019 * \return newCoords new coords filled by this method.
5021 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation(const MEDCouplingUMesh *mesh1D, bool isQuad) const
5023 if(mesh1D->getSpaceDimension()==2)
5024 return fillExtCoordsUsingTranslAndAutoRotation2D(mesh1D,isQuad);
5025 if(mesh1D->getSpaceDimension()==3)
5026 return fillExtCoordsUsingTranslAndAutoRotation3D(mesh1D,isQuad);
5027 throw INTERP_KERNEL::Exception("Not implemented rotation and translation alg. for spacedim other than 2 and 3 !");
5031 * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method.
5032 * \param mesh1D is the input 1D mesh used for translation and automatic rotation computation.
5033 * \return newCoords new coords filled by this method.
5035 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D(const MEDCouplingUMesh *mesh1D, bool isQuad) const
5038 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D : not implemented for quadratic cells !");
5039 int oldNbOfNodes=getNumberOfNodes();
5040 int nbOf1DCells=mesh1D->getNumberOfCells();
5042 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D : impossible to detect any angle of rotation ! Change extrusion policy 1->0 !");
5043 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
5044 int nbOfLevsInVec=nbOf1DCells+1;
5045 ret->alloc(oldNbOfNodes*nbOfLevsInVec,2);
5046 double *retPtr=ret->getPointer();
5047 retPtr=std::copy(getCoords()->getConstPointer(),getCoords()->getConstPointer()+getCoords()->getNbOfElems(),retPtr);
5048 MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
5049 MCAuto<DataArrayDouble> tmp2=getCoords()->deepCopy();
5050 tmp->setCoords(tmp2);
5051 const double *coo1D=mesh1D->getCoords()->getConstPointer();
5052 const int *conn1D=mesh1D->getNodalConnectivity()->getConstPointer();
5053 const int *connI1D=mesh1D->getNodalConnectivityIndex()->getConstPointer();
5054 for(int i=1;i<nbOfLevsInVec;i++)
5056 const double *begin=coo1D+2*conn1D[connI1D[i-1]+1];
5057 const double *end=coo1D+2*conn1D[connI1D[i-1]+2];
5058 const double *third=i+1<nbOfLevsInVec?coo1D+2*conn1D[connI1D[i]+2]:coo1D+2*conn1D[connI1D[i-2]+1];
5059 const double vec[2]={end[0]-begin[0],end[1]-begin[1]};
5060 tmp->translate(vec);
5061 double tmp3[2],radius,alpha,alpha0;
5062 const double *p0=i+1<nbOfLevsInVec?begin:third;
5063 const double *p1=i+1<nbOfLevsInVec?end:begin;
5064 const double *p2=i+1<nbOfLevsInVec?third:end;
5065 INTERP_KERNEL::EdgeArcCircle::GetArcOfCirclePassingThru(p0,p1,p2,tmp3,radius,alpha,alpha0);
5066 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]);
5067 double angle=acos(cosangle/(radius*radius));
5068 tmp->rotate(end,0,angle);
5069 retPtr=std::copy(tmp2->getConstPointer(),tmp2->getConstPointer()+tmp2->getNbOfElems(),retPtr);
5075 * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method.
5076 * \param mesh1D is the input 1D mesh used for translation and automatic rotation computation.
5077 * \return newCoords new coords filled by this method.
5079 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D(const MEDCouplingUMesh *mesh1D, bool isQuad) const
5082 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D : not implemented for quadratic cells !");
5083 int oldNbOfNodes=getNumberOfNodes();
5084 int nbOf1DCells=mesh1D->getNumberOfCells();
5086 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D : impossible to detect any angle of rotation ! Change extrusion policy 1->0 !");
5087 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
5088 int nbOfLevsInVec=nbOf1DCells+1;
5089 ret->alloc(oldNbOfNodes*nbOfLevsInVec,3);
5090 double *retPtr=ret->getPointer();
5091 retPtr=std::copy(getCoords()->getConstPointer(),getCoords()->getConstPointer()+getCoords()->getNbOfElems(),retPtr);
5092 MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
5093 MCAuto<DataArrayDouble> tmp2=getCoords()->deepCopy();
5094 tmp->setCoords(tmp2);
5095 const double *coo1D=mesh1D->getCoords()->getConstPointer();
5096 const int *conn1D=mesh1D->getNodalConnectivity()->getConstPointer();
5097 const int *connI1D=mesh1D->getNodalConnectivityIndex()->getConstPointer();
5098 for(int i=1;i<nbOfLevsInVec;i++)
5100 const double *begin=coo1D+3*conn1D[connI1D[i-1]+1];
5101 const double *end=coo1D+3*conn1D[connI1D[i-1]+2];
5102 const double *third=i+1<nbOfLevsInVec?coo1D+3*conn1D[connI1D[i]+2]:coo1D+3*conn1D[connI1D[i-2]+1];
5103 const double vec[3]={end[0]-begin[0],end[1]-begin[1],end[2]-begin[2]};
5104 tmp->translate(vec);
5105 double tmp3[2],radius,alpha,alpha0;
5106 const double *p0=i+1<nbOfLevsInVec?begin:third;
5107 const double *p1=i+1<nbOfLevsInVec?end:begin;
5108 const double *p2=i+1<nbOfLevsInVec?third:end;
5109 double vecPlane[3]={
5110 (p1[1]-p0[1])*(p2[2]-p1[2])-(p1[2]-p0[2])*(p2[1]-p1[1]),
5111 (p1[2]-p0[2])*(p2[0]-p1[0])-(p1[0]-p0[0])*(p2[2]-p1[2]),
5112 (p1[0]-p0[0])*(p2[1]-p1[1])-(p1[1]-p0[1])*(p2[0]-p1[0]),
5114 double norm=sqrt(vecPlane[0]*vecPlane[0]+vecPlane[1]*vecPlane[1]+vecPlane[2]*vecPlane[2]);
5117 vecPlane[0]/=norm; vecPlane[1]/=norm; vecPlane[2]/=norm;
5118 double norm2=sqrt(vecPlane[0]*vecPlane[0]+vecPlane[1]*vecPlane[1]);
5119 double vec2[2]={vecPlane[1]/norm2,-vecPlane[0]/norm2};
5121 double c2=cos(asin(s2));
5123 {vec2[0]*vec2[0]*(1-c2)+c2, vec2[0]*vec2[1]*(1-c2), vec2[1]*s2},
5124 {vec2[0]*vec2[1]*(1-c2), vec2[1]*vec2[1]*(1-c2)+c2, -vec2[0]*s2},
5125 {-vec2[1]*s2, vec2[0]*s2, c2}
5127 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]};
5128 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]};
5129 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]};
5130 INTERP_KERNEL::EdgeArcCircle::GetArcOfCirclePassingThru(p0r,p1r,p2r,tmp3,radius,alpha,alpha0);
5131 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]);
5132 double angle=acos(cosangle/(radius*radius));
5133 tmp->rotate(end,vecPlane,angle);
5135 retPtr=std::copy(tmp2->getConstPointer(),tmp2->getConstPointer()+tmp2->getNbOfElems(),retPtr);
5141 * This method is private because not easy to use for end user. This method is const contrary to
5142 * MEDCouplingUMesh::buildExtrudedMesh method because this->_coords are expected to contain
5143 * the coords sorted slice by slice.
5144 * \param isQuad specifies presence of quadratic cells.
5146 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMeshFromThisLowLev(int nbOfNodesOf1Lev, bool isQuad) const
5148 int nbOf1DCells(getNumberOfNodes()/nbOfNodesOf1Lev-1);
5149 int nbOf2DCells(getNumberOfCells());
5150 int nbOf3DCells(nbOf2DCells*nbOf1DCells);
5151 MEDCouplingUMesh *ret(MEDCouplingUMesh::New("Extruded",getMeshDimension()+1));
5152 const int *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5153 MCAuto<DataArrayInt> newConn(DataArrayInt::New()),newConnI(DataArrayInt::New());
5154 newConnI->alloc(nbOf3DCells+1,1);
5155 int *newConnIPtr(newConnI->getPointer());
5157 std::vector<int> newc;
5158 for(int j=0;j<nbOf2DCells;j++)
5160 AppendExtrudedCell(conn+connI[j],conn+connI[j+1],nbOfNodesOf1Lev,isQuad,newc);
5161 *newConnIPtr++=(int)newc.size();
5163 newConn->alloc((int)(newc.size())*nbOf1DCells,1);
5164 int *newConnPtr(newConn->getPointer());
5165 int deltaPerLev(isQuad?2*nbOfNodesOf1Lev:nbOfNodesOf1Lev);
5166 newConnIPtr=newConnI->getPointer();
5167 for(int iz=0;iz<nbOf1DCells;iz++)
5170 std::transform(newConnIPtr+1,newConnIPtr+1+nbOf2DCells,newConnIPtr+1+iz*nbOf2DCells,std::bind2nd(std::plus<int>(),newConnIPtr[iz*nbOf2DCells]));
5171 const int *posOfTypeOfCell(newConnIPtr);
5172 for(std::vector<int>::const_iterator iter=newc.begin();iter!=newc.end();iter++,newConnPtr++)
5174 int icell((int)(iter-newc.begin()));//std::distance unfortunately cannot been called here in C++98
5175 if(icell!=*posOfTypeOfCell)
5178 *newConnPtr=(*iter)+iz*deltaPerLev;
5189 ret->setConnectivity(newConn,newConnI,true);
5190 ret->setCoords(getCoords());
5195 * Checks if \a this mesh is constituted by only quadratic cells.
5196 * \return bool - \c true if there are only quadratic cells in \a this mesh.
5197 * \throw If the coordinates array is not set.
5198 * \throw If the nodal connectivity of cells is not defined.
5200 bool MEDCouplingUMesh::isFullyQuadratic() const
5202 checkFullyDefined();
5204 int nbOfCells=getNumberOfCells();
5205 for(int i=0;i<nbOfCells && ret;i++)
5207 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
5208 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5209 ret=cm.isQuadratic();
5215 * Checks if \a this mesh includes any quadratic cell.
5216 * \return bool - \c true if there is at least one quadratic cells in \a this mesh.
5217 * \throw If the coordinates array is not set.
5218 * \throw If the nodal connectivity of cells is not defined.
5220 bool MEDCouplingUMesh::isPresenceOfQuadratic() const
5222 checkFullyDefined();
5224 int nbOfCells=getNumberOfCells();
5225 for(int i=0;i<nbOfCells && !ret;i++)
5227 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
5228 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5229 ret=cm.isQuadratic();
5235 * Converts all quadratic cells to linear ones. If there are no quadratic cells in \a
5236 * this mesh, it remains unchanged.
5237 * \throw If the coordinates array is not set.
5238 * \throw If the nodal connectivity of cells is not defined.
5240 void MEDCouplingUMesh::convertQuadraticCellsToLinear()
5242 checkFullyDefined();
5243 int nbOfCells(getNumberOfCells());
5245 const int *iciptr=_nodal_connec_index->begin();
5246 for(int i=0;i<nbOfCells;i++)
5248 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
5249 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5250 if(cm.isQuadratic())
5252 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
5253 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
5254 if(!cml.isDynamic())
5255 delta+=cm.getNumberOfNodes()-cml.getNumberOfNodes();
5257 delta+=(iciptr[i+1]-iciptr[i]-1)/2;
5262 MCAuto<DataArrayInt> newConn(DataArrayInt::New()),newConnI(DataArrayInt::New());
5263 const int *icptr(_nodal_connec->begin());
5264 newConn->alloc(getNodalConnectivityArrayLen()-delta,1);
5265 newConnI->alloc(nbOfCells+1,1);
5266 int *ocptr(newConn->getPointer()),*ociptr(newConnI->getPointer());
5269 for(int i=0;i<nbOfCells;i++,ociptr++)
5271 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)icptr[iciptr[i]];
5272 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5273 if(!cm.isQuadratic())
5275 _types.insert(type);
5276 ocptr=std::copy(icptr+iciptr[i],icptr+iciptr[i+1],ocptr);
5277 ociptr[1]=ociptr[0]+iciptr[i+1]-iciptr[i];
5281 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
5282 _types.insert(typel);
5283 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
5284 int newNbOfNodes=cml.getNumberOfNodes();
5286 newNbOfNodes=(iciptr[i+1]-iciptr[i]-1)/2;
5287 *ocptr++=(int)typel;
5288 ocptr=std::copy(icptr+iciptr[i]+1,icptr+iciptr[i]+newNbOfNodes+1,ocptr);
5289 ociptr[1]=ociptr[0]+newNbOfNodes+1;
5292 setConnectivity(newConn,newConnI,false);
5296 * This method converts all linear cell in \a this to quadratic one.
5297 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, here it is needed to specify the target
5298 * 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)
5299 * 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.
5300 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, the coordinates in \a this can be become bigger. All created nodes will be put at the
5301 * end of the existing coordinates.
5303 * \param [in] conversionType specifies the type of conversion expected. Only 0 (default) and 1 are supported presently. 0 those that creates the 'most' simple
5304 * corresponding quadratic cells. 1 is those creating the 'most' complex.
5305 * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5307 * \throw if \a this is not fully defined. It throws too if \a conversionType is not in [0,1].
5309 * \sa MEDCouplingUMesh::convertQuadraticCellsToLinear
5311 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic(int conversionType)
5313 DataArrayInt *conn=0,*connI=0;
5314 DataArrayDouble *coords=0;
5315 std::set<INTERP_KERNEL::NormalizedCellType> types;
5316 checkFullyDefined();
5317 MCAuto<DataArrayInt> ret,connSafe,connISafe;
5318 MCAuto<DataArrayDouble> coordsSafe;
5319 int meshDim=getMeshDimension();
5320 switch(conversionType)
5326 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);
5327 connSafe=conn; connISafe=connI; coordsSafe=coords;
5330 ret=convertLinearCellsToQuadratic2D0(conn,connI,coords,types);
5331 connSafe=conn; connISafe=connI; coordsSafe=coords;
5334 ret=convertLinearCellsToQuadratic3D0(conn,connI,coords,types);
5335 connSafe=conn; connISafe=connI; coordsSafe=coords;
5338 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 0 mesh dimensions available are [1,2,3] !");
5346 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);//it is not a bug. In 1D policy 0 and 1 are equals
5347 connSafe=conn; connISafe=connI; coordsSafe=coords;
5350 ret=convertLinearCellsToQuadratic2D1(conn,connI,coords,types);
5351 connSafe=conn; connISafe=connI; coordsSafe=coords;
5354 ret=convertLinearCellsToQuadratic3D1(conn,connI,coords,types);
5355 connSafe=conn; connISafe=connI; coordsSafe=coords;
5358 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 1 mesh dimensions available are [1,2,3] !");
5363 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion type available are 0 (default, the simplest) and 1 (the most complex) !");
5365 setConnectivity(connSafe,connISafe,false);
5367 setCoords(coordsSafe);
5372 * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
5373 * so that the number of cells remains the same. Quadratic faces are converted to
5374 * polygons. This method works only for 2D meshes in
5375 * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
5376 * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
5377 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
5378 * \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
5379 * a polylinized edge constituting the input polygon.
5380 * \throw If the coordinates array is not set.
5381 * \throw If the nodal connectivity of cells is not defined.
5382 * \throw If \a this->getMeshDimension() != 2.
5383 * \throw If \a this->getSpaceDimension() != 2.
5385 void MEDCouplingUMesh::tessellate2D(double eps)
5387 int meshDim(getMeshDimension()),spaceDim(getSpaceDimension());
5389 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : works only with space dimension equal to 2 !");
5393 return tessellate2DCurveInternal(eps);
5395 return tessellate2DInternal(eps);
5397 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : mesh dimension must be in [1,2] !");
5401 * Tessellates \a this 1D mesh in 2D space by dividing not straight quadratic edges.
5402 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
5403 * \param [in] eps - specifies the maximal angle (in radian) between 2 sub-edges of
5404 * a sub-divided edge.
5405 * \throw If the coordinates array is not set.
5406 * \throw If the nodal connectivity of cells is not defined.
5407 * \throw If \a this->getMeshDimension() != 1.
5408 * \throw If \a this->getSpaceDimension() != 2.
5413 * This method only works if \a this has spaceDimension equal to 2 and meshDimension also equal to 2.
5414 * This method allows to modify connectivity of cells in \a this that shares some edges in \a edgeIdsToBeSplit.
5415 * The nodes to be added in those 2D cells are defined by the pair of \a nodeIdsToAdd and \a nodeIdsIndexToAdd.
5416 * Length of \a nodeIdsIndexToAdd is expected to equal to length of \a edgeIdsToBeSplit + 1.
5417 * The node ids in \a nodeIdsToAdd should be valid. Those nodes have to be sorted exactly following exactly the direction of the edge.
5418 * This method can be seen as the opposite method of colinearize2D.
5419 * 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
5420 * to avoid to modify the numbering of existing nodes.
5422 * \param [in] nodeIdsToAdd - the list of node ids to be added (\a nodeIdsIndexToAdd array allows to walk on this array)
5423 * \param [in] nodeIdsIndexToAdd - the entry point of \a nodeIdsToAdd to point to the corresponding nodes to be added.
5424 * \param [in] mesh1Desc - 1st output of buildDescendingConnectivity2 on \a this.
5425 * \param [in] desc - 2nd output of buildDescendingConnectivity2 on \a this.
5426 * \param [in] descI - 3rd output of buildDescendingConnectivity2 on \a this.
5427 * \param [in] revDesc - 4th output of buildDescendingConnectivity2 on \a this.
5428 * \param [in] revDescI - 5th output of buildDescendingConnectivity2 on \a this.
5430 * \sa buildDescendingConnectivity2
5432 void MEDCouplingUMesh::splitSomeEdgesOf2DMesh(const DataArrayInt *nodeIdsToAdd, const DataArrayInt *nodeIdsIndexToAdd, const DataArrayInt *edgeIdsToBeSplit,
5433 const MEDCouplingUMesh *mesh1Desc, const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *revDesc, const DataArrayInt *revDescI)
5435 if(!nodeIdsToAdd || !nodeIdsIndexToAdd || !edgeIdsToBeSplit || !mesh1Desc || !desc || !descI || !revDesc || !revDescI)
5436 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : input pointers must be not NULL !");
5437 nodeIdsToAdd->checkAllocated(); nodeIdsIndexToAdd->checkAllocated(); edgeIdsToBeSplit->checkAllocated(); desc->checkAllocated(); descI->checkAllocated(); revDesc->checkAllocated(); revDescI->checkAllocated();
5438 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
5439 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : this must have spacedim=meshdim=2 !");
5440 if(mesh1Desc->getSpaceDimension()!=2 || mesh1Desc->getMeshDimension()!=1)
5441 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : mesh1Desc must be the explosion of this with spaceDim=2 and meshDim = 1 !");
5442 //DataArrayInt *out0(0),*outi0(0);
5443 //MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
5444 //MCAuto<DataArrayInt> out0s(out0),outi0s(outi0);
5445 //out0s=out0s->buildUnique(); out0s->sort(true);
5450 * Implementes \a conversionType 0 for meshes with meshDim = 1, of MEDCouplingUMesh::convertLinearCellsToQuadratic method.
5451 * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5452 * \sa MEDCouplingUMesh::convertLinearCellsToQuadratic.
5454 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic1D0(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5456 MCAuto<DataArrayDouble> bary=computeCellCenterOfMass();
5457 MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5458 MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5459 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
5460 int nbOfCells=getNumberOfCells();
5461 int nbOfNodes=getNumberOfNodes();
5462 const int *cPtr=_nodal_connec->begin();
5463 const int *icPtr=_nodal_connec_index->begin();
5464 int lastVal=0,offset=nbOfNodes;
5465 for(int i=0;i<nbOfCells;i++,icPtr++)
5467 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5468 if(type==INTERP_KERNEL::NORM_SEG2)
5470 types.insert(INTERP_KERNEL::NORM_SEG3);
5471 newConn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG3);
5472 newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[0]+3);
5473 newConn->pushBackSilent(offset++);
5475 newConnI->pushBackSilent(lastVal);
5476 ret->pushBackSilent(i);
5481 lastVal+=(icPtr[1]-icPtr[0]);
5482 newConnI->pushBackSilent(lastVal);
5483 newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5486 MCAuto<DataArrayDouble> tmp=bary->selectByTupleIdSafe(ret->begin(),ret->end());
5487 coords=DataArrayDouble::Aggregate(getCoords(),tmp); conn=newConn.retn(); connI=newConnI.retn();
5491 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic2DAnd3D0(const MEDCouplingUMesh *m1D, const DataArrayInt *desc, const DataArrayInt *descI, DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5493 MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5494 MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5495 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
5497 const int *descPtr(desc->begin()),*descIPtr(descI->begin());
5498 DataArrayInt *conn1D=0,*conn1DI=0;
5499 std::set<INTERP_KERNEL::NormalizedCellType> types1D;
5500 DataArrayDouble *coordsTmp=0;
5501 MCAuto<DataArrayInt> ret1D=m1D->convertLinearCellsToQuadratic1D0(conn1D,conn1DI,coordsTmp,types1D); ret1D=0;
5502 MCAuto<DataArrayDouble> coordsTmpSafe(coordsTmp);
5503 MCAuto<DataArrayInt> conn1DSafe(conn1D),conn1DISafe(conn1DI);
5504 const int *c1DPtr=conn1D->begin();
5505 const int *c1DIPtr=conn1DI->begin();
5506 int nbOfCells=getNumberOfCells();
5507 const int *cPtr=_nodal_connec->begin();
5508 const int *icPtr=_nodal_connec_index->begin();
5510 for(int i=0;i<nbOfCells;i++,icPtr++,descIPtr++)
5512 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5513 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
5514 if(!cm.isQuadratic())
5516 INTERP_KERNEL::NormalizedCellType typ2=cm.getQuadraticType();
5517 types.insert(typ2); newConn->pushBackSilent(typ2);
5518 newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[1]);
5519 for(const int *d=descPtr+descIPtr[0];d!=descPtr+descIPtr[1];d++)
5520 newConn->pushBackSilent(c1DPtr[c1DIPtr[*d]+3]);
5521 lastVal+=(icPtr[1]-icPtr[0])+(descIPtr[1]-descIPtr[0]);
5522 newConnI->pushBackSilent(lastVal);
5523 ret->pushBackSilent(i);
5528 lastVal+=(icPtr[1]-icPtr[0]);
5529 newConnI->pushBackSilent(lastVal);
5530 newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5533 conn=newConn.retn(); connI=newConnI.retn(); coords=coordsTmpSafe.retn();
5538 * Implementes \a conversionType 0 for meshes with meshDim = 2, of MEDCouplingUMesh::convertLinearCellsToQuadratic method.
5539 * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5540 * \sa MEDCouplingUMesh::convertLinearCellsToQuadratic.
5542 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic2D0(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5544 MCAuto<DataArrayInt> desc(DataArrayInt::New()),descI(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5545 MCAuto<MEDCouplingUMesh> m1D=buildDescendingConnectivity(desc,descI,tmp2,tmp3); tmp2=0; tmp3=0;
5546 return convertLinearCellsToQuadratic2DAnd3D0(m1D,desc,descI,conn,connI,coords,types);
5549 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic2D1(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5551 MCAuto<DataArrayInt> desc(DataArrayInt::New()),descI(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5552 MCAuto<MEDCouplingUMesh> m1D=buildDescendingConnectivity(desc,descI,tmp2,tmp3); tmp2=0; tmp3=0;
5554 MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5555 MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5556 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
5558 MCAuto<DataArrayDouble> bary=computeCellCenterOfMass();
5559 const int *descPtr(desc->begin()),*descIPtr(descI->begin());
5560 DataArrayInt *conn1D=0,*conn1DI=0;
5561 std::set<INTERP_KERNEL::NormalizedCellType> types1D;
5562 DataArrayDouble *coordsTmp=0;
5563 MCAuto<DataArrayInt> ret1D=m1D->convertLinearCellsToQuadratic1D0(conn1D,conn1DI,coordsTmp,types1D); ret1D=0;
5564 MCAuto<DataArrayDouble> coordsTmpSafe(coordsTmp);
5565 MCAuto<DataArrayInt> conn1DSafe(conn1D),conn1DISafe(conn1DI);
5566 const int *c1DPtr=conn1D->begin();
5567 const int *c1DIPtr=conn1DI->begin();
5568 int nbOfCells=getNumberOfCells();
5569 const int *cPtr=_nodal_connec->begin();
5570 const int *icPtr=_nodal_connec_index->begin();
5571 int lastVal=0,offset=coordsTmpSafe->getNumberOfTuples();
5572 for(int i=0;i<nbOfCells;i++,icPtr++,descIPtr++)
5574 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5575 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
5576 if(!cm.isQuadratic())
5578 INTERP_KERNEL::NormalizedCellType typ2=cm.getQuadraticType2();
5579 types.insert(typ2); newConn->pushBackSilent(typ2);
5580 newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[1]);
5581 for(const int *d=descPtr+descIPtr[0];d!=descPtr+descIPtr[1];d++)
5582 newConn->pushBackSilent(c1DPtr[c1DIPtr[*d]+3]);
5583 newConn->pushBackSilent(offset+ret->getNumberOfTuples());
5584 lastVal+=(icPtr[1]-icPtr[0])+(descIPtr[1]-descIPtr[0])+1;
5585 newConnI->pushBackSilent(lastVal);
5586 ret->pushBackSilent(i);
5591 lastVal+=(icPtr[1]-icPtr[0]);
5592 newConnI->pushBackSilent(lastVal);
5593 newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5596 MCAuto<DataArrayDouble> tmp=bary->selectByTupleIdSafe(ret->begin(),ret->end());
5597 coords=DataArrayDouble::Aggregate(coordsTmpSafe,tmp); conn=newConn.retn(); connI=newConnI.retn();
5602 * Implementes \a conversionType 0 for meshes with meshDim = 3, of MEDCouplingUMesh::convertLinearCellsToQuadratic method.
5603 * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5604 * \sa MEDCouplingUMesh::convertLinearCellsToQuadratic.
5606 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic3D0(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5608 MCAuto<DataArrayInt> desc(DataArrayInt::New()),descI(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5609 MCAuto<MEDCouplingUMesh> m1D=explode3DMeshTo1D(desc,descI,tmp2,tmp3); tmp2=0; tmp3=0;
5610 return convertLinearCellsToQuadratic2DAnd3D0(m1D,desc,descI,conn,connI,coords,types);
5613 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic3D1(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5615 MCAuto<DataArrayInt> desc2(DataArrayInt::New()),desc2I(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5616 MCAuto<MEDCouplingUMesh> m2D=buildDescendingConnectivityGen<MinusOneSonsGeneratorBiQuadratic>(desc2,desc2I,tmp2,tmp3,MEDCouplingFastNbrer); tmp2=0; tmp3=0;
5617 MCAuto<DataArrayInt> desc1(DataArrayInt::New()),desc1I(DataArrayInt::New()),tmp4(DataArrayInt::New()),tmp5(DataArrayInt::New());
5618 MCAuto<MEDCouplingUMesh> m1D=explode3DMeshTo1D(desc1,desc1I,tmp4,tmp5); tmp4=0; tmp5=0;
5620 MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5621 MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5622 MCAuto<DataArrayInt> ret=DataArrayInt::New(),ret2=DataArrayInt::New(); ret->alloc(0,1); ret2->alloc(0,1);
5624 MCAuto<DataArrayDouble> bary=computeCellCenterOfMass();
5625 const int *descPtr(desc1->begin()),*descIPtr(desc1I->begin()),*desc2Ptr(desc2->begin()),*desc2IPtr(desc2I->begin());
5626 DataArrayInt *conn1D=0,*conn1DI=0,*conn2D=0,*conn2DI=0;
5627 std::set<INTERP_KERNEL::NormalizedCellType> types1D,types2D;
5628 DataArrayDouble *coordsTmp=0,*coordsTmp2=0;
5629 MCAuto<DataArrayInt> ret1D=m1D->convertLinearCellsToQuadratic1D0(conn1D,conn1DI,coordsTmp,types1D); ret1D=DataArrayInt::New(); ret1D->alloc(0,1);
5630 MCAuto<DataArrayInt> conn1DSafe(conn1D),conn1DISafe(conn1DI);
5631 MCAuto<DataArrayDouble> coordsTmpSafe(coordsTmp);
5632 MCAuto<DataArrayInt> ret2D=m2D->convertLinearCellsToQuadratic2D1(conn2D,conn2DI,coordsTmp2,types2D); ret2D=DataArrayInt::New(); ret2D->alloc(0,1);
5633 MCAuto<DataArrayDouble> coordsTmp2Safe(coordsTmp2);
5634 MCAuto<DataArrayInt> conn2DSafe(conn2D),conn2DISafe(conn2DI);
5635 const int *c1DPtr=conn1D->begin(),*c1DIPtr=conn1DI->begin(),*c2DPtr=conn2D->begin(),*c2DIPtr=conn2DI->begin();
5636 int nbOfCells=getNumberOfCells();
5637 const int *cPtr=_nodal_connec->begin();
5638 const int *icPtr=_nodal_connec_index->begin();
5639 int lastVal=0,offset=coordsTmpSafe->getNumberOfTuples();
5640 for(int i=0;i<nbOfCells;i++,icPtr++,descIPtr++,desc2IPtr++)
5642 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5643 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
5644 if(!cm.isQuadratic())
5646 INTERP_KERNEL::NormalizedCellType typ2=cm.getQuadraticType2();
5647 if(typ2==INTERP_KERNEL::NORM_ERROR)
5649 std::ostringstream oss; oss << "MEDCouplingUMesh::convertLinearCellsToQuadratic3D1 : On cell #" << i << " the linear cell type does not support advanced quadratization !";
5650 throw INTERP_KERNEL::Exception(oss.str());
5652 types.insert(typ2); newConn->pushBackSilent(typ2);
5653 newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[1]);
5654 for(const int *d=descPtr+descIPtr[0];d!=descPtr+descIPtr[1];d++)
5655 newConn->pushBackSilent(c1DPtr[c1DIPtr[*d]+3]);
5656 for(const int *d=desc2Ptr+desc2IPtr[0];d!=desc2Ptr+desc2IPtr[1];d++)
5658 int nodeId2=c2DPtr[c2DIPtr[(*d)+1]-1];
5659 int tmpPos=newConn->getNumberOfTuples();
5660 newConn->pushBackSilent(nodeId2);
5661 ret2D->pushBackSilent(nodeId2); ret1D->pushBackSilent(tmpPos);
5663 newConn->pushBackSilent(offset+ret->getNumberOfTuples());
5664 lastVal+=(icPtr[1]-icPtr[0])+(descIPtr[1]-descIPtr[0])+(desc2IPtr[1]-desc2IPtr[0])+1;
5665 newConnI->pushBackSilent(lastVal);
5666 ret->pushBackSilent(i);
5671 lastVal+=(icPtr[1]-icPtr[0]);
5672 newConnI->pushBackSilent(lastVal);
5673 newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5676 MCAuto<DataArrayInt> diffRet2D=ret2D->getDifferentValues();
5677 MCAuto<DataArrayInt> o2nRet2D=diffRet2D->invertArrayN2O2O2N(coordsTmp2Safe->getNumberOfTuples());
5678 coordsTmp2Safe=coordsTmp2Safe->selectByTupleId(diffRet2D->begin(),diffRet2D->end());
5679 MCAuto<DataArrayDouble> tmp=bary->selectByTupleIdSafe(ret->begin(),ret->end());
5680 std::vector<const DataArrayDouble *> v(3); v[0]=coordsTmpSafe; v[1]=coordsTmp2Safe; v[2]=tmp;
5681 int *c=newConn->getPointer();
5682 const int *cI(newConnI->begin());
5683 for(const int *elt=ret1D->begin();elt!=ret1D->end();elt++)
5684 c[*elt]=o2nRet2D->getIJ(c[*elt],0)+offset;
5685 offset=coordsTmp2Safe->getNumberOfTuples();
5686 for(const int *elt=ret->begin();elt!=ret->end();elt++)
5687 c[cI[(*elt)+1]-1]+=offset;
5688 coords=DataArrayDouble::Aggregate(v); conn=newConn.retn(); connI=newConnI.retn();
5693 * Divides every cell of \a this mesh into simplices (triangles in 2D and tetrahedra in 3D).
5694 * In addition, returns an array mapping new cells to old ones. <br>
5695 * This method typically increases the number of cells in \a this mesh
5696 * but the number of nodes remains \b unchanged.
5697 * That's why the 3D splitting policies
5698 * INTERP_KERNEL::GENERAL_24 and INTERP_KERNEL::GENERAL_48 are not available here.
5699 * \param [in] policy - specifies a pattern used for splitting.
5700 * The semantic of \a policy is:
5701 * - 0 - to split QUAD4 by cutting it along 0-2 diagonal (for 2D mesh only).
5702 * - 1 - to split QUAD4 by cutting it along 1-3 diagonal (for 2D mesh only).
5703 * - INTERP_KERNEL::PLANAR_FACE_5 - to split HEXA8 into 5 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
5704 * - INTERP_KERNEL::PLANAR_FACE_6 - to split HEXA8 into 6 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
5707 * \return DataArrayInt * - a new instance of DataArrayInt holding, for each new cell,
5708 * an id of old cell producing it. The caller is to delete this array using
5709 * decrRef() as it is no more needed.
5711 * \throw If \a policy is 0 or 1 and \a this->getMeshDimension() != 2.
5712 * \throw If \a policy is INTERP_KERNEL::PLANAR_FACE_5 or INTERP_KERNEL::PLANAR_FACE_6
5713 * and \a this->getMeshDimension() != 3.
5714 * \throw If \a policy is not one of the four discussed above.
5715 * \throw If the nodal connectivity of cells is not defined.
5716 * \sa MEDCouplingUMesh::tetrahedrize, MEDCoupling1SGTUMesh::sortHexa8EachOther
5718 DataArrayInt *MEDCouplingUMesh::simplexize(int policy)
5723 return simplexizePol0();
5725 return simplexizePol1();
5726 case (int) INTERP_KERNEL::PLANAR_FACE_5:
5727 return simplexizePlanarFace5();
5728 case (int) INTERP_KERNEL::PLANAR_FACE_6:
5729 return simplexizePlanarFace6();
5731 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)");
5736 * Checks if \a this mesh is constituted by simplex cells only. Simplex cells are:
5737 * - 1D: INTERP_KERNEL::NORM_SEG2
5738 * - 2D: INTERP_KERNEL::NORM_TRI3
5739 * - 3D: INTERP_KERNEL::NORM_TETRA4.
5741 * This method is useful for users that need to use P1 field services as
5742 * MEDCouplingFieldDouble::getValueOn(), MEDCouplingField::buildMeasureField() etc.
5743 * All these methods need mesh support containing only simplex cells.
5744 * \return bool - \c true if there are only simplex cells in \a this mesh.
5745 * \throw If the coordinates array is not set.
5746 * \throw If the nodal connectivity of cells is not defined.
5747 * \throw If \a this->getMeshDimension() < 1.
5749 bool MEDCouplingUMesh::areOnlySimplexCells() const
5751 checkFullyDefined();
5752 int mdim=getMeshDimension();
5753 if(mdim<1 || mdim>3)
5754 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::areOnlySimplexCells : only available with meshes having a meshdim 1, 2 or 3 !");
5755 int nbCells=getNumberOfCells();
5756 const int *conn=_nodal_connec->begin();
5757 const int *connI=_nodal_connec_index->begin();
5758 for(int i=0;i<nbCells;i++)
5760 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5768 * This method implements policy 0 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5770 DataArrayInt *MEDCouplingUMesh::simplexizePol0()
5772 checkConnectivityFullyDefined();
5773 if(getMeshDimension()!=2)
5774 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePol0 : this policy is only available for mesh with meshdim == 2 !");
5775 int nbOfCells=getNumberOfCells();
5776 MCAuto<DataArrayInt> ret=DataArrayInt::New();
5777 int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_QUAD4);
5778 ret->alloc(nbOfCells+nbOfCutCells,1);
5779 if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5780 int *retPt=ret->getPointer();
5781 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5782 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5783 newConnI->alloc(nbOfCells+nbOfCutCells+1,1);
5784 newConn->alloc(getNodalConnectivityArrayLen()+3*nbOfCutCells,1);
5785 int *pt=newConn->getPointer();
5786 int *ptI=newConnI->getPointer();
5788 const int *oldc=_nodal_connec->begin();
5789 const int *ci=_nodal_connec_index->begin();
5790 for(int i=0;i<nbOfCells;i++,ci++)
5792 if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_QUAD4)
5794 const int tmp[8]={(int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+1],oldc[ci[0]+2],oldc[ci[0]+3],
5795 (int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+1],oldc[ci[0]+3],oldc[ci[0]+4]};
5796 pt=std::copy(tmp,tmp+8,pt);
5805 pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5806 ptI[1]=ptI[0]+ci[1]-ci[0];
5811 _nodal_connec->decrRef();
5812 _nodal_connec=newConn.retn();
5813 _nodal_connec_index->decrRef();
5814 _nodal_connec_index=newConnI.retn();
5821 * This method implements policy 1 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5823 DataArrayInt *MEDCouplingUMesh::simplexizePol1()
5825 checkConnectivityFullyDefined();
5826 if(getMeshDimension()!=2)
5827 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePol0 : this policy is only available for mesh with meshdim == 2 !");
5828 int nbOfCells=getNumberOfCells();
5829 MCAuto<DataArrayInt> ret=DataArrayInt::New();
5830 int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_QUAD4);
5831 ret->alloc(nbOfCells+nbOfCutCells,1);
5832 if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5833 int *retPt=ret->getPointer();
5834 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5835 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5836 newConnI->alloc(nbOfCells+nbOfCutCells+1,1);
5837 newConn->alloc(getNodalConnectivityArrayLen()+3*nbOfCutCells,1);
5838 int *pt=newConn->getPointer();
5839 int *ptI=newConnI->getPointer();
5841 const int *oldc=_nodal_connec->begin();
5842 const int *ci=_nodal_connec_index->begin();
5843 for(int i=0;i<nbOfCells;i++,ci++)
5845 if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_QUAD4)
5847 const int tmp[8]={(int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+1],oldc[ci[0]+2],oldc[ci[0]+4],
5848 (int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+2],oldc[ci[0]+3],oldc[ci[0]+4]};
5849 pt=std::copy(tmp,tmp+8,pt);
5858 pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5859 ptI[1]=ptI[0]+ci[1]-ci[0];
5864 _nodal_connec->decrRef();
5865 _nodal_connec=newConn.retn();
5866 _nodal_connec_index->decrRef();
5867 _nodal_connec_index=newConnI.retn();
5874 * This method implements policy INTERP_KERNEL::PLANAR_FACE_5 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5876 DataArrayInt *MEDCouplingUMesh::simplexizePlanarFace5()
5878 checkConnectivityFullyDefined();
5879 if(getMeshDimension()!=3)
5880 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePlanarFace5 : this policy is only available for mesh with meshdim == 3 !");
5881 int nbOfCells=getNumberOfCells();
5882 MCAuto<DataArrayInt> ret=DataArrayInt::New();
5883 int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_HEXA8);
5884 ret->alloc(nbOfCells+4*nbOfCutCells,1);
5885 if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5886 int *retPt=ret->getPointer();
5887 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5888 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5889 newConnI->alloc(nbOfCells+4*nbOfCutCells+1,1);
5890 newConn->alloc(getNodalConnectivityArrayLen()+16*nbOfCutCells,1);//21
5891 int *pt=newConn->getPointer();
5892 int *ptI=newConnI->getPointer();
5894 const int *oldc=_nodal_connec->begin();
5895 const int *ci=_nodal_connec_index->begin();
5896 for(int i=0;i<nbOfCells;i++,ci++)
5898 if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_HEXA8)
5900 for(int j=0;j<5;j++,pt+=5,ptI++)
5902 pt[0]=(int)INTERP_KERNEL::NORM_TETRA4;
5903 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];
5910 pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5911 ptI[1]=ptI[0]+ci[1]-ci[0];
5916 _nodal_connec->decrRef();
5917 _nodal_connec=newConn.retn();
5918 _nodal_connec_index->decrRef();
5919 _nodal_connec_index=newConnI.retn();
5926 * This method implements policy INTERP_KERNEL::PLANAR_FACE_6 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5928 DataArrayInt *MEDCouplingUMesh::simplexizePlanarFace6()
5930 checkConnectivityFullyDefined();
5931 if(getMeshDimension()!=3)
5932 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePlanarFace6 : this policy is only available for mesh with meshdim == 3 !");
5933 int nbOfCells=getNumberOfCells();
5934 MCAuto<DataArrayInt> ret=DataArrayInt::New();
5935 int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_HEXA8);
5936 ret->alloc(nbOfCells+5*nbOfCutCells,1);
5937 if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5938 int *retPt=ret->getPointer();
5939 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5940 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5941 newConnI->alloc(nbOfCells+5*nbOfCutCells+1,1);
5942 newConn->alloc(getNodalConnectivityArrayLen()+21*nbOfCutCells,1);
5943 int *pt=newConn->getPointer();
5944 int *ptI=newConnI->getPointer();
5946 const int *oldc=_nodal_connec->begin();
5947 const int *ci=_nodal_connec_index->begin();
5948 for(int i=0;i<nbOfCells;i++,ci++)
5950 if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_HEXA8)
5952 for(int j=0;j<6;j++,pt+=5,ptI++)
5954 pt[0]=(int)INTERP_KERNEL::NORM_TETRA4;
5955 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];
5962 pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5963 ptI[1]=ptI[0]+ci[1]-ci[0];
5968 _nodal_connec->decrRef();
5969 _nodal_connec=newConn.retn();
5970 _nodal_connec_index->decrRef();
5971 _nodal_connec_index=newConnI.retn();
5978 * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
5979 * so that the number of cells remains the same. Quadratic faces are converted to
5980 * polygons. This method works only for 2D meshes in
5981 * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
5982 * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
5983 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
5984 * \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
5985 * a polylinized edge constituting the input polygon.
5986 * \throw If the coordinates array is not set.
5987 * \throw If the nodal connectivity of cells is not defined.
5988 * \throw If \a this->getMeshDimension() != 2.
5989 * \throw If \a this->getSpaceDimension() != 2.
5991 void MEDCouplingUMesh::tessellate2DInternal(double eps)
5993 checkFullyDefined();
5994 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
5995 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2DInternal works on umeshes with meshdim equal to 2 and spaceDim equal to 2 too!");
5996 double epsa=fabs(eps);
5997 if(epsa<std::numeric_limits<double>::min())
5998 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 !");
5999 MCAuto<DataArrayInt> desc1(DataArrayInt::New()),descIndx1(DataArrayInt::New()),revDesc1(DataArrayInt::New()),revDescIndx1(DataArrayInt::New());
6000 MCAuto<MEDCouplingUMesh> mDesc(buildDescendingConnectivity2(desc1,descIndx1,revDesc1,revDescIndx1));
6001 revDesc1=0; revDescIndx1=0;
6002 mDesc->tessellate2D(eps);
6003 subDivide2DMesh(mDesc->_nodal_connec->begin(),mDesc->_nodal_connec_index->begin(),desc1->begin(),descIndx1->begin());
6004 setCoords(mDesc->getCoords());
6008 * Tessellates \a this 1D mesh in 2D space by dividing not straight quadratic edges.
6009 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
6010 * \param [in] eps - specifies the maximal angle (in radian) between 2 sub-edges of
6011 * a sub-divided edge.
6012 * \throw If the coordinates array is not set.
6013 * \throw If the nodal connectivity of cells is not defined.
6014 * \throw If \a this->getMeshDimension() != 1.
6015 * \throw If \a this->getSpaceDimension() != 2.
6017 void MEDCouplingUMesh::tessellate2DCurveInternal(double eps)
6019 checkFullyDefined();
6020 if(getMeshDimension()!=1 || getSpaceDimension()!=2)
6021 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2DCurveInternal works on umeshes with meshdim equal to 1 and spaceDim equal to 2 too!");
6022 double epsa=fabs(eps);
6023 if(epsa<std::numeric_limits<double>::min())
6024 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 !");
6025 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=1.e-10;
6026 int nbCells=getNumberOfCells();
6027 int nbNodes=getNumberOfNodes();
6028 const int *conn=_nodal_connec->begin();
6029 const int *connI=_nodal_connec_index->begin();
6030 const double *coords=_coords->begin();
6031 std::vector<double> addCoo;
6032 std::vector<int> newConn;//no direct DataArrayInt because interface with Geometric2D
6033 MCAuto<DataArrayInt> newConnI(DataArrayInt::New());
6034 newConnI->alloc(nbCells+1,1);
6035 int *newConnIPtr=newConnI->getPointer();
6038 INTERP_KERNEL::Node *tmp2[3];
6039 std::set<INTERP_KERNEL::NormalizedCellType> types;
6040 for(int i=0;i<nbCells;i++,newConnIPtr++)
6042 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6043 if(cm.isQuadratic())
6044 {//assert(connI[i+1]-connI[i]-1==3)
6045 tmp1[0]=conn[connI[i]+1+0]; tmp1[1]=conn[connI[i]+1+1]; tmp1[2]=conn[connI[i]+1+2];
6046 tmp2[0]=new INTERP_KERNEL::Node(coords[2*tmp1[0]],coords[2*tmp1[0]+1]);
6047 tmp2[1]=new INTERP_KERNEL::Node(coords[2*tmp1[1]],coords[2*tmp1[1]+1]);
6048 tmp2[2]=new INTERP_KERNEL::Node(coords[2*tmp1[2]],coords[2*tmp1[2]+1]);
6049 INTERP_KERNEL::EdgeArcCircle *eac=INTERP_KERNEL::EdgeArcCircle::BuildFromNodes(tmp2[0],tmp2[2],tmp2[1]);
6052 eac->tesselate(tmp1,nbNodes,epsa,newConn,addCoo);
6053 types.insert((INTERP_KERNEL::NormalizedCellType)newConn[newConnIPtr[0]]);
6055 newConnIPtr[1]=(int)newConn.size();
6059 types.insert(INTERP_KERNEL::NORM_SEG2);
6060 newConn.push_back(INTERP_KERNEL::NORM_SEG2);
6061 newConn.insert(newConn.end(),conn+connI[i]+1,conn+connI[i]+3);
6062 newConnIPtr[1]=newConnIPtr[0]+3;
6067 types.insert((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6068 newConn.insert(newConn.end(),conn+connI[i],conn+connI[i+1]);
6069 newConnIPtr[1]=newConnIPtr[0]+3;
6072 if(addCoo.empty() && ((int)newConn.size())==_nodal_connec->getNumberOfTuples())//nothing happens during tessellation : no update needed
6075 DataArrayInt::SetArrayIn(newConnI,_nodal_connec_index);
6076 MCAuto<DataArrayInt> newConnArr=DataArrayInt::New();
6077 newConnArr->alloc((int)newConn.size(),1);
6078 std::copy(newConn.begin(),newConn.end(),newConnArr->getPointer());
6079 DataArrayInt::SetArrayIn(newConnArr,_nodal_connec);
6080 MCAuto<DataArrayDouble> newCoords=DataArrayDouble::New();
6081 newCoords->alloc(nbNodes+((int)addCoo.size())/2,2);
6082 double *work=std::copy(_coords->begin(),_coords->end(),newCoords->getPointer());
6083 std::copy(addCoo.begin(),addCoo.end(),work);
6084 DataArrayDouble::SetArrayIn(newCoords,_coords);
6089 * 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.
6090 * This method completly ignore coordinates.
6091 * \param nodeSubdived is the nodal connectivity of subdivision of edges
6092 * \param nodeIndxSubdived is the nodal connectivity index of subdivision of edges
6093 * \param desc is descending connectivity in format specified in MEDCouplingUMesh::buildDescendingConnectivity2
6094 * \param descIndex is descending connectivity index in format specified in MEDCouplingUMesh::buildDescendingConnectivity2
6096 void MEDCouplingUMesh::subDivide2DMesh(const int *nodeSubdived, const int *nodeIndxSubdived, const int *desc, const int *descIndex)
6098 checkFullyDefined();
6099 if(getMeshDimension()!=2)
6100 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::subDivide2DMesh : works only on umesh with meshdim==2 !");
6101 int nbOfCells=getNumberOfCells();
6102 int *connI=_nodal_connec_index->getPointer();
6104 for(int i=0;i<nbOfCells;i++,connI++)
6106 int offset=descIndex[i];
6107 int nbOfEdges=descIndex[i+1]-offset;
6109 bool ddirect=desc[offset+nbOfEdges-1]>0;
6110 int eedgeId=std::abs(desc[offset+nbOfEdges-1])-1;
6111 int ref=ddirect?nodeSubdived[nodeIndxSubdived[eedgeId+1]-1]:nodeSubdived[nodeIndxSubdived[eedgeId]+1];
6112 for(int j=0;j<nbOfEdges;j++)
6114 bool direct=desc[offset+j]>0;
6115 int edgeId=std::abs(desc[offset+j])-1;
6116 if(!INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)nodeSubdived[nodeIndxSubdived[edgeId]]).isQuadratic())
6118 int id1=nodeSubdived[nodeIndxSubdived[edgeId]+1];
6119 int id2=nodeSubdived[nodeIndxSubdived[edgeId+1]-1];
6120 int ref2=direct?id1:id2;
6123 int nbOfSubNodes=nodeIndxSubdived[edgeId+1]-nodeIndxSubdived[edgeId]-1;
6124 newConnLgth+=nbOfSubNodes-1;
6129 std::ostringstream oss; oss << "MEDCouplingUMesh::subDivide2DMesh : On polygon #" << i << " edgeid #" << j << " subedges mismatch : end subedge k!=start subedge k+1 !";
6130 throw INTERP_KERNEL::Exception(oss.str());
6135 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::subDivide2DMesh : this method only subdivides into linear edges !");
6138 newConnLgth++;//+1 is for cell type
6139 connI[1]=newConnLgth;
6142 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
6143 newConn->alloc(newConnLgth,1);
6144 int *work=newConn->getPointer();
6145 for(int i=0;i<nbOfCells;i++)
6147 *work++=INTERP_KERNEL::NORM_POLYGON;
6148 int offset=descIndex[i];
6149 int nbOfEdges=descIndex[i+1]-offset;
6150 for(int j=0;j<nbOfEdges;j++)
6152 bool direct=desc[offset+j]>0;
6153 int edgeId=std::abs(desc[offset+j])-1;
6155 work=std::copy(nodeSubdived+nodeIndxSubdived[edgeId]+1,nodeSubdived+nodeIndxSubdived[edgeId+1]-1,work);
6158 int nbOfSubNodes=nodeIndxSubdived[edgeId+1]-nodeIndxSubdived[edgeId]-1;
6159 std::reverse_iterator<const int *> it(nodeSubdived+nodeIndxSubdived[edgeId+1]);
6160 work=std::copy(it,it+nbOfSubNodes-1,work);
6164 DataArrayInt::SetArrayIn(newConn,_nodal_connec);
6167 _types.insert(INTERP_KERNEL::NORM_POLYGON);
6171 * Converts degenerated 2D or 3D linear cells of \a this mesh into cells of simpler
6172 * type. For example an INTERP_KERNEL::NORM_QUAD4 cell having only three unique nodes in
6173 * its connectivity is transformed into an INTERP_KERNEL::NORM_TRI3 cell. This method
6174 * does \b not perform geometrical checks and checks only nodal connectivity of cells,
6175 * so it can be useful to call mergeNodes() before calling this method.
6176 * \throw If \a this->getMeshDimension() <= 1.
6177 * \throw If the coordinates array is not set.
6178 * \throw If the nodal connectivity of cells is not defined.
6180 void MEDCouplingUMesh::convertDegeneratedCells()
6182 checkFullyDefined();
6183 if(getMeshDimension()<=1)
6184 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
6185 int nbOfCells=getNumberOfCells();
6188 int initMeshLgth=getNodalConnectivityArrayLen();
6189 int *conn=_nodal_connec->getPointer();
6190 int *index=_nodal_connec_index->getPointer();
6194 for(int i=0;i<nbOfCells;i++)
6196 lgthOfCurCell=index[i+1]-posOfCurCell;
6197 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
6199 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
6200 conn+newPos+1,newLgth);
6201 conn[newPos]=newType;
6203 posOfCurCell=index[i+1];
6206 if(newPos!=initMeshLgth)
6207 _nodal_connec->reAlloc(newPos);
6212 * Finds incorrectly oriented cells of this 2D mesh in 3D space.
6213 * A cell is considered to be oriented correctly if an angle between its
6214 * normal vector and a given vector is less than \c PI / \c 2.
6215 * \param [in] vec - 3 components of the vector specifying the correct orientation of
6217 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
6219 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
6220 * is not cleared before filling in.
6221 * \throw If \a this->getMeshDimension() != 2.
6222 * \throw If \a this->getSpaceDimension() != 3.
6224 * \if ENABLE_EXAMPLES
6225 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
6226 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
6229 void MEDCouplingUMesh::are2DCellsNotCorrectlyOriented(const double *vec, bool polyOnly, std::vector<int>& cells) const
6231 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
6232 throw INTERP_KERNEL::Exception("Invalid mesh to apply are2DCellsNotCorrectlyOriented on it : must be meshDim==2 and spaceDim==3 !");
6233 int nbOfCells=getNumberOfCells();
6234 const int *conn=_nodal_connec->begin();
6235 const int *connI=_nodal_connec_index->begin();
6236 const double *coordsPtr=_coords->begin();
6237 for(int i=0;i<nbOfCells;i++)
6239 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6240 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
6242 bool isQuadratic=INTERP_KERNEL::CellModel::GetCellModel(type).isQuadratic();
6243 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6250 * Reverse connectivity of 2D cells whose orientation is not correct. A cell is
6251 * considered to be oriented correctly if an angle between its normal vector and a
6252 * given vector is less than \c PI / \c 2.
6253 * \param [in] vec - 3 components of the vector specifying the correct orientation of
6255 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
6257 * \throw If \a this->getMeshDimension() != 2.
6258 * \throw If \a this->getSpaceDimension() != 3.
6260 * \if ENABLE_EXAMPLES
6261 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
6262 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
6265 * \sa changeOrientationOfCells
6267 void MEDCouplingUMesh::orientCorrectly2DCells(const double *vec, bool polyOnly)
6269 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
6270 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectly2DCells on it : must be meshDim==2 and spaceDim==3 !");
6271 int nbOfCells(getNumberOfCells()),*conn(_nodal_connec->getPointer());
6272 const int *connI(_nodal_connec_index->begin());
6273 const double *coordsPtr(_coords->begin());
6274 bool isModified(false);
6275 for(int i=0;i<nbOfCells;i++)
6277 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6278 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
6280 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
6281 bool isQuadratic(cm.isQuadratic());
6282 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6285 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
6290 _nodal_connec->declareAsNew();
6295 * This method change the orientation of cells in \a this without any consideration of coordinates. Only connectivity is impacted.
6297 * \sa orientCorrectly2DCells
6299 void MEDCouplingUMesh::changeOrientationOfCells()
6301 int mdim(getMeshDimension());
6302 if(mdim!=2 && mdim!=1)
6303 throw INTERP_KERNEL::Exception("Invalid mesh to apply changeOrientationOfCells on it : must be meshDim==2 or meshDim==1 !");
6304 int nbOfCells(getNumberOfCells()),*conn(_nodal_connec->getPointer());
6305 const int *connI(_nodal_connec_index->begin());
6308 for(int i=0;i<nbOfCells;i++)
6310 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6311 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
6312 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
6317 for(int i=0;i<nbOfCells;i++)
6319 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6320 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
6321 cm.changeOrientationOf1D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
6327 * Finds incorrectly oriented polyhedral cells, i.e. polyhedrons having correctly
6328 * oriented facets. The normal vector of the facet should point out of the cell.
6329 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
6330 * is not cleared before filling in.
6331 * \throw If \a this->getMeshDimension() != 3.
6332 * \throw If \a this->getSpaceDimension() != 3.
6333 * \throw If the coordinates array is not set.
6334 * \throw If the nodal connectivity of cells is not defined.
6336 * \if ENABLE_EXAMPLES
6337 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
6338 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
6341 void MEDCouplingUMesh::arePolyhedronsNotCorrectlyOriented(std::vector<int>& cells) const
6343 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
6344 throw INTERP_KERNEL::Exception("Invalid mesh to apply arePolyhedronsNotCorrectlyOriented on it : must be meshDim==3 and spaceDim==3 !");
6345 int nbOfCells=getNumberOfCells();
6346 const int *conn=_nodal_connec->begin();
6347 const int *connI=_nodal_connec_index->begin();
6348 const double *coordsPtr=_coords->begin();
6349 for(int i=0;i<nbOfCells;i++)
6351 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6352 if(type==INTERP_KERNEL::NORM_POLYHED)
6354 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6361 * Tries to fix connectivity of polyhedra, so that normal vector of all facets to point
6363 * \throw If \a this->getMeshDimension() != 3.
6364 * \throw If \a this->getSpaceDimension() != 3.
6365 * \throw If the coordinates array is not set.
6366 * \throw If the nodal connectivity of cells is not defined.
6367 * \throw If the reparation fails.
6369 * \if ENABLE_EXAMPLES
6370 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
6371 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
6373 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
6375 void MEDCouplingUMesh::orientCorrectlyPolyhedrons()
6377 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
6378 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectlyPolyhedrons on it : must be meshDim==3 and spaceDim==3 !");
6379 int nbOfCells=getNumberOfCells();
6380 int *conn=_nodal_connec->getPointer();
6381 const int *connI=_nodal_connec_index->begin();
6382 const double *coordsPtr=_coords->begin();
6383 for(int i=0;i<nbOfCells;i++)
6385 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6386 if(type==INTERP_KERNEL::NORM_POLYHED)
6390 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6391 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
6393 catch(INTERP_KERNEL::Exception& e)
6395 std::ostringstream oss; oss << "Something wrong in polyhedron #" << i << " : " << e.what();
6396 throw INTERP_KERNEL::Exception(oss.str());
6404 * Finds and fixes incorrectly oriented linear extruded volumes (INTERP_KERNEL::NORM_HEXA8,
6405 * INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXGP12 etc) to respect the MED convention
6406 * according to which the first facet of the cell should be oriented to have the normal vector
6407 * pointing out of cell.
6408 * \return DataArrayInt * - a new instance of DataArrayInt holding ids of fixed
6409 * cells. The caller is to delete this array using decrRef() as it is no more
6411 * \throw If \a this->getMeshDimension() != 3.
6412 * \throw If \a this->getSpaceDimension() != 3.
6413 * \throw If the coordinates array is not set.
6414 * \throw If the nodal connectivity of cells is not defined.
6416 * \if ENABLE_EXAMPLES
6417 * \ref cpp_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a C++ example".<br>
6418 * \ref py_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a Python example".
6420 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
6422 DataArrayInt *MEDCouplingUMesh::findAndCorrectBadOriented3DExtrudedCells()
6424 const char msg[]="check3DCellsWellOriented detection works only for 3D cells !";
6425 if(getMeshDimension()!=3)
6426 throw INTERP_KERNEL::Exception(msg);
6427 int spaceDim=getSpaceDimension();
6429 throw INTERP_KERNEL::Exception(msg);
6431 int nbOfCells=getNumberOfCells();
6432 int *conn=_nodal_connec->getPointer();
6433 const int *connI=_nodal_connec_index->begin();
6434 const double *coo=getCoords()->begin();
6435 MCAuto<DataArrayInt> cells(DataArrayInt::New()); cells->alloc(0,1);
6436 for(int i=0;i<nbOfCells;i++)
6438 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6439 if(cm.isExtruded() && !cm.isDynamic() && !cm.isQuadratic())
6441 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coo))
6443 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
6444 cells->pushBackSilent(i);
6448 return cells.retn();
6452 * This method is a faster method to correct orientation of all 3D cells in \a this.
6453 * 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.
6454 * This method makes the hypothesis that \a this a coherent that is to say MEDCouplingUMesh::checkConsistency should throw no exception.
6456 * \return a newly allocated int array with one components containing cell ids renumbered to fit the convention of MED (MED file and MEDCoupling)
6457 * \sa MEDCouplingUMesh::orientCorrectlyPolyhedrons,
6459 DataArrayInt *MEDCouplingUMesh::findAndCorrectBadOriented3DCells()
6461 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
6462 throw INTERP_KERNEL::Exception("Invalid mesh to apply findAndCorrectBadOriented3DCells on it : must be meshDim==3 and spaceDim==3 !");
6463 int nbOfCells=getNumberOfCells();
6464 int *conn=_nodal_connec->getPointer();
6465 const int *connI=_nodal_connec_index->begin();
6466 const double *coordsPtr=_coords->begin();
6467 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
6468 for(int i=0;i<nbOfCells;i++)
6470 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6473 case INTERP_KERNEL::NORM_TETRA4:
6475 if(!IsTetra4WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6477 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+3));
6478 ret->pushBackSilent(i);
6482 case INTERP_KERNEL::NORM_PYRA5:
6484 if(!IsPyra5WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6486 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+4));
6487 ret->pushBackSilent(i);
6491 case INTERP_KERNEL::NORM_PENTA6:
6492 case INTERP_KERNEL::NORM_HEXA8:
6493 case INTERP_KERNEL::NORM_HEXGP12:
6495 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6497 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
6498 ret->pushBackSilent(i);
6502 case INTERP_KERNEL::NORM_POLYHED:
6504 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6506 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
6507 ret->pushBackSilent(i);
6512 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 !");
6520 * This method has a sense for meshes with spaceDim==3 and meshDim==2.
6521 * If it is not the case an exception will be thrown.
6522 * This method is fast because the first cell of \a this is used to compute the plane.
6523 * \param vec output of size at least 3 used to store the normal vector (with norm equal to Area ) of searched plane.
6524 * \param pos output of size at least 3 used to store a point owned of searched plane.
6526 void MEDCouplingUMesh::getFastAveragePlaneOfThis(double *vec, double *pos) const
6528 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
6529 throw INTERP_KERNEL::Exception("Invalid mesh to apply getFastAveragePlaneOfThis on it : must be meshDim==2 and spaceDim==3 !");
6530 const int *conn=_nodal_connec->begin();
6531 const int *connI=_nodal_connec_index->begin();
6532 const double *coordsPtr=_coords->begin();
6533 INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(conn+1,connI[1]-connI[0]-1,coordsPtr,vec);
6534 std::copy(coordsPtr+3*conn[1],coordsPtr+3*conn[1]+3,pos);
6538 * Creates a new MEDCouplingFieldDouble holding Edge Ratio values of all
6539 * cells. Currently cells of the following types are treated:
6540 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
6541 * For a cell of other type an exception is thrown.
6542 * Space dimension of a 2D mesh can be either 2 or 3.
6543 * The Edge Ratio of a cell \f$t\f$ is:
6544 * \f$\frac{|t|_\infty}{|t|_0}\f$,
6545 * where \f$|t|_\infty\f$ and \f$|t|_0\f$ respectively denote the greatest and
6546 * the smallest edge lengths of \f$t\f$.
6547 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6548 * cells and one time, lying on \a this mesh. The caller is to delete this
6549 * field using decrRef() as it is no more needed.
6550 * \throw If the coordinates array is not set.
6551 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6552 * \throw If the connectivity data array has more than one component.
6553 * \throw If the connectivity data array has a named component.
6554 * \throw If the connectivity index data array has more than one component.
6555 * \throw If the connectivity index data array has a named component.
6556 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
6557 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
6558 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
6560 MEDCouplingFieldDouble *MEDCouplingUMesh::getEdgeRatioField() const
6562 checkConsistencyLight();
6563 int spaceDim=getSpaceDimension();
6564 int meshDim=getMeshDimension();
6565 if(spaceDim!=2 && spaceDim!=3)
6566 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : SpaceDimension must be equal to 2 or 3 !");
6567 if(meshDim!=2 && meshDim!=3)
6568 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : MeshDimension must be equal to 2 or 3 !");
6569 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6571 int nbOfCells=getNumberOfCells();
6572 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6573 arr->alloc(nbOfCells,1);
6574 double *pt=arr->getPointer();
6575 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6576 const int *conn=_nodal_connec->begin();
6577 const int *connI=_nodal_connec_index->begin();
6578 const double *coo=_coords->begin();
6580 for(int i=0;i<nbOfCells;i++,pt++)
6582 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6585 case INTERP_KERNEL::NORM_TRI3:
6587 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
6588 *pt=INTERP_KERNEL::triEdgeRatio(tmp);
6591 case INTERP_KERNEL::NORM_QUAD4:
6593 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6594 *pt=INTERP_KERNEL::quadEdgeRatio(tmp);
6597 case INTERP_KERNEL::NORM_TETRA4:
6599 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6600 *pt=INTERP_KERNEL::tetraEdgeRatio(tmp);
6604 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
6606 conn+=connI[i+1]-connI[i];
6608 ret->setName("EdgeRatio");
6609 ret->synchronizeTimeWithSupport();
6614 * Creates a new MEDCouplingFieldDouble holding Aspect Ratio values of all
6615 * cells. Currently cells of the following types are treated:
6616 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
6617 * For a cell of other type an exception is thrown.
6618 * Space dimension of a 2D mesh can be either 2 or 3.
6619 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6620 * cells and one time, lying on \a this mesh. The caller is to delete this
6621 * field using decrRef() as it is no more needed.
6622 * \throw If the coordinates array is not set.
6623 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6624 * \throw If the connectivity data array has more than one component.
6625 * \throw If the connectivity data array has a named component.
6626 * \throw If the connectivity index data array has more than one component.
6627 * \throw If the connectivity index data array has a named component.
6628 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
6629 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
6630 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
6632 MEDCouplingFieldDouble *MEDCouplingUMesh::getAspectRatioField() const
6634 checkConsistencyLight();
6635 int spaceDim=getSpaceDimension();
6636 int meshDim=getMeshDimension();
6637 if(spaceDim!=2 && spaceDim!=3)
6638 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : SpaceDimension must be equal to 2 or 3 !");
6639 if(meshDim!=2 && meshDim!=3)
6640 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : MeshDimension must be equal to 2 or 3 !");
6641 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6643 int nbOfCells=getNumberOfCells();
6644 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6645 arr->alloc(nbOfCells,1);
6646 double *pt=arr->getPointer();
6647 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6648 const int *conn=_nodal_connec->begin();
6649 const int *connI=_nodal_connec_index->begin();
6650 const double *coo=_coords->begin();
6652 for(int i=0;i<nbOfCells;i++,pt++)
6654 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6657 case INTERP_KERNEL::NORM_TRI3:
6659 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
6660 *pt=INTERP_KERNEL::triAspectRatio(tmp);
6663 case INTERP_KERNEL::NORM_QUAD4:
6665 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6666 *pt=INTERP_KERNEL::quadAspectRatio(tmp);
6669 case INTERP_KERNEL::NORM_TETRA4:
6671 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6672 *pt=INTERP_KERNEL::tetraAspectRatio(tmp);
6676 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
6678 conn+=connI[i+1]-connI[i];
6680 ret->setName("AspectRatio");
6681 ret->synchronizeTimeWithSupport();
6686 * Creates a new MEDCouplingFieldDouble holding Warping factor values of all
6687 * cells of \a this 2D mesh in 3D space. It is a measure of the "planarity" of 2D cell
6688 * in 3D space. Currently only cells of the following types are
6689 * treated: INTERP_KERNEL::NORM_QUAD4.
6690 * For a cell of other type an exception is thrown.
6691 * The warp field is computed as follows: let (a,b,c,d) be the points of the quad.
6693 * \f$t=\vec{da}\times\vec{ab}\f$,
6694 * \f$u=\vec{ab}\times\vec{bc}\f$
6695 * \f$v=\vec{bc}\times\vec{cd}\f$
6696 * \f$w=\vec{cd}\times\vec{da}\f$, the warp is defined as \f$W^3\f$ with
6698 * W=min(\frac{t}{|t|}\cdot\frac{v}{|v|}, \frac{u}{|u|}\cdot\frac{w}{|w|})
6700 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6701 * cells and one time, lying on \a this mesh. The caller is to delete this
6702 * field using decrRef() as it is no more needed.
6703 * \throw If the coordinates array is not set.
6704 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6705 * \throw If the connectivity data array has more than one component.
6706 * \throw If the connectivity data array has a named component.
6707 * \throw If the connectivity index data array has more than one component.
6708 * \throw If the connectivity index data array has a named component.
6709 * \throw If \a this->getMeshDimension() != 2.
6710 * \throw If \a this->getSpaceDimension() != 3.
6711 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
6713 MEDCouplingFieldDouble *MEDCouplingUMesh::getWarpField() const
6715 checkConsistencyLight();
6716 int spaceDim=getSpaceDimension();
6717 int meshDim=getMeshDimension();
6719 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : SpaceDimension must be equal to 3 !");
6721 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : MeshDimension must be equal to 2 !");
6722 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6724 int nbOfCells=getNumberOfCells();
6725 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6726 arr->alloc(nbOfCells,1);
6727 double *pt=arr->getPointer();
6728 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6729 const int *conn=_nodal_connec->begin();
6730 const int *connI=_nodal_connec_index->begin();
6731 const double *coo=_coords->begin();
6733 for(int i=0;i<nbOfCells;i++,pt++)
6735 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6738 case INTERP_KERNEL::NORM_QUAD4:
6740 FillInCompact3DMode(3,4,conn+1,coo,tmp);
6741 *pt=INTERP_KERNEL::quadWarp(tmp);
6745 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : A cell with not manged type (NORM_QUAD4) has been detected !");
6747 conn+=connI[i+1]-connI[i];
6749 ret->setName("Warp");
6750 ret->synchronizeTimeWithSupport();
6756 * Creates a new MEDCouplingFieldDouble holding Skew factor values of all
6757 * cells of \a this 2D mesh in 3D space. Currently cells of the following types are
6758 * treated: INTERP_KERNEL::NORM_QUAD4.
6759 * The skew is computed as follow for a quad with points (a,b,c,d): let
6760 * \f$u=\vec{ab}+\vec{dc}\f$ and \f$v=\vec{ac}+\vec{bd}\f$
6761 * then the skew is computed as:
6763 * s=\frac{u}{|u|}\cdot\frac{v}{|v|}
6766 * For a cell of other type an exception is thrown.
6767 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6768 * cells and one time, lying on \a this mesh. The caller is to delete this
6769 * field using decrRef() as it is no more needed.
6770 * \throw If the coordinates array is not set.
6771 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6772 * \throw If the connectivity data array has more than one component.
6773 * \throw If the connectivity data array has a named component.
6774 * \throw If the connectivity index data array has more than one component.
6775 * \throw If the connectivity index data array has a named component.
6776 * \throw If \a this->getMeshDimension() != 2.
6777 * \throw If \a this->getSpaceDimension() != 3.
6778 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
6780 MEDCouplingFieldDouble *MEDCouplingUMesh::getSkewField() const
6782 checkConsistencyLight();
6783 int spaceDim=getSpaceDimension();
6784 int meshDim=getMeshDimension();
6786 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : SpaceDimension must be equal to 3 !");
6788 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : MeshDimension must be equal to 2 !");
6789 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6791 int nbOfCells=getNumberOfCells();
6792 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6793 arr->alloc(nbOfCells,1);
6794 double *pt=arr->getPointer();
6795 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6796 const int *conn=_nodal_connec->begin();
6797 const int *connI=_nodal_connec_index->begin();
6798 const double *coo=_coords->begin();
6800 for(int i=0;i<nbOfCells;i++,pt++)
6802 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6805 case INTERP_KERNEL::NORM_QUAD4:
6807 FillInCompact3DMode(3,4,conn+1,coo,tmp);
6808 *pt=INTERP_KERNEL::quadSkew(tmp);
6812 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : A cell with not manged type (NORM_QUAD4) has been detected !");
6814 conn+=connI[i+1]-connI[i];
6816 ret->setName("Skew");
6817 ret->synchronizeTimeWithSupport();
6822 * Returns the cell field giving for each cell in \a this its diameter. Diameter means the max length of all possible SEG2 in the cell.
6824 * \return a new instance of field containing the result. The returned instance has to be deallocated by the caller.
6826 * \sa getSkewField, getWarpField, getAspectRatioField, getEdgeRatioField
6828 MEDCouplingFieldDouble *MEDCouplingUMesh::computeDiameterField() const
6830 checkConsistencyLight();
6831 MCAuto<MEDCouplingFieldDouble> ret(MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME));
6833 std::set<INTERP_KERNEL::NormalizedCellType> types;
6834 ComputeAllTypesInternal(types,_nodal_connec,_nodal_connec_index);
6835 int spaceDim(getSpaceDimension()),nbCells(getNumberOfCells());
6836 MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
6837 arr->alloc(nbCells,1);
6838 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++)
6840 INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::DiameterCalculator> dc(INTERP_KERNEL::CellModel::GetCellModel(*it).buildInstanceOfDiameterCalulator(spaceDim));
6841 MCAuto<DataArrayInt> cellIds(giveCellsWithType(*it));
6842 dc->computeForListOfCellIdsUMeshFrmt(cellIds->begin(),cellIds->end(),_nodal_connec_index->begin(),_nodal_connec->begin(),getCoords()->begin(),arr->getPointer());
6845 ret->setName("Diameter");
6850 * This method aggregate the bbox of each cell and put it into bbox parameter (xmin,xmax,ymin,ymax,zmin,zmax).
6852 * \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)
6853 * For all other cases this input parameter is ignored.
6854 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6856 * \throw If \a this is not fully set (coordinates and connectivity).
6857 * \throw If a cell in \a this has no valid nodeId.
6858 * \sa MEDCouplingUMesh::getBoundingBoxForBBTreeFast, MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
6860 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree(double arcDetEps) const
6862 int mDim(getMeshDimension()),sDim(getSpaceDimension());
6863 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.
6864 return getBoundingBoxForBBTreeFast();
6865 if((mDim==2 && sDim==2) || (mDim==1 && sDim==2))
6867 bool presenceOfQuadratic(false);
6868 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=_types.begin();it!=_types.end();it++)
6870 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(*it));
6871 if(cm.isQuadratic())
6872 presenceOfQuadratic=true;
6874 if(!presenceOfQuadratic)
6875 return getBoundingBoxForBBTreeFast();
6876 if(mDim==2 && sDim==2)
6877 return getBoundingBoxForBBTree2DQuadratic(arcDetEps);
6879 return getBoundingBoxForBBTree1DQuadratic(arcDetEps);
6881 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) !");
6885 * This method aggregate the bbox of each cell only considering the nodes constituting each cell and put it into bbox parameter.
6886 * So meshes having quadratic cells the computed bounding boxes can be invalid !
6888 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6890 * \throw If \a this is not fully set (coordinates and connectivity).
6891 * \throw If a cell in \a this has no valid nodeId.
6893 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTreeFast() const
6895 checkFullyDefined();
6896 int spaceDim(getSpaceDimension()),nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
6897 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
6898 double *bbox(ret->getPointer());
6899 for(int i=0;i<nbOfCells*spaceDim;i++)
6901 bbox[2*i]=std::numeric_limits<double>::max();
6902 bbox[2*i+1]=-std::numeric_limits<double>::max();
6904 const double *coordsPtr(_coords->begin());
6905 const int *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
6906 for(int i=0;i<nbOfCells;i++)
6908 int offset=connI[i]+1;
6909 int nbOfNodesForCell(connI[i+1]-offset),kk(0);
6910 for(int j=0;j<nbOfNodesForCell;j++)
6912 int nodeId=conn[offset+j];
6913 if(nodeId>=0 && nodeId<nbOfNodes)
6915 for(int k=0;k<spaceDim;k++)
6917 bbox[2*spaceDim*i+2*k]=std::min(bbox[2*spaceDim*i+2*k],coordsPtr[spaceDim*nodeId+k]);
6918 bbox[2*spaceDim*i+2*k+1]=std::max(bbox[2*spaceDim*i+2*k+1],coordsPtr[spaceDim*nodeId+k]);
6925 std::ostringstream oss; oss << "MEDCouplingUMesh::getBoundingBoxForBBTree : cell #" << i << " contains no valid nodeId !";
6926 throw INTERP_KERNEL::Exception(oss.str());
6933 * This method aggregates the bbox of each 2D cell in \a this considering the whole shape. This method is particularly
6934 * useful for 2D meshes having quadratic cells
6935 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
6936 * the two extremities of the arc of circle).
6938 * \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)
6939 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6940 * \throw If \a this is not fully defined.
6941 * \throw If \a this is not a mesh with meshDimension equal to 2.
6942 * \throw If \a this is not a mesh with spaceDimension equal to 2.
6943 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic
6945 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic(double arcDetEps) const
6947 checkFullyDefined();
6948 int spaceDim(getSpaceDimension()),mDim(getMeshDimension()),nbOfCells(getNumberOfCells());
6949 if(spaceDim!=2 || mDim!=2)
6950 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!");
6951 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
6952 double *bbox(ret->getPointer());
6953 const double *coords(_coords->begin());
6954 const int *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
6955 for(int i=0;i<nbOfCells;i++,bbox+=4,connI++)
6957 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
6958 int sz(connI[1]-connI[0]-1);
6959 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=arcDetEps;
6960 std::vector<INTERP_KERNEL::Node *> nodes(sz);
6961 INTERP_KERNEL::QuadraticPolygon *pol(0);
6962 for(int j=0;j<sz;j++)
6964 int nodeId(conn[*connI+1+j]);
6965 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
6967 if(!cm.isQuadratic())
6968 pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
6970 pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
6971 INTERP_KERNEL::Bounds b; b.prepareForAggregation(); pol->fillBounds(b); delete pol;
6972 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax();
6978 * This method aggregates the bbox of each 1D cell in \a this considering the whole shape. This method is particularly
6979 * useful for 2D meshes having quadratic cells
6980 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
6981 * the two extremities of the arc of circle).
6983 * \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)
6984 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6985 * \throw If \a this is not fully defined.
6986 * \throw If \a this is not a mesh with meshDimension equal to 1.
6987 * \throw If \a this is not a mesh with spaceDimension equal to 2.
6988 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
6990 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic(double arcDetEps) const
6992 checkFullyDefined();
6993 int spaceDim(getSpaceDimension()),mDim(getMeshDimension()),nbOfCells(getNumberOfCells());
6994 if(spaceDim!=2 || mDim!=1)
6995 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!");
6996 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
6997 double *bbox(ret->getPointer());
6998 const double *coords(_coords->begin());
6999 const int *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
7000 for(int i=0;i<nbOfCells;i++,bbox+=4,connI++)
7002 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
7003 int sz(connI[1]-connI[0]-1);
7004 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=arcDetEps;
7005 std::vector<INTERP_KERNEL::Node *> nodes(sz);
7006 INTERP_KERNEL::Edge *edge(0);
7007 for(int j=0;j<sz;j++)
7009 int nodeId(conn[*connI+1+j]);
7010 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
7012 if(!cm.isQuadratic())
7013 edge=INTERP_KERNEL::QuadraticPolygon::BuildLinearEdge(nodes);
7015 edge=INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(nodes);
7016 const INTERP_KERNEL::Bounds& b(edge->getBounds());
7017 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax(); edge->decrRef();
7024 namespace MEDCouplingImpl
7029 ConnReader(const int *c, int val):_conn(c),_val(val) { }
7030 bool operator() (const int& pos) { return _conn[pos]!=_val; }
7039 ConnReader2(const int *c, int val):_conn(c),_val(val) { }
7040 bool operator() (const int& pos) { return _conn[pos]==_val; }
7050 * This method expects that \a this is sorted by types. If not an exception will be thrown.
7051 * This method returns in the same format as code (see MEDCouplingUMesh::checkTypeConsistencyAndContig or MEDCouplingUMesh::splitProfilePerType) how
7052 * \a this is composed in cell types.
7053 * The returned array is of size 3*n where n is the number of different types present in \a this.
7054 * For every k in [0,n] ret[3*k+2]==-1 because it has no sense here.
7055 * This parameter is kept only for compatibility with other methode listed above.
7057 std::vector<int> MEDCouplingUMesh::getDistributionOfTypes() const
7059 checkConnectivityFullyDefined();
7060 const int *conn=_nodal_connec->begin();
7061 const int *connI=_nodal_connec_index->begin();
7062 const int *work=connI;
7063 int nbOfCells=getNumberOfCells();
7064 std::size_t n=getAllGeoTypes().size();
7065 std::vector<int> ret(3*n,-1); //ret[3*k+2]==-1 because it has no sense here
7066 std::set<INTERP_KERNEL::NormalizedCellType> types;
7067 for(std::size_t i=0;work!=connI+nbOfCells;i++)
7069 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn[*work];
7070 if(types.find(typ)!=types.end())
7072 std::ostringstream oss; oss << "MEDCouplingUMesh::getDistributionOfTypes : Type " << INTERP_KERNEL::CellModel::GetCellModel(typ).getRepr();
7073 oss << " is not contiguous !";
7074 throw INTERP_KERNEL::Exception(oss.str());
7078 const int *work2=std::find_if(work+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,typ));
7079 ret[3*i+1]=(int)std::distance(work,work2);
7086 * This method is used to check that this has contiguous cell type in same order than described in \a code.
7087 * only for types cell, type node is not managed.
7088 * Format of \a code is the following. \a code should be of size 3*n and non empty. If not an exception is thrown.
7089 * foreach k in [0,n) on 3*k pos represent the geometric type and 3*k+1 number of elements of type 3*k.
7090 * 3*k+2 refers if different from -1 the pos in 'idsPerType' to get the corresponding array.
7091 * If 2 or more same geometric type is in \a code and exception is thrown too.
7093 * This method firstly checks
7094 * If it exists k so that 3*k geometric type is not in geometric types of this an exception will be thrown.
7095 * If it exists k so that 3*k geometric type exists but the number of consecutive cell types does not match,
7096 * an exception is thrown too.
7098 * If all geometric types in \a code are exactly those in \a this null pointer is returned.
7099 * If it exists a geometric type in \a this \b not in \a code \b no exception is thrown
7100 * and a DataArrayInt instance is returned that the user has the responsability to deallocate.
7102 DataArrayInt *MEDCouplingUMesh::checkTypeConsistencyAndContig(const std::vector<int>& code, const std::vector<const DataArrayInt *>& idsPerType) const
7105 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code is empty, should not !");
7106 std::size_t sz=code.size();
7109 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code size is NOT %3 !");
7110 std::vector<INTERP_KERNEL::NormalizedCellType> types;
7112 bool isNoPflUsed=true;
7113 for(std::size_t i=0;i<n;i++)
7114 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)code[3*i])==types.end())
7116 types.push_back((INTERP_KERNEL::NormalizedCellType)code[3*i]);
7118 if(_types.find((INTERP_KERNEL::NormalizedCellType)code[3*i])==_types.end())
7119 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : expected geo types not in this !");
7120 isNoPflUsed=isNoPflUsed && (code[3*i+2]==-1);
7123 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code contains duplication of types in unstructured mesh !");
7126 if(!checkConsecutiveCellTypesAndOrder(&types[0],&types[0]+types.size()))
7127 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : non contiguous type !");
7128 if(types.size()==_types.size())
7131 MCAuto<DataArrayInt> ret=DataArrayInt::New();
7133 int *retPtr=ret->getPointer();
7134 const int *connI=_nodal_connec_index->begin();
7135 const int *conn=_nodal_connec->begin();
7136 int nbOfCells=getNumberOfCells();
7139 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++,kk++)
7141 i=std::find_if(i,connI+nbOfCells,MEDCouplingImpl::ConnReader2(conn,(int)(*it)));
7142 int offset=(int)std::distance(connI,i);
7143 const int *j=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)(*it)));
7144 int nbOfCellsOfCurType=(int)std::distance(i,j);
7145 if(code[3*kk+2]==-1)
7146 for(int k=0;k<nbOfCellsOfCurType;k++)
7150 int idInIdsPerType=code[3*kk+2];
7151 if(idInIdsPerType>=0 && idInIdsPerType<(int)idsPerType.size())
7153 const DataArrayInt *zePfl=idsPerType[idInIdsPerType];
7156 zePfl->checkAllocated();
7157 if(zePfl->getNumberOfComponents()==1)
7159 for(const int *k=zePfl->begin();k!=zePfl->end();k++,retPtr++)
7161 if(*k>=0 && *k<nbOfCellsOfCurType)
7162 *retPtr=(*k)+offset;
7165 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : the section " << kk << " points to the profile #" << idInIdsPerType;
7166 oss << ", and this profile contains a value " << *k << " should be in [0," << nbOfCellsOfCurType << ") !";
7167 throw INTERP_KERNEL::Exception(oss.str());
7172 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of a profile with nb of compo != 1 !");
7175 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of null profile !");
7179 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : at section " << kk << " of code it points to the array #" << idInIdsPerType;
7180 oss << " should be in [0," << idsPerType.size() << ") !";
7181 throw INTERP_KERNEL::Exception(oss.str());
7190 * This method makes the hypothesis that \a this is sorted by type. If not an exception will be thrown.
7191 * 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.
7192 * 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.
7193 * This method has 1 input \a profile and 3 outputs \a code \a idsInPflPerType and \a idsPerType.
7195 * \param [in] profile
7196 * \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.
7197 * \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,
7198 * \a idsInPflPerType[i] stores the tuple ids in \a profile that correspond to the geometric type code[3*i+0]
7199 * \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.
7200 * This vector can be empty in case of all geometric type cells are fully covered in ascending in the given input \a profile.
7201 * \throw if \a profile has not exactly one component. It throws too, if \a profile contains some values not in [0,getNumberOfCells()) or if \a this is not fully defined
7203 void MEDCouplingUMesh::splitProfilePerType(const DataArrayInt *profile, std::vector<int>& code, std::vector<DataArrayInt *>& idsInPflPerType, std::vector<DataArrayInt *>& idsPerType) const
7206 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile is NULL !");
7207 if(profile->getNumberOfComponents()!=1)
7208 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile should have exactly one component !");
7209 checkConnectivityFullyDefined();
7210 const int *conn=_nodal_connec->begin();
7211 const int *connI=_nodal_connec_index->begin();
7212 int nbOfCells=getNumberOfCells();
7213 std::vector<INTERP_KERNEL::NormalizedCellType> types;
7214 std::vector<int> typeRangeVals(1);
7215 for(const int *i=connI;i!=connI+nbOfCells;)
7217 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7218 if(std::find(types.begin(),types.end(),curType)!=types.end())
7220 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : current mesh is not sorted by type !");
7222 types.push_back(curType);
7223 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7224 typeRangeVals.push_back((int)std::distance(connI,i));
7227 DataArrayInt *castArr=0,*rankInsideCast=0,*castsPresent=0;
7228 profile->splitByValueRange(&typeRangeVals[0],&typeRangeVals[0]+typeRangeVals.size(),castArr,rankInsideCast,castsPresent);
7229 MCAuto<DataArrayInt> tmp0=castArr;
7230 MCAuto<DataArrayInt> tmp1=rankInsideCast;
7231 MCAuto<DataArrayInt> tmp2=castsPresent;
7233 int nbOfCastsFinal=castsPresent->getNumberOfTuples();
7234 code.resize(3*nbOfCastsFinal);
7235 std::vector< MCAuto<DataArrayInt> > idsInPflPerType2;
7236 std::vector< MCAuto<DataArrayInt> > idsPerType2;
7237 for(int i=0;i<nbOfCastsFinal;i++)
7239 int castId=castsPresent->getIJ(i,0);
7240 MCAuto<DataArrayInt> tmp3=castArr->findIdsEqual(castId);
7241 idsInPflPerType2.push_back(tmp3);
7242 code[3*i]=(int)types[castId];
7243 code[3*i+1]=tmp3->getNumberOfTuples();
7244 MCAuto<DataArrayInt> tmp4=rankInsideCast->selectByTupleId(tmp3->begin(),tmp3->begin()+tmp3->getNumberOfTuples());
7245 if(!tmp4->isIota(typeRangeVals[castId+1]-typeRangeVals[castId]))
7247 tmp4->copyStringInfoFrom(*profile);
7248 idsPerType2.push_back(tmp4);
7249 code[3*i+2]=(int)idsPerType2.size()-1;
7256 std::size_t sz2=idsInPflPerType2.size();
7257 idsInPflPerType.resize(sz2);
7258 for(std::size_t i=0;i<sz2;i++)
7260 DataArrayInt *locDa=idsInPflPerType2[i];
7262 idsInPflPerType[i]=locDa;
7264 std::size_t sz=idsPerType2.size();
7265 idsPerType.resize(sz);
7266 for(std::size_t i=0;i<sz;i++)
7268 DataArrayInt *locDa=idsPerType2[i];
7270 idsPerType[i]=locDa;
7275 * This method is here too emulate the MEDMEM behaviour on BDC (buildDescendingConnectivity). Hoping this method becomes deprecated very soon.
7276 * This method make the assumption that \a this and 'nM1LevMesh' mesh lyies on same coords (same pointer) as MED and MEDMEM does.
7277 * The following equality should be verified 'nM1LevMesh->getMeshDimension()==this->getMeshDimension()-1'
7278 * This method returns 5+2 elements. 'desc', 'descIndx', 'revDesc', 'revDescIndx' and 'meshnM1' behaves exactly as MEDCoupling::MEDCouplingUMesh::buildDescendingConnectivity except the content as described after. The returned array specifies the n-1 mesh reordered by type as MEDMEM does. 'nM1LevMeshIds' contains the ids in returned 'meshnM1'. Finally 'meshnM1Old2New' contains numbering old2new that is to say the cell #k in coarse 'nM1LevMesh' will have the number ret[k] in returned mesh 'nM1LevMesh' MEDMEM reordered.
7280 MEDCouplingUMesh *MEDCouplingUMesh::emulateMEDMEMBDC(const MEDCouplingUMesh *nM1LevMesh, DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *&revDesc, DataArrayInt *&revDescIndx, DataArrayInt *& nM1LevMeshIds, DataArrayInt *&meshnM1Old2New) const
7282 checkFullyDefined();
7283 nM1LevMesh->checkFullyDefined();
7284 if(getMeshDimension()-1!=nM1LevMesh->getMeshDimension())
7285 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : The mesh passed as first argument should have a meshDim equal to this->getMeshDimension()-1 !" );
7286 if(_coords!=nM1LevMesh->getCoords())
7287 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : 'this' and mesh in first argument should share the same coords : Use tryToShareSameCoords method !");
7288 MCAuto<DataArrayInt> tmp0=DataArrayInt::New();
7289 MCAuto<DataArrayInt> tmp1=DataArrayInt::New();
7290 MCAuto<MEDCouplingUMesh> ret1=buildDescendingConnectivity(desc,descIndx,tmp0,tmp1);
7291 MCAuto<DataArrayInt> ret0=ret1->sortCellsInMEDFileFrmt();
7292 desc->transformWithIndArr(ret0->begin(),ret0->begin()+ret0->getNbOfElems());
7293 MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
7294 tmp->setConnectivity(tmp0,tmp1);
7295 tmp->renumberCells(ret0->begin(),false);
7296 revDesc=tmp->getNodalConnectivity();
7297 revDescIndx=tmp->getNodalConnectivityIndex();
7298 DataArrayInt *ret=0;
7299 if(!ret1->areCellsIncludedIn(nM1LevMesh,2,ret))
7302 ret->getMaxValue(tmp2);
7304 std::ostringstream oss; oss << "MEDCouplingUMesh::emulateMEDMEMBDC : input N-1 mesh present a cell not in descending mesh ... Id of cell is " << tmp2 << " !";
7305 throw INTERP_KERNEL::Exception(oss.str());
7310 revDescIndx->incrRef();
7313 meshnM1Old2New=ret0;
7318 * Permutes the nodal connectivity arrays so that the cells are sorted by type, which is
7319 * necessary for writing the mesh to MED file. Additionally returns a permutation array
7320 * in "Old to New" mode.
7321 * \return DataArrayInt * - a new instance of DataArrayInt. The caller is to delete
7322 * this array using decrRef() as it is no more needed.
7323 * \throw If the nodal connectivity of cells is not defined.
7325 DataArrayInt *MEDCouplingUMesh::sortCellsInMEDFileFrmt()
7327 checkConnectivityFullyDefined();
7328 MCAuto<DataArrayInt> ret=getRenumArrForMEDFileFrmt();
7329 renumberCells(ret->begin(),false);
7334 * This methods checks that cells are sorted by their types.
7335 * This method makes asumption (no check) that connectivity is correctly set before calling.
7337 bool MEDCouplingUMesh::checkConsecutiveCellTypes() const
7339 checkFullyDefined();
7340 const int *conn=_nodal_connec->begin();
7341 const int *connI=_nodal_connec_index->begin();
7342 int nbOfCells=getNumberOfCells();
7343 std::set<INTERP_KERNEL::NormalizedCellType> types;
7344 for(const int *i=connI;i!=connI+nbOfCells;)
7346 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7347 if(types.find(curType)!=types.end())
7349 types.insert(curType);
7350 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7356 * This method is a specialization of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method that is called here.
7357 * The geometric type order is specified by MED file.
7359 * \sa MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder
7361 bool MEDCouplingUMesh::checkConsecutiveCellTypesForMEDFileFrmt() const
7363 return checkConsecutiveCellTypesAndOrder(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
7367 * This method performs the same job as checkConsecutiveCellTypes except that the order of types sequence is analyzed to check
7368 * that the order is specified in array defined by [ \a orderBg , \a orderEnd ).
7369 * If there is some geo types in \a this \b NOT in [ \a orderBg, \a orderEnd ) it is OK (return true) if contiguous.
7370 * If there is some geo types in [ \a orderBg, \a orderEnd ) \b NOT in \a this it is OK too (return true) if contiguous.
7372 bool MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
7374 checkFullyDefined();
7375 const int *conn=_nodal_connec->begin();
7376 const int *connI=_nodal_connec_index->begin();
7377 int nbOfCells=getNumberOfCells();
7381 std::set<INTERP_KERNEL::NormalizedCellType> sg;
7382 for(const int *i=connI;i!=connI+nbOfCells;)
7384 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7385 const INTERP_KERNEL::NormalizedCellType *isTypeExists=std::find(orderBg,orderEnd,curType);
7386 if(isTypeExists!=orderEnd)
7388 int pos=(int)std::distance(orderBg,isTypeExists);
7392 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7396 if(sg.find(curType)==sg.end())
7398 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7409 * This method returns 2 newly allocated DataArrayInt instances. The first is an array of size 'this->getNumberOfCells()' with one component,
7410 * 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
7411 * number of tuples than input type array and with one component. This 2nd output array gives type by type the number of occurence of type in 'this'.
7413 DataArrayInt *MEDCouplingUMesh::getLevArrPerCellTypes(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd, DataArrayInt *&nbPerType) const
7415 checkConnectivityFullyDefined();
7416 int nbOfCells=getNumberOfCells();
7417 const int *conn=_nodal_connec->begin();
7418 const int *connI=_nodal_connec_index->begin();
7419 MCAuto<DataArrayInt> tmpa=DataArrayInt::New();
7420 MCAuto<DataArrayInt> tmpb=DataArrayInt::New();
7421 tmpa->alloc(nbOfCells,1);
7422 tmpb->alloc((int)std::distance(orderBg,orderEnd),1);
7423 tmpb->fillWithZero();
7424 int *tmp=tmpa->getPointer();
7425 int *tmp2=tmpb->getPointer();
7426 for(const int *i=connI;i!=connI+nbOfCells;i++)
7428 const INTERP_KERNEL::NormalizedCellType *where=std::find(orderBg,orderEnd,(INTERP_KERNEL::NormalizedCellType)conn[*i]);
7431 int pos=(int)std::distance(orderBg,where);
7433 tmp[std::distance(connI,i)]=pos;
7437 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*i]);
7438 std::ostringstream oss; oss << "MEDCouplingUMesh::getLevArrPerCellTypes : Cell #" << std::distance(connI,i);
7439 oss << " has a type " << cm.getRepr() << " not in input array of type !";
7440 throw INTERP_KERNEL::Exception(oss.str());
7443 nbPerType=tmpb.retn();
7448 * This method behaves exactly as MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec but the order is those defined in MED file spec.
7450 * \return a new object containing the old to new correspondance.
7452 * \sa MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec, MEDCouplingUMesh::sortCellsInMEDFileFrmt.
7454 DataArrayInt *MEDCouplingUMesh::getRenumArrForMEDFileFrmt() const
7456 return getRenumArrForConsecutiveCellTypesSpec(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
7460 * 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.
7461 * This method returns an array of size getNumberOfCells() that gives a renumber array old2New that can be used as input of MEDCouplingMesh::renumberCells.
7462 * The mesh after this call to MEDCouplingMesh::renumberCells will pass the test of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder with the same inputs.
7463 * The returned array minimizes the permutations that is to say the order of cells inside same geometric type remains the same.
7465 DataArrayInt *MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
7467 DataArrayInt *nbPerType=0;
7468 MCAuto<DataArrayInt> tmpa=getLevArrPerCellTypes(orderBg,orderEnd,nbPerType);
7469 nbPerType->decrRef();
7470 return tmpa->buildPermArrPerLevel();
7474 * This method reorganize the cells of \a this so that the cells with same geometric types are put together.
7475 * The number of cells remains unchanged after the call of this method.
7476 * This method tries to minimizes the number of needed permutations. So, this method behaves not exactly as
7477 * MEDCouplingUMesh::sortCellsInMEDFileFrmt.
7479 * \return the array giving the correspondance old to new.
7481 DataArrayInt *MEDCouplingUMesh::rearrange2ConsecutiveCellTypes()
7483 checkFullyDefined();
7485 const int *conn=_nodal_connec->begin();
7486 const int *connI=_nodal_connec_index->begin();
7487 int nbOfCells=getNumberOfCells();
7488 std::vector<INTERP_KERNEL::NormalizedCellType> types;
7489 for(const int *i=connI;i!=connI+nbOfCells && (types.size()!=_types.size());)
7490 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)conn[*i])==types.end())
7492 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7493 types.push_back(curType);
7494 for(i++;i!=connI+nbOfCells && (INTERP_KERNEL::NormalizedCellType)conn[*i]==curType;i++);
7496 DataArrayInt *ret=DataArrayInt::New();
7497 ret->alloc(nbOfCells,1);
7498 int *retPtr=ret->getPointer();
7499 std::fill(retPtr,retPtr+nbOfCells,-1);
7501 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
7503 for(const int *i=connI;i!=connI+nbOfCells;i++)
7504 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
7505 retPtr[std::distance(connI,i)]=newCellId++;
7507 renumberCells(retPtr,false);
7512 * This method splits \a this into as mush as untructured meshes that consecutive set of same type cells.
7513 * So this method has typically a sense if MEDCouplingUMesh::checkConsecutiveCellTypes has a sense.
7514 * This method makes asumption that connectivity is correctly set before calling.
7516 std::vector<MEDCouplingUMesh *> MEDCouplingUMesh::splitByType() const
7518 checkConnectivityFullyDefined();
7519 const int *conn=_nodal_connec->begin();
7520 const int *connI=_nodal_connec_index->begin();
7521 int nbOfCells=getNumberOfCells();
7522 std::vector<MEDCouplingUMesh *> ret;
7523 for(const int *i=connI;i!=connI+nbOfCells;)
7525 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7526 int beginCellId=(int)std::distance(connI,i);
7527 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7528 int endCellId=(int)std::distance(connI,i);
7529 int sz=endCellId-beginCellId;
7530 int *cells=new int[sz];
7531 for(int j=0;j<sz;j++)
7532 cells[j]=beginCellId+j;
7533 MEDCouplingUMesh *m=(MEDCouplingUMesh *)buildPartOfMySelf(cells,cells+sz,true);
7541 * This method performs the opposite operation than those in MEDCoupling1SGTUMesh::buildUnstructured.
7542 * If \a this is a single geometric type unstructured mesh, it will be converted into a more compact data structure,
7543 * MEDCoupling1GTUMesh instance. The returned instance will aggregate the same DataArrayDouble instance of coordinates than \a this.
7545 * \return a newly allocated instance, that the caller must manage.
7546 * \throw If \a this contains more than one geometric type.
7547 * \throw If the nodal connectivity of \a this is not fully defined.
7548 * \throw If the internal data is not coherent.
7550 MEDCoupling1GTUMesh *MEDCouplingUMesh::convertIntoSingleGeoTypeMesh() const
7552 checkConnectivityFullyDefined();
7553 if(_types.size()!=1)
7554 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : current mesh does not contain exactly one geometric type !");
7555 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
7556 MCAuto<MEDCoupling1GTUMesh> ret=MEDCoupling1GTUMesh::New(getName(),typ);
7557 ret->setCoords(getCoords());
7558 MEDCoupling1SGTUMesh *retC=dynamic_cast<MEDCoupling1SGTUMesh *>((MEDCoupling1GTUMesh*)ret);
7561 MCAuto<DataArrayInt> c=convertNodalConnectivityToStaticGeoTypeMesh();
7562 retC->setNodalConnectivity(c);
7566 MEDCoupling1DGTUMesh *retD=dynamic_cast<MEDCoupling1DGTUMesh *>((MEDCoupling1GTUMesh*)ret);
7568 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : Internal error !");
7569 DataArrayInt *c=0,*ci=0;
7570 convertNodalConnectivityToDynamicGeoTypeMesh(c,ci);
7571 MCAuto<DataArrayInt> cs(c),cis(ci);
7572 retD->setNodalConnectivity(cs,cis);
7577 DataArrayInt *MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh() const
7579 checkConnectivityFullyDefined();
7580 if(_types.size()!=1)
7581 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : current mesh does not contain exactly one geometric type !");
7582 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
7583 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
7586 std::ostringstream oss; oss << "MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : this contains a single geo type (" << cm.getRepr() << ") but ";
7587 oss << "this type is dynamic ! Only static geometric type is possible for that type ! call convertNodalConnectivityToDynamicGeoTypeMesh instead !";
7588 throw INTERP_KERNEL::Exception(oss.str());
7590 int nbCells=getNumberOfCells();
7592 int nbNodesPerCell=(int)cm.getNumberOfNodes();
7593 MCAuto<DataArrayInt> connOut=DataArrayInt::New(); connOut->alloc(nbCells*nbNodesPerCell,1);
7594 int *outPtr=connOut->getPointer();
7595 const int *conn=_nodal_connec->begin();
7596 const int *connI=_nodal_connec_index->begin();
7598 for(int i=0;i<nbCells;i++,connI++)
7600 if(conn[connI[0]]==typi && connI[1]-connI[0]==nbNodesPerCell)
7601 outPtr=std::copy(conn+connI[0]+1,conn+connI[1],outPtr);
7604 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 << ") !";
7605 throw INTERP_KERNEL::Exception(oss.str());
7608 return connOut.retn();
7612 * Convert the nodal connectivity of the mesh so that all the cells are of dynamic types (polygon or quadratic
7613 * polygon). This returns the corresponding new nodal connectivity in \ref numbering-indirect format.
7617 void MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh(DataArrayInt *&nodalConn, DataArrayInt *&nodalConnIndex) const
7619 static const char msg0[]="MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : nodal connectivity in this are invalid ! Call checkConsistency !";
7620 checkConnectivityFullyDefined();
7621 if(_types.size()!=1)
7622 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : current mesh does not contain exactly one geometric type !");
7623 int nbCells=getNumberOfCells(),lgth=_nodal_connec->getNumberOfTuples();
7625 throw INTERP_KERNEL::Exception(msg0);
7626 MCAuto<DataArrayInt> c(DataArrayInt::New()),ci(DataArrayInt::New());
7627 c->alloc(lgth-nbCells,1); ci->alloc(nbCells+1,1);
7628 int *cp(c->getPointer()),*cip(ci->getPointer());
7629 const int *incp(_nodal_connec->begin()),*incip(_nodal_connec_index->begin());
7631 for(int i=0;i<nbCells;i++,cip++,incip++)
7633 int strt(incip[0]+1),stop(incip[1]);//+1 to skip geo type
7634 int delta(stop-strt);
7637 if((strt>=0 && strt<lgth) && (stop>=0 && stop<=lgth))
7638 cp=std::copy(incp+strt,incp+stop,cp);
7640 throw INTERP_KERNEL::Exception(msg0);
7643 throw INTERP_KERNEL::Exception(msg0);
7644 cip[1]=cip[0]+delta;
7646 nodalConn=c.retn(); nodalConnIndex=ci.retn();
7650 * This method takes in input a vector of MEDCouplingUMesh instances lying on the same coordinates with same mesh dimensions.
7651 * Each mesh in \b ms must be sorted by type with the same order (typically using MEDCouplingUMesh::sortCellsInMEDFileFrmt).
7652 * This method is particulary useful for MED file interaction. It allows to aggregate several meshes and keeping the type sorting
7653 * and the track of the permutation by chunk of same geotype cells to retrieve it. The traditional formats old2new and new2old
7654 * are not used here to avoid the build of big permutation array.
7656 * \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
7657 * those specified in MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
7658 * \param [out] szOfCellGrpOfSameType is a newly allocated DataArrayInt instance whose number of tuples is equal to the number of chunks of same geotype
7659 * in all meshes in \b ms. The accumulation of all values of this array is equal to the number of cells of returned mesh.
7660 * \param [out] idInMsOfCellGrpOfSameType is a newly allocated DataArrayInt instance having the same size than \b szOfCellGrpOfSameType. This
7661 * output array gives for each chunck of same type the corresponding mesh id in \b ms.
7662 * \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
7663 * is sorted by type following the geo cell types order of MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
7665 MEDCouplingUMesh *MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& ms,
7666 DataArrayInt *&szOfCellGrpOfSameType,
7667 DataArrayInt *&idInMsOfCellGrpOfSameType)
7669 std::vector<const MEDCouplingUMesh *> ms2;
7670 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms.begin();it!=ms.end();it++)
7673 (*it)->checkConnectivityFullyDefined();
7677 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : input vector is empty !");
7678 const DataArrayDouble *refCoo=ms2[0]->getCoords();
7679 int meshDim=ms2[0]->getMeshDimension();
7680 std::vector<const MEDCouplingUMesh *> m1ssm;
7681 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmAuto;
7683 std::vector<const MEDCouplingUMesh *> m1ssmSingle;
7684 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmSingleAuto;
7686 MCAuto<DataArrayInt> ret1(DataArrayInt::New()),ret2(DataArrayInt::New());
7687 ret1->alloc(0,1); ret2->alloc(0,1);
7688 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms2.begin();it!=ms2.end();it++,rk++)
7690 if(meshDim!=(*it)->getMeshDimension())
7691 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshdims mismatch !");
7692 if(refCoo!=(*it)->getCoords())
7693 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshes are not shared by a single coordinates coords !");
7694 std::vector<MEDCouplingUMesh *> sp=(*it)->splitByType();
7695 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<const MEDCouplingUMesh *> >(m1ssm));
7696 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<MCAuto<MEDCouplingUMesh> > >(m1ssmAuto));
7697 for(std::vector<MEDCouplingUMesh *>::const_iterator it2=sp.begin();it2!=sp.end();it2++)
7699 MEDCouplingUMesh *singleCell=static_cast<MEDCouplingUMesh *>((*it2)->buildPartOfMySelf(&fake,&fake+1,true));
7700 m1ssmSingleAuto.push_back(singleCell);
7701 m1ssmSingle.push_back(singleCell);
7702 ret1->pushBackSilent((*it2)->getNumberOfCells()); ret2->pushBackSilent(rk);
7705 MCAuto<MEDCouplingUMesh> m1ssmSingle2=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmSingle);
7706 MCAuto<DataArrayInt> renum=m1ssmSingle2->sortCellsInMEDFileFrmt();
7707 std::vector<const MEDCouplingUMesh *> m1ssmfinal(m1ssm.size());
7708 for(std::size_t i=0;i<m1ssm.size();i++)
7709 m1ssmfinal[renum->getIJ(i,0)]=m1ssm[i];
7710 MCAuto<MEDCouplingUMesh> ret0=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmfinal);
7711 szOfCellGrpOfSameType=ret1->renumber(renum->begin());
7712 idInMsOfCellGrpOfSameType=ret2->renumber(renum->begin());
7717 * This method returns a newly created DataArrayInt instance.
7718 * This method retrieves cell ids in [ \a begin, \a end ) that have the type \a type.
7720 DataArrayInt *MEDCouplingUMesh::keepCellIdsByType(INTERP_KERNEL::NormalizedCellType type, const int *begin, const int *end) const
7722 checkFullyDefined();
7723 const int *conn=_nodal_connec->begin();
7724 const int *connIndex=_nodal_connec_index->begin();
7725 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(0,1);
7726 for(const int *w=begin;w!=end;w++)
7727 if((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]==type)
7728 ret->pushBackSilent(*w);
7733 * This method makes the assumption that da->getNumberOfTuples()<this->getNumberOfCells(). This method makes the assumption that ids contained in 'da'
7734 * are in [0:getNumberOfCells())
7736 DataArrayInt *MEDCouplingUMesh::convertCellArrayPerGeoType(const DataArrayInt *da) const
7738 checkFullyDefined();
7739 const int *conn=_nodal_connec->begin();
7740 const int *connI=_nodal_connec_index->begin();
7741 int nbOfCells=getNumberOfCells();
7742 std::set<INTERP_KERNEL::NormalizedCellType> types(getAllGeoTypes());
7743 int *tmp=new int[nbOfCells];
7744 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
7747 for(const int *i=connI;i!=connI+nbOfCells;i++)
7748 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
7749 tmp[std::distance(connI,i)]=j++;
7751 DataArrayInt *ret=DataArrayInt::New();
7752 ret->alloc(da->getNumberOfTuples(),da->getNumberOfComponents());
7753 ret->copyStringInfoFrom(*da);
7754 int *retPtr=ret->getPointer();
7755 const int *daPtr=da->begin();
7756 int nbOfElems=da->getNbOfElems();
7757 for(int k=0;k<nbOfElems;k++)
7758 retPtr[k]=tmp[daPtr[k]];
7764 * This method reduced number of cells of this by keeping cells whose type is different from 'type' and if type=='type'
7765 * This method \b works \b for mesh sorted by type.
7766 * cells whose ids is in 'idsPerGeoType' array.
7767 * This method conserves coords and name of mesh.
7769 MEDCouplingUMesh *MEDCouplingUMesh::keepSpecifiedCells(INTERP_KERNEL::NormalizedCellType type, const int *idsPerGeoTypeBg, const int *idsPerGeoTypeEnd) const
7771 std::vector<int> code=getDistributionOfTypes();
7772 std::size_t nOfTypesInThis=code.size()/3;
7773 int sz=0,szOfType=0;
7774 for(std::size_t i=0;i<nOfTypesInThis;i++)
7779 szOfType=code[3*i+1];
7781 for(const int *work=idsPerGeoTypeBg;work!=idsPerGeoTypeEnd;work++)
7782 if(*work<0 || *work>=szOfType)
7784 std::ostringstream oss; oss << "MEDCouplingUMesh::keepSpecifiedCells : Request on type " << type << " at place #" << std::distance(idsPerGeoTypeBg,work) << " value " << *work;
7785 oss << ". It should be in [0," << szOfType << ") !";
7786 throw INTERP_KERNEL::Exception(oss.str());
7788 MCAuto<DataArrayInt> idsTokeep=DataArrayInt::New(); idsTokeep->alloc(sz+(int)std::distance(idsPerGeoTypeBg,idsPerGeoTypeEnd),1);
7789 int *idsPtr=idsTokeep->getPointer();
7791 for(std::size_t i=0;i<nOfTypesInThis;i++)
7794 for(int j=0;j<code[3*i+1];j++)
7797 idsPtr=std::transform(idsPerGeoTypeBg,idsPerGeoTypeEnd,idsPtr,std::bind2nd(std::plus<int>(),offset));
7798 offset+=code[3*i+1];
7800 MCAuto<MEDCouplingUMesh> ret=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(idsTokeep->begin(),idsTokeep->end(),true));
7801 ret->copyTinyInfoFrom(this);
7806 * This method returns a vector of size 'this->getNumberOfCells()'.
7807 * This method retrieves for each cell in \a this if it is linear (false) or quadratic(true).
7809 std::vector<bool> MEDCouplingUMesh::getQuadraticStatus() const
7811 int ncell=getNumberOfCells();
7812 std::vector<bool> ret(ncell);
7813 const int *cI=getNodalConnectivityIndex()->begin();
7814 const int *c=getNodalConnectivity()->begin();
7815 for(int i=0;i<ncell;i++)
7817 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[i]];
7818 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
7819 ret[i]=cm.isQuadratic();
7825 * Returns a newly created mesh (with ref count ==1) that contains merge of \a this and \a other.
7827 MEDCouplingMesh *MEDCouplingUMesh::mergeMyselfWith(const MEDCouplingMesh *other) const
7829 if(other->getType()!=UNSTRUCTURED)
7830 throw INTERP_KERNEL::Exception("Merge of umesh only available with umesh each other !");
7831 const MEDCouplingUMesh *otherC=static_cast<const MEDCouplingUMesh *>(other);
7832 return MergeUMeshes(this,otherC);
7836 * Returns a new DataArrayDouble holding barycenters of all cells. The barycenter is
7837 * computed by averaging coordinates of cell nodes, so this method is not a right
7838 * choice for degnerated meshes (not well oriented, cells with measure close to zero).
7839 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
7840 * this->getNumberOfCells() tuples per \a this->getSpaceDimension()
7841 * components. The caller is to delete this array using decrRef() as it is
7843 * \throw If the coordinates array is not set.
7844 * \throw If the nodal connectivity of cells is not defined.
7845 * \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
7847 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMass() const
7849 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
7850 int spaceDim=getSpaceDimension();
7851 int nbOfCells=getNumberOfCells();
7852 ret->alloc(nbOfCells,spaceDim);
7853 ret->copyStringInfoFrom(*getCoords());
7854 double *ptToFill=ret->getPointer();
7855 const int *nodal=_nodal_connec->begin();
7856 const int *nodalI=_nodal_connec_index->begin();
7857 const double *coor=_coords->begin();
7858 for(int i=0;i<nbOfCells;i++)
7860 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
7861 INTERP_KERNEL::computeBarycenter2<int,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[i]+1,nodalI[i+1]-nodalI[i]-1,coor,spaceDim,ptToFill);
7868 * This method computes for each cell in \a this, the location of the iso barycenter of nodes constituting
7869 * the cell. Contrary to badly named MEDCouplingUMesh::computeCellCenterOfMass method that returns the center of inertia of the
7871 * \return a newly allocated DataArrayDouble instance that the caller has to deal with. The returned
7872 * DataArrayDouble instance will have \c this->getNumberOfCells() tuples and \c this->getSpaceDimension() components.
7874 * \sa MEDCouplingUMesh::computeCellCenterOfMass
7875 * \throw If \a this is not fully defined (coordinates and connectivity)
7876 * \throw If there is presence in nodal connectivity in \a this of node ids not in [0, \c this->getNumberOfNodes() )
7878 DataArrayDouble *MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell() const
7880 checkFullyDefined();
7881 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
7882 int spaceDim=getSpaceDimension();
7883 int nbOfCells=getNumberOfCells();
7884 int nbOfNodes=getNumberOfNodes();
7885 ret->alloc(nbOfCells,spaceDim);
7886 double *ptToFill=ret->getPointer();
7887 const int *nodal=_nodal_connec->begin();
7888 const int *nodalI=_nodal_connec_index->begin();
7889 const double *coor=_coords->begin();
7890 for(int i=0;i<nbOfCells;i++,ptToFill+=spaceDim)
7892 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
7893 std::fill(ptToFill,ptToFill+spaceDim,0.);
7894 if(type!=INTERP_KERNEL::NORM_POLYHED)
7896 for(const int *conn=nodal+nodalI[i]+1;conn!=nodal+nodalI[i+1];conn++)
7898 if(*conn>=0 && *conn<nbOfNodes)
7899 std::transform(coor+spaceDim*conn[0],coor+spaceDim*(conn[0]+1),ptToFill,ptToFill,std::plus<double>());
7902 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of nodeId #" << *conn << " should be in [0," << nbOfNodes << ") !";
7903 throw INTERP_KERNEL::Exception(oss.str());
7906 int nbOfNodesInCell=nodalI[i+1]-nodalI[i]-1;
7907 if(nbOfNodesInCell>0)
7908 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies<double>(),1./(double)nbOfNodesInCell));
7911 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of cell with no nodes !";
7912 throw INTERP_KERNEL::Exception(oss.str());
7917 std::set<int> s(nodal+nodalI[i]+1,nodal+nodalI[i+1]);
7919 for(std::set<int>::const_iterator it=s.begin();it!=s.end();it++)
7921 if(*it>=0 && *it<nbOfNodes)
7922 std::transform(coor+spaceDim*(*it),coor+spaceDim*((*it)+1),ptToFill,ptToFill,std::plus<double>());
7925 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell polyhedron cell #" << i << " presence of nodeId #" << *it << " should be in [0," << nbOfNodes << ") !";
7926 throw INTERP_KERNEL::Exception(oss.str());
7930 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies<double>(),1./(double)s.size()));
7933 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on polyhedron cell #" << i << " there are no nodes !";
7934 throw INTERP_KERNEL::Exception(oss.str());
7942 * Returns a new DataArrayDouble holding barycenters of specified cells. The
7943 * barycenter is computed by averaging coordinates of cell nodes. The cells to treat
7944 * are specified via an array of cell ids.
7945 * \warning Validity of the specified cell ids is not checked!
7946 * Valid range is [ 0, \a this->getNumberOfCells() ).
7947 * \param [in] begin - an array of cell ids of interest.
7948 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
7949 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size ( \a
7950 * end - \a begin ) tuples per \a this->getSpaceDimension() components. The
7951 * caller is to delete this array using decrRef() as it is no more needed.
7952 * \throw If the coordinates array is not set.
7953 * \throw If the nodal connectivity of cells is not defined.
7955 * \if ENABLE_EXAMPLES
7956 * \ref cpp_mcumesh_getPartBarycenterAndOwner "Here is a C++ example".<br>
7957 * \ref py_mcumesh_getPartBarycenterAndOwner "Here is a Python example".
7960 DataArrayDouble *MEDCouplingUMesh::getPartBarycenterAndOwner(const int *begin, const int *end) const
7962 DataArrayDouble *ret=DataArrayDouble::New();
7963 int spaceDim=getSpaceDimension();
7964 int nbOfTuple=(int)std::distance(begin,end);
7965 ret->alloc(nbOfTuple,spaceDim);
7966 double *ptToFill=ret->getPointer();
7967 double *tmp=new double[spaceDim];
7968 const int *nodal=_nodal_connec->begin();
7969 const int *nodalI=_nodal_connec_index->begin();
7970 const double *coor=_coords->begin();
7971 for(const int *w=begin;w!=end;w++)
7973 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[*w]];
7974 INTERP_KERNEL::computeBarycenter2<int,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[*w]+1,nodalI[*w+1]-nodalI[*w]-1,coor,spaceDim,ptToFill);
7982 * 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".
7983 * So the returned instance will have 4 components and \c this->getNumberOfCells() tuples.
7984 * So this method expects that \a this has a spaceDimension equal to 3 and meshDimension equal to 2.
7985 * The computation of the plane equation is done using each time the 3 first nodes of 2D cells.
7986 * This method is useful to detect 2D cells in 3D space that are not coplanar.
7988 * \return DataArrayDouble * - a new instance of DataArrayDouble having 4 components and a number of tuples equal to number of cells in \a this.
7989 * \throw If spaceDim!=3 or meshDim!=2.
7990 * \throw If connectivity of \a this is invalid.
7991 * \throw If connectivity of a cell in \a this points to an invalid node.
7993 DataArrayDouble *MEDCouplingUMesh::computePlaneEquationOf3DFaces() const
7995 MCAuto<DataArrayDouble> ret(DataArrayDouble::New());
7996 int nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
7997 if(getSpaceDimension()!=3 || getMeshDimension()!=2)
7998 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computePlaneEquationOf3DFaces : This method must be applied on a mesh having meshDimension equal 2 and a spaceDimension equal to 3 !");
7999 ret->alloc(nbOfCells,4);
8000 double *retPtr(ret->getPointer());
8001 const int *nodal(_nodal_connec->begin()),*nodalI(_nodal_connec_index->begin());
8002 const double *coor(_coords->begin());
8003 for(int i=0;i<nbOfCells;i++,nodalI++,retPtr+=4)
8005 double matrix[16]={0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,0},matrix2[16];
8006 if(nodalI[1]-nodalI[0]>=3)
8008 for(int j=0;j<3;j++)
8010 int nodeId(nodal[nodalI[0]+1+j]);
8011 if(nodeId>=0 && nodeId<nbOfNodes)
8012 std::copy(coor+nodeId*3,coor+(nodeId+1)*3,matrix+4*j);
8015 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! This cell points to an invalid nodeId : " << nodeId << " !";
8016 throw INTERP_KERNEL::Exception(oss.str());
8022 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! Must be constitued by more than 3 nodes !";
8023 throw INTERP_KERNEL::Exception(oss.str());
8025 INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
8026 retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
8032 * This method expects as input a DataArrayDouble non nul instance 'da' that should be allocated. If not an exception is thrown.
8035 MEDCouplingUMesh *MEDCouplingUMesh::Build0DMeshFromCoords(DataArrayDouble *da)
8038 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build0DMeshFromCoords : instance of DataArrayDouble must be not null !");
8039 da->checkAllocated();
8040 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(da->getName(),0);
8042 int nbOfTuples=da->getNumberOfTuples();
8043 MCAuto<DataArrayInt> c=DataArrayInt::New();
8044 MCAuto<DataArrayInt> cI=DataArrayInt::New();
8045 c->alloc(2*nbOfTuples,1);
8046 cI->alloc(nbOfTuples+1,1);
8047 int *cp=c->getPointer();
8048 int *cip=cI->getPointer();
8050 for(int i=0;i<nbOfTuples;i++)
8052 *cp++=INTERP_KERNEL::NORM_POINT1;
8056 ret->setConnectivity(c,cI,true);
8060 * Creates a new MEDCouplingUMesh by concatenating two given meshes of the same dimension.
8061 * Cells and nodes of
8062 * the first mesh precede cells and nodes of the second mesh within the result mesh.
8063 * \param [in] mesh1 - the first mesh.
8064 * \param [in] mesh2 - the second mesh.
8065 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
8066 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
8067 * is no more needed.
8068 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
8069 * \throw If the coordinates array is not set in none of the meshes.
8070 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
8071 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
8073 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
8075 std::vector<const MEDCouplingUMesh *> tmp(2);
8076 tmp[0]=const_cast<MEDCouplingUMesh *>(mesh1); tmp[1]=const_cast<MEDCouplingUMesh *>(mesh2);
8077 return MergeUMeshes(tmp);
8081 * Creates a new MEDCouplingUMesh by concatenating all given meshes of the same dimension.
8082 * Cells and nodes of
8083 * the *i*-th mesh precede cells and nodes of the (*i*+1)-th mesh within the result mesh.
8084 * \param [in] a - a vector of meshes (MEDCouplingUMesh) to concatenate.
8085 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
8086 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
8087 * is no more needed.
8088 * \throw If \a a.size() == 0.
8089 * \throw If \a a[ *i* ] == NULL.
8090 * \throw If the coordinates array is not set in none of the meshes.
8091 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
8092 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
8094 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const std::vector<const MEDCouplingUMesh *>& a)
8096 std::size_t sz=a.size();
8098 return MergeUMeshesLL(a);
8099 for(std::size_t ii=0;ii<sz;ii++)
8102 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshes : item #" << ii << " in input array of size "<< sz << " is empty !";
8103 throw INTERP_KERNEL::Exception(oss.str());
8105 std::vector< MCAuto<MEDCouplingUMesh> > bb(sz);
8106 std::vector< const MEDCouplingUMesh * > aa(sz);
8108 for(std::size_t i=0;i<sz && spaceDim==-3;i++)
8110 const MEDCouplingUMesh *cur=a[i];
8111 const DataArrayDouble *coo=cur->getCoords();
8113 spaceDim=coo->getNumberOfComponents();
8116 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : no spaceDim specified ! unable to perform merge !");
8117 for(std::size_t i=0;i<sz;i++)
8119 bb[i]=a[i]->buildSetInstanceFromThis(spaceDim);
8122 return MergeUMeshesLL(aa);
8127 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesLL(const std::vector<const MEDCouplingUMesh *>& a)
8130 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : input array must be NON EMPTY !");
8131 std::vector<const MEDCouplingUMesh *>::const_iterator it=a.begin();
8132 int meshDim=(*it)->getMeshDimension();
8133 int nbOfCells=(*it)->getNumberOfCells();
8134 int meshLgth=(*it++)->getNodalConnectivityArrayLen();
8135 for(;it!=a.end();it++)
8137 if(meshDim!=(*it)->getMeshDimension())
8138 throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, MergeUMeshes impossible !");
8139 nbOfCells+=(*it)->getNumberOfCells();
8140 meshLgth+=(*it)->getNodalConnectivityArrayLen();
8142 std::vector<const MEDCouplingPointSet *> aps(a.size());
8143 std::copy(a.begin(),a.end(),aps.begin());
8144 MCAuto<DataArrayDouble> pts=MergeNodesArray(aps);
8145 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("merge",meshDim);
8146 ret->setCoords(pts);
8147 MCAuto<DataArrayInt> c=DataArrayInt::New();
8148 c->alloc(meshLgth,1);
8149 int *cPtr=c->getPointer();
8150 MCAuto<DataArrayInt> cI=DataArrayInt::New();
8151 cI->alloc(nbOfCells+1,1);
8152 int *cIPtr=cI->getPointer();
8156 for(it=a.begin();it!=a.end();it++)
8158 int curNbOfCell=(*it)->getNumberOfCells();
8159 const int *curCI=(*it)->_nodal_connec_index->begin();
8160 const int *curC=(*it)->_nodal_connec->begin();
8161 cIPtr=std::transform(curCI+1,curCI+curNbOfCell+1,cIPtr,std::bind2nd(std::plus<int>(),offset));
8162 for(int j=0;j<curNbOfCell;j++)
8164 const int *src=curC+curCI[j];
8166 for(;src!=curC+curCI[j+1];src++,cPtr++)
8174 offset+=curCI[curNbOfCell];
8175 offset2+=(*it)->getNumberOfNodes();
8178 ret->setConnectivity(c,cI,true);
8185 * Creates a new MEDCouplingUMesh by concatenating cells of two given meshes of same
8186 * dimension and sharing the node coordinates array.
8187 * All cells of the first mesh precede all cells of the second mesh
8188 * within the result mesh.
8189 * \param [in] mesh1 - the first mesh.
8190 * \param [in] mesh2 - the second mesh.
8191 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
8192 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
8193 * is no more needed.
8194 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
8195 * \throw If the meshes do not share the node coordinates array.
8196 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
8197 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
8199 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
8201 std::vector<const MEDCouplingUMesh *> tmp(2);
8202 tmp[0]=mesh1; tmp[1]=mesh2;
8203 return MergeUMeshesOnSameCoords(tmp);
8207 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
8208 * dimension and sharing the node coordinates array.
8209 * All cells of the *i*-th mesh precede all cells of the
8210 * (*i*+1)-th mesh within the result mesh.
8211 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
8212 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
8213 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
8214 * is no more needed.
8215 * \throw If \a a.size() == 0.
8216 * \throw If \a a[ *i* ] == NULL.
8217 * \throw If the meshes do not share the node coordinates array.
8218 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
8219 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
8221 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes)
8224 throw INTERP_KERNEL::Exception("meshes input parameter is expected to be non empty.");
8225 for(std::size_t ii=0;ii<meshes.size();ii++)
8228 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshesOnSameCoords : item #" << ii << " in input array of size "<< meshes.size() << " is empty !";
8229 throw INTERP_KERNEL::Exception(oss.str());
8231 const DataArrayDouble *coords=meshes.front()->getCoords();
8232 int meshDim=meshes.front()->getMeshDimension();
8233 std::vector<const MEDCouplingUMesh *>::const_iterator iter=meshes.begin();
8235 int meshIndexLgth=0;
8236 for(;iter!=meshes.end();iter++)
8238 if(coords!=(*iter)->getCoords())
8239 throw INTERP_KERNEL::Exception("meshes does not share the same coords ! Try using tryToShareSameCoords method !");
8240 if(meshDim!=(*iter)->getMeshDimension())
8241 throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, FuseUMeshesOnSameCoords impossible !");
8242 meshLgth+=(*iter)->getNodalConnectivityArrayLen();
8243 meshIndexLgth+=(*iter)->getNumberOfCells();
8245 MCAuto<DataArrayInt> nodal=DataArrayInt::New();
8246 nodal->alloc(meshLgth,1);
8247 int *nodalPtr=nodal->getPointer();
8248 MCAuto<DataArrayInt> nodalIndex=DataArrayInt::New();
8249 nodalIndex->alloc(meshIndexLgth+1,1);
8250 int *nodalIndexPtr=nodalIndex->getPointer();
8252 for(iter=meshes.begin();iter!=meshes.end();iter++)
8254 const int *nod=(*iter)->getNodalConnectivity()->begin();
8255 const int *index=(*iter)->getNodalConnectivityIndex()->begin();
8256 int nbOfCells=(*iter)->getNumberOfCells();
8257 int meshLgth2=(*iter)->getNodalConnectivityArrayLen();
8258 nodalPtr=std::copy(nod,nod+meshLgth2,nodalPtr);
8259 if(iter!=meshes.begin())
8260 nodalIndexPtr=std::transform(index+1,index+nbOfCells+1,nodalIndexPtr,std::bind2nd(std::plus<int>(),offset));
8262 nodalIndexPtr=std::copy(index,index+nbOfCells+1,nodalIndexPtr);
8265 MEDCouplingUMesh *ret=MEDCouplingUMesh::New();
8266 ret->setName("merge");
8267 ret->setMeshDimension(meshDim);
8268 ret->setConnectivity(nodal,nodalIndex,true);
8269 ret->setCoords(coords);
8274 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
8275 * dimension and sharing the node coordinates array. Cells of the *i*-th mesh precede
8276 * cells of the (*i*+1)-th mesh within the result mesh. Duplicates of cells are
8277 * removed from \a this mesh and arrays mapping between new and old cell ids in "Old to
8278 * New" mode are returned for each input mesh.
8279 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
8280 * \param [in] compType - specifies a cell comparison technique. For meaning of its
8281 * valid values [0,1,2], see zipConnectivityTraducer().
8282 * \param [in,out] corr - an array of DataArrayInt, of the same size as \a
8283 * meshes. The *i*-th array describes cell ids mapping for \a meshes[ *i* ]
8284 * mesh. The caller is to delete each of the arrays using decrRef() as it is
8286 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
8287 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
8288 * is no more needed.
8289 * \throw If \a meshes.size() == 0.
8290 * \throw If \a meshes[ *i* ] == NULL.
8291 * \throw If the meshes do not share the node coordinates array.
8292 * \throw If \a meshes[ *i* ]->getMeshDimension() < 0.
8293 * \throw If the \a meshes are of different dimension (getMeshDimension()).
8294 * \throw If the nodal connectivity of cells of any of \a meshes is not defined.
8295 * \throw If the nodal connectivity any of \a meshes includes an invalid id.
8297 MEDCouplingUMesh *MEDCouplingUMesh::FuseUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes, int compType, std::vector<DataArrayInt *>& corr)
8299 //All checks are delegated to MergeUMeshesOnSameCoords
8300 MCAuto<MEDCouplingUMesh> ret=MergeUMeshesOnSameCoords(meshes);
8301 MCAuto<DataArrayInt> o2n=ret->zipConnectivityTraducer(compType);
8302 corr.resize(meshes.size());
8303 std::size_t nbOfMeshes=meshes.size();
8305 const int *o2nPtr=o2n->begin();
8306 for(std::size_t i=0;i<nbOfMeshes;i++)
8308 DataArrayInt *tmp=DataArrayInt::New();
8309 int curNbOfCells=meshes[i]->getNumberOfCells();
8310 tmp->alloc(curNbOfCells,1);
8311 std::copy(o2nPtr+offset,o2nPtr+offset+curNbOfCells,tmp->getPointer());
8312 offset+=curNbOfCells;
8313 tmp->setName(meshes[i]->getName());
8320 * Makes all given meshes share the nodal connectivity array. The common connectivity
8321 * array is created by concatenating the connectivity arrays of all given meshes. All
8322 * the given meshes must be of the same space dimension but dimension of cells **can
8323 * differ**. This method is particulary useful in MEDLoader context to build a \ref
8324 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
8325 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
8326 * \param [in,out] meshes - a vector of meshes to update.
8327 * \throw If any of \a meshes is NULL.
8328 * \throw If the coordinates array is not set in any of \a meshes.
8329 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
8330 * \throw If \a meshes are of different space dimension.
8332 void MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords(const std::vector<MEDCouplingUMesh *>& meshes)
8334 std::size_t sz=meshes.size();
8337 std::vector< const DataArrayDouble * > coords(meshes.size());
8338 std::vector< const DataArrayDouble * >::iterator it2=coords.begin();
8339 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++,it2++)
8343 (*it)->checkConnectivityFullyDefined();
8344 const DataArrayDouble *coo=(*it)->getCoords();
8349 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
8350 oss << " has no coordinate array defined !";
8351 throw INTERP_KERNEL::Exception(oss.str());
8356 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
8357 oss << " is null !";
8358 throw INTERP_KERNEL::Exception(oss.str());
8361 MCAuto<DataArrayDouble> res=DataArrayDouble::Aggregate(coords);
8362 std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();
8363 int offset=(*it)->getNumberOfNodes();
8364 (*it++)->setCoords(res);
8365 for(;it!=meshes.end();it++)
8367 int oldNumberOfNodes=(*it)->getNumberOfNodes();
8368 (*it)->setCoords(res);
8369 (*it)->shiftNodeNumbersInConn(offset);
8370 offset+=oldNumberOfNodes;
8375 * Merges nodes coincident with a given precision within all given meshes that share
8376 * the nodal connectivity array. The given meshes **can be of different** mesh
8377 * dimension. This method is particulary useful in MEDLoader context to build a \ref
8378 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
8379 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
8380 * \param [in,out] meshes - a vector of meshes to update.
8381 * \param [in] eps - the precision used to detect coincident nodes (infinite norm).
8382 * \throw If any of \a meshes is NULL.
8383 * \throw If the \a meshes do not share the same node coordinates array.
8384 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
8386 void MEDCouplingUMesh::MergeNodesOnUMeshesSharingSameCoords(const std::vector<MEDCouplingUMesh *>& meshes, double eps)
8390 std::set<const DataArrayDouble *> s;
8391 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
8394 s.insert((*it)->getCoords());
8397 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 !";
8398 throw INTERP_KERNEL::Exception(oss.str());
8403 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 !";
8404 throw INTERP_KERNEL::Exception(oss.str());
8406 const DataArrayDouble *coo=*(s.begin());
8410 DataArrayInt *comm,*commI;
8411 coo->findCommonTuples(eps,-1,comm,commI);
8412 MCAuto<DataArrayInt> tmp1(comm),tmp2(commI);
8413 int oldNbOfNodes=coo->getNumberOfTuples();
8415 MCAuto<DataArrayInt> o2n=DataArrayInt::ConvertIndexArrayToO2N(oldNbOfNodes,comm->begin(),commI->begin(),commI->end(),newNbOfNodes);
8416 if(oldNbOfNodes==newNbOfNodes)
8418 MCAuto<DataArrayDouble> newCoords=coo->renumberAndReduce(o2n->begin(),newNbOfNodes);
8419 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
8421 (*it)->renumberNodesInConn(o2n->begin());
8422 (*it)->setCoords(newCoords);
8427 * 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.
8428 * \param nbOfNodesPerLev in parameter that specifies the number of nodes of one slice of global dataset
8429 * \param isQuad specifies the policy of connectivity.
8430 * @ret in/out parameter in which the result will be append
8432 void MEDCouplingUMesh::AppendExtrudedCell(const int *connBg, const int *connEnd, int nbOfNodesPerLev, bool isQuad, std::vector<int>& ret)
8434 INTERP_KERNEL::NormalizedCellType flatType=(INTERP_KERNEL::NormalizedCellType)connBg[0];
8435 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(flatType);
8436 ret.push_back(cm.getExtrudedType());
8437 int deltaz=isQuad?2*nbOfNodesPerLev:nbOfNodesPerLev;
8440 case INTERP_KERNEL::NORM_POINT1:
8442 ret.push_back(connBg[1]);
8443 ret.push_back(connBg[1]+nbOfNodesPerLev);
8446 case INTERP_KERNEL::NORM_SEG2:
8448 int conn[4]={connBg[1],connBg[2],connBg[2]+deltaz,connBg[1]+deltaz};
8449 ret.insert(ret.end(),conn,conn+4);
8452 case INTERP_KERNEL::NORM_SEG3:
8454 int conn[8]={connBg[1],connBg[3],connBg[3]+deltaz,connBg[1]+deltaz,connBg[2],connBg[3]+nbOfNodesPerLev,connBg[2]+deltaz,connBg[1]+nbOfNodesPerLev};
8455 ret.insert(ret.end(),conn,conn+8);
8458 case INTERP_KERNEL::NORM_QUAD4:
8460 int conn[8]={connBg[1],connBg[2],connBg[3],connBg[4],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz,connBg[4]+deltaz};
8461 ret.insert(ret.end(),conn,conn+8);
8464 case INTERP_KERNEL::NORM_TRI3:
8466 int conn[6]={connBg[1],connBg[2],connBg[3],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz};
8467 ret.insert(ret.end(),conn,conn+6);
8470 case INTERP_KERNEL::NORM_TRI6:
8472 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,
8473 connBg[1]+nbOfNodesPerLev,connBg[2]+nbOfNodesPerLev,connBg[3]+nbOfNodesPerLev};
8474 ret.insert(ret.end(),conn,conn+15);
8477 case INTERP_KERNEL::NORM_QUAD8:
8480 connBg[1],connBg[2],connBg[3],connBg[4],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz,connBg[4]+deltaz,
8481 connBg[5],connBg[6],connBg[7],connBg[8],connBg[5]+deltaz,connBg[6]+deltaz,connBg[7]+deltaz,connBg[8]+deltaz,
8482 connBg[1]+nbOfNodesPerLev,connBg[2]+nbOfNodesPerLev,connBg[3]+nbOfNodesPerLev,connBg[4]+nbOfNodesPerLev
8484 ret.insert(ret.end(),conn,conn+20);
8487 case INTERP_KERNEL::NORM_POLYGON:
8489 std::back_insert_iterator< std::vector<int> > ii(ret);
8490 std::copy(connBg+1,connEnd,ii);
8492 std::reverse_iterator<const int *> rConnBg(connEnd);
8493 std::reverse_iterator<const int *> rConnEnd(connBg+1);
8494 std::transform(rConnBg,rConnEnd,ii,std::bind2nd(std::plus<int>(),deltaz));
8495 std::size_t nbOfRadFaces=std::distance(connBg+1,connEnd);
8496 for(std::size_t i=0;i<nbOfRadFaces;i++)
8499 int conn[4]={connBg[(i+1)%nbOfRadFaces+1],connBg[i+1],connBg[i+1]+deltaz,connBg[(i+1)%nbOfRadFaces+1]+deltaz};
8500 std::copy(conn,conn+4,ii);
8505 throw INTERP_KERNEL::Exception("A flat type has been detected that has not its extruded representation !");
8510 * This static operates only for coords in 3D. The polygon is specfied by its connectivity nodes in [ \a begin , \a end ).
8512 bool MEDCouplingUMesh::IsPolygonWellOriented(bool isQuadratic, const double *vec, const int *begin, const int *end, const double *coords)
8515 double v[3]={0.,0.,0.};
8516 std::size_t sz=std::distance(begin,end);
8521 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];
8522 v[1]+=coords[3*begin[i]+2]*coords[3*begin[(i+1)%sz]]-coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+2];
8523 v[2]+=coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+1]-coords[3*begin[i]+1]*coords[3*begin[(i+1)%sz]];
8525 double ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
8527 // Try using quadratic points if standard points are degenerated (for example a QPOLYG with two
8528 // SEG3 forming a circle):
8529 if (fabs(ret) < INTERP_KERNEL::DEFAULT_ABS_TOL && isQuadratic)
8531 v[0] = 0.0; v[1] = 0.0; v[2] = 0.0;
8532 for(std::size_t j=0;j<sz;j++)
8534 if (j%2) // current point i is quadratic, next point i+1 is standard
8537 ip1 = (j+1)%sz; // ip1 = "i+1"
8539 else // current point i is standard, next point i+1 is quadratic
8544 v[0]+=coords[3*begin[i]+1]*coords[3*begin[ip1]+2]-coords[3*begin[i]+2]*coords[3*begin[ip1]+1];
8545 v[1]+=coords[3*begin[i]+2]*coords[3*begin[ip1]]-coords[3*begin[i]]*coords[3*begin[ip1]+2];
8546 v[2]+=coords[3*begin[i]]*coords[3*begin[ip1]+1]-coords[3*begin[i]+1]*coords[3*begin[ip1]];
8548 ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
8554 * The polyhedron is specfied by its connectivity nodes in [ \a begin , \a end ).
8556 bool MEDCouplingUMesh::IsPolyhedronWellOriented(const int *begin, const int *end, const double *coords)
8558 std::vector<std::pair<int,int> > edges;
8559 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
8560 const int *bgFace=begin;
8561 for(std::size_t i=0;i<nbOfFaces;i++)
8563 const int *endFace=std::find(bgFace+1,end,-1);
8564 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
8565 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
8567 std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
8568 if(std::find(edges.begin(),edges.end(),p1)!=edges.end())
8570 edges.push_back(p1);
8574 return INTERP_KERNEL::calculateVolumeForPolyh2<int,INTERP_KERNEL::ALL_C_MODE>(begin,(int)std::distance(begin,end),coords)>-EPS_FOR_POLYH_ORIENTATION;
8578 * The 3D extruded static cell (PENTA6,HEXA8,HEXAGP12...) its connectivity nodes in [ \a begin , \a end ).
8580 bool MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented(const int *begin, const int *end, const double *coords)
8582 double vec0[3],vec1[3];
8583 std::size_t sz=std::distance(begin,end);
8585 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented : the length of nodal connectivity of extruded cell is not even !");
8586 int nbOfNodes=(int)sz/2;
8587 INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(begin,nbOfNodes,coords,vec0);
8588 const double *pt0=coords+3*begin[0];
8589 const double *pt1=coords+3*begin[nbOfNodes];
8590 vec1[0]=pt1[0]-pt0[0]; vec1[1]=pt1[1]-pt0[1]; vec1[2]=pt1[2]-pt0[2];
8591 return (vec0[0]*vec1[0]+vec0[1]*vec1[1]+vec0[2]*vec1[2])<0.;
8594 void MEDCouplingUMesh::CorrectExtrudedStaticCell(int *begin, int *end)
8596 std::size_t sz=std::distance(begin,end);
8597 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz];
8598 std::size_t nbOfNodes(sz/2);
8599 std::copy(begin,end,(int *)tmp);
8600 for(std::size_t j=1;j<nbOfNodes;j++)
8602 begin[j]=tmp[nbOfNodes-j];
8603 begin[j+nbOfNodes]=tmp[nbOfNodes+nbOfNodes-j];
8607 bool MEDCouplingUMesh::IsTetra4WellOriented(const int *begin, const int *end, const double *coords)
8609 std::size_t sz=std::distance(begin,end);
8611 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsTetra4WellOriented : Tetra4 cell with not 4 nodes ! Call checkConsistency !");
8612 double vec0[3],vec1[3];
8613 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[1],*pt2=coords+3*begin[2],*pt3=coords+3*begin[3];
8614 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];
8615 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;
8618 bool MEDCouplingUMesh::IsPyra5WellOriented(const int *begin, const int *end, const double *coords)
8620 std::size_t sz=std::distance(begin,end);
8622 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsPyra5WellOriented : Pyra5 cell with not 5 nodes ! Call checkConsistency !");
8624 INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(begin,4,coords,vec0);
8625 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[4];
8626 return (vec0[0]*(pt1[0]-pt0[0])+vec0[1]*(pt1[1]-pt0[1])+vec0[2]*(pt1[2]-pt0[2]))<0.;
8630 * 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 )
8631 * 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
8634 * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not.
8635 * \param [in] coords the coordinates with nb of components exactly equal to 3
8636 * \param [in] begin begin of the nodal connectivity (geometric type included) of a single polyhedron cell
8637 * \param [in] end end of nodal connectivity of a single polyhedron cell (excluded)
8638 * \param [out] res the result is put at the end of the vector without any alteration of the data.
8640 void MEDCouplingUMesh::SimplifyPolyhedronCell(double eps, const DataArrayDouble *coords, const int *begin, const int *end, DataArrayInt *res)
8642 int nbFaces=std::count(begin+1,end,-1)+1;
8643 MCAuto<DataArrayDouble> v=DataArrayDouble::New(); v->alloc(nbFaces,3);
8644 double *vPtr=v->getPointer();
8645 MCAuto<DataArrayDouble> p=DataArrayDouble::New(); p->alloc(nbFaces,1);
8646 double *pPtr=p->getPointer();
8647 const int *stFaceConn=begin+1;
8648 for(int i=0;i<nbFaces;i++,vPtr+=3,pPtr++)
8650 const int *endFaceConn=std::find(stFaceConn,end,-1);
8651 ComputeVecAndPtOfFace(eps,coords->begin(),stFaceConn,endFaceConn,vPtr,pPtr);
8652 stFaceConn=endFaceConn+1;
8654 pPtr=p->getPointer(); vPtr=v->getPointer();
8655 DataArrayInt *comm1=0,*commI1=0;
8656 v->findCommonTuples(eps,-1,comm1,commI1);
8657 MCAuto<DataArrayInt> comm1Auto(comm1),commI1Auto(commI1);
8658 const int *comm1Ptr=comm1->begin();
8659 const int *commI1Ptr=commI1->begin();
8660 int nbOfGrps1=commI1Auto->getNumberOfTuples()-1;
8661 res->pushBackSilent((int)INTERP_KERNEL::NORM_POLYHED);
8663 MCAuto<MEDCouplingUMesh> mm=MEDCouplingUMesh::New("",3);
8664 mm->setCoords(const_cast<DataArrayDouble *>(coords)); mm->allocateCells(1); mm->insertNextCell(INTERP_KERNEL::NORM_POLYHED,(int)std::distance(begin+1,end),begin+1);
8665 mm->finishInsertingCells();
8667 for(int i=0;i<nbOfGrps1;i++)
8669 int vecId=comm1Ptr[commI1Ptr[i]];
8670 MCAuto<DataArrayDouble> tmpgrp2=p->selectByTupleId(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
8671 DataArrayInt *comm2=0,*commI2=0;
8672 tmpgrp2->findCommonTuples(eps,-1,comm2,commI2);
8673 MCAuto<DataArrayInt> comm2Auto(comm2),commI2Auto(commI2);
8674 const int *comm2Ptr=comm2->begin();
8675 const int *commI2Ptr=commI2->begin();
8676 int nbOfGrps2=commI2Auto->getNumberOfTuples()-1;
8677 for(int j=0;j<nbOfGrps2;j++)
8679 if(commI2Ptr[j+1]-commI2Ptr[j]<=1)
8681 res->insertAtTheEnd(begin,end);
8682 res->pushBackSilent(-1);
8686 int pointId=comm1Ptr[commI1Ptr[i]+comm2Ptr[commI2Ptr[j]]];
8687 MCAuto<DataArrayInt> ids2=comm2->selectByTupleIdSafeSlice(commI2Ptr[j],commI2Ptr[j+1],1);
8688 ids2->transformWithIndArr(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
8689 DataArrayInt *tmp0=DataArrayInt::New(),*tmp1=DataArrayInt::New(),*tmp2=DataArrayInt::New(),*tmp3=DataArrayInt::New();
8690 MCAuto<MEDCouplingUMesh> mm2=mm->buildDescendingConnectivity(tmp0,tmp1,tmp2,tmp3); tmp0->decrRef(); tmp1->decrRef(); tmp2->decrRef(); tmp3->decrRef();
8691 MCAuto<MEDCouplingUMesh> mm3=static_cast<MEDCouplingUMesh *>(mm2->buildPartOfMySelf(ids2->begin(),ids2->end(),true));
8692 MCAuto<DataArrayInt> idsNodeTmp=mm3->zipCoordsTraducer();
8693 MCAuto<DataArrayInt> idsNode=idsNodeTmp->invertArrayO2N2N2O(mm3->getNumberOfNodes());
8694 const int *idsNodePtr=idsNode->begin();
8695 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];
8696 double vec[3]; vec[0]=vPtr[3*vecId+1]; vec[1]=-vPtr[3*vecId]; vec[2]=0.;
8697 double norm=vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2];
8698 if(std::abs(norm)>eps)
8700 double angle=INTERP_KERNEL::EdgeArcCircle::SafeAsin(norm);
8701 mm3->rotate(center,vec,angle);
8703 mm3->changeSpaceDimension(2);
8704 MCAuto<MEDCouplingUMesh> mm4=mm3->buildSpreadZonesWithPoly();
8705 const int *conn4=mm4->getNodalConnectivity()->begin();
8706 const int *connI4=mm4->getNodalConnectivityIndex()->begin();
8707 int nbOfCells=mm4->getNumberOfCells();
8708 for(int k=0;k<nbOfCells;k++)
8711 for(const int *work=conn4+connI4[k]+1;work!=conn4+connI4[k+1];work++,l++)
8712 res->pushBackSilent(idsNodePtr[*work]);
8713 res->pushBackSilent(-1);
8718 res->popBackSilent();
8722 * 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
8723 * through origin. The plane is defined by its nodal connectivity [ \b begin, \b end ).
8725 * \param [in] eps below that value the dot product of 2 vectors is considered as colinears
8726 * \param [in] coords coordinates expected to have 3 components.
8727 * \param [in] begin start of the nodal connectivity of the face.
8728 * \param [in] end end of the nodal connectivity (excluded) of the face.
8729 * \param [out] v the normalized vector of size 3
8730 * \param [out] p the pos of plane
8732 void MEDCouplingUMesh::ComputeVecAndPtOfFace(double eps, const double *coords, const int *begin, const int *end, double *v, double *p)
8734 std::size_t nbPoints=std::distance(begin,end);
8736 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeVecAndPtOfFace : < of 3 points in face ! not able to find a plane on that face !");
8737 double vec[3]={0.,0.,0.};
8739 bool refFound=false;
8740 for(;j<nbPoints-1 && !refFound;j++)
8742 vec[0]=coords[3*begin[j+1]]-coords[3*begin[j]];
8743 vec[1]=coords[3*begin[j+1]+1]-coords[3*begin[j]+1];
8744 vec[2]=coords[3*begin[j+1]+2]-coords[3*begin[j]+2];
8745 double norm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
8749 vec[0]/=norm; vec[1]/=norm; vec[2]/=norm;
8752 for(std::size_t i=j;i<nbPoints-1;i++)
8755 curVec[0]=coords[3*begin[i+1]]-coords[3*begin[i]];
8756 curVec[1]=coords[3*begin[i+1]+1]-coords[3*begin[i]+1];
8757 curVec[2]=coords[3*begin[i+1]+2]-coords[3*begin[i]+2];
8758 double norm=sqrt(curVec[0]*curVec[0]+curVec[1]*curVec[1]+curVec[2]*curVec[2]);
8761 curVec[0]/=norm; curVec[1]/=norm; curVec[2]/=norm;
8762 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];
8763 norm=sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
8766 v[0]/=norm; v[1]/=norm; v[2]/=norm;
8767 *p=v[0]*coords[3*begin[i]]+v[1]*coords[3*begin[i]+1]+v[2]*coords[3*begin[i]+2];
8771 throw INTERP_KERNEL::Exception("Not able to find a normal vector of that 3D face !");
8775 * This method tries to obtain a well oriented polyhedron.
8776 * If the algorithm fails, an exception will be thrown.
8778 void MEDCouplingUMesh::TryToCorrectPolyhedronOrientation(int *begin, int *end, const double *coords)
8780 std::list< std::pair<int,int> > edgesOK,edgesFinished;
8781 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
8782 std::vector<bool> isPerm(nbOfFaces,false);//field on faces False: I don't know, True : oriented
8784 int *bgFace=begin,*endFace=std::find(begin+1,end,-1);
8785 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
8786 for(std::size_t l=0;l<nbOfEdgesInFace;l++) { std::pair<int,int> p1(bgFace[l],bgFace[(l+1)%nbOfEdgesInFace]); edgesOK.push_back(p1); }
8788 while(std::find(isPerm.begin(),isPerm.end(),false)!=isPerm.end())
8791 std::size_t smthChanged=0;
8792 for(std::size_t i=0;i<nbOfFaces;i++)
8794 endFace=std::find(bgFace+1,end,-1);
8795 nbOfEdgesInFace=std::distance(bgFace,endFace);
8799 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
8801 std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
8802 std::pair<int,int> p2(p1.second,p1.first);
8803 bool b1=std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end();
8804 bool b2=std::find(edgesOK.begin(),edgesOK.end(),p2)!=edgesOK.end();
8805 if(b1 || b2) { b=b2; isPerm[i]=true; smthChanged++; break; }
8810 std::reverse(bgFace+1,endFace);
8811 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
8813 std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
8814 std::pair<int,int> p2(p1.second,p1.first);
8815 if(std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end())
8816 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
8817 if(std::find(edgesFinished.begin(),edgesFinished.end(),p1)!=edgesFinished.end() || std::find(edgesFinished.begin(),edgesFinished.end(),p2)!=edgesFinished.end())
8818 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
8819 std::list< std::pair<int,int> >::iterator it=std::find(edgesOK.begin(),edgesOK.end(),p2);
8820 if(it!=edgesOK.end())
8823 edgesFinished.push_back(p1);
8826 edgesOK.push_back(p1);
8833 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired !"); }
8835 if(!edgesOK.empty())
8836 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired : Some edges are shared only once !"); }
8837 if(INTERP_KERNEL::calculateVolumeForPolyh2<int,INTERP_KERNEL::ALL_C_MODE>(begin,(int)std::distance(begin,end),coords)<-EPS_FOR_POLYH_ORIENTATION)
8838 {//not lucky ! The first face was not correctly oriented : reorient all faces...
8840 for(std::size_t i=0;i<nbOfFaces;i++)
8842 endFace=std::find(bgFace+1,end,-1);
8843 std::reverse(bgFace+1,endFace);
8849 DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMeshLinear(const MEDCouplingUMesh *skin, const DataArrayInt *n2o) const
8851 int nbOfNodesExpected(skin->getNumberOfNodes());
8852 const int *n2oPtr(n2o->begin());
8853 MCAuto<DataArrayInt> revNodal(DataArrayInt::New()),revNodalI(DataArrayInt::New());
8854 skin->getReverseNodalConnectivity(revNodal,revNodalI);
8855 const int *revNodalPtr(revNodal->begin()),*revNodalIPtr(revNodalI->begin());
8856 const int *nodalPtr(skin->getNodalConnectivity()->begin());
8857 const int *nodalIPtr(skin->getNodalConnectivityIndex()->begin());
8858 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(nbOfNodesExpected+1,1);
8859 int *work(ret->getPointer()); *work++=INTERP_KERNEL::NORM_POLYGON;
8860 if(nbOfNodesExpected<1)
8862 int prevCell(0),prevNode(nodalPtr[nodalIPtr[0]+1]);
8863 *work++=n2oPtr[prevNode];
8864 for(int i=1;i<nbOfNodesExpected;i++)
8866 if(nodalIPtr[prevCell+1]-nodalIPtr[prevCell]==3)
8868 std::set<int> conn(nodalPtr+nodalIPtr[prevCell]+1,nodalPtr+nodalIPtr[prevCell]+3);
8869 conn.erase(prevNode);
8872 int curNode(*(conn.begin()));
8873 *work++=n2oPtr[curNode];
8874 std::set<int> shar(revNodalPtr+revNodalIPtr[curNode],revNodalPtr+revNodalIPtr[curNode+1]);
8875 shar.erase(prevCell);
8878 prevCell=*(shar.begin());
8882 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshLinear : presence of unexpected 2 !");
8885 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshLinear : presence of unexpected 1 !");
8888 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshLinear : presence of unexpected cell !");
8893 DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMeshQuadratic(const MEDCouplingUMesh *skin, const DataArrayInt *n2o) const
8895 int nbOfNodesExpected(skin->getNumberOfNodes());
8896 int nbOfTurn(nbOfNodesExpected/2);
8897 const int *n2oPtr(n2o->begin());
8898 MCAuto<DataArrayInt> revNodal(DataArrayInt::New()),revNodalI(DataArrayInt::New());
8899 skin->getReverseNodalConnectivity(revNodal,revNodalI);
8900 const int *revNodalPtr(revNodal->begin()),*revNodalIPtr(revNodalI->begin());
8901 const int *nodalPtr(skin->getNodalConnectivity()->begin());
8902 const int *nodalIPtr(skin->getNodalConnectivityIndex()->begin());
8903 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(nbOfNodesExpected+1,1);
8904 int *work(ret->getPointer()); *work++=INTERP_KERNEL::NORM_QPOLYG;
8905 if(nbOfNodesExpected<1)
8907 int prevCell(0),prevNode(nodalPtr[nodalIPtr[0]+1]);
8908 *work=n2oPtr[prevNode]; work[nbOfTurn]=n2oPtr[nodalPtr[nodalIPtr[0]+3]]; work++;
8909 for(int i=1;i<nbOfTurn;i++)
8911 if(nodalIPtr[prevCell+1]-nodalIPtr[prevCell]==4)
8913 std::set<int> conn(nodalPtr+nodalIPtr[prevCell]+1,nodalPtr+nodalIPtr[prevCell]+3);
8914 conn.erase(prevNode);
8917 int curNode(*(conn.begin()));
8918 *work=n2oPtr[curNode];
8919 std::set<int> shar(revNodalPtr+revNodalIPtr[curNode],revNodalPtr+revNodalIPtr[curNode+1]);
8920 shar.erase(prevCell);
8923 int curCell(*(shar.begin()));
8924 work[nbOfTurn]=n2oPtr[nodalPtr[nodalIPtr[curCell]+3]];
8930 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshQuadratic : presence of unexpected 2 !");
8933 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshQuadratic : presence of unexpected 1 !");
8936 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshQuadratic : presence of unexpected cell !");
8942 * This method makes the assumption spacedimension == meshdimension == 2.
8943 * This method works only for linear cells.
8945 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYGON in pos#0)
8947 DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMesh() const
8949 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
8950 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : meshdimension, spacedimension must be equal to 2 !");
8951 MCAuto<MEDCouplingUMesh> skin(computeSkin());
8952 int oldNbOfNodes(skin->getNumberOfNodes());
8953 MCAuto<DataArrayInt> o2n(skin->zipCoordsTraducer());
8954 int nbOfNodesExpected(skin->getNumberOfNodes());
8955 MCAuto<DataArrayInt> n2o(o2n->invertArrayO2N2N2O(oldNbOfNodes));
8956 int nbCells(skin->getNumberOfCells());
8957 if(nbCells==nbOfNodesExpected)
8958 return buildUnionOf2DMeshLinear(skin,n2o);
8959 else if(2*nbCells==nbOfNodesExpected)
8960 return buildUnionOf2DMeshQuadratic(skin,n2o);
8962 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : the mesh 2D in input appears to be not in a single part of a 2D mesh !");
8966 * This method makes the assumption spacedimension == meshdimension == 3.
8967 * This method works only for linear cells.
8969 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYHED in pos#0)
8971 DataArrayInt *MEDCouplingUMesh::buildUnionOf3DMesh() const
8973 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
8974 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf3DMesh : meshdimension, spacedimension must be equal to 2 !");
8975 MCAuto<MEDCouplingUMesh> m=computeSkin();
8976 const int *conn=m->getNodalConnectivity()->begin();
8977 const int *connI=m->getNodalConnectivityIndex()->begin();
8978 int nbOfCells=m->getNumberOfCells();
8979 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(m->getNodalConnectivity()->getNumberOfTuples(),1);
8980 int *work=ret->getPointer(); *work++=INTERP_KERNEL::NORM_POLYHED;
8983 work=std::copy(conn+connI[0]+1,conn+connI[1],work);
8984 for(int i=1;i<nbOfCells;i++)
8987 work=std::copy(conn+connI[i]+1,conn+connI[i+1],work);
8993 * \brief Creates a graph of cell neighbors
8994 * \return MEDCouplingSkyLineArray * - an sky line array the user should delete.
8995 * In the sky line array, graph arcs are stored in terms of (index,value) notation.
8997 * - index: 0 3 5 6 6
8998 * - value: 1 2 3 2 3 3
8999 * means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
9000 * Arcs are not doubled but reflexive (1,1) arcs are present for each cell
9002 MEDCouplingSkyLineArray *MEDCouplingUMesh::generateGraph() const
9004 checkConnectivityFullyDefined();
9006 int meshDim = this->getMeshDimension();
9007 MEDCoupling::DataArrayInt* indexr=MEDCoupling::DataArrayInt::New();
9008 MEDCoupling::DataArrayInt* revConn=MEDCoupling::DataArrayInt::New();
9009 this->getReverseNodalConnectivity(revConn,indexr);
9010 const int* indexr_ptr=indexr->begin();
9011 const int* revConn_ptr=revConn->begin();
9013 const MEDCoupling::DataArrayInt* index;
9014 const MEDCoupling::DataArrayInt* conn;
9015 conn=this->getNodalConnectivity(); // it includes a type as the 1st element!!!
9016 index=this->getNodalConnectivityIndex();
9017 int nbCells=this->getNumberOfCells();
9018 const int* index_ptr=index->begin();
9019 const int* conn_ptr=conn->begin();
9021 //creating graph arcs (cell to cell relations)
9022 //arcs are stored in terms of (index,value) notation
9025 // means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
9026 // in present version arcs are not doubled but reflexive (1,1) arcs are present for each cell
9028 //warning here one node have less than or equal effective number of cell with it
9029 //but cell could have more than effective nodes
9030 //because other equals nodes in other domain (with other global inode)
9031 std::vector <int> cell2cell_index(nbCells+1,0);
9032 std::vector <int> cell2cell;
9033 cell2cell.reserve(3*nbCells);
9035 for (int icell=0; icell<nbCells;icell++)
9037 std::map<int,int > counter;
9038 for (int iconn=index_ptr[icell]+1; iconn<index_ptr[icell+1];iconn++)
9040 int inode=conn_ptr[iconn];
9041 for (int iconnr=indexr_ptr[inode]; iconnr<indexr_ptr[inode+1];iconnr++)
9043 int icell2=revConn_ptr[iconnr];
9044 std::map<int,int>::iterator iter=counter.find(icell2);
9045 if (iter!=counter.end()) (iter->second)++;
9046 else counter.insert(std::make_pair(icell2,1));
9049 for (std::map<int,int>::const_iterator iter=counter.begin();
9050 iter!=counter.end(); iter++)
9051 if (iter->second >= meshDim)
9053 cell2cell_index[icell+1]++;
9054 cell2cell.push_back(iter->first);
9059 cell2cell_index[0]=0;
9060 for (int icell=0; icell<nbCells;icell++)
9061 cell2cell_index[icell+1]=cell2cell_index[icell]+cell2cell_index[icell+1];
9063 //filling up index and value to create skylinearray structure
9064 MEDCouplingSkyLineArray* array=new MEDCouplingSkyLineArray(cell2cell_index,cell2cell);
9069 * This method put in zip format into parameter 'zipFrmt' in full interlace mode.
9070 * This format is often asked by INTERP_KERNEL algorithms to avoid many indirections into coordinates array.
9072 void MEDCouplingUMesh::FillInCompact3DMode(int spaceDim, int nbOfNodesInCell, const int *conn, const double *coo, double *zipFrmt)
9076 for(int i=0;i<nbOfNodesInCell;i++)
9077 w=std::copy(coo+3*conn[i],coo+3*conn[i]+3,w);
9078 else if(spaceDim==2)
9080 for(int i=0;i<nbOfNodesInCell;i++)
9082 w=std::copy(coo+2*conn[i],coo+2*conn[i]+2,w);
9087 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::FillInCompact3DMode : Invalid spaceDim specified : must be 2 or 3 !");
9090 void MEDCouplingUMesh::writeVTKLL(std::ostream& ofs, const std::string& cellData, const std::string& pointData, DataArrayByte *byteData) const
9092 int nbOfCells=getNumberOfCells();
9094 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::writeVTK : the unstructured mesh has no cells !");
9095 ofs << " <" << getVTKDataSetType() << ">\n";
9096 ofs << " <Piece NumberOfPoints=\"" << getNumberOfNodes() << "\" NumberOfCells=\"" << nbOfCells << "\">\n";
9097 ofs << " <PointData>\n" << pointData << std::endl;
9098 ofs << " </PointData>\n";
9099 ofs << " <CellData>\n" << cellData << std::endl;
9100 ofs << " </CellData>\n";
9101 ofs << " <Points>\n";
9102 if(getSpaceDimension()==3)
9103 _coords->writeVTK(ofs,8,"Points",byteData);
9106 MCAuto<DataArrayDouble> coo=_coords->changeNbOfComponents(3,0.);
9107 coo->writeVTK(ofs,8,"Points",byteData);
9109 ofs << " </Points>\n";
9110 ofs << " <Cells>\n";
9111 const int *cPtr=_nodal_connec->begin();
9112 const int *cIPtr=_nodal_connec_index->begin();
9113 MCAuto<DataArrayInt> faceoffsets=DataArrayInt::New(); faceoffsets->alloc(nbOfCells,1);
9114 MCAuto<DataArrayInt> types=DataArrayInt::New(); types->alloc(nbOfCells,1);
9115 MCAuto<DataArrayInt> offsets=DataArrayInt::New(); offsets->alloc(nbOfCells,1);
9116 MCAuto<DataArrayInt> connectivity=DataArrayInt::New(); connectivity->alloc(_nodal_connec->getNumberOfTuples()-nbOfCells,1);
9117 int *w1=faceoffsets->getPointer(),*w2=types->getPointer(),*w3=offsets->getPointer(),*w4=connectivity->getPointer();
9118 int szFaceOffsets=0,szConn=0;
9119 for(int i=0;i<nbOfCells;i++,w1++,w2++,w3++)
9122 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]!=INTERP_KERNEL::NORM_POLYHED)
9125 *w3=szConn+cIPtr[i+1]-cIPtr[i]-1; szConn+=cIPtr[i+1]-cIPtr[i]-1;
9126 w4=std::copy(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],w4);
9130 int deltaFaceOffset=cIPtr[i+1]-cIPtr[i]+1;
9131 *w1=szFaceOffsets+deltaFaceOffset; szFaceOffsets+=deltaFaceOffset;
9132 std::set<int> c(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1]); c.erase(-1);
9133 *w3=szConn+(int)c.size(); szConn+=(int)c.size();
9134 w4=std::copy(c.begin(),c.end(),w4);
9137 types->transformWithIndArr(MEDCOUPLING2VTKTYPETRADUCER,MEDCOUPLING2VTKTYPETRADUCER+INTERP_KERNEL::NORM_MAXTYPE+1);
9138 types->writeVTK(ofs,8,"UInt8","types",byteData);
9139 offsets->writeVTK(ofs,8,"Int32","offsets",byteData);
9140 if(szFaceOffsets!=0)
9141 {//presence of Polyhedra
9142 connectivity->reAlloc(szConn);
9143 faceoffsets->writeVTK(ofs,8,"Int32","faceoffsets",byteData);
9144 MCAuto<DataArrayInt> faces=DataArrayInt::New(); faces->alloc(szFaceOffsets,1);
9145 w1=faces->getPointer();
9146 for(int i=0;i<nbOfCells;i++)
9147 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]==INTERP_KERNEL::NORM_POLYHED)
9149 int nbFaces=std::count(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],-1)+1;
9151 const int *w6=cPtr+cIPtr[i]+1,*w5=0;
9152 for(int j=0;j<nbFaces;j++)
9154 w5=std::find(w6,cPtr+cIPtr[i+1],-1);
9155 *w1++=(int)std::distance(w6,w5);
9156 w1=std::copy(w6,w5,w1);
9160 faces->writeVTK(ofs,8,"Int32","faces",byteData);
9162 connectivity->writeVTK(ofs,8,"Int32","connectivity",byteData);
9163 ofs << " </Cells>\n";
9164 ofs << " </Piece>\n";
9165 ofs << " </" << getVTKDataSetType() << ">\n";
9168 void MEDCouplingUMesh::reprQuickOverview(std::ostream& stream) const
9170 stream << "MEDCouplingUMesh C++ instance at " << this << ". Name : \"" << getName() << "\".";
9172 { stream << " Not set !"; return ; }
9173 stream << " Mesh dimension : " << _mesh_dim << ".";
9177 { stream << " No coordinates set !"; return ; }
9178 if(!_coords->isAllocated())
9179 { stream << " Coordinates set but not allocated !"; return ; }
9180 stream << " Space dimension : " << _coords->getNumberOfComponents() << "." << std::endl;
9181 stream << "Number of nodes : " << _coords->getNumberOfTuples() << ".";
9182 if(!_nodal_connec_index)
9183 { stream << std::endl << "Nodal connectivity NOT set !"; return ; }
9184 if(!_nodal_connec_index->isAllocated())
9185 { stream << std::endl << "Nodal connectivity set but not allocated !"; return ; }
9186 int lgth=_nodal_connec_index->getNumberOfTuples();
9187 int cpt=_nodal_connec_index->getNumberOfComponents();
9188 if(cpt!=1 || lgth<1)
9190 stream << std::endl << "Number of cells : " << lgth-1 << ".";
9193 std::string MEDCouplingUMesh::getVTKDataSetType() const
9195 return std::string("UnstructuredGrid");
9198 std::string MEDCouplingUMesh::getVTKFileExtension() const
9200 return std::string("vtu");
9204 * Partitions the first given 2D mesh using the second given 2D mesh as a tool, and
9205 * returns a result mesh constituted by polygons.
9206 * Thus the final result contains all nodes from m1 plus new nodes. However it doesn't necessarily contains
9207 * all nodes from m2.
9208 * The meshes should be in 2D space. In
9209 * addition, returns two arrays mapping cells of the result mesh to cells of the input
9211 * \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
9212 * 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)
9213 * \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
9214 * 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)
9215 * \param [in] eps - precision used to detect coincident mesh entities.
9216 * \param [out] cellNb1 - a new instance of DataArrayInt holding for each result
9217 * cell an id of the cell of \a m1 it comes from. The caller is to delete
9218 * this array using decrRef() as it is no more needed.
9219 * \param [out] cellNb2 - a new instance of DataArrayInt holding for each result
9220 * cell an id of the cell of \a m2 it comes from. -1 value means that a
9221 * result cell comes from a cell (or part of cell) of \a m1 not overlapped by
9222 * any cell of \a m2. The caller is to delete this array using decrRef() as
9223 * it is no more needed.
9224 * \return MEDCouplingUMesh * - the result 2D mesh which is a new instance of
9225 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
9226 * is no more needed.
9227 * \throw If the coordinates array is not set in any of the meshes.
9228 * \throw If the nodal connectivity of cells is not defined in any of the meshes.
9229 * \throw If any of the meshes is not a 2D mesh in 2D space.
9231 * \sa conformize2D, mergeNodes
9233 MEDCouplingUMesh *MEDCouplingUMesh::Intersect2DMeshes(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2,
9234 double eps, DataArrayInt *&cellNb1, DataArrayInt *&cellNb2)
9237 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshes : input meshes must be not NULL !");
9238 m1->checkFullyDefined();
9239 m2->checkFullyDefined();
9240 if(m1->getMeshDimension()!=2 || m1->getSpaceDimension()!=2 || m2->getMeshDimension()!=2 || m2->getSpaceDimension()!=2)
9241 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshes works on umeshes m1 AND m2 with meshdim equal to 2 and spaceDim equal to 2 too!");
9243 // Step 1: compute all edge intersections (new nodes)
9244 std::vector< std::vector<int> > intersectEdge1, colinear2, subDiv2;
9245 MEDCouplingUMesh *m1Desc=0,*m2Desc=0; // descending connec. meshes
9246 DataArrayInt *desc1=0,*descIndx1=0,*revDesc1=0,*revDescIndx1=0,*desc2=0,*descIndx2=0,*revDesc2=0,*revDescIndx2=0;
9247 std::vector<double> addCoo,addCoordsQuadratic; // coordinates of newly created nodes
9248 IntersectDescending2DMeshes(m1,m2,eps,intersectEdge1,colinear2, subDiv2,
9249 m1Desc,desc1,descIndx1,revDesc1,revDescIndx1,
9250 addCoo, m2Desc,desc2,descIndx2,revDesc2,revDescIndx2);
9251 revDesc1->decrRef(); revDescIndx1->decrRef(); revDesc2->decrRef(); revDescIndx2->decrRef();
9252 MCAuto<DataArrayInt> dd1(desc1),dd2(descIndx1),dd3(desc2),dd4(descIndx2);
9253 MCAuto<MEDCouplingUMesh> dd5(m1Desc),dd6(m2Desc);
9255 // Step 2: re-order newly created nodes according to the ordering found in m2
9256 std::vector< std::vector<int> > intersectEdge2;
9257 BuildIntersectEdges(m1Desc,m2Desc,addCoo,subDiv2,intersectEdge2);
9258 subDiv2.clear(); dd5=0; dd6=0;
9261 std::vector<int> cr,crI; //no DataArrayInt because interface with Geometric2D
9262 std::vector<int> cNb1,cNb2; //no DataArrayInt because interface with Geometric2D
9263 BuildIntersecting2DCellsFromEdges(eps,m1,desc1->begin(),descIndx1->begin(),intersectEdge1,colinear2,m2,desc2->begin(),descIndx2->begin(),intersectEdge2,addCoo,
9264 /* outputs -> */addCoordsQuadratic,cr,crI,cNb1,cNb2);
9266 // Step 4: Prepare final result:
9267 MCAuto<DataArrayDouble> addCooDa(DataArrayDouble::New());
9268 addCooDa->alloc((int)(addCoo.size())/2,2);
9269 std::copy(addCoo.begin(),addCoo.end(),addCooDa->getPointer());
9270 MCAuto<DataArrayDouble> addCoordsQuadraticDa(DataArrayDouble::New());
9271 addCoordsQuadraticDa->alloc((int)(addCoordsQuadratic.size())/2,2);
9272 std::copy(addCoordsQuadratic.begin(),addCoordsQuadratic.end(),addCoordsQuadraticDa->getPointer());
9273 std::vector<const DataArrayDouble *> coordss(4);
9274 coordss[0]=m1->getCoords(); coordss[1]=m2->getCoords(); coordss[2]=addCooDa; coordss[3]=addCoordsQuadraticDa;
9275 MCAuto<DataArrayDouble> coo(DataArrayDouble::Aggregate(coordss));
9276 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("Intersect2D",2));
9277 MCAuto<DataArrayInt> conn(DataArrayInt::New()); conn->alloc((int)cr.size(),1); std::copy(cr.begin(),cr.end(),conn->getPointer());
9278 MCAuto<DataArrayInt> connI(DataArrayInt::New()); connI->alloc((int)crI.size(),1); std::copy(crI.begin(),crI.end(),connI->getPointer());
9279 MCAuto<DataArrayInt> c1(DataArrayInt::New()); c1->alloc((int)cNb1.size(),1); std::copy(cNb1.begin(),cNb1.end(),c1->getPointer());
9280 MCAuto<DataArrayInt> c2(DataArrayInt::New()); c2->alloc((int)cNb2.size(),1); std::copy(cNb2.begin(),cNb2.end(),c2->getPointer());
9281 ret->setConnectivity(conn,connI,true);
9282 ret->setCoords(coo);
9283 cellNb1=c1.retn(); cellNb2=c2.retn();
9289 bool IsColinearOfACellOf(const std::vector< std::vector<int> >& intersectEdge1, const std::vector<int>& candidates, int start, int stop, int& retVal)
9291 if(candidates.empty())
9293 for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
9295 const std::vector<int>& pool(intersectEdge1[*it]);
9296 int tmp[2]; tmp[0]=start; tmp[1]=stop;
9297 if(std::search(pool.begin(),pool.end(),tmp,tmp+2)!=pool.end())
9302 tmp[0]=stop; tmp[1]=start;
9303 if(std::search(pool.begin(),pool.end(),tmp,tmp+2)!=pool.end())
9312 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,
9313 MCAuto<DataArrayInt>& idsInRetColinear, MCAuto<DataArrayInt>& idsInMesh1DForIdsInRetColinear)
9315 idsInRetColinear=DataArrayInt::New(); idsInRetColinear->alloc(0,1);
9316 idsInMesh1DForIdsInRetColinear=DataArrayInt::New(); idsInMesh1DForIdsInRetColinear->alloc(0,1);
9317 int nCells(mesh1D->getNumberOfCells());
9318 if(nCells!=(int)intersectEdge2.size())
9319 throw INTERP_KERNEL::Exception("BuildMesh1DCutFrom : internal error # 1 !");
9320 const DataArrayDouble *coo2(mesh1D->getCoords());
9321 const int *c(mesh1D->getNodalConnectivity()->begin()),*ci(mesh1D->getNodalConnectivityIndex()->begin());
9322 const double *coo2Ptr(coo2->begin());
9323 int offset1(coords1->getNumberOfTuples());
9324 int offset2(offset1+coo2->getNumberOfTuples());
9325 int offset3(offset2+addCoo.size()/2);
9326 std::vector<double> addCooQuad;
9327 MCAuto<DataArrayInt> cOut(DataArrayInt::New()),ciOut(DataArrayInt::New()); cOut->alloc(0,1); ciOut->alloc(1,1); ciOut->setIJ(0,0,0);
9328 int tmp[4],cicnt(0),kk(0);
9329 for(int i=0;i<nCells;i++)
9331 std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
9332 INTERP_KERNEL::Edge *e(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[i]],c+ci[i]+1,coo2Ptr,m));
9333 const std::vector<int>& subEdges(intersectEdge2[i]);
9334 int nbSubEdge(subEdges.size()/2);
9335 for(int j=0;j<nbSubEdge;j++,kk++)
9337 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));
9338 MCAuto<INTERP_KERNEL::Edge> e2(e->buildEdgeLyingOnMe(n1,n2));
9339 INTERP_KERNEL::Edge *e2Ptr(e2);
9340 std::map<int,int>::const_iterator itm;
9341 if(dynamic_cast<INTERP_KERNEL::EdgeArcCircle *>(e2Ptr))
9343 tmp[0]=INTERP_KERNEL::NORM_SEG3;
9344 itm=mergedNodes.find(subEdges[2*j]);
9345 tmp[1]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j];
9346 itm=mergedNodes.find(subEdges[2*j+1]);
9347 tmp[2]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j+1];
9348 tmp[3]=offset3+(int)addCooQuad.size()/2;
9350 e2->getBarycenter(tmp2); addCooQuad.insert(addCooQuad.end(),tmp2,tmp2+2);
9352 cOut->insertAtTheEnd(tmp,tmp+4);
9353 ciOut->pushBackSilent(cicnt);
9357 tmp[0]=INTERP_KERNEL::NORM_SEG2;
9358 itm=mergedNodes.find(subEdges[2*j]);
9359 tmp[1]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j];
9360 itm=mergedNodes.find(subEdges[2*j+1]);
9361 tmp[2]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j+1];
9363 cOut->insertAtTheEnd(tmp,tmp+3);
9364 ciOut->pushBackSilent(cicnt);
9367 if(IsColinearOfACellOf(intersectEdge1,colinear2[i],tmp[1],tmp[2],tmp00))
9369 idsInRetColinear->pushBackSilent(kk);
9370 idsInMesh1DForIdsInRetColinear->pushBackSilent(tmp00);
9375 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New(mesh1D->getName(),1));
9376 ret->setConnectivity(cOut,ciOut,true);
9377 MCAuto<DataArrayDouble> arr3(DataArrayDouble::New());
9378 arr3->useArray(&addCoo[0],false,C_DEALLOC,(int)addCoo.size()/2,2);
9379 MCAuto<DataArrayDouble> arr4(DataArrayDouble::New()); arr4->useArray(&addCooQuad[0],false,C_DEALLOC,(int)addCooQuad.size()/2,2);
9380 std::vector<const DataArrayDouble *> coordss(4);
9381 coordss[0]=coords1; coordss[1]=mesh1D->getCoords(); coordss[2]=arr3; coordss[3]=arr4;
9382 MCAuto<DataArrayDouble> arr(DataArrayDouble::Aggregate(coordss));
9383 ret->setCoords(arr);
9387 MEDCouplingUMesh *BuildRefined2DCellLinear(const DataArrayDouble *coords, const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1)
9389 std::vector<int> allEdges;
9390 for(const int *it2(descBg);it2!=descEnd;it2++)
9392 const std::vector<int>& edge1(intersectEdge1[std::abs(*it2)-1]);
9394 allEdges.insert(allEdges.end(),edge1.begin(),edge1.end());
9396 allEdges.insert(allEdges.end(),edge1.rbegin(),edge1.rend());
9398 std::size_t nb(allEdges.size());
9400 throw INTERP_KERNEL::Exception("BuildRefined2DCellLinear : internal error 1 !");
9401 std::size_t nbOfEdgesOf2DCellSplit(nb/2);
9402 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
9403 ret->setCoords(coords);
9404 ret->allocateCells(1);
9405 std::vector<int> connOut(nbOfEdgesOf2DCellSplit);
9406 for(std::size_t kk=0;kk<nbOfEdgesOf2DCellSplit;kk++)
9407 connOut[kk]=allEdges[2*kk];
9408 ret->insertNextCell(INTERP_KERNEL::NORM_POLYGON,connOut.size(),&connOut[0]);
9412 MEDCouplingUMesh *BuildRefined2DCellQuadratic(const DataArrayDouble *coords, const MEDCouplingUMesh *mesh2D, int cellIdInMesh2D, const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1)
9414 const int *c(mesh2D->getNodalConnectivity()->begin()),*ci(mesh2D->getNodalConnectivityIndex()->begin());
9415 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c[ci[cellIdInMesh2D]]));
9417 unsigned sz(cm.getNumberOfSons2(c+ci[cellIdInMesh2D]+1,ci[cellIdInMesh2D+1]-ci[cellIdInMesh2D]-1));
9418 if(sz!=std::distance(descBg,descEnd))
9419 throw INTERP_KERNEL::Exception("BuildRefined2DCellQuadratic : internal error 1 !");
9420 INTERP_KERNEL::AutoPtr<int> tmpPtr(new int[ci[cellIdInMesh2D+1]-ci[cellIdInMesh2D]]);
9421 std::vector<int> allEdges,centers;
9422 const double *coordsPtr(coords->begin());
9423 MCAuto<DataArrayDouble> addCoo(DataArrayDouble::New()); addCoo->alloc(0,1);
9424 int offset(coords->getNumberOfTuples());
9425 for(const int *it2(descBg);it2!=descEnd;it2++,ii++)
9427 INTERP_KERNEL::NormalizedCellType typeOfSon;
9428 cm.fillSonCellNodalConnectivity2(ii,c+ci[cellIdInMesh2D]+1,ci[cellIdInMesh2D+1]-ci[cellIdInMesh2D]-1,tmpPtr,typeOfSon);
9429 const std::vector<int>& edge1(intersectEdge1[std::abs(*it2)-1]);
9431 allEdges.insert(allEdges.end(),edge1.begin(),edge1.end());
9433 allEdges.insert(allEdges.end(),edge1.rbegin(),edge1.rend());
9435 centers.push_back(tmpPtr[2]);//special case where no subsplit of edge -> reuse the original center.
9437 {//the current edge has been subsplit -> create corresponding centers.
9438 std::size_t nbOfCentersToAppend(edge1.size()/2);
9439 std::map< MCAuto<INTERP_KERNEL::Node>,int> m;
9440 MCAuto<INTERP_KERNEL::Edge> ee(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpPtr,coordsPtr,m));
9441 std::vector<int>::const_iterator it3(allEdges.end()-edge1.size());
9442 for(std::size_t k=0;k<nbOfCentersToAppend;k++)
9445 const double *aa(coordsPtr+2*(*it3++));
9446 const double *bb(coordsPtr+2*(*it3++));
9447 ee->getMiddleOfPoints(aa,bb,tmpp);
9448 addCoo->insertAtTheEnd(tmpp,tmpp+2);
9449 centers.push_back(offset+k);
9453 std::size_t nb(allEdges.size());
9455 throw INTERP_KERNEL::Exception("BuildRefined2DCellQuadratic : internal error 2 !");
9456 std::size_t nbOfEdgesOf2DCellSplit(nb/2);
9457 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
9459 ret->setCoords(coords);
9462 addCoo->rearrange(2);
9463 addCoo=DataArrayDouble::Aggregate(coords,addCoo);
9464 ret->setCoords(addCoo);
9466 ret->allocateCells(1);
9467 std::vector<int> connOut(nbOfEdgesOf2DCellSplit);
9468 for(std::size_t kk=0;kk<nbOfEdgesOf2DCellSplit;kk++)
9469 connOut[kk]=allEdges[2*kk];
9470 connOut.insert(connOut.end(),centers.begin(),centers.end());
9471 ret->insertNextCell(INTERP_KERNEL::NORM_QPOLYG,connOut.size(),&connOut[0]);
9476 * This method creates a refinement of a cell in \a mesh2D. Those cell is defined by descending connectivity and the sorted subdivided nodal connectivity
9479 * \param [in] mesh2D - The origin 2D mesh. \b Warning \b coords are not those of \a mesh2D. But mesh2D->getCoords()==coords[:mesh2D->getNumberOfNodes()]
9481 MEDCouplingUMesh *BuildRefined2DCell(const DataArrayDouble *coords, const MEDCouplingUMesh *mesh2D, int cellIdInMesh2D, const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1)
9483 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(mesh2D->getTypeOfCell(cellIdInMesh2D)));
9484 if(!cm.isQuadratic())
9485 return BuildRefined2DCellLinear(coords,descBg,descEnd,intersectEdge1);
9487 return BuildRefined2DCellQuadratic(coords,mesh2D,cellIdInMesh2D,descBg,descEnd,intersectEdge1);
9490 void AddCellInMesh2D(MEDCouplingUMesh *mesh2D, const std::vector<int>& conn, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edges)
9493 for(std::vector< MCAuto<INTERP_KERNEL::Edge> >::const_iterator it=edges.begin();it!=edges.end();it++)
9495 const INTERP_KERNEL::Edge *ee(*it);
9496 if(dynamic_cast<const INTERP_KERNEL::EdgeArcCircle *>(ee))
9500 mesh2D->insertNextCell(INTERP_KERNEL::NORM_POLYGON,conn.size(),&conn[0]);
9503 const double *coo(mesh2D->getCoords()->begin());
9504 std::size_t sz(conn.size());
9505 std::vector<double> addCoo;
9506 std::vector<int> conn2(conn);
9507 int offset(mesh2D->getNumberOfNodes());
9508 for(std::size_t i=0;i<sz;i++)
9511 edges[(i+1)%sz]->getMiddleOfPoints(coo+2*conn[i],coo+2*conn[(i+1)%sz],tmp);// tony a chier i+1 -> i
9512 addCoo.insert(addCoo.end(),tmp,tmp+2);
9513 conn2.push_back(offset+(int)i);
9515 mesh2D->getCoords()->rearrange(1);
9516 mesh2D->getCoords()->pushBackValsSilent(&addCoo[0],&addCoo[0]+addCoo.size());
9517 mesh2D->getCoords()->rearrange(2);
9518 mesh2D->insertNextCell(INTERP_KERNEL::NORM_QPOLYG,conn2.size(),&conn2[0]);
9523 * \b WARNING edges in out1 coming from \a splitMesh1D are \b NOT oriented because only used for equation of curve.
9525 * This method cuts in 2 parts the input 2D cell given using boundaries description (\a edge1Bis and \a edge1BisPtr) using
9526 * a set of edges defined in \a splitMesh1D.
9528 void BuildMesh2DCutInternal2(const MEDCouplingUMesh *splitMesh1D, const std::vector<int>& edge1Bis, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edge1BisPtr,
9529 std::vector< std::vector<int> >& out0, std::vector< std::vector< MCAuto<INTERP_KERNEL::Edge> > >& out1)
9531 std::size_t nb(edge1Bis.size()/2);
9532 std::size_t nbOfEdgesOf2DCellSplit(nb/2);
9533 int iEnd(splitMesh1D->getNumberOfCells());
9535 throw INTERP_KERNEL::Exception("BuildMesh2DCutInternal2 : internal error ! input 1D mesh must have at least one cell !");
9537 const int *cSplitPtr(splitMesh1D->getNodalConnectivity()->begin()),*ciSplitPtr(splitMesh1D->getNodalConnectivityIndex()->begin());
9538 for(ii=0;ii<nb && edge1Bis[2*ii]!=cSplitPtr[ciSplitPtr[0]+1];ii++);
9539 for(jj=ii;jj<nb && edge1Bis[2*jj+1]!=cSplitPtr[ciSplitPtr[iEnd-1]+2];jj++);
9542 {//the edges splitMesh1D[iStart:iEnd] does not fully cut the current 2D cell -> single output cell
9543 out0.resize(1); out1.resize(1);
9544 std::vector<int>& connOut(out0[0]);
9545 connOut.resize(nbOfEdgesOf2DCellSplit);
9546 std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr(out1[0]);
9547 edgesPtr.resize(nbOfEdgesOf2DCellSplit);
9548 for(std::size_t kk=0;kk<nbOfEdgesOf2DCellSplit;kk++)
9550 connOut[kk]=edge1Bis[2*kk];
9551 edgesPtr[kk]=edge1BisPtr[2*kk];
9556 // [i,iEnd[ contains the
9557 out0.resize(2); out1.resize(2);
9558 std::vector<int>& connOutLeft(out0[0]);
9559 std::vector<int>& connOutRight(out0[1]);//connOutLeft should end with edge1Bis[2*ii] and connOutRight should end with edge1Bis[2*jj+1]
9560 std::vector< MCAuto<INTERP_KERNEL::Edge> >& eleft(out1[0]);
9561 std::vector< MCAuto<INTERP_KERNEL::Edge> >& eright(out1[1]);
9562 for(std::size_t k=ii;k<jj+1;k++)
9563 { connOutLeft.push_back(edge1Bis[2*k+1]); eleft.push_back(edge1BisPtr[2*k+1]); }
9564 std::vector< MCAuto<INTERP_KERNEL::Edge> > ees(iEnd);
9565 for(int ik=0;ik<iEnd;ik++)
9567 std::map< MCAuto<INTERP_KERNEL::Node>,int> m;
9568 MCAuto<INTERP_KERNEL::Edge> ee(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)cSplitPtr[ciSplitPtr[ik]],cSplitPtr+ciSplitPtr[ik]+1,splitMesh1D->getCoords()->begin(),m));
9571 for(int ik=iEnd-1;ik>=0;ik--)
9572 connOutLeft.push_back(cSplitPtr[ciSplitPtr[ik]+1]);
9573 for(std::size_t k=jj+1;k<nbOfEdgesOf2DCellSplit+ii;k++)
9574 { connOutRight.push_back(edge1Bis[2*k+1]); eright.push_back(edge1BisPtr[2*k+1]); }
9575 eleft.insert(eleft.end(),ees.rbegin(),ees.rend());
9576 for(int ik=0;ik<iEnd;ik++)
9577 connOutRight.push_back(cSplitPtr[ciSplitPtr[ik]+2]);
9578 eright.insert(eright.end(),ees.begin(),ees.end());
9590 CellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr);
9592 std::vector<int> _edges;
9593 std::vector< MCAuto<INTERP_KERNEL::Edge> > _edges_ptr;
9596 CellInfo::CellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr)
9598 std::size_t nbe(edges.size());
9599 std::vector<int> edges2(2*nbe); std::vector< MCAuto<INTERP_KERNEL::Edge> > edgesPtr2(2*nbe);
9600 for(std::size_t i=0;i<nbe;i++)
9602 edges2[2*i]=edges[i]; edges2[2*i+1]=edges[(i+1)%nbe];
9603 edgesPtr2[2*i]=edgesPtr[(i+1)%nbe]; edgesPtr2[2*i+1]=edgesPtr[(i+1)%nbe];//tony a chier
9605 _edges.resize(4*nbe); _edges_ptr.resize(4*nbe);
9606 std::copy(edges2.begin(),edges2.end(),_edges.begin()); std::copy(edges2.begin(),edges2.end(),_edges.begin()+2*nbe);
9607 std::copy(edgesPtr2.begin(),edgesPtr2.end(),_edges_ptr.begin()); std::copy(edgesPtr2.begin(),edgesPtr2.end(),_edges_ptr.begin()+2*nbe);
9613 EdgeInfo(int istart, int iend, const MCAuto<MEDCouplingUMesh>& mesh):_istart(istart),_iend(iend),_mesh(mesh),_left(-7),_right(-7) { }
9614 EdgeInfo(int istart, int iend, int pos, const MCAuto<INTERP_KERNEL::Edge>& edge):_istart(istart),_iend(iend),_edge(edge),_left(pos),_right(pos+1) { }
9615 bool isInMyRange(int pos) const { return pos>=_istart && pos<_iend; }
9616 void somethingHappendAt(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight);
9617 void feedEdgeInfoAt(double eps, const MEDCouplingUMesh *mesh2D, int offset, int neighbors[2]) const;
9621 MCAuto<MEDCouplingUMesh> _mesh;
9622 MCAuto<INTERP_KERNEL::Edge> _edge;
9627 void EdgeInfo::somethingHappendAt(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight)
9629 const MEDCouplingUMesh *mesh(_mesh);
9635 { _left++; _right++; return ; }
9638 bool isLeft(std::find(newLeft.begin(),newLeft.end(),_edge)!=newLeft.end()),isRight(std::find(newRight.begin(),newRight.end(),_edge)!=newRight.end());
9639 if((isLeft && isRight) || (!isLeft && !isRight))
9640 throw INTERP_KERNEL::Exception("EdgeInfo::somethingHappendAt : internal error # 1 !");
9651 bool isLeft(std::find(newLeft.begin(),newLeft.end(),_edge)!=newLeft.end()),isRight(std::find(newRight.begin(),newRight.end(),_edge)!=newRight.end());
9652 if((isLeft && isRight) || (!isLeft && !isRight))
9653 throw INTERP_KERNEL::Exception("EdgeInfo::somethingHappendAt : internal error # 2 !");
9668 void EdgeInfo::feedEdgeInfoAt(double eps, const MEDCouplingUMesh *mesh2D, int offset, int neighbors[2]) const
9670 const MEDCouplingUMesh *mesh(_mesh);
9673 neighbors[0]=offset+_left; neighbors[1]=offset+_right;
9676 {// not fully splitting cell case
9677 if(mesh2D->getNumberOfCells()==1)
9678 {//little optimization. 1 cell no need to find in which cell mesh is !
9679 neighbors[0]=offset; neighbors[1]=offset;
9684 MCAuto<DataArrayDouble> barys(mesh->computeCellCenterOfMass());
9685 int cellId(mesh2D->getCellContainingPoint(barys->begin(),eps));
9687 throw INTERP_KERNEL::Exception("EdgeInfo::feedEdgeInfoAt : internal error !");
9688 neighbors[0]=offset+cellId; neighbors[1]=offset+cellId;
9693 class VectorOfCellInfo
9696 VectorOfCellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr);
9697 std::size_t size() const { return _pool.size(); }
9698 int getPositionOf(double eps, const MEDCouplingUMesh *mesh) const;
9699 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);
9700 const std::vector<int>& getConnOf(int pos) const { return get(pos)._edges; }
9701 const std::vector< MCAuto<INTERP_KERNEL::Edge> >& getEdgePtrOf(int pos) const { return get(pos)._edges_ptr; }
9702 MCAuto<MEDCouplingUMesh> getZeMesh() const { return _ze_mesh; }
9703 void feedEdgeInfoAt(double eps, int pos, int offset, int neighbors[2]) const;
9705 int getZePosOfEdgeGivenItsGlobalId(int pos) const;
9706 void updateEdgeInfo(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight);
9707 const CellInfo& get(int pos) const;
9708 CellInfo& get(int pos);
9710 std::vector<CellInfo> _pool;
9711 MCAuto<MEDCouplingUMesh> _ze_mesh;
9712 std::vector<EdgeInfo> _edge_info;
9715 VectorOfCellInfo::VectorOfCellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr):_pool(1)
9717 _pool[0]._edges=edges;
9718 _pool[0]._edges_ptr=edgesPtr;
9721 int VectorOfCellInfo::getPositionOf(double eps, const MEDCouplingUMesh *mesh) const
9724 throw INTERP_KERNEL::Exception("VectorOfCellSplitter::getPositionOf : empty !");
9727 const MEDCouplingUMesh *zeMesh(_ze_mesh);
9729 throw INTERP_KERNEL::Exception("VectorOfCellSplitter::getPositionOf : null aggregated mesh !");
9730 MCAuto<DataArrayDouble> barys(mesh->computeCellCenterOfMass());
9731 return zeMesh->getCellContainingPoint(barys->begin(),eps);
9734 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)
9736 get(pos);//to check pos
9737 bool isFast(pos==0 && _pool.size()==1);
9738 std::size_t sz(edges.size());
9739 // dealing with edges
9741 _edge_info.push_back(EdgeInfo(istart,iend,mesh1DInCase));
9743 _edge_info.push_back(EdgeInfo(istart,iend,pos,edgePtrs[0].back()));
9745 std::vector<CellInfo> pool(_pool.size()-1+sz);
9746 for(int i=0;i<pos;i++)
9748 for(std::size_t j=0;j<sz;j++)
9749 pool[pos+j]=CellInfo(edges[j],edgePtrs[j]);
9750 for(int i=pos+1;i<(int)_pool.size();i++)
9751 pool[i+sz-1]=_pool[i];
9755 updateEdgeInfo(pos,edgePtrs[0],edgePtrs[1]);
9763 std::vector< MCAuto<MEDCouplingUMesh> > ms;
9766 MCAuto<MEDCouplingUMesh> elt(static_cast<MEDCouplingUMesh *>(_ze_mesh->buildPartOfMySelfSlice(0,pos,true)));
9770 if(pos<_ze_mesh->getNumberOfCells()-1)
9772 MCAuto<MEDCouplingUMesh> elt(static_cast<MEDCouplingUMesh *>(_ze_mesh->buildPartOfMySelfSlice(pos+1,_ze_mesh->getNumberOfCells(),true)));
9775 std::vector< const MEDCouplingUMesh *> ms2(ms.size());
9776 for(std::size_t j=0;j<ms2.size();j++)
9778 _ze_mesh=MEDCouplingUMesh::MergeUMeshesOnSameCoords(ms2);
9781 void VectorOfCellInfo::feedEdgeInfoAt(double eps, int pos, int offset, int neighbors[2]) const
9783 _edge_info[getZePosOfEdgeGivenItsGlobalId(pos)].feedEdgeInfoAt(eps,_ze_mesh,offset,neighbors);
9786 int VectorOfCellInfo::getZePosOfEdgeGivenItsGlobalId(int pos) const
9789 throw INTERP_KERNEL::Exception("VectorOfCellInfo::getZePosOfEdgeGivenItsGlobalId : invalid id ! Must be >=0 !");
9791 for(std::vector<EdgeInfo>::const_iterator it=_edge_info.begin();it!=_edge_info.end();it++,ret++)
9793 if((*it).isInMyRange(pos))
9796 throw INTERP_KERNEL::Exception("VectorOfCellInfo::getZePosOfEdgeGivenItsGlobalId : invalid id !");
9799 void VectorOfCellInfo::updateEdgeInfo(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight)
9801 get(pos);//to check;
9802 if(_edge_info.empty())
9804 std::size_t sz(_edge_info.size()-1);
9805 for(std::size_t i=0;i<sz;i++)
9806 _edge_info[i].somethingHappendAt(pos,newLeft,newRight);
9809 const CellInfo& VectorOfCellInfo::get(int pos) const
9811 if(pos<0 || pos>=(int)_pool.size())
9812 throw INTERP_KERNEL::Exception("VectorOfCellSplitter::get const : invalid pos !");
9816 CellInfo& VectorOfCellInfo::get(int pos)
9818 if(pos<0 || pos>=(int)_pool.size())
9819 throw INTERP_KERNEL::Exception("VectorOfCellSplitter::get : invalid pos !");
9825 * - a \b closed set of edges ( \a allEdges and \a allEdgesPtr ) that defines the split descending 2D cell.
9826 * - \a splitMesh1D a split 2D curve mesh contained into 2D cell defined above.
9828 * This method returns the 2D mesh and feeds \a idsLeftRight using offset.
9830 * Algorithm : \a splitMesh1D is cut into contiguous parts. Each contiguous parts will build incrementally the output 2D cells.
9832 * \param [in] allEdges a list of pairs (beginNode, endNode). Linked with \a allEdgesPtr to get the equation of edge.
9834 MEDCouplingUMesh *BuildMesh2DCutInternal(double eps, const MEDCouplingUMesh *splitMesh1D, const std::vector<int>& allEdges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& allEdgesPtr, int offset,
9835 MCAuto<DataArrayInt>& idsLeftRight)
9837 int nbCellsInSplitMesh1D(splitMesh1D->getNumberOfCells());
9838 if(nbCellsInSplitMesh1D==0)
9839 throw INTERP_KERNEL::Exception("BuildMesh2DCutInternal : internal error ! input 1D mesh must have at least one cell !");
9840 const int *cSplitPtr(splitMesh1D->getNodalConnectivity()->begin()),*ciSplitPtr(splitMesh1D->getNodalConnectivityIndex()->begin());
9841 std::size_t nb(allEdges.size()),jj;
9843 throw INTERP_KERNEL::Exception("BuildMesh2DCutFrom : internal error 2 !");
9844 std::vector<int> edge1Bis(nb*2);
9845 std::vector< MCAuto<INTERP_KERNEL::Edge> > edge1BisPtr(nb*2);
9846 std::copy(allEdges.begin(),allEdges.end(),edge1Bis.begin());
9847 std::copy(allEdges.begin(),allEdges.end(),edge1Bis.begin()+nb);
9848 std::copy(allEdgesPtr.begin(),allEdgesPtr.end(),edge1BisPtr.begin());
9849 std::copy(allEdgesPtr.begin(),allEdgesPtr.end(),edge1BisPtr.begin()+nb);
9851 idsLeftRight=DataArrayInt::New(); idsLeftRight->alloc(nbCellsInSplitMesh1D*2); idsLeftRight->fillWithValue(-2); idsLeftRight->rearrange(2);
9852 int *idsLeftRightPtr(idsLeftRight->getPointer());
9853 VectorOfCellInfo pool(edge1Bis,edge1BisPtr);
9854 for(int iStart=0;iStart<nbCellsInSplitMesh1D;)
9855 {// split [0:nbCellsInSplitMesh1D) in contiguous parts [iStart:iEnd)
9857 for(;iEnd<nbCellsInSplitMesh1D;)
9859 for(jj=0;jj<nb && edge1Bis[2*jj+1]!=cSplitPtr[ciSplitPtr[iEnd]+2];jj++);
9865 if(iEnd<nbCellsInSplitMesh1D)
9868 MCAuto<MEDCouplingUMesh> partOfSplitMesh1D(static_cast<MEDCouplingUMesh *>(splitMesh1D->buildPartOfMySelfSlice(iStart,iEnd,1,true)));
9869 int pos(pool.getPositionOf(eps,partOfSplitMesh1D));
9871 MCAuto<MEDCouplingUMesh>retTmp(MEDCouplingUMesh::New("",2));
9872 retTmp->setCoords(splitMesh1D->getCoords());
9873 retTmp->allocateCells();
9875 std::vector< std::vector<int> > out0;
9876 std::vector< std::vector< MCAuto<INTERP_KERNEL::Edge> > > out1;
9878 BuildMesh2DCutInternal2(partOfSplitMesh1D,pool.getConnOf(pos),pool.getEdgePtrOf(pos),out0,out1);
9879 for(std::size_t cnt=0;cnt<out0.size();cnt++)
9880 AddCellInMesh2D(retTmp,out0[cnt],out1[cnt]);
9881 pool.setMeshAt(pos,retTmp,iStart,iEnd,partOfSplitMesh1D,out0,out1);
9885 for(int mm=0;mm<nbCellsInSplitMesh1D;mm++)
9886 pool.feedEdgeInfoAt(eps,mm,offset,idsLeftRightPtr+2*mm);
9887 return pool.getZeMesh().retn();
9890 MEDCouplingUMesh *BuildMesh2DCutFrom(double eps, int cellIdInMesh2D, const MEDCouplingUMesh *mesh2DDesc, const MEDCouplingUMesh *splitMesh1D,
9891 const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1, int offset,
9892 MCAuto<DataArrayInt>& idsLeftRight)
9894 const int *cdescPtr(mesh2DDesc->getNodalConnectivity()->begin()),*cidescPtr(mesh2DDesc->getNodalConnectivityIndex()->begin());
9896 std::vector<int> allEdges;
9897 std::vector< MCAuto<INTERP_KERNEL::Edge> > allEdgesPtr; // for each sub edge in splitMesh2D the uncut Edge object of the original mesh2D
9898 for(const int *it(descBg);it!=descEnd;it++) // for all edges in the descending connectivity of the 2D mesh in relative Fortran mode
9900 int edgeId(std::abs(*it)-1);
9901 std::map< MCAuto<INTERP_KERNEL::Node>,int> m;
9902 MCAuto<INTERP_KERNEL::Edge> ee(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)cdescPtr[cidescPtr[edgeId]],cdescPtr+cidescPtr[edgeId]+1,mesh2DDesc->getCoords()->begin(),m));
9903 const std::vector<int>& edge1(intersectEdge1[edgeId]);
9905 allEdges.insert(allEdges.end(),edge1.begin(),edge1.end());
9907 allEdges.insert(allEdges.end(),edge1.rbegin(),edge1.rend());
9908 std::size_t sz(edge1.size());
9909 for(std::size_t cnt=0;cnt<sz;cnt++)
9910 allEdgesPtr.push_back(ee);
9913 return BuildMesh2DCutInternal(eps,splitMesh1D,allEdges,allEdgesPtr,offset,idsLeftRight);
9916 bool AreEdgeEqual(const double *coo2D, const INTERP_KERNEL::CellModel& typ1, const int *conn1, const INTERP_KERNEL::CellModel& typ2, const int *conn2, double eps)
9918 if(!typ1.isQuadratic() && !typ2.isQuadratic())
9919 {//easy case comparison not
9920 return conn1[0]==conn2[0] && conn1[1]==conn2[1];
9922 else if(typ1.isQuadratic() && typ2.isQuadratic())
9924 bool status0(conn1[0]==conn2[0] && conn1[1]==conn2[1]);
9927 if(conn1[2]==conn2[2])
9929 const double *a(coo2D+2*conn1[2]),*b(coo2D+2*conn2[2]);
9930 double dist(sqrt((a[0]-b[0])*(a[0]-b[0])+(a[1]-b[1])*(a[1]-b[1])));
9934 {//only one is quadratic
9935 bool status0(conn1[0]==conn2[0] && conn1[1]==conn2[1]);
9938 const double *a(0),*bb(0),*be(0);
9939 if(typ1.isQuadratic())
9941 a=coo2D+2*conn1[2]; bb=coo2D+2*conn2[0]; be=coo2D+2*conn2[1];
9945 a=coo2D+2*conn2[2]; bb=coo2D+2*conn1[0]; be=coo2D+2*conn1[1];
9947 double b[2]; b[0]=(be[0]+bb[0])/2.; b[1]=(be[1]+bb[1])/2.;
9948 double dist(sqrt((a[0]-b[0])*(a[0]-b[0])+(a[1]-b[1])*(a[1]-b[1])));
9954 * This method returns among the cellIds [ \a candidatesIn2DBg , \a candidatesIn2DEnd ) in \a mesh2DSplit those exactly sharing \a cellIdInMesh1DSplitRelative in \a mesh1DSplit.
9955 * \a mesh2DSplit and \a mesh1DSplit are expected to share the coordinates array.
9957 * \param [in] cellIdInMesh1DSplitRelative is in Fortran mode using sign to specify direction.
9959 int FindRightCandidateAmong(const MEDCouplingUMesh *mesh2DSplit, const int *candidatesIn2DBg, const int *candidatesIn2DEnd, const MEDCouplingUMesh *mesh1DSplit, int cellIdInMesh1DSplitRelative, double eps)
9961 if(candidatesIn2DEnd==candidatesIn2DBg)
9962 throw INTERP_KERNEL::Exception("FindRightCandidateAmong : internal error 1 !");
9963 const double *coo(mesh2DSplit->getCoords()->begin());
9964 if(std::distance(candidatesIn2DBg,candidatesIn2DEnd)==1)
9965 return *candidatesIn2DBg;
9966 int edgeId(std::abs(cellIdInMesh1DSplitRelative)-1);
9967 MCAuto<MEDCouplingUMesh> cur1D(static_cast<MEDCouplingUMesh *>(mesh1DSplit->buildPartOfMySelf(&edgeId,&edgeId+1,true)));
9968 if(cellIdInMesh1DSplitRelative<0)
9969 cur1D->changeOrientationOfCells();
9970 const int *c1D(cur1D->getNodalConnectivity()->begin());
9971 const INTERP_KERNEL::CellModel& ref1DType(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c1D[0]));
9972 for(const int *it=candidatesIn2DBg;it!=candidatesIn2DEnd;it++)
9974 MCAuto<MEDCouplingUMesh> cur2D(static_cast<MEDCouplingUMesh *>(mesh2DSplit->buildPartOfMySelf(it,it+1,true)));
9975 const int *c(cur2D->getNodalConnectivity()->begin()),*ci(cur2D->getNodalConnectivityIndex()->begin());
9976 const INTERP_KERNEL::CellModel &cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c[ci[0]]));
9977 unsigned sz(cm.getNumberOfSons2(c+ci[0]+1,ci[1]-ci[0]-1));
9978 INTERP_KERNEL::AutoPtr<int> tmpPtr(new int[ci[1]-ci[0]]);
9979 for(unsigned it2=0;it2<sz;it2++)
9981 INTERP_KERNEL::NormalizedCellType typeOfSon;
9982 cm.fillSonCellNodalConnectivity2(it2,c+ci[0]+1,ci[1]-ci[0]-1,tmpPtr,typeOfSon);
9983 const INTERP_KERNEL::CellModel &curCM(INTERP_KERNEL::CellModel::GetCellModel(typeOfSon));
9984 if(AreEdgeEqual(coo,ref1DType,c1D+1,curCM,tmpPtr,eps))
9988 throw INTERP_KERNEL::Exception("FindRightCandidateAmong : internal error 2 ! Unable to find the edge among split cell !");
9994 * Partitions the first given 2D mesh using the second given 1D mesh as a tool.
9995 * 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
9996 * and finaly, in case of quadratic polygon the centers of edges new nodes.
9997 * The meshes should be in 2D space. In addition, returns two arrays mapping cells of the resulting mesh to cells of the input.
9999 * \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
10000 * 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)
10001 * \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
10002 * you can invoke orderConsecutiveCells1D on \a mesh1D.
10003 * \param [in] eps - precision used to perform intersections and localization operations.
10004 * \param [out] splitMesh2D - the result of the split of \a mesh2D mesh.
10005 * \param [out] splitMesh1D - the result of the split of \a mesh1D mesh.
10006 * \param [out] cellIdInMesh2D - the array that gives for each cell id \a i in \a splitMesh2D the id in \a mesh2D it comes from.
10007 * 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.
10008 * \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
10009 * and the cell in \a splitMesh2D on the right for the 2nt component. -1 means no cell.
10010 * 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.
10012 * \sa Intersect2DMeshes, orderConsecutiveCells1D, conformize2D, mergeNodes
10014 void MEDCouplingUMesh::Intersect2DMeshWith1DLine(const MEDCouplingUMesh *mesh2D, const MEDCouplingUMesh *mesh1D, double eps, MEDCouplingUMesh *&splitMesh2D, MEDCouplingUMesh *&splitMesh1D, DataArrayInt *&cellIdInMesh2D, DataArrayInt *&cellIdInMesh1D)
10016 if(!mesh2D || !mesh1D)
10017 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshWith1DLine : input meshes must be not NULL !");
10018 mesh2D->checkFullyDefined();
10019 mesh1D->checkFullyDefined();
10020 const std::vector<std::string>& compNames(mesh2D->getCoords()->getInfoOnComponents());
10021 if(mesh2D->getMeshDimension()!=2 || mesh2D->getSpaceDimension()!=2 || mesh1D->getMeshDimension()!=1 || mesh1D->getSpaceDimension()!=2)
10022 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshWith1DLine works with mesh2D with spacedim=meshdim=2 and mesh1D with meshdim=1 spaceDim=2 !");
10023 // Step 1: compute all edge intersections (new nodes)
10024 std::vector< std::vector<int> > intersectEdge1, colinear2, subDiv2;
10025 std::vector<double> addCoo,addCoordsQuadratic; // coordinates of newly created nodes
10026 INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
10027 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
10029 // Build desc connectivity
10030 DataArrayInt *desc1(DataArrayInt::New()),*descIndx1(DataArrayInt::New()),*revDesc1(DataArrayInt::New()),*revDescIndx1(DataArrayInt::New());
10031 MCAuto<DataArrayInt> dd1(desc1),dd2(descIndx1),dd3(revDesc1),dd4(revDescIndx1);
10032 MCAuto<MEDCouplingUMesh> m1Desc(mesh2D->buildDescendingConnectivity2(desc1,descIndx1,revDesc1,revDescIndx1));
10033 std::map<int,int> mergedNodes;
10034 Intersect1DMeshes(m1Desc,mesh1D,eps,intersectEdge1,colinear2,subDiv2,addCoo,mergedNodes);
10035 // use mergeNodes to fix intersectEdge1
10036 for(std::vector< std::vector<int> >::iterator it0=intersectEdge1.begin();it0!=intersectEdge1.end();it0++)
10038 std::size_t n((*it0).size()/2);
10039 int eltStart((*it0)[0]),eltEnd((*it0)[2*n-1]);
10040 std::map<int,int>::const_iterator it1;
10041 it1=mergedNodes.find(eltStart);
10042 if(it1!=mergedNodes.end())
10043 (*it0)[0]=(*it1).second;
10044 it1=mergedNodes.find(eltEnd);
10045 if(it1!=mergedNodes.end())
10046 (*it0)[2*n-1]=(*it1).second;
10049 MCAuto<DataArrayDouble> addCooDa(DataArrayDouble::New());
10050 addCooDa->useArray(&addCoo[0],false,C_DEALLOC,(int)addCoo.size()/2,2);
10051 // Step 2: re-order newly created nodes according to the ordering found in m2
10052 std::vector< std::vector<int> > intersectEdge2;
10053 BuildIntersectEdges(m1Desc,mesh1D,addCoo,subDiv2,intersectEdge2);
10055 // Step 3: compute splitMesh1D
10056 MCAuto<DataArrayInt> idsInRet1Colinear,idsInDescMesh2DForIdsInRetColinear;
10057 MCAuto<DataArrayInt> ret2(DataArrayInt::New()); ret2->alloc(0,1);
10058 MCAuto<MEDCouplingUMesh> ret1(BuildMesh1DCutFrom(mesh1D,intersectEdge2,mesh2D->getCoords(),addCoo,mergedNodes,colinear2,intersectEdge1,
10059 idsInRet1Colinear,idsInDescMesh2DForIdsInRetColinear));
10060 MCAuto<DataArrayInt> ret3(DataArrayInt::New()); ret3->alloc(ret1->getNumberOfCells()*2,1); ret3->fillWithValue(std::numeric_limits<int>::max()); ret3->rearrange(2);
10061 MCAuto<DataArrayInt> idsInRet1NotColinear(idsInRet1Colinear->buildComplement(ret1->getNumberOfCells()));
10062 // deal with cells in mesh2D that are not cut but only some of their edges are
10063 MCAuto<DataArrayInt> idsInDesc2DToBeRefined(idsInDescMesh2DForIdsInRetColinear->deepCopy());
10064 idsInDesc2DToBeRefined->abs(); idsInDesc2DToBeRefined->applyLin(1,-1);
10065 idsInDesc2DToBeRefined=idsInDesc2DToBeRefined->buildUnique();
10066 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
10067 if(!idsInDesc2DToBeRefined->empty())
10069 DataArrayInt *out0(0),*outi0(0);
10070 MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
10071 MCAuto<DataArrayInt> outi0s(outi0);
10073 out0s=out0s->buildUnique();
10077 MCAuto<MEDCouplingUMesh> ret1NonCol(static_cast<MEDCouplingUMesh *>(ret1->buildPartOfMySelf(idsInRet1NotColinear->begin(),idsInRet1NotColinear->end())));
10078 MCAuto<DataArrayDouble> baryRet1(ret1NonCol->computeCellCenterOfMass());
10079 MCAuto<DataArrayInt> elts,eltsIndex;
10080 mesh2D->getCellsContainingPoints(baryRet1->begin(),baryRet1->getNumberOfTuples(),eps,elts,eltsIndex);
10081 MCAuto<DataArrayInt> eltsIndex2(eltsIndex->deltaShiftIndex());
10082 MCAuto<DataArrayInt> eltsIndex3(eltsIndex2->findIdsEqual(1));
10083 if(eltsIndex2->count(0)+eltsIndex3->getNumberOfTuples()!=ret1NonCol->getNumberOfCells())
10084 throw INTERP_KERNEL::Exception("Intersect2DMeshWith1DLine : internal error 1 !");
10085 MCAuto<DataArrayInt> cellsToBeModified(elts->buildUnique());
10086 MCAuto<DataArrayInt> untouchedCells(cellsToBeModified->buildComplement(mesh2D->getNumberOfCells()));
10087 if((DataArrayInt *)out0s)
10088 untouchedCells=untouchedCells->buildSubstraction(out0s);//if some edges in ret1 are colinear to descending mesh of mesh2D remove cells from untouched one
10089 std::vector< MCAuto<MEDCouplingUMesh> > outMesh2DSplit;
10090 // OK all is ready to insert in ret2 mesh
10091 if(!untouchedCells->empty())
10092 {// the most easy part, cells in mesh2D not impacted at all
10093 outMesh2DSplit.push_back(static_cast<MEDCouplingUMesh *>(mesh2D->buildPartOfMySelf(untouchedCells->begin(),untouchedCells->end())));
10094 outMesh2DSplit.back()->setCoords(ret1->getCoords());
10095 ret2->pushBackValsSilent(untouchedCells->begin(),untouchedCells->end());
10097 if((DataArrayInt *)out0s)
10098 {// here dealing with cells in out0s but not in cellsToBeModified
10099 MCAuto<DataArrayInt> fewModifiedCells(out0s->buildSubstraction(cellsToBeModified));
10100 const int *rdptr(dd3->begin()),*rdiptr(dd4->begin()),*dptr(dd1->begin()),*diptr(dd2->begin());
10101 for(const int *it=fewModifiedCells->begin();it!=fewModifiedCells->end();it++)
10103 outMesh2DSplit.push_back(BuildRefined2DCell(ret1->getCoords(),mesh2D,*it,dptr+diptr[*it],dptr+diptr[*it+1],intersectEdge1));
10104 ret1->setCoords(outMesh2DSplit.back()->getCoords());
10106 int offset(ret2->getNumberOfTuples());
10107 ret2->pushBackValsSilent(fewModifiedCells->begin(),fewModifiedCells->end());
10108 MCAuto<DataArrayInt> partOfRet3(DataArrayInt::New()); partOfRet3->alloc(2*idsInRet1Colinear->getNumberOfTuples(),1);
10109 partOfRet3->fillWithValue(std::numeric_limits<int>::max()); partOfRet3->rearrange(2);
10110 int kk(0),*ret3ptr(partOfRet3->getPointer());
10111 for(const int *it=idsInDescMesh2DForIdsInRetColinear->begin();it!=idsInDescMesh2DForIdsInRetColinear->end();it++,kk++)
10113 int faceId(std::abs(*it)-1);
10114 for(const int *it2=rdptr+rdiptr[faceId];it2!=rdptr+rdiptr[faceId+1];it2++)
10116 int tmp(fewModifiedCells->findIdFirstEqual(*it2));
10119 if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],-(*it))!=dptr+diptr[*it2+1])
10120 ret3ptr[2*kk]=tmp+offset;
10121 if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],(*it))!=dptr+diptr[*it2+1])
10122 ret3ptr[2*kk+1]=tmp+offset;
10125 {//the current edge is shared by a 2D cell that will be split just after
10126 if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],-(*it))!=dptr+diptr[*it2+1])
10127 ret3ptr[2*kk]=-(*it2+1);
10128 if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],(*it))!=dptr+diptr[*it2+1])
10129 ret3ptr[2*kk+1]=-(*it2+1);
10133 m1Desc->setCoords(ret1->getCoords());
10134 ret1NonCol->setCoords(ret1->getCoords());
10135 ret3->setPartOfValues3(partOfRet3,idsInRet1Colinear->begin(),idsInRet1Colinear->end(),0,2,1,true);
10136 if(!outMesh2DSplit.empty())
10138 DataArrayDouble *da(outMesh2DSplit.back()->getCoords());
10139 for(std::vector< MCAuto<MEDCouplingUMesh> >::iterator itt=outMesh2DSplit.begin();itt!=outMesh2DSplit.end();itt++)
10140 (*itt)->setCoords(da);
10143 cellsToBeModified=cellsToBeModified->buildUniqueNotSorted();
10144 for(const int *it=cellsToBeModified->begin();it!=cellsToBeModified->end();it++)
10146 MCAuto<DataArrayInt> idsNonColPerCell(elts->findIdsEqual(*it));
10147 idsNonColPerCell->transformWithIndArr(eltsIndex3->begin(),eltsIndex3->end());
10148 MCAuto<DataArrayInt> idsNonColPerCell2(idsInRet1NotColinear->selectByTupleId(idsNonColPerCell->begin(),idsNonColPerCell->end()));
10149 MCAuto<MEDCouplingUMesh> partOfMesh1CuttingCur2DCell(static_cast<MEDCouplingUMesh *>(ret1NonCol->buildPartOfMySelf(idsNonColPerCell->begin(),idsNonColPerCell->end())));
10150 MCAuto<DataArrayInt> partOfRet3;
10151 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));
10152 ret3->setPartOfValues3(partOfRet3,idsNonColPerCell2->begin(),idsNonColPerCell2->end(),0,2,1,true);
10153 outMesh2DSplit.push_back(splitOfOneCell);
10154 for(int i=0;i<splitOfOneCell->getNumberOfCells();i++)
10155 ret2->pushBackSilent(*it);
10158 std::size_t nbOfMeshes(outMesh2DSplit.size());
10159 std::vector<const MEDCouplingUMesh *> tmp(nbOfMeshes);
10160 for(std::size_t i=0;i<nbOfMeshes;i++)
10161 tmp[i]=outMesh2DSplit[i];
10163 ret1->getCoords()->setInfoOnComponents(compNames);
10164 MCAuto<MEDCouplingUMesh> ret2D(MEDCouplingUMesh::MergeUMeshesOnSameCoords(tmp));
10165 // To finish - filter ret3 - std::numeric_limits<int>::max() -> -1 - negate values must be resolved.
10166 ret3->rearrange(1);
10167 MCAuto<DataArrayInt> edgesToDealWith(ret3->findIdsStricltyNegative());
10168 for(const int *it=edgesToDealWith->begin();it!=edgesToDealWith->end();it++)
10170 int old2DCellId(-ret3->getIJ(*it,0)-1);
10171 MCAuto<DataArrayInt> candidates(ret2->findIdsEqual(old2DCellId));
10172 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
10174 ret3->changeValue(std::numeric_limits<int>::max(),-1);
10175 ret3->rearrange(2);
10177 splitMesh1D=ret1.retn();
10178 splitMesh2D=ret2D.retn();
10179 cellIdInMesh2D=ret2.retn();
10180 cellIdInMesh1D=ret3.retn();
10184 * Private. Third step of the partitioning algorithm (Intersect2DMeshes): reconstruct full 2D cells from the
10185 * (newly created) nodes corresponding to the edge intersections.
10187 * @param[out] cr, crI connectivity of the resulting mesh
10188 * @param[out] cNb1, cNb2 correspondance arrays giving for the merged mesh the initial cells IDs in m1 / m2
10189 * TODO: describe input parameters
10191 void MEDCouplingUMesh::BuildIntersecting2DCellsFromEdges(double eps, const MEDCouplingUMesh *m1, const int *desc1, const int *descIndx1,
10192 const std::vector<std::vector<int> >& intesctEdges1, const std::vector< std::vector<int> >& colinear2,
10193 const MEDCouplingUMesh *m2, const int *desc2, const int *descIndx2, const std::vector<std::vector<int> >& intesctEdges2,
10194 const std::vector<double>& addCoords,
10195 std::vector<double>& addCoordsQuadratic, std::vector<int>& cr, std::vector<int>& crI, std::vector<int>& cNb1, std::vector<int>& cNb2)
10197 static const int SPACEDIM=2;
10198 const double *coo1(m1->getCoords()->begin());
10199 const int *conn1(m1->getNodalConnectivity()->begin()),*connI1(m1->getNodalConnectivityIndex()->begin());
10200 int offset1(m1->getNumberOfNodes());
10201 const double *coo2(m2->getCoords()->begin());
10202 const int *conn2(m2->getNodalConnectivity()->begin()),*connI2(m2->getNodalConnectivityIndex()->begin());
10203 int offset2(offset1+m2->getNumberOfNodes());
10204 int offset3(offset2+((int)addCoords.size())/2);
10205 MCAuto<DataArrayDouble> bbox1Arr(m1->getBoundingBoxForBBTree()),bbox2Arr(m2->getBoundingBoxForBBTree());
10206 const double *bbox1(bbox1Arr->begin()),*bbox2(bbox2Arr->begin());
10207 // Here a BBTree on 2D-cells, not on segments:
10208 BBTree<SPACEDIM,int> myTree(bbox2,0,0,m2->getNumberOfCells(),eps);
10209 int ncell1(m1->getNumberOfCells());
10211 for(int i=0;i<ncell1;i++)
10213 std::vector<int> candidates2;
10214 myTree.getIntersectingElems(bbox1+i*2*SPACEDIM,candidates2);
10215 std::map<INTERP_KERNEL::Node *,int> mapp;
10216 std::map<int,INTERP_KERNEL::Node *> mappRev;
10217 INTERP_KERNEL::QuadraticPolygon pol1;
10218 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn1[connI1[i]];
10219 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
10220 // Populate mapp and mappRev with nodes from the current cell (i) from mesh1 - this also builds the Node* objects:
10221 MEDCouplingUMeshBuildQPFromMesh3(coo1,offset1,coo2,offset2,addCoords,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,/* output */mapp,mappRev);
10222 // pol1 is the full cell from mesh2, in QP format, with all the additional intersecting nodes.
10223 pol1.buildFromCrudeDataArray(mappRev,cm.isQuadratic(),conn1+connI1[i]+1,coo1,
10224 desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1);
10226 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
10227 std::set<INTERP_KERNEL::Edge *> edgesBoundary2;// store all edges that are on boundary of (pol2 intersect pol1) minus edges on pol1.
10228 INTERP_KERNEL::IteratorOnComposedEdge it1(&pol1);
10229 for(it1.first();!it1.finished();it1.next())
10230 edges1.insert(it1.current()->getPtr());
10232 std::map<int,std::vector<INTERP_KERNEL::ElementaryEdge *> > edgesIn2ForShare; // common edges
10233 std::vector<INTERP_KERNEL::QuadraticPolygon> pol2s(candidates2.size());
10235 for(std::vector<int>::const_iterator it2=candidates2.begin();it2!=candidates2.end();it2++,ii++)
10237 INTERP_KERNEL::NormalizedCellType typ2=(INTERP_KERNEL::NormalizedCellType)conn2[connI2[*it2]];
10238 const INTERP_KERNEL::CellModel& cm2=INTERP_KERNEL::CellModel::GetCellModel(typ2);
10239 // Complete mapping with elements coming from the current cell it2 in mesh2:
10240 MEDCouplingUMeshBuildQPFromMesh3(coo1,offset1,coo2,offset2,addCoords,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,/* output */mapp,mappRev);
10241 // pol2 is the new QP in the final merged result.
10242 pol2s[ii].buildFromCrudeDataArray2(mappRev,cm2.isQuadratic(),conn2+connI2[*it2]+1,coo2,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,
10243 pol1,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,colinear2, /* output */ edgesIn2ForShare);
10246 for(std::vector<int>::const_iterator it2=candidates2.begin();it2!=candidates2.end();it2++,ii++)
10248 INTERP_KERNEL::ComposedEdge::InitLocationsWithOther(pol1,pol2s[ii]);
10249 pol2s[ii].updateLocOfEdgeFromCrudeDataArray2(desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,pol1,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,colinear2);
10250 //MEDCouplingUMeshAssignOnLoc(pol1,pol2,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,colinear2);
10251 pol1.buildPartitionsAbs(pol2s[ii],edges1,edgesBoundary2,mapp,i,*it2,offset3,addCoordsQuadratic,cr,crI,cNb1,cNb2);
10253 // Deals with remaining (non-consumed) edges from m1: these are the edges that were never touched
10254 // by m2 but that we still want to keep in the final result.
10255 if(!edges1.empty())
10259 INTERP_KERNEL::QuadraticPolygon::ComputeResidual(pol1,edges1,edgesBoundary2,mapp,offset3,i,addCoordsQuadratic,cr,crI,cNb1,cNb2);
10261 catch(INTERP_KERNEL::Exception& e)
10263 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();
10264 throw INTERP_KERNEL::Exception(oss.str());
10267 for(std::map<int,INTERP_KERNEL::Node *>::const_iterator it=mappRev.begin();it!=mappRev.end();it++)
10268 (*it).second->decrRef();
10273 * Provides a renumbering of the cells of this (which has to be a piecewise connected 1D line), so that
10274 * the segments of the line are indexed in consecutive order (i.e. cells \a i and \a i+1 are neighbors).
10275 * This doesn't modify the mesh. This method only works using nodal connectivity consideration. Coordinates of nodes are ignored here.
10276 * The caller is to deal with the resulting DataArrayInt.
10277 * \throw If the coordinate array is not set.
10278 * \throw If the nodal connectivity of the cells is not defined.
10279 * \throw If m1 is not a mesh of dimension 2, or m1 is not a mesh of dimension 1
10280 * \throw If m2 is not a (piecewise) line (i.e. if a point has more than 2 adjacent segments)
10282 * \sa DataArrayInt::sortEachPairToMakeALinkedList
10284 DataArrayInt *MEDCouplingUMesh::orderConsecutiveCells1D() const
10286 checkFullyDefined();
10287 if(getMeshDimension()!=1)
10288 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D works on unstructured mesh with meshdim = 1 !");
10290 // Check that this is a line (and not a more complex 1D mesh) - each point is used at most by 2 segments:
10291 MCAuto<DataArrayInt> _d(DataArrayInt::New()),_dI(DataArrayInt::New());
10292 MCAuto<DataArrayInt> _rD(DataArrayInt::New()),_rDI(DataArrayInt::New());
10293 MCAuto<MEDCouplingUMesh> m_points(buildDescendingConnectivity(_d, _dI, _rD, _rDI));
10294 const int *d(_d->begin()), *dI(_dI->begin());
10295 const int *rD(_rD->begin()), *rDI(_rDI->begin());
10296 MCAuto<DataArrayInt> _dsi(_rDI->deltaShiftIndex());
10297 const int * dsi(_dsi->begin());
10298 MCAuto<DataArrayInt> dsii = _dsi->findIdsNotInRange(0,3);
10300 if (dsii->getNumberOfTuples())
10301 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D only work with a mesh being a (piecewise) connected line!");
10303 int nc(getNumberOfCells());
10304 MCAuto<DataArrayInt> result(DataArrayInt::New());
10305 result->alloc(nc,1);
10307 // set of edges not used so far
10308 std::set<int> edgeSet;
10309 for (int i=0; i<nc; edgeSet.insert(i), i++);
10313 // while we have points with only one neighbor segments
10316 std::list<int> linePiece;
10317 // fills a list of consecutive segment linked to startSeg. This can go forward or backward.
10318 for (int direction=0;direction<2;direction++) // direction=0 --> forward, direction=1 --> backward
10320 // Fill the list forward (resp. backward) from the start segment:
10321 int activeSeg = startSeg;
10322 int prevPointId = -20;
10324 while (!edgeSet.empty())
10326 if (!(direction == 1 && prevPointId==-20)) // prevent adding twice startSeg
10329 linePiece.push_back(activeSeg);
10331 linePiece.push_front(activeSeg);
10332 edgeSet.erase(activeSeg);
10335 int ptId1 = d[dI[activeSeg]], ptId2 = d[dI[activeSeg]+1];
10336 ptId = direction ? (ptId1 == prevPointId ? ptId2 : ptId1) : (ptId2 == prevPointId ? ptId1 : ptId2);
10337 if (dsi[ptId] == 1) // hitting the end of the line
10339 prevPointId = ptId;
10340 int seg1 = rD[rDI[ptId]], seg2 = rD[rDI[ptId]+1];
10341 activeSeg = (seg1 == activeSeg) ? seg2 : seg1;
10344 // Done, save final piece into DA:
10345 std::copy(linePiece.begin(), linePiece.end(), result->getPointer()+newIdx);
10346 newIdx += linePiece.size();
10348 // identify next valid start segment (one which is not consumed)
10349 if(!edgeSet.empty())
10350 startSeg = *(edgeSet.begin());
10352 while (!edgeSet.empty());
10353 return result.retn();
10358 void IKGeo2DInternalMapper2(INTERP_KERNEL::Node *n, const std::map<MCAuto<INTERP_KERNEL::Node>,int>& m, int forbVal0, int forbVal1, std::vector<int>& isect)
10360 MCAuto<INTERP_KERNEL::Node> nTmp(n); nTmp->incrRef();
10361 std::map<MCAuto<INTERP_KERNEL::Node>,int>::const_iterator it(m.find(nTmp));
10363 throw INTERP_KERNEL::Exception("Internal error in remapping !");
10364 int v((*it).second);
10365 if(v==forbVal0 || v==forbVal1)
10367 if(std::find(isect.begin(),isect.end(),v)==isect.end())
10368 isect.push_back(v);
10371 bool IKGeo2DInternalMapper(const INTERP_KERNEL::ComposedEdge& c, const std::map<MCAuto<INTERP_KERNEL::Node>,int>& m, int forbVal0, int forbVal1, std::vector<int>& isect)
10376 bool presenceOfOn(false);
10377 for(int i=0;i<sz;i++)
10379 INTERP_KERNEL::ElementaryEdge *e(c[i]);
10380 if(e->getLoc()!=INTERP_KERNEL::FULL_ON_1)
10382 IKGeo2DInternalMapper2(e->getStartNode(),m,forbVal0,forbVal1,isect);
10383 IKGeo2DInternalMapper2(e->getEndNode(),m,forbVal0,forbVal1,isect);
10385 return presenceOfOn;
10391 * This method split some of edges of 2D cells in \a this. The edges to be split are specified in \a subNodesInSeg
10392 * and in \a subNodesInSegI using \ref numbering-indirect storage mode.
10393 * To do the work this method can optionally needs information about middle of subedges for quadratic cases if
10394 * a minimal creation of new nodes is wanted.
10395 * So this method try to reduce at most the number of new nodes. The only case that can lead this method to add
10396 * nodes if a SEG3 is split without information of middle.
10397 * \b WARNING : is returned value is different from 0 a call to MEDCouplingUMesh::mergeNodes is necessary to
10398 * avoid to have a non conform mesh.
10400 * \return int - the number of new nodes created (in most of cases 0).
10402 * \throw If \a this is not coherent.
10403 * \throw If \a this has not spaceDim equal to 2.
10404 * \throw If \a this has not meshDim equal to 2.
10405 * \throw If some subcells needed to be split are orphan.
10406 * \sa MEDCouplingUMesh::conformize2D
10408 int MEDCouplingUMesh::split2DCells(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI, const DataArrayInt *midOpt, const DataArrayInt *midOptI)
10410 if(!desc || !descI || !subNodesInSeg || !subNodesInSegI)
10411 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : the 4 first arrays must be not null !");
10412 desc->checkAllocated(); descI->checkAllocated(); subNodesInSeg->checkAllocated(); subNodesInSegI->checkAllocated();
10413 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
10414 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : This method only works for meshes with spaceDim=2 and meshDim=2 !");
10415 if(midOpt==0 && midOptI==0)
10417 split2DCellsLinear(desc,descI,subNodesInSeg,subNodesInSegI);
10420 else if(midOpt!=0 && midOptI!=0)
10421 return split2DCellsQuadratic(desc,descI,subNodesInSeg,subNodesInSegI,midOpt,midOptI);
10423 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : middle parameters must be set to null for all or not null for all.");
10427 * \b WARNING this method is \b potentially \b non \b const (if returned array is empty).
10428 * \b WARNING this method lead to have a non geometric type sorted mesh (for MED file users) !
10429 * 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
10430 * 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).
10431 * 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.
10433 * Whatever the returned value, this method does not alter the order of cells in \a this neither the orientation of cells.
10434 * The modified cells, if any, are systematically declared as NORM_POLYGON or NORM_QPOLYG depending on the initial quadraticness of geometric type.
10436 * This method expects that \b this has a meshDim equal 2 and spaceDim equal to 2 too.
10437 * This method expects that all nodes in \a this are not closer than \a eps.
10438 * If it is not the case you can invoke MEDCouplingUMesh::mergeNodes before calling this method.
10440 * \param [in] eps the relative error to detect merged edges.
10441 * \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
10442 * that the user is expected to deal with.
10444 * \throw If \a this is not coherent.
10445 * \throw If \a this has not spaceDim equal to 2.
10446 * \throw If \a this has not meshDim equal to 2.
10447 * \sa MEDCouplingUMesh::mergeNodes, MEDCouplingUMesh::split2DCells
10449 DataArrayInt *MEDCouplingUMesh::conformize2D(double eps)
10451 static const int SPACEDIM=2;
10452 checkConsistencyLight();
10453 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
10454 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::conformize2D : This method only works for meshes with spaceDim=2 and meshDim=2 !");
10455 MCAuto<DataArrayInt> desc1(DataArrayInt::New()),descIndx1(DataArrayInt::New()),revDesc1(DataArrayInt::New()),revDescIndx1(DataArrayInt::New());
10456 MCAuto<MEDCouplingUMesh> mDesc(buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));
10457 const int *c(mDesc->getNodalConnectivity()->begin()),*ci(mDesc->getNodalConnectivityIndex()->begin()),*rd(revDesc1->begin()),*rdi(revDescIndx1->begin());
10458 MCAuto<DataArrayDouble> bboxArr(mDesc->getBoundingBoxForBBTree());
10459 const double *bbox(bboxArr->begin()),*coords(getCoords()->begin());
10460 int nCell(getNumberOfCells()),nDescCell(mDesc->getNumberOfCells());
10461 std::vector< std::vector<int> > intersectEdge(nDescCell),overlapEdge(nDescCell);
10462 std::vector<double> addCoo;
10463 BBTree<SPACEDIM,int> myTree(bbox,0,0,nDescCell,-eps);
10464 INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
10465 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
10466 for(int i=0;i<nDescCell;i++)
10468 std::vector<int> candidates;
10469 myTree.getIntersectingElems(bbox+i*2*SPACEDIM,candidates);
10470 for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
10473 std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
10474 INTERP_KERNEL::Edge *e1(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[i]],c+ci[i]+1,coords,m)),
10475 *e2(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[*it]],c+ci[*it]+1,coords,m));
10476 INTERP_KERNEL::MergePoints merge;
10477 INTERP_KERNEL::QuadraticPolygon c1,c2;
10478 e1->intersectWith(e2,merge,c1,c2);
10479 e1->decrRef(); e2->decrRef();
10480 if(IKGeo2DInternalMapper(c1,m,c[ci[i]+1],c[ci[i]+2],intersectEdge[i]))
10481 overlapEdge[i].push_back(*it);
10482 if(IKGeo2DInternalMapper(c2,m,c[ci[*it]+1],c[ci[*it]+2],intersectEdge[*it]))
10483 overlapEdge[*it].push_back(i);
10486 // splitting done. sort intersect point in intersectEdge.
10487 std::vector< std::vector<int> > middle(nDescCell);
10488 int nbOf2DCellsToBeSplit(0);
10489 bool middleNeedsToBeUsed(false);
10490 std::vector<bool> cells2DToTreat(nDescCell,false);
10491 for(int i=0;i<nDescCell;i++)
10493 std::vector<int>& isect(intersectEdge[i]);
10494 int sz((int)isect.size());
10497 std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
10498 INTERP_KERNEL::Edge *e(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[i]],c+ci[i]+1,coords,m));
10499 e->sortSubNodesAbs(coords,isect);
10504 int idx0(rdi[i]),idx1(rdi[i+1]);
10506 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::conformize2D : internal error #0 !");
10507 if(!cells2DToTreat[rd[idx0]])
10509 cells2DToTreat[rd[idx0]]=true;
10510 nbOf2DCellsToBeSplit++;
10512 // try to reuse at most eventual 'middle' of SEG3
10513 std::vector<int>& mid(middle[i]);
10514 mid.resize(sz+1,-1);
10515 if((INTERP_KERNEL::NormalizedCellType)c[ci[i]]==INTERP_KERNEL::NORM_SEG3)
10517 middleNeedsToBeUsed=true;
10518 const std::vector<int>& candidates(overlapEdge[i]);
10519 std::vector<int> trueCandidates;
10520 for(std::vector<int>::const_iterator itc=candidates.begin();itc!=candidates.end();itc++)
10521 if((INTERP_KERNEL::NormalizedCellType)c[ci[*itc]]==INTERP_KERNEL::NORM_SEG3)
10522 trueCandidates.push_back(*itc);
10523 int stNode(c[ci[i]+1]),endNode(isect[0]);
10524 for(int j=0;j<sz+1;j++)
10526 for(std::vector<int>::const_iterator itc=trueCandidates.begin();itc!=trueCandidates.end();itc++)
10528 int tmpSt(c[ci[*itc]+1]),tmpEnd(c[ci[*itc]+2]);
10529 if((tmpSt==stNode && tmpEnd==endNode) || (tmpSt==endNode && tmpEnd==stNode))
10530 { mid[j]=*itc; break; }
10533 endNode=j<sz-1?isect[j+1]:c[ci[i]+2];
10538 MCAuto<DataArrayInt> ret(DataArrayInt::New()),notRet(DataArrayInt::New()); ret->alloc(nbOf2DCellsToBeSplit,1);
10539 if(nbOf2DCellsToBeSplit==0)
10542 int *retPtr(ret->getPointer());
10543 for(int i=0;i<nCell;i++)
10544 if(cells2DToTreat[i])
10547 MCAuto<DataArrayInt> mSafe,nSafe,oSafe,pSafe,qSafe,rSafe;
10548 DataArrayInt *m(0),*n(0),*o(0),*p(0),*q(0),*r(0);
10549 MEDCouplingUMesh::ExtractFromIndexedArrays(ret->begin(),ret->end(),desc1,descIndx1,m,n); mSafe=m; nSafe=n;
10550 DataArrayInt::PutIntoToSkylineFrmt(intersectEdge,o,p); oSafe=o; pSafe=p;
10551 if(middleNeedsToBeUsed)
10552 { DataArrayInt::PutIntoToSkylineFrmt(middle,q,r); qSafe=q; rSafe=r; }
10553 MCAuto<MEDCouplingUMesh> modif(static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(ret->begin(),ret->end(),true)));
10554 int nbOfNodesCreated(modif->split2DCells(mSafe,nSafe,oSafe,pSafe,qSafe,rSafe));
10555 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.
10556 setPartOfMySelf(ret->begin(),ret->end(),*modif);
10558 bool areNodesMerged; int newNbOfNodes;
10559 if(nbOfNodesCreated!=0)
10560 MCAuto<DataArrayInt> tmp(mergeNodes(eps,areNodesMerged,newNbOfNodes));
10566 * 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.
10567 * 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).
10568 * 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
10569 * to invoke MEDCouplingUMesh::mergeNodes and MEDCouplingUMesh::conformize2D right after this call.
10570 * 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
10571 * new nodes for center of merged edges is are systematically created and appended at the end of the previously existing nodes.
10573 * 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
10574 * using new instance, idem for coordinates.
10576 * 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.
10578 * \return DataArrayInt * - The list of cellIds in \a this that have at least one edge colinearized.
10580 * \throw If \a this is not coherent.
10581 * \throw If \a this has not spaceDim equal to 2.
10582 * \throw If \a this has not meshDim equal to 2.
10584 * \sa MEDCouplingUMesh::conformize2D, MEDCouplingUMesh::mergeNodes, MEDCouplingUMesh::convexEnvelop2D.
10586 DataArrayInt *MEDCouplingUMesh::colinearize2D(double eps)
10588 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(0,1);
10589 checkConsistencyLight();
10590 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
10591 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::colinearize2D : This method only works for meshes with spaceDim=2 and meshDim=2 !");
10592 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
10593 INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
10594 int nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
10595 const int *cptr(_nodal_connec->begin()),*ciptr(_nodal_connec_index->begin());
10596 MCAuto<DataArrayInt> newc(DataArrayInt::New()),newci(DataArrayInt::New()); newci->alloc(nbOfCells+1,1); newc->alloc(0,1); newci->setIJ(0,0,0);
10597 MCAuto<DataArrayDouble> appendedCoords(DataArrayDouble::New()); appendedCoords->alloc(0,1);//1 not 2 it is not a bug.
10598 const double *coords(_coords->begin());
10599 int *newciptr(newci->getPointer());
10600 for(int i=0;i<nbOfCells;i++,newciptr++,ciptr++)
10602 if(Colinearize2DCell(coords,cptr+ciptr[0],cptr+ciptr[1],nbOfNodes,newc,appendedCoords))
10603 ret->pushBackSilent(i);
10604 newciptr[1]=newc->getNumberOfTuples();
10609 if(!appendedCoords->empty())
10611 appendedCoords->rearrange(2);
10612 MCAuto<DataArrayDouble> newCoords(DataArrayDouble::Aggregate(getCoords(),appendedCoords));//treat info on components
10614 setCoords(newCoords);
10617 setConnectivity(newc,newci,true);
10622 * \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.
10623 * 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.
10624 * And for each j in [1,n) intersect[i][2*(j-1)+1]==intersect[i][2*j].
10625 * \param [out] subDiv2 - for each cell in \a m2Desc returns nodes that split it using convention \a m1Desc first, then \a m2Desc, then addCoo
10626 * \param [out] colinear2 - for each cell in \a m2Desc returns the edges in \a m1Desc that are colinear to it.
10627 * \param [out] addCoo - nodes to be append at the end
10628 * \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.
10630 void MEDCouplingUMesh::Intersect1DMeshes(const MEDCouplingUMesh *m1Desc, const MEDCouplingUMesh *m2Desc, double eps,
10631 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)
10633 static const int SPACEDIM=2;
10634 INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
10635 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
10636 const int *c1(m1Desc->getNodalConnectivity()->begin()),*ci1(m1Desc->getNodalConnectivityIndex()->begin());
10637 // Build BB tree of all edges in the tool mesh (second mesh)
10638 MCAuto<DataArrayDouble> bbox1Arr(m1Desc->getBoundingBoxForBBTree()),bbox2Arr(m2Desc->getBoundingBoxForBBTree());
10639 const double *bbox1(bbox1Arr->begin()),*bbox2(bbox2Arr->begin());
10640 int nDescCell1(m1Desc->getNumberOfCells()),nDescCell2(m2Desc->getNumberOfCells());
10641 intersectEdge1.resize(nDescCell1);
10642 colinear2.resize(nDescCell2);
10643 subDiv2.resize(nDescCell2);
10644 BBTree<SPACEDIM,int> myTree(bbox2,0,0,m2Desc->getNumberOfCells(),-eps);
10646 std::vector<int> candidates1(1);
10647 int offset1(m1Desc->getNumberOfNodes());
10648 int offset2(offset1+m2Desc->getNumberOfNodes());
10649 for(int i=0;i<nDescCell1;i++) // for all edges in the first mesh
10651 std::vector<int> candidates2; // edges of mesh2 candidate for intersection
10652 myTree.getIntersectingElems(bbox1+i*2*SPACEDIM,candidates2);
10653 if(!candidates2.empty()) // candidates2 holds edges from the second mesh potentially intersecting current edge i in mesh1
10655 std::map<INTERP_KERNEL::Node *,int> map1,map2;
10656 // pol2 is not necessarily a closed polygon: just a set of (quadratic) edges (same as candidates2) in the Geometric DS format
10657 INTERP_KERNEL::QuadraticPolygon *pol2=MEDCouplingUMeshBuildQPFromMesh(m2Desc,candidates2,map2);
10659 INTERP_KERNEL::QuadraticPolygon *pol1=MEDCouplingUMeshBuildQPFromMesh(m1Desc,candidates1,map1);
10660 // 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
10661 // This trick guarantees that Node * are discriminant (i.e. form a unique identifier)
10662 std::set<INTERP_KERNEL::Node *> nodes;
10663 pol1->getAllNodes(nodes); pol2->getAllNodes(nodes);
10664 std::size_t szz(nodes.size());
10665 std::vector< MCAuto<INTERP_KERNEL::Node> > nodesSafe(szz);
10666 std::set<INTERP_KERNEL::Node *>::const_iterator itt(nodes.begin());
10667 for(std::size_t iii=0;iii<szz;iii++,itt++)
10668 { (*itt)->incrRef(); nodesSafe[iii]=*itt; }
10669 // end of protection
10670 // Performs egde cutting:
10671 pol1->splitAbs(*pol2,map1,map2,offset1,offset2,candidates2,intersectEdge1[i],i,colinear2,subDiv2,addCoo,mergedNodes);
10676 // Copy the edge (take only the two first points, ie discard quadratic point at this stage)
10677 intersectEdge1[i].insert(intersectEdge1[i].end(),c1+ci1[i]+1,c1+ci1[i]+3);
10682 * This method is private and is the first step of Partition of 2D mesh (spaceDim==2 and meshDim==2).
10683 * It builds the descending connectivity of the two meshes, and then using a binary tree
10684 * it computes the edge intersections. This results in new points being created : they're stored in addCoo.
10685 * Documentation about parameters colinear2 and subDiv2 can be found in method QuadraticPolygon::splitAbs().
10687 void MEDCouplingUMesh::IntersectDescending2DMeshes(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2, double eps,
10688 std::vector< std::vector<int> >& intersectEdge1, std::vector< std::vector<int> >& colinear2, std::vector< std::vector<int> >& subDiv2,
10689 MEDCouplingUMesh *& m1Desc, DataArrayInt *&desc1, DataArrayInt *&descIndx1, DataArrayInt *&revDesc1, DataArrayInt *&revDescIndx1,
10690 std::vector<double>& addCoo,
10691 MEDCouplingUMesh *& m2Desc, DataArrayInt *&desc2, DataArrayInt *&descIndx2, DataArrayInt *&revDesc2, DataArrayInt *&revDescIndx2)
10693 // Build desc connectivity
10694 desc1=DataArrayInt::New(); descIndx1=DataArrayInt::New(); revDesc1=DataArrayInt::New(); revDescIndx1=DataArrayInt::New();
10695 desc2=DataArrayInt::New();
10696 descIndx2=DataArrayInt::New();
10697 revDesc2=DataArrayInt::New();
10698 revDescIndx2=DataArrayInt::New();
10699 MCAuto<DataArrayInt> dd1(desc1),dd2(descIndx1),dd3(revDesc1),dd4(revDescIndx1);
10700 MCAuto<DataArrayInt> dd5(desc2),dd6(descIndx2),dd7(revDesc2),dd8(revDescIndx2);
10701 m1Desc=m1->buildDescendingConnectivity2(desc1,descIndx1,revDesc1,revDescIndx1);
10702 m2Desc=m2->buildDescendingConnectivity2(desc2,descIndx2,revDesc2,revDescIndx2);
10703 MCAuto<MEDCouplingUMesh> dd9(m1Desc),dd10(m2Desc);
10704 std::map<int,int> notUsedMap;
10705 Intersect1DMeshes(m1Desc,m2Desc,eps,intersectEdge1,colinear2,subDiv2,addCoo,notUsedMap);
10706 m1Desc->incrRef(); desc1->incrRef(); descIndx1->incrRef(); revDesc1->incrRef(); revDescIndx1->incrRef();
10707 m2Desc->incrRef(); desc2->incrRef(); descIndx2->incrRef(); revDesc2->incrRef(); revDescIndx2->incrRef();
10711 * This method performs the 2nd step of Partition of 2D mesh.
10712 * This method has 4 inputs :
10713 * - a mesh 'm1' with meshDim==1 and a SpaceDim==2
10714 * - a mesh 'm2' with meshDim==1 and a SpaceDim==2
10715 * - subDiv of size 'm2->getNumberOfCells()' that lists for each seg cell in 'm' the splitting node ids randomly sorted.
10716 * 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'
10717 * Nodes end up lying consecutively on a cutted edge.
10718 * \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.
10719 * (Only present for its coords in case of 'subDiv' shares some nodes of 'm1')
10720 * \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.
10721 * \param addCoo input parameter with additional nodes linked to intersection of the 2 meshes.
10722 * \param[out] intersectEdge the same content as subDiv, but correclty oriented.
10724 void MEDCouplingUMesh::BuildIntersectEdges(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2,
10725 const std::vector<double>& addCoo,
10726 const std::vector< std::vector<int> >& subDiv, std::vector< std::vector<int> >& intersectEdge)
10728 int offset1=m1->getNumberOfNodes();
10729 int ncell=m2->getNumberOfCells();
10730 const int *c=m2->getNodalConnectivity()->begin();
10731 const int *cI=m2->getNodalConnectivityIndex()->begin();
10732 const double *coo=m2->getCoords()->begin();
10733 const double *cooBis=m1->getCoords()->begin();
10734 int offset2=offset1+m2->getNumberOfNodes();
10735 intersectEdge.resize(ncell);
10736 for(int i=0;i<ncell;i++,cI++)
10738 const std::vector<int>& divs=subDiv[i];
10739 int nnode=cI[1]-cI[0]-1;
10740 std::map<int, std::pair<INTERP_KERNEL::Node *,bool> > mapp2;
10741 std::map<INTERP_KERNEL::Node *, int> mapp22;
10742 for(int j=0;j<nnode;j++)
10744 INTERP_KERNEL::Node *nn=new INTERP_KERNEL::Node(coo[2*c[(*cI)+j+1]],coo[2*c[(*cI)+j+1]+1]);
10745 int nnid=c[(*cI)+j+1];
10746 mapp2[nnid]=std::pair<INTERP_KERNEL::Node *,bool>(nn,true);
10747 mapp22[nn]=nnid+offset1;
10749 INTERP_KERNEL::Edge *e=MEDCouplingUMeshBuildQPFromEdge((INTERP_KERNEL::NormalizedCellType)c[*cI],mapp2,c+(*cI)+1);
10750 for(std::map<int, std::pair<INTERP_KERNEL::Node *,bool> >::const_iterator it=mapp2.begin();it!=mapp2.end();it++)
10751 ((*it).second.first)->decrRef();
10752 std::vector<INTERP_KERNEL::Node *> addNodes(divs.size());
10753 std::map<INTERP_KERNEL::Node *,int> mapp3;
10754 for(std::size_t j=0;j<divs.size();j++)
10757 INTERP_KERNEL::Node *tmp=0;
10759 tmp=new INTERP_KERNEL::Node(cooBis[2*id],cooBis[2*id+1]);
10760 else if(id<offset2)
10761 tmp=new INTERP_KERNEL::Node(coo[2*(id-offset1)],coo[2*(id-offset1)+1]);//if it happens, bad news mesh 'm2' is non conform.
10763 tmp=new INTERP_KERNEL::Node(addCoo[2*(id-offset2)],addCoo[2*(id-offset2)+1]);
10767 e->sortIdsAbs(addNodes,mapp22,mapp3,intersectEdge[i]);
10768 for(std::vector<INTERP_KERNEL::Node *>::const_iterator it=addNodes.begin();it!=addNodes.end();it++)
10775 * 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).
10776 * 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
10777 * with a plane. The result will be put in 'cut3DSuf' out parameter.
10778 * \param [in] cut3DCurve input paramter that gives for each 3DCurve cell if it owns fully to the plane or partially.
10779 * \param [out] nodesOnPlane, returns all the nodes that are on the plane.
10780 * \param [in] nodal3DSurf is the nodal connectivity of 3D surf mesh.
10781 * \param [in] nodalIndx3DSurf is the nodal connectivity index of 3D surf mesh.
10782 * \param [in] nodal3DCurve is the nodal connectivity of 3D curve mesh.
10783 * \param [in] nodal3DIndxCurve is the nodal connectivity index of 3D curve mesh.
10784 * \param [in] desc is the descending connectivity 3DSurf->3DCurve
10785 * \param [in] descIndx is the descending connectivity index 3DSurf->3DCurve
10786 * \param [out] cut3DSuf input/output param.
10788 void MEDCouplingUMesh::AssemblyForSplitFrom3DCurve(const std::vector<int>& cut3DCurve, std::vector<int>& nodesOnPlane, const int *nodal3DSurf, const int *nodalIndx3DSurf,
10789 const int *nodal3DCurve, const int *nodalIndx3DCurve,
10790 const int *desc, const int *descIndx,
10791 std::vector< std::pair<int,int> >& cut3DSurf)
10793 std::set<int> nodesOnP(nodesOnPlane.begin(),nodesOnPlane.end());
10794 int nbOf3DSurfCell=(int)cut3DSurf.size();
10795 for(int i=0;i<nbOf3DSurfCell;i++)
10797 std::vector<int> res;
10798 int offset=descIndx[i];
10799 int nbOfSeg=descIndx[i+1]-offset;
10800 for(int j=0;j<nbOfSeg;j++)
10802 int edgeId=desc[offset+j];
10803 int status=cut3DCurve[edgeId];
10807 res.push_back(status);
10810 res.push_back(nodal3DCurve[nodalIndx3DCurve[edgeId]+1]);
10811 res.push_back(nodal3DCurve[nodalIndx3DCurve[edgeId]+2]);
10819 cut3DSurf[i].first=res[0]; cut3DSurf[i].second=res[1];
10825 std::set<int> s1(nodal3DSurf+nodalIndx3DSurf[i]+1,nodal3DSurf+nodalIndx3DSurf[i+1]);
10826 std::set_intersection(nodesOnP.begin(),nodesOnP.end(),s1.begin(),s1.end(),std::back_insert_iterator< std::vector<int> >(res));
10829 cut3DSurf[i].first=res[0]; cut3DSurf[i].second=res[1];
10833 cut3DSurf[i].first=-1; cut3DSurf[i].second=-1;
10838 {// case when plane is on a multi colinear edge of a polyhedron
10839 if((int)res.size()==2*nbOfSeg)
10841 cut3DSurf[i].first=-2; cut3DSurf[i].second=i;
10844 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AssemblyPointsFrom3DCurve : unexpected situation !");
10851 * \a this is expected to be a mesh with spaceDim==3 and meshDim==3. If not an exception will be thrown.
10852 * 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).
10853 * 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
10854 * with a plane. The result will be put in 'nodalRes' 'nodalResIndx' and 'cellIds' out parameters.
10855 * \param cut3DSurf input paramter that gives for each 3DSurf its intersection with plane (result of MEDCouplingUMesh::AssemblyForSplitFrom3DCurve).
10856 * \param desc is the descending connectivity 3D->3DSurf
10857 * \param descIndx is the descending connectivity index 3D->3DSurf
10859 void MEDCouplingUMesh::assemblyForSplitFrom3DSurf(const std::vector< std::pair<int,int> >& cut3DSurf,
10860 const int *desc, const int *descIndx,
10861 DataArrayInt *nodalRes, DataArrayInt *nodalResIndx, DataArrayInt *cellIds) const
10863 checkFullyDefined();
10864 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
10865 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::assemblyForSplitFrom3DSurf works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
10866 const int *nodal3D(_nodal_connec->begin()),*nodalIndx3D(_nodal_connec_index->begin());
10867 int nbOfCells(getNumberOfCells());
10868 for(int i=0;i<nbOfCells;i++)
10870 std::map<int, std::set<int> > m;
10871 int offset=descIndx[i];
10872 int nbOfFaces=descIndx[i+1]-offset;
10875 for(int j=0;j<nbOfFaces;j++)
10877 const std::pair<int,int>& p=cut3DSurf[desc[offset+j]];
10878 if(p.first!=-1 && p.second!=-1)
10882 start=p.first; end=p.second;
10883 m[p.first].insert(p.second);
10884 m[p.second].insert(p.first);
10888 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)nodal3D[nodalIndx3D[i]]);
10889 int sz=nodalIndx3D[i+1]-nodalIndx3D[i]-1;
10890 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz];
10891 INTERP_KERNEL::NormalizedCellType cmsId;
10892 unsigned nbOfNodesSon=cm.fillSonCellNodalConnectivity2(j,nodal3D+nodalIndx3D[i]+1,sz,tmp,cmsId);
10893 start=tmp[0]; end=tmp[nbOfNodesSon-1];
10894 for(unsigned k=0;k<nbOfNodesSon;k++)
10896 m[tmp[k]].insert(tmp[(k+1)%nbOfNodesSon]);
10897 m[tmp[(k+1)%nbOfNodesSon]].insert(tmp[k]);
10904 std::vector<int> conn(1,(int)INTERP_KERNEL::NORM_POLYGON);
10908 std::map<int, std::set<int> >::const_iterator it=m.find(start);
10909 const std::set<int>& s=(*it).second;
10910 std::set<int> s2; s2.insert(prev);
10912 std::set_difference(s.begin(),s.end(),s2.begin(),s2.end(),inserter(s3,s3.begin()));
10915 int val=*s3.begin();
10916 conn.push_back(start);
10923 conn.push_back(end);
10926 nodalRes->insertAtTheEnd(conn.begin(),conn.end());
10927 nodalResIndx->pushBackSilent(nodalRes->getNumberOfTuples());
10928 cellIds->pushBackSilent(i);
10933 void InsertNodeInConnIfNecessary(int nodeIdToInsert, std::vector<int>& conn, const double *coords, double eps)
10935 std::vector<int>::iterator it(std::find(conn.begin(),conn.end(),nodeIdToInsert));
10938 std::size_t sz(conn.size());
10939 std::size_t found(std::numeric_limits<std::size_t>::max());
10940 for(std::size_t i=0;i<sz;i++)
10942 int pt0(conn[i]),pt1(conn[(i+1)%sz]);
10943 double v1[3]={coords[3*pt1+0]-coords[3*pt0+0],coords[3*pt1+1]-coords[3*pt0+1],coords[3*pt1+2]-coords[3*pt0+2]},v2[3]={coords[3*nodeIdToInsert+0]-coords[3*pt0+0],coords[3*nodeIdToInsert+1]-coords[3*pt0+1],coords[3*nodeIdToInsert+2]-coords[3*pt0+2]};
10944 double normm(sqrt(v1[0]*v1[0]+v1[1]*v1[1]+v1[2]*v1[2]));
10945 std::transform(v1,v1+3,v1,std::bind2nd(std::multiplies<double>(),1./normm));
10946 std::transform(v2,v2+3,v2,std::bind2nd(std::multiplies<double>(),1./normm));
10948 v3[0]=v1[1]*v2[2]-v1[2]*v2[1]; v3[1]=v1[2]*v2[0]-v1[0]*v2[2]; v3[2]=v1[0]*v2[1]-v1[1]*v2[0];
10949 double normm2(sqrt(v3[0]*v3[0]+v3[1]*v3[1]+v3[2]*v3[2])),dotTest(v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2]);
10951 if(dotTest>eps && dotTest<1.-eps)
10957 if(found==std::numeric_limits<std::size_t>::max())
10958 throw INTERP_KERNEL::Exception("InsertNodeInConnIfNecessary : not found point !");
10959 conn.insert(conn.begin()+(found+1)%sz,nodeIdToInsert);
10962 void SplitIntoToPart(const std::vector<int>& conn, int pt0, int pt1, std::vector<int>& part0, std::vector<int>& part1)
10964 std::size_t sz(conn.size());
10965 std::vector<int> *curPart(&part0);
10966 for(std::size_t i=0;i<sz;i++)
10968 int nextt(conn[(i+1)%sz]);
10969 (*curPart).push_back(nextt);
10970 if(nextt==pt0 || nextt==pt1)
10972 if(curPart==&part0)
10976 (*curPart).push_back(nextt);
10982 * this method method splits cur cells 3D Surf in sub cells 3DSurf using the previous subsplit. This method is the last one used to clip.
10984 void MEDCouplingUMesh::buildSubCellsFromCut(const std::vector< std::pair<int,int> >& cut3DSurf,
10985 const int *desc, const int *descIndx, const double *coords, double eps,
10986 std::vector<std::vector<int> >& res) const
10988 checkFullyDefined();
10989 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
10990 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSubCellsFromCut works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
10991 const int *nodal3D(_nodal_connec->begin()),*nodalIndx3D(_nodal_connec_index->begin());
10992 int nbOfCells(getNumberOfCells());
10994 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSubCellsFromCut works only with single cell presently !");
10995 for(int i=0;i<nbOfCells;i++)
10997 int offset(descIndx[i]),nbOfFaces(descIndx[i+1]-offset),start(-1),end(-1);
10998 for(int j=0;j<nbOfFaces;j++)
11000 const std::pair<int,int>& p=cut3DSurf[desc[offset+j]];
11001 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)nodal3D[nodalIndx3D[i]]));
11002 int sz=nodalIndx3D[i+1]-nodalIndx3D[i]-1;
11003 INTERP_KERNEL::AutoPtr<int> tmp(new int[sz]);
11004 INTERP_KERNEL::NormalizedCellType cmsId;
11005 unsigned nbOfNodesSon(cm.fillSonCellNodalConnectivity2(j,nodal3D+nodalIndx3D[i]+1,sz,tmp,cmsId));
11006 std::vector<int> elt((int *)tmp,(int *)tmp+nbOfNodesSon);
11007 if(p.first!=-1 && p.second!=-1)
11011 InsertNodeInConnIfNecessary(p.first,elt,coords,eps);
11012 InsertNodeInConnIfNecessary(p.second,elt,coords,eps);
11013 std::vector<int> elt1,elt2;
11014 SplitIntoToPart(elt,p.first,p.second,elt1,elt2);
11015 res.push_back(elt1);
11016 res.push_back(elt2);
11019 res.push_back(elt);
11022 res.push_back(elt);
11028 * 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
11029 * 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
11030 * the geometric cell type set to INTERP_KERNEL::NORM_POLYGON.
11031 * 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
11032 * 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.
11034 * \return false if the input connectivity represents already the convex hull, true if the input cell needs to be reordered.
11036 bool MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis(const double *coords, const int *nodalConnBg, const int *nodalConnEnd, DataArrayInt *nodalConnecOut)
11038 std::size_t sz=std::distance(nodalConnBg,nodalConnEnd);
11041 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)*nodalConnBg);
11042 if(cm.getDimension()==2)
11044 const int *node=nodalConnBg+1;
11045 int startNode=*node++;
11046 double refX=coords[2*startNode];
11047 for(;node!=nodalConnEnd;node++)
11049 if(coords[2*(*node)]<refX)
11052 refX=coords[2*startNode];
11055 std::vector<int> tmpOut; tmpOut.reserve(sz); tmpOut.push_back(startNode);
11059 double angle0=-M_PI/2;
11064 double angleNext=0.;
11065 while(nextNode!=startNode)
11069 for(node=nodalConnBg+1;node!=nodalConnEnd;node++)
11071 if(*node!=tmpOut.back() && *node!=prevNode)
11073 tmp2[0]=coords[2*(*node)]-coords[2*tmpOut.back()]; tmp2[1]=coords[2*(*node)+1]-coords[2*tmpOut.back()+1];
11074 double angleM=INTERP_KERNEL::EdgeArcCircle::GetAbsoluteAngle(tmp2,tmp1);
11079 res=angle0-angleM+2.*M_PI;
11088 if(nextNode!=startNode)
11090 angle0=angleNext-M_PI;
11093 prevNode=tmpOut.back();
11094 tmpOut.push_back(nextNode);
11097 std::vector<int> tmp3(2*(sz-1));
11098 std::vector<int>::iterator it=std::copy(nodalConnBg+1,nodalConnEnd,tmp3.begin());
11099 std::copy(nodalConnBg+1,nodalConnEnd,it);
11100 if(std::search(tmp3.begin(),tmp3.end(),tmpOut.begin(),tmpOut.end())!=tmp3.end())
11102 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
11105 if(std::search(tmp3.rbegin(),tmp3.rend(),tmpOut.begin(),tmpOut.end())!=tmp3.rend())
11107 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
11112 nodalConnecOut->pushBackSilent((int)INTERP_KERNEL::NORM_POLYGON);
11113 nodalConnecOut->insertAtTheEnd(tmpOut.begin(),tmpOut.end());
11118 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
11121 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
11125 * This method works on an input pair (\b arr, \b arrIndx) where \b arr indexes is in \b arrIndx.
11126 * 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.
11128 * \param [in] idsToRemoveBg begin of set of ids to remove in \b arr (included)
11129 * \param [in] idsToRemoveEnd end of set of ids to remove in \b arr (excluded)
11130 * \param [in,out] arr array in which the remove operation will be done.
11131 * \param [in,out] arrIndx array in the remove operation will modify
11132 * \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])
11133 * \return true if \b arr and \b arrIndx have been modified, false if not.
11135 bool MEDCouplingUMesh::RemoveIdsFromIndexedArrays(const int *idsToRemoveBg, const int *idsToRemoveEnd, DataArrayInt *arr, DataArrayInt *arrIndx, int offsetForRemoval)
11137 if(!arrIndx || !arr)
11138 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::RemoveIdsFromIndexedArrays : some input arrays are empty !");
11139 if(offsetForRemoval<0)
11140 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::RemoveIdsFromIndexedArrays : offsetForRemoval should be >=0 !");
11141 std::set<int> s(idsToRemoveBg,idsToRemoveEnd);
11142 int nbOfGrps=arrIndx->getNumberOfTuples()-1;
11143 int *arrIPtr=arrIndx->getPointer();
11145 int previousArrI=0;
11146 const int *arrPtr=arr->begin();
11147 std::vector<int> arrOut;//no utility to switch to DataArrayInt because copy always needed
11148 for(int i=0;i<nbOfGrps;i++,arrIPtr++)
11150 if(*arrIPtr-previousArrI>offsetForRemoval)
11152 for(const int *work=arrPtr+previousArrI+offsetForRemoval;work!=arrPtr+*arrIPtr;work++)
11154 if(s.find(*work)==s.end())
11155 arrOut.push_back(*work);
11158 previousArrI=*arrIPtr;
11159 *arrIPtr=(int)arrOut.size();
11161 if(arr->getNumberOfTuples()==(int)arrOut.size())
11163 arr->alloc((int)arrOut.size(),1);
11164 std::copy(arrOut.begin(),arrOut.end(),arr->getPointer());
11169 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn
11170 * (\ref numbering-indirect).
11171 * This method returns the result of the extraction ( specified by a set of ids in [\b idsOfSelectBg , \b idsOfSelectEnd ) ).
11172 * The selection of extraction is done standardly in new2old format.
11173 * This method returns indexed arrays (\ref numbering-indirect) using 2 arrays (arrOut,arrIndexOut).
11175 * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
11176 * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
11177 * \param [in] arrIn arr origin array from which the extraction will be done.
11178 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11179 * \param [out] arrOut the resulting array
11180 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
11181 * \sa MEDCouplingUMesh::ExtractFromIndexedArraysSlice
11183 void MEDCouplingUMesh::ExtractFromIndexedArrays(const int *idsOfSelectBg, const int *idsOfSelectEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
11184 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
11186 if(!arrIn || !arrIndxIn)
11187 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : input pointer is NULL !");
11188 arrIn->checkAllocated(); arrIndxIn->checkAllocated();
11189 if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1)
11190 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : input arrays must have exactly one component !");
11191 std::size_t sz=std::distance(idsOfSelectBg,idsOfSelectEnd);
11192 const int *arrInPtr=arrIn->begin();
11193 const int *arrIndxPtr=arrIndxIn->begin();
11194 int nbOfGrps=arrIndxIn->getNumberOfTuples()-1;
11196 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : The format of \"arrIndxIn\" is invalid ! Its nb of tuples should be >=1 !");
11197 int maxSizeOfArr=arrIn->getNumberOfTuples();
11198 MCAuto<DataArrayInt> arro=DataArrayInt::New();
11199 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
11200 arrIo->alloc((int)(sz+1),1);
11201 const int *idsIt=idsOfSelectBg;
11202 int *work=arrIo->getPointer();
11205 for(std::size_t i=0;i<sz;i++,work++,idsIt++)
11207 if(*idsIt>=0 && *idsIt<nbOfGrps)
11208 lgth+=arrIndxPtr[*idsIt+1]-arrIndxPtr[*idsIt];
11211 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " ! Must be in [0," << nbOfGrps << ") !";
11212 throw INTERP_KERNEL::Exception(oss.str());
11218 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " and at this pos arrIndxIn[" << *idsIt;
11219 oss << "+1]-arrIndxIn[" << *idsIt << "] < 0 ! The input index array is bugged !";
11220 throw INTERP_KERNEL::Exception(oss.str());
11223 arro->alloc(lgth,1);
11224 work=arro->getPointer();
11225 idsIt=idsOfSelectBg;
11226 for(std::size_t i=0;i<sz;i++,idsIt++)
11228 if(arrIndxPtr[*idsIt]>=0 && arrIndxPtr[*idsIt+1]<=maxSizeOfArr)
11229 work=std::copy(arrInPtr+arrIndxPtr[*idsIt],arrInPtr+arrIndxPtr[*idsIt+1],work);
11232 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " arrIndx[" << *idsIt << "] must be >= 0 and arrIndx[";
11233 oss << *idsIt << "+1] <= " << maxSizeOfArr << " (the size of arrIn)!";
11234 throw INTERP_KERNEL::Exception(oss.str());
11237 arrOut=arro.retn();
11238 arrIndexOut=arrIo.retn();
11242 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn
11243 * (\ref numbering-indirect).
11244 * 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 ).
11245 * The selection of extraction is done standardly in new2old format.
11246 * This method returns indexed arrays (\ref numbering-indirect) using 2 arrays (arrOut,arrIndexOut).
11248 * \param [in] idsOfSelectStart begin of set of ids of the input extraction (included)
11249 * \param [in] idsOfSelectStop end of set of ids of the input extraction (excluded)
11250 * \param [in] idsOfSelectStep
11251 * \param [in] arrIn arr origin array from which the extraction will be done.
11252 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11253 * \param [out] arrOut the resulting array
11254 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
11255 * \sa MEDCouplingUMesh::ExtractFromIndexedArrays
11257 void MEDCouplingUMesh::ExtractFromIndexedArraysSlice(int idsOfSelectStart, int idsOfSelectStop, int idsOfSelectStep, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
11258 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
11260 if(!arrIn || !arrIndxIn)
11261 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : input pointer is NULL !");
11262 arrIn->checkAllocated(); arrIndxIn->checkAllocated();
11263 if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1)
11264 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : input arrays must have exactly one component !");
11265 int sz=DataArrayInt::GetNumberOfItemGivenBESRelative(idsOfSelectStart,idsOfSelectStop,idsOfSelectStep,"MEDCouplingUMesh::ExtractFromIndexedArraysSlice : Input slice ");
11266 const int *arrInPtr=arrIn->begin();
11267 const int *arrIndxPtr=arrIndxIn->begin();
11268 int nbOfGrps=arrIndxIn->getNumberOfTuples()-1;
11270 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : The format of \"arrIndxIn\" is invalid ! Its nb of tuples should be >=1 !");
11271 int maxSizeOfArr=arrIn->getNumberOfTuples();
11272 MCAuto<DataArrayInt> arro=DataArrayInt::New();
11273 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
11274 arrIo->alloc((int)(sz+1),1);
11275 int idsIt=idsOfSelectStart;
11276 int *work=arrIo->getPointer();
11279 for(int i=0;i<sz;i++,work++,idsIt+=idsOfSelectStep)
11281 if(idsIt>=0 && idsIt<nbOfGrps)
11282 lgth+=arrIndxPtr[idsIt+1]-arrIndxPtr[idsIt];
11285 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " ! Must be in [0," << nbOfGrps << ") !";
11286 throw INTERP_KERNEL::Exception(oss.str());
11292 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " and at this pos arrIndxIn[" << idsIt;
11293 oss << "+1]-arrIndxIn[" << idsIt << "] < 0 ! The input index array is bugged !";
11294 throw INTERP_KERNEL::Exception(oss.str());
11297 arro->alloc(lgth,1);
11298 work=arro->getPointer();
11299 idsIt=idsOfSelectStart;
11300 for(int i=0;i<sz;i++,idsIt+=idsOfSelectStep)
11302 if(arrIndxPtr[idsIt]>=0 && arrIndxPtr[idsIt+1]<=maxSizeOfArr)
11303 work=std::copy(arrInPtr+arrIndxPtr[idsIt],arrInPtr+arrIndxPtr[idsIt+1],work);
11306 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " arrIndx[" << idsIt << "] must be >= 0 and arrIndx[";
11307 oss << idsIt << "+1] <= " << maxSizeOfArr << " (the size of arrIn)!";
11308 throw INTERP_KERNEL::Exception(oss.str());
11311 arrOut=arro.retn();
11312 arrIndexOut=arrIo.retn();
11316 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11317 * 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
11318 * cellIds \b in [ \b idsOfSelectBg , \b idsOfSelectEnd ) a copy coming from the corresponding values in input pair (\b srcArr, \b srcArrIndex).
11319 * This method is an generalization of MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx that performs the same thing but by without building explicitely a result output arrays.
11321 * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
11322 * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
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
11330 * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx
11332 void MEDCouplingUMesh::SetPartOfIndexedArrays(const int *idsOfSelectBg, const int *idsOfSelectEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
11333 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex,
11334 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
11336 if(arrIn==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11337 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArrays : 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 std::vector<bool> v(nbOfTuples,true);
11343 const int *arrIndxInPtr=arrIndxIn->begin();
11344 const int *srcArrIndexPtr=srcArrIndex->begin();
11345 for(const int *it=idsOfSelectBg;it!=idsOfSelectEnd;it++,srcArrIndexPtr++)
11347 if(*it>=0 && *it<nbOfTuples)
11350 offset+=(srcArrIndexPtr[1]-srcArrIndexPtr[0])-(arrIndxInPtr[*it+1]-arrIndxInPtr[*it]);
11354 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArrays : On pos #" << std::distance(idsOfSelectBg,it) << " value is " << *it << " not in [0," << nbOfTuples << ") !";
11355 throw INTERP_KERNEL::Exception(oss.str());
11358 srcArrIndexPtr=srcArrIndex->begin();
11359 arrIo->alloc(nbOfTuples+1,1);
11360 arro->alloc(arrIn->getNumberOfTuples()+offset,1);
11361 const int *arrInPtr=arrIn->begin();
11362 const int *srcArrPtr=srcArr->begin();
11363 int *arrIoPtr=arrIo->getPointer(); *arrIoPtr++=0;
11364 int *arroPtr=arro->getPointer();
11365 for(int ii=0;ii<nbOfTuples;ii++,arrIoPtr++)
11369 arroPtr=std::copy(arrInPtr+arrIndxInPtr[ii],arrInPtr+arrIndxInPtr[ii+1],arroPtr);
11370 *arrIoPtr=arrIoPtr[-1]+(arrIndxInPtr[ii+1]-arrIndxInPtr[ii]);
11374 std::size_t pos=std::distance(idsOfSelectBg,std::find(idsOfSelectBg,idsOfSelectEnd,ii));
11375 arroPtr=std::copy(srcArrPtr+srcArrIndexPtr[pos],srcArrPtr+srcArrIndexPtr[pos+1],arroPtr);
11376 *arrIoPtr=arrIoPtr[-1]+(srcArrIndexPtr[pos+1]-srcArrIndexPtr[pos]);
11379 arrOut=arro.retn();
11380 arrIndexOut=arrIo.retn();
11384 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11385 * This method is an specialization of MEDCouplingUMesh::SetPartOfIndexedArrays in the case of assignement do not modify the index in \b arrIndxIn.
11387 * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
11388 * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
11389 * \param [in,out] arrInOut arr origin array from which the extraction will be done.
11390 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11391 * \param [in] srcArr input array that will be used as source of copy for ids in [ \b idsOfSelectBg , \b idsOfSelectEnd )
11392 * \param [in] srcArrIndex index array of \b srcArr
11394 * \sa MEDCouplingUMesh::SetPartOfIndexedArrays
11396 void MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx(const int *idsOfSelectBg, const int *idsOfSelectEnd, DataArrayInt *arrInOut, const DataArrayInt *arrIndxIn,
11397 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex)
11399 if(arrInOut==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11400 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx : presence of null pointer in input parameter !");
11401 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11402 const int *arrIndxInPtr=arrIndxIn->begin();
11403 const int *srcArrIndexPtr=srcArrIndex->begin();
11404 int *arrInOutPtr=arrInOut->getPointer();
11405 const int *srcArrPtr=srcArr->begin();
11406 for(const int *it=idsOfSelectBg;it!=idsOfSelectEnd;it++,srcArrIndexPtr++)
11408 if(*it>=0 && *it<nbOfTuples)
11410 if(srcArrIndexPtr[1]-srcArrIndexPtr[0]==arrIndxInPtr[*it+1]-arrIndxInPtr[*it])
11411 std::copy(srcArrPtr+srcArrIndexPtr[0],srcArrPtr+srcArrIndexPtr[1],arrInOutPtr+arrIndxInPtr[*it]);
11414 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] !";
11415 throw INTERP_KERNEL::Exception(oss.str());
11420 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx : On pos #" << std::distance(idsOfSelectBg,it) << " value is " << *it << " not in [0," << nbOfTuples << ") !";
11421 throw INTERP_KERNEL::Exception(oss.str());
11427 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
11428 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
11429 * 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]].
11430 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
11431 * A negative value in \b arrIn means that it is ignored.
11432 * 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.
11434 * \param [in] arrIn arr origin array from which the extraction will be done.
11435 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11436 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
11437 * \sa MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed, MEDCouplingUMesh::partitionBySpreadZone
11439 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGradually(const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn)
11441 int seed=0,nbOfDepthPeelingPerformed=0;
11442 return ComputeSpreadZoneGraduallyFromSeed(&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfDepthPeelingPerformed);
11446 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
11447 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
11448 * 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]].
11449 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
11450 * A negative value in \b arrIn means that it is ignored.
11451 * 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.
11452 * \param [in] seedBg the begin pointer (included) of an array containing the seed of the search zone
11453 * \param [in] seedEnd the end pointer (not included) of an array containing the seed of the search zone
11454 * \param [in] arrIn arr origin array from which the extraction will be done.
11455 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11456 * \param [in] nbOfDepthPeeling the max number of peels requested in search. By default -1, that is to say, no limit.
11457 * \param [out] nbOfDepthPeelingPerformed the number of peels effectively performed. May be different from \a nbOfDepthPeeling
11458 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
11459 * \sa MEDCouplingUMesh::partitionBySpreadZone
11461 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(const int *seedBg, const int *seedEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn, int nbOfDepthPeeling, int& nbOfDepthPeelingPerformed)
11463 nbOfDepthPeelingPerformed=0;
11465 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed : arrIndxIn input pointer is NULL !");
11466 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11469 DataArrayInt *ret=DataArrayInt::New(); ret->alloc(0,1);
11473 std::vector<bool> fetched(nbOfTuples,false);
11474 return ComputeSpreadZoneGraduallyFromSeedAlg(fetched,seedBg,seedEnd,arrIn,arrIndxIn,nbOfDepthPeeling,nbOfDepthPeelingPerformed);
11477 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeedAlg(std::vector<bool>& fetched, const int *seedBg, const int *seedEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn, int nbOfDepthPeeling, int& nbOfDepthPeelingPerformed)
11479 nbOfDepthPeelingPerformed=0;
11480 if(!seedBg || !seedEnd || !arrIn || !arrIndxIn)
11481 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeedAlg : some input pointer is NULL !");
11482 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11483 std::vector<bool> fetched2(nbOfTuples,false);
11485 for(const int *seedElt=seedBg;seedElt!=seedEnd;seedElt++,i++)
11487 if(*seedElt>=0 && *seedElt<nbOfTuples)
11488 { fetched[*seedElt]=true; fetched2[*seedElt]=true; }
11490 { 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()); }
11492 const int *arrInPtr=arrIn->begin();
11493 const int *arrIndxPtr=arrIndxIn->begin();
11494 int targetNbOfDepthPeeling=nbOfDepthPeeling!=-1?nbOfDepthPeeling:std::numeric_limits<int>::max();
11495 std::vector<int> idsToFetch1(seedBg,seedEnd);
11496 std::vector<int> idsToFetch2;
11497 std::vector<int> *idsToFetch=&idsToFetch1;
11498 std::vector<int> *idsToFetchOther=&idsToFetch2;
11499 while(!idsToFetch->empty() && nbOfDepthPeelingPerformed<targetNbOfDepthPeeling)
11501 for(std::vector<int>::const_iterator it=idsToFetch->begin();it!=idsToFetch->end();it++)
11502 for(const int *it2=arrInPtr+arrIndxPtr[*it];it2!=arrInPtr+arrIndxPtr[*it+1];it2++)
11504 { fetched[*it2]=true; fetched2[*it2]=true; idsToFetchOther->push_back(*it2); }
11505 std::swap(idsToFetch,idsToFetchOther);
11506 idsToFetchOther->clear();
11507 nbOfDepthPeelingPerformed++;
11509 int lgth=(int)std::count(fetched2.begin(),fetched2.end(),true);
11511 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(lgth,1);
11512 int *retPtr=ret->getPointer();
11513 for(std::vector<bool>::const_iterator it=fetched2.begin();it!=fetched2.end();it++,i++)
11520 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11521 * 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
11522 * cellIds \b in [\b idsOfSelectBg, \b idsOfSelectEnd) a copy coming from the corresponding values in input pair (\b srcArr, \b srcArrIndex).
11523 * This method is an generalization of MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx that performs the same thing but by without building explicitely a result output arrays.
11525 * \param [in] start begin of set of ids of the input extraction (included)
11526 * \param [in] end end of set of ids of the input extraction (excluded)
11527 * \param [in] step step of the set of ids in range mode.
11528 * \param [in] arrIn arr origin array from which the extraction will be done.
11529 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11530 * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd)
11531 * \param [in] srcArrIndex index array of \b srcArr
11532 * \param [out] arrOut the resulting array
11533 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
11535 * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx MEDCouplingUMesh::SetPartOfIndexedArrays
11537 void MEDCouplingUMesh::SetPartOfIndexedArraysSlice(int start, int end, int step, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
11538 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex,
11539 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
11541 if(arrIn==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11542 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSlice : presence of null pointer in input parameter !");
11543 MCAuto<DataArrayInt> arro=DataArrayInt::New();
11544 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
11545 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11547 const int *arrIndxInPtr=arrIndxIn->begin();
11548 const int *srcArrIndexPtr=srcArrIndex->begin();
11549 int nbOfElemsToSet=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::SetPartOfIndexedArraysSlice : ");
11551 for(int i=0;i<nbOfElemsToSet;i++,srcArrIndexPtr++,it+=step)
11553 if(it>=0 && it<nbOfTuples)
11554 offset+=(srcArrIndexPtr[1]-srcArrIndexPtr[0])-(arrIndxInPtr[it+1]-arrIndxInPtr[it]);
11557 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSlice : On pos #" << i << " value is " << it << " not in [0," << nbOfTuples << ") !";
11558 throw INTERP_KERNEL::Exception(oss.str());
11561 srcArrIndexPtr=srcArrIndex->begin();
11562 arrIo->alloc(nbOfTuples+1,1);
11563 arro->alloc(arrIn->getNumberOfTuples()+offset,1);
11564 const int *arrInPtr=arrIn->begin();
11565 const int *srcArrPtr=srcArr->begin();
11566 int *arrIoPtr=arrIo->getPointer(); *arrIoPtr++=0;
11567 int *arroPtr=arro->getPointer();
11568 for(int ii=0;ii<nbOfTuples;ii++,arrIoPtr++)
11570 int pos=DataArray::GetPosOfItemGivenBESRelativeNoThrow(ii,start,end,step);
11573 arroPtr=std::copy(arrInPtr+arrIndxInPtr[ii],arrInPtr+arrIndxInPtr[ii+1],arroPtr);
11574 *arrIoPtr=arrIoPtr[-1]+(arrIndxInPtr[ii+1]-arrIndxInPtr[ii]);
11578 arroPtr=std::copy(srcArrPtr+srcArrIndexPtr[pos],srcArrPtr+srcArrIndexPtr[pos+1],arroPtr);
11579 *arrIoPtr=arrIoPtr[-1]+(srcArrIndexPtr[pos+1]-srcArrIndexPtr[pos]);
11582 arrOut=arro.retn();
11583 arrIndexOut=arrIo.retn();
11587 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11588 * This method is an specialization of MEDCouplingUMesh::SetPartOfIndexedArrays in the case of assignement do not modify the index in \b arrIndxIn.
11590 * \param [in] start begin of set of ids of the input extraction (included)
11591 * \param [in] end end of set of ids of the input extraction (excluded)
11592 * \param [in] step step of the set of ids in range mode.
11593 * \param [in,out] arrInOut arr origin array from which the extraction will be done.
11594 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11595 * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd)
11596 * \param [in] srcArrIndex index array of \b srcArr
11598 * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSlice MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx
11600 void MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice(int start, int end, int step, DataArrayInt *arrInOut, const DataArrayInt *arrIndxIn,
11601 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex)
11603 if(arrInOut==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11604 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : presence of null pointer in input parameter !");
11605 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11606 const int *arrIndxInPtr=arrIndxIn->begin();
11607 const int *srcArrIndexPtr=srcArrIndex->begin();
11608 int *arrInOutPtr=arrInOut->getPointer();
11609 const int *srcArrPtr=srcArr->begin();
11610 int nbOfElemsToSet=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : ");
11612 for(int i=0;i<nbOfElemsToSet;i++,srcArrIndexPtr++,it+=step)
11614 if(it>=0 && it<nbOfTuples)
11616 if(srcArrIndexPtr[1]-srcArrIndexPtr[0]==arrIndxInPtr[it+1]-arrIndxInPtr[it])
11617 std::copy(srcArrPtr+srcArrIndexPtr[0],srcArrPtr+srcArrIndexPtr[1],arrInOutPtr+arrIndxInPtr[it]);
11620 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : On pos #" << i << " id (idsOfSelectBg[" << i << "]) is " << it << " arrIndxIn[id+1]-arrIndxIn[id]!=srcArrIndex[pos+1]-srcArrIndex[pos] !";
11621 throw INTERP_KERNEL::Exception(oss.str());
11626 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : On pos #" << i << " value is " << it << " not in [0," << nbOfTuples << ") !";
11627 throw INTERP_KERNEL::Exception(oss.str());
11633 * \b this is expected to be a mesh fully defined whose spaceDim==meshDim.
11634 * It returns a new allocated mesh having the same mesh dimension and lying on same coordinates.
11635 * The returned mesh contains as poly cells as number of contiguous zone (regarding connectivity).
11636 * A spread contiguous zone is built using poly cells (polyhedra in 3D, polygons in 2D and polyline in 1D).
11637 * The sum of measure field of returned mesh is equal to the sum of measure field of this.
11639 * \return a newly allocated mesh lying on the same coords than \b this with same meshdimension than \b this.
11641 MEDCouplingUMesh *MEDCouplingUMesh::buildSpreadZonesWithPoly() const
11643 checkFullyDefined();
11644 int mdim=getMeshDimension();
11645 int spaceDim=getSpaceDimension();
11647 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension and spacedimension do not match !");
11648 std::vector<DataArrayInt *> partition=partitionBySpreadZone();
11649 std::vector< MCAuto<DataArrayInt> > partitionAuto; partitionAuto.reserve(partition.size());
11650 std::copy(partition.begin(),partition.end(),std::back_insert_iterator<std::vector< MCAuto<DataArrayInt> > >(partitionAuto));
11651 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
11652 ret->setCoords(getCoords());
11653 ret->allocateCells((int)partition.size());
11655 for(std::vector<DataArrayInt *>::const_iterator it=partition.begin();it!=partition.end();it++)
11657 MCAuto<MEDCouplingUMesh> tmp=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf((*it)->begin(),(*it)->end(),true));
11658 MCAuto<DataArrayInt> cell;
11662 cell=tmp->buildUnionOf2DMesh();
11665 cell=tmp->buildUnionOf3DMesh();
11668 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension supported are [2,3] ! Not implemented yet for others !");
11671 ret->insertNextCell((INTERP_KERNEL::NormalizedCellType)cell->getIJSafe(0,0),cell->getNumberOfTuples()-1,cell->begin()+1);
11674 ret->finishInsertingCells();
11679 * This method partitions \b this into contiguous zone.
11680 * This method only needs a well defined connectivity. Coordinates are not considered here.
11681 * This method returns a vector of \b newly allocated arrays that the caller has to deal with.
11683 std::vector<DataArrayInt *> MEDCouplingUMesh::partitionBySpreadZone() const
11685 DataArrayInt *neigh=0,*neighI=0;
11686 computeNeighborsOfCells(neigh,neighI);
11687 MCAuto<DataArrayInt> neighAuto(neigh),neighIAuto(neighI);
11688 return PartitionBySpreadZone(neighAuto,neighIAuto);
11691 std::vector<DataArrayInt *> MEDCouplingUMesh::PartitionBySpreadZone(const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn)
11693 if(!arrIn || !arrIndxIn)
11694 throw INTERP_KERNEL::Exception("PartitionBySpreadZone : null input pointers !");
11695 arrIn->checkAllocated(); arrIndxIn->checkAllocated();
11696 int nbOfTuples(arrIndxIn->getNumberOfTuples());
11697 if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1 || nbOfTuples<1)
11698 throw INTERP_KERNEL::Exception("PartitionBySpreadZone : invalid arrays in input !");
11699 int nbOfCellsCur(nbOfTuples-1);
11700 std::vector<DataArrayInt *> ret;
11701 if(nbOfCellsCur<=0)
11703 std::vector<bool> fetchedCells(nbOfCellsCur,false);
11704 std::vector< MCAuto<DataArrayInt> > ret2;
11706 while(seed<nbOfCellsCur)
11708 int nbOfPeelPerformed=0;
11709 ret2.push_back(ComputeSpreadZoneGraduallyFromSeedAlg(fetchedCells,&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfPeelPerformed));
11710 seed=(int)std::distance(fetchedCells.begin(),std::find(fetchedCells.begin()+seed,fetchedCells.end(),false));
11712 for(std::vector< MCAuto<DataArrayInt> >::iterator it=ret2.begin();it!=ret2.end();it++)
11713 ret.push_back((*it).retn());
11718 * This method returns given a distribution of cell type (returned for example by MEDCouplingUMesh::getDistributionOfTypes method and customized after) a
11719 * newly allocated DataArrayInt instance with 2 components ready to be interpreted as input of DataArrayInt::findRangeIdForEachTuple method.
11721 * \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.
11722 * \return a newly allocated DataArrayInt to be managed by the caller.
11723 * \throw In case of \a code has not the right format (typically of size 3*n)
11725 DataArrayInt *MEDCouplingUMesh::ComputeRangesFromTypeDistribution(const std::vector<int>& code)
11727 MCAuto<DataArrayInt> ret=DataArrayInt::New();
11728 std::size_t nb=code.size()/3;
11729 if(code.size()%3!=0)
11730 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeRangesFromTypeDistribution : invalid input code !");
11731 ret->alloc((int)nb,2);
11732 int *retPtr=ret->getPointer();
11733 for(std::size_t i=0;i<nb;i++,retPtr+=2)
11735 retPtr[0]=code[3*i+2];
11736 retPtr[1]=code[3*i+2]+code[3*i+1];
11742 * This method expects that \a this a 3D mesh (spaceDim=3 and meshDim=3) with all coordinates and connectivities set.
11743 * All cells in \a this are expected to be linear 3D cells.
11744 * This method will split **all** 3D cells in \a this into INTERP_KERNEL::NORM_TETRA4 cells and put them in the returned mesh.
11745 * It leads to an increase to number of cells.
11746 * This method contrary to MEDCouplingUMesh::simplexize can append coordinates in \a this to perform its work.
11747 * The \a nbOfAdditionalPoints returned value informs about it. If > 0, the coordinates array in returned mesh will have \a nbOfAdditionalPoints
11748 * more tuples (nodes) than in \a this. Anyway, all the nodes in \a this (with the same order) will be in the returned mesh.
11750 * \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.
11751 * For all other cells, the splitting policy will be ignored. See INTERP_KERNEL::SplittingPolicy for the images.
11752 * \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.
11753 * \param [out] n2oCells - A new instance of DataArrayInt holding, for each new cell,
11754 * an id of old cell producing it. The caller is to delete this array using
11755 * decrRef() as it is no more needed.
11756 * \return MEDCoupling1SGTUMesh * - the mesh containing only INTERP_KERNEL::NORM_TETRA4 cells.
11758 * \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
11759 * the policy PLANAR_FACE_6 should be used on a mesh sorted with MEDCoupling1SGTUMesh::sortHexa8EachOther.
11761 * \throw If \a this is not a 3D mesh (spaceDim==3 and meshDim==3).
11762 * \throw If \a this is not fully constituted with linear 3D cells.
11763 * \sa MEDCouplingUMesh::simplexize, MEDCoupling1SGTUMesh::sortHexa8EachOther
11765 MEDCoupling1SGTUMesh *MEDCouplingUMesh::tetrahedrize(int policy, DataArrayInt *& n2oCells, int& nbOfAdditionalPoints) const
11767 INTERP_KERNEL::SplittingPolicy pol((INTERP_KERNEL::SplittingPolicy)policy);
11768 checkConnectivityFullyDefined();
11769 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
11770 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tetrahedrize : only available for mesh with meshdim == 3 and spacedim == 3 !");
11771 int nbOfCells(getNumberOfCells()),nbNodes(getNumberOfNodes());
11772 MCAuto<MEDCoupling1SGTUMesh> ret0(MEDCoupling1SGTUMesh::New(getName(),INTERP_KERNEL::NORM_TETRA4));
11773 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(nbOfCells,1);
11774 int *retPt(ret->getPointer());
11775 MCAuto<DataArrayInt> newConn(DataArrayInt::New()); newConn->alloc(0,1);
11776 MCAuto<DataArrayDouble> addPts(DataArrayDouble::New()); addPts->alloc(0,1);
11777 const int *oldc(_nodal_connec->begin());
11778 const int *oldci(_nodal_connec_index->begin());
11779 const double *coords(_coords->begin());
11780 for(int i=0;i<nbOfCells;i++,oldci++,retPt++)
11782 std::vector<int> a; std::vector<double> b;
11783 INTERP_KERNEL::SplitIntoTetras(pol,(INTERP_KERNEL::NormalizedCellType)oldc[oldci[0]],oldc+oldci[0]+1,oldc+oldci[1],coords,a,b);
11784 std::size_t nbOfTet(a.size()/4); *retPt=(int)nbOfTet;
11785 const int *aa(&a[0]);
11788 for(std::vector<int>::iterator it=a.begin();it!=a.end();it++)
11790 *it=(-(*(it))-1+nbNodes);
11791 addPts->insertAtTheEnd(b.begin(),b.end());
11792 nbNodes+=(int)b.size()/3;
11794 for(std::size_t j=0;j<nbOfTet;j++,aa+=4)
11795 newConn->insertAtTheEnd(aa,aa+4);
11797 if(!addPts->empty())
11799 addPts->rearrange(3);
11800 nbOfAdditionalPoints=addPts->getNumberOfTuples();
11801 addPts=DataArrayDouble::Aggregate(getCoords(),addPts);
11802 ret0->setCoords(addPts);
11806 nbOfAdditionalPoints=0;
11807 ret0->setCoords(getCoords());
11809 ret0->setNodalConnectivity(newConn);
11811 ret->computeOffsetsFull();
11812 n2oCells=ret->buildExplicitArrOfSliceOnScaledArr(0,nbOfCells,1);
11813 return ret0.retn();
11817 * 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).
11819 * \sa MEDCouplingUMesh::split2DCells
11821 void MEDCouplingUMesh::split2DCellsLinear(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI)
11823 checkConnectivityFullyDefined();
11824 int ncells(getNumberOfCells()),lgthToReach(getNodalConnectivityArrayLen()+subNodesInSeg->getNumberOfTuples());
11825 MCAuto<DataArrayInt> c(DataArrayInt::New()); c->alloc((std::size_t)lgthToReach);
11826 const int *subPtr(subNodesInSeg->begin()),*subIPtr(subNodesInSegI->begin()),*descPtr(desc->begin()),*descIPtr(descI->begin()),*oldConn(getNodalConnectivity()->begin());
11827 int *cPtr(c->getPointer()),*ciPtr(getNodalConnectivityIndex()->getPointer());
11828 int prevPosOfCi(ciPtr[0]);
11829 for(int i=0;i<ncells;i++,ciPtr++,descIPtr++)
11831 int offset(descIPtr[0]),sz(descIPtr[1]-descIPtr[0]),deltaSz(0);
11832 *cPtr++=(int)INTERP_KERNEL::NORM_POLYGON; *cPtr++=oldConn[prevPosOfCi+1];
11833 for(int j=0;j<sz;j++)
11835 int offset2(subIPtr[descPtr[offset+j]]),sz2(subIPtr[descPtr[offset+j]+1]-subIPtr[descPtr[offset+j]]);
11836 for(int k=0;k<sz2;k++)
11837 *cPtr++=subPtr[offset2+k];
11839 *cPtr++=oldConn[prevPosOfCi+j+2];
11842 prevPosOfCi=ciPtr[1];
11843 ciPtr[1]=ciPtr[0]+1+sz+deltaSz;//sz==old nb of nodes because (nb of subedges=nb of nodes for polygons)
11846 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCellsLinear : Some of edges to be split are orphan !");
11847 _nodal_connec->decrRef();
11848 _nodal_connec=c.retn(); _types.clear(); _types.insert(INTERP_KERNEL::NORM_POLYGON);
11851 int InternalAddPoint(const INTERP_KERNEL::Edge *e, int id, const double *coo, int startId, int endId, DataArrayDouble& addCoo, int& nodesCnter)
11857 int ret(nodesCnter++);
11859 e->getMiddleOfPoints(coo+2*startId,coo+2*endId,newPt);
11860 addCoo.insertAtTheEnd(newPt,newPt+2);
11865 int InternalAddPointOriented(const INTERP_KERNEL::Edge *e, int id, const double *coo, int startId, int endId, DataArrayDouble& addCoo, int& nodesCnter)
11871 int ret(nodesCnter++);
11873 e->getMiddleOfPointsOriented(coo+2*startId,coo+2*endId,newPt);
11874 addCoo.insertAtTheEnd(newPt,newPt+2);
11882 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)
11885 int trueStart(start>=0?start:nbOfEdges+start);
11886 tmp[0]=linOrArc?(int)INTERP_KERNEL::NORM_QPOLYG:(int)INTERP_KERNEL::NORM_POLYGON; tmp[1]=connBg[trueStart]; tmp[2]=connBg[stp];
11887 newConnOfCell->insertAtTheEnd(tmp,tmp+3);
11892 int tmp2(0),tmp3(appendedCoords->getNumberOfTuples()/2);
11893 InternalAddPointOriented(e,-1,coords,tmp[1],tmp[2],*appendedCoords,tmp2);
11894 middles.push_back(tmp3+offset);
11897 middles.push_back(connBg[trueStart+nbOfEdges]);
11901 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)
11903 int tmpSrt(newConnOfCell->back()),tmpEnd(connBg[stp]);
11904 newConnOfCell->pushBackSilent(tmpEnd);
11909 int tmp2(0),tmp3(appendedCoords->getNumberOfTuples()/2);
11910 InternalAddPointOriented(e,-1,coords,tmpSrt,tmpEnd,*appendedCoords,tmp2);
11911 middles.push_back(tmp3+offset);
11914 middles.push_back(connBg[start+nbOfEdges]);
11918 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)
11920 // only the quadratic point to deal with:
11925 int tmpSrt(connBg[start]),tmpEnd(connBg[stp]);
11926 int tmp2(0),tmp3(appendedCoords->getNumberOfTuples()/2);
11927 InternalAddPointOriented(e,-1,coords,tmpSrt,tmpEnd,*appendedCoords,tmp2);
11928 middles.push_back(tmp3+offset);
11931 middles.push_back(connBg[start+nbOfEdges]);
11938 * 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 ) .
11939 * \a appendedCoords is a DataArrayDouble instance with number of components equal to one (even if the items are pushed by pair).
11941 bool MEDCouplingUMesh::Colinearize2DCell(const double *coords, const int *connBg, const int *connEnd, int offset, DataArrayInt *newConnOfCell, DataArrayDouble *appendedCoords)
11943 std::size_t sz(std::distance(connBg,connEnd));
11944 if(sz<3)//3 because 2+1(for the cell type) and 2 is the minimal number of edges of 2D cell.
11945 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Colinearize2DCell : the input cell has invalid format !");
11947 INTERP_KERNEL::AutoPtr<int> tmpConn(new int[sz]);
11948 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connBg[0]));
11949 unsigned nbs(cm.getNumberOfSons2(connBg+1,sz));
11950 unsigned nbOfHit(0); // number of fusions operated
11951 int posBaseElt(0),posEndElt(0),nbOfTurn(0);
11952 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
11953 INTERP_KERNEL::NormalizedCellType typeOfSon;
11954 std::vector<int> middles;
11956 for(;(nbOfTurn+nbOfHit)<nbs;nbOfTurn++)
11958 cm.fillSonCellNodalConnectivity2(posBaseElt,connBg+1,sz,tmpConn,typeOfSon);
11959 std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
11960 INTERP_KERNEL::Edge *e(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpConn,coords,m));
11961 posEndElt = posBaseElt+1;
11963 // Look backward first: are the final edges of the cells colinear with the first ones?
11964 // This initializes posBaseElt.
11967 for(unsigned i=1;i<nbs && nbOfHit<maxNbOfHit;i++) // 2nd condition is to avoid ending with a cell wih one single edge
11969 cm.fillSonCellNodalConnectivity2(nbs-i,connBg+1,sz,tmpConn,typeOfSon);
11970 INTERP_KERNEL::Edge *eCand(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpConn,coords,m));
11971 INTERP_KERNEL::EdgeIntersector *eint(INTERP_KERNEL::Edge::BuildIntersectorWith(e,eCand));
11972 bool isColinear=eint->areColinears();
11985 // Now move forward:
11986 const unsigned fwdStart = (nbOfTurn == 0 ? 0 : posBaseElt); // the first element to be inspected going forward
11987 for(unsigned j=fwdStart+1;j<nbs && nbOfHit<maxNbOfHit;j++) // 2nd condition is to avoid ending with a cell wih one single edge
11989 cm.fillSonCellNodalConnectivity2((int)j,connBg+1,sz,tmpConn,typeOfSon); // get edge #j's connectivity
11990 INTERP_KERNEL::Edge *eCand(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpConn,coords,m));
11991 INTERP_KERNEL::EdgeIntersector *eint(INTERP_KERNEL::Edge::BuildIntersectorWith(e,eCand));
11992 bool isColinear(eint->areColinears());
12004 //push [posBaseElt,posEndElt) in newConnOfCell using e
12005 // 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!
12007 // at the begining of the connectivity (insert type)
12008 EnterTheResultOf2DCellFirst(e,posBaseElt,posEndElt,(int)nbs,cm.isQuadratic(),coords,connBg+1,offset,newConnOfCell,appendedCoords,middles);
12009 else if((nbOfHit+nbOfTurn) != (nbs-1))
12011 EnterTheResultOf2DCellMiddle(e,posBaseElt,posEndElt,(int)nbs,cm.isQuadratic(),coords,connBg+1,offset,newConnOfCell,appendedCoords,middles);
12012 if ((nbOfHit+nbOfTurn) == (nbs-1))
12013 // at the end (only quad points to deal with)
12014 EnterTheResultOf2DCellEnd(e,posBaseElt,posEndElt,(int)nbs,cm.isQuadratic(),coords,connBg+1,offset,newConnOfCell,appendedCoords,middles);
12015 posBaseElt=posEndElt;
12018 if(!middles.empty())
12019 newConnOfCell->insertAtTheEnd(middles.begin(),middles.end());
12024 * It is the quadratic part of MEDCouplingUMesh::split2DCells. Here some additionnal nodes can be added at the end of coordinates array object.
12026 * \return int - the number of new nodes created.
12027 * \sa MEDCouplingUMesh::split2DCells
12029 int MEDCouplingUMesh::split2DCellsQuadratic(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI, const DataArrayInt *mid, const DataArrayInt *midI)
12031 checkConsistencyLight();
12032 int ncells(getNumberOfCells()),lgthToReach(getNodalConnectivityArrayLen()+2*subNodesInSeg->getNumberOfTuples()),nodesCnt(getNumberOfNodes());
12033 MCAuto<DataArrayInt> c(DataArrayInt::New()); c->alloc((std::size_t)lgthToReach);
12034 MCAuto<DataArrayDouble> addCoo(DataArrayDouble::New()); addCoo->alloc(0,1);
12035 const int *subPtr(subNodesInSeg->begin()),*subIPtr(subNodesInSegI->begin()),*descPtr(desc->begin()),*descIPtr(descI->begin()),*oldConn(getNodalConnectivity()->begin());
12036 const int *midPtr(mid->begin()),*midIPtr(midI->begin());
12037 const double *oldCoordsPtr(getCoords()->begin());
12038 int *cPtr(c->getPointer()),*ciPtr(getNodalConnectivityIndex()->getPointer());
12039 int prevPosOfCi(ciPtr[0]);
12040 for(int i=0;i<ncells;i++,ciPtr++,descIPtr++)
12042 int offset(descIPtr[0]),sz(descIPtr[1]-descIPtr[0]),deltaSz(sz);
12043 for(int j=0;j<sz;j++)
12044 { int sz2(subIPtr[descPtr[offset+j]+1]-subIPtr[descPtr[offset+j]]); deltaSz+=sz2; }
12045 *cPtr++=(int)INTERP_KERNEL::NORM_QPOLYG; cPtr[0]=oldConn[prevPosOfCi+1];
12046 for(int j=0;j<sz;j++)//loop over subedges of oldConn
12048 int offset2(subIPtr[descPtr[offset+j]]),sz2(subIPtr[descPtr[offset+j]+1]-subIPtr[descPtr[offset+j]]),offset3(midIPtr[descPtr[offset+j]]);
12052 cPtr[1]=oldConn[prevPosOfCi+2+j];
12053 cPtr[deltaSz]=oldConn[prevPosOfCi+1+j+sz]; cPtr++;
12056 std::vector<INTERP_KERNEL::Node *> ns(3);
12057 ns[0]=new INTERP_KERNEL::Node(oldCoordsPtr[2*oldConn[prevPosOfCi+1+j]],oldCoordsPtr[2*oldConn[prevPosOfCi+1+j]+1]);
12058 ns[1]=new INTERP_KERNEL::Node(oldCoordsPtr[2*oldConn[prevPosOfCi+1+(1+j)%sz]],oldCoordsPtr[2*oldConn[prevPosOfCi+1+(1+j)%sz]+1]);
12059 ns[2]=new INTERP_KERNEL::Node(oldCoordsPtr[2*oldConn[prevPosOfCi+1+sz+j]],oldCoordsPtr[2*oldConn[prevPosOfCi+1+sz+j]+1]);
12060 MCAuto<INTERP_KERNEL::Edge> e(INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(ns));
12061 for(int k=0;k<sz2;k++)//loop over subsplit of current subedge
12063 cPtr[1]=subPtr[offset2+k];
12064 cPtr[deltaSz]=InternalAddPoint(e,midPtr[offset3+k],oldCoordsPtr,cPtr[0],cPtr[1],*addCoo,nodesCnt); cPtr++;
12066 int tmpEnd(oldConn[prevPosOfCi+1+(j+1)%sz]);
12068 { cPtr[1]=tmpEnd; }
12069 cPtr[deltaSz]=InternalAddPoint(e,midPtr[offset3+sz2],oldCoordsPtr,cPtr[0],tmpEnd,*addCoo,nodesCnt); cPtr++;
12071 prevPosOfCi=ciPtr[1]; cPtr+=deltaSz;
12072 ciPtr[1]=ciPtr[0]+1+2*deltaSz;//sz==old nb of nodes because (nb of subedges=nb of nodes for polygons)
12075 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCellsQuadratic : Some of edges to be split are orphan !");
12076 _nodal_connec->decrRef();
12077 _nodal_connec=c.retn(); _types.clear(); _types.insert(INTERP_KERNEL::NORM_QPOLYG);
12078 addCoo->rearrange(2);
12079 MCAuto<DataArrayDouble> coo(DataArrayDouble::Aggregate(getCoords(),addCoo));//info are copied from getCoords() by using Aggregate
12081 return addCoo->getNumberOfTuples();
12084 void MEDCouplingUMesh::ComputeAllTypesInternal(std::set<INTERP_KERNEL::NormalizedCellType>& types, const DataArrayInt *nodalConnec, const DataArrayInt *nodalConnecIndex)
12086 if(nodalConnec && nodalConnecIndex)
12089 const int *conn(nodalConnec->begin()),*connIndex(nodalConnecIndex->begin());
12090 int nbOfElem(nodalConnecIndex->getNbOfElems()-1);
12092 for(const int *pt=connIndex;pt!=connIndex+nbOfElem;pt++)
12093 types.insert((INTERP_KERNEL::NormalizedCellType)conn[*pt]);
12097 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),
12098 _own_cell(true),_cell_id(-1),_nb_cell(0)
12103 _nb_cell=mesh->getNumberOfCells();
12107 MEDCouplingUMeshCellIterator::~MEDCouplingUMeshCellIterator()
12115 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh, MEDCouplingUMeshCell *itc, int bg, int end):_mesh(mesh),_cell(itc),
12116 _own_cell(false),_cell_id(bg-1),
12123 MEDCouplingUMeshCell *MEDCouplingUMeshCellIterator::nextt()
12126 if(_cell_id<_nb_cell)
12135 MEDCouplingUMeshCellByTypeEntry::MEDCouplingUMeshCellByTypeEntry(MEDCouplingUMesh *mesh):_mesh(mesh)
12141 MEDCouplingUMeshCellByTypeIterator *MEDCouplingUMeshCellByTypeEntry::iterator()
12143 return new MEDCouplingUMeshCellByTypeIterator(_mesh);
12146 MEDCouplingUMeshCellByTypeEntry::~MEDCouplingUMeshCellByTypeEntry()
12152 MEDCouplingUMeshCellEntry::MEDCouplingUMeshCellEntry(MEDCouplingUMesh *mesh, INTERP_KERNEL::NormalizedCellType type, MEDCouplingUMeshCell *itc, int bg, int end):_mesh(mesh),_type(type),
12160 MEDCouplingUMeshCellEntry::~MEDCouplingUMeshCellEntry()
12166 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCellEntry::getType() const
12171 int MEDCouplingUMeshCellEntry::getNumberOfElems() const
12176 MEDCouplingUMeshCellIterator *MEDCouplingUMeshCellEntry::iterator()
12178 return new MEDCouplingUMeshCellIterator(_mesh,_itc,_bg,_end);
12181 MEDCouplingUMeshCellByTypeIterator::MEDCouplingUMeshCellByTypeIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),_cell_id(0),_nb_cell(0)
12186 _nb_cell=mesh->getNumberOfCells();
12190 MEDCouplingUMeshCellByTypeIterator::~MEDCouplingUMeshCellByTypeIterator()
12197 MEDCouplingUMeshCellEntry *MEDCouplingUMeshCellByTypeIterator::nextt()
12199 const int *c=_mesh->getNodalConnectivity()->begin();
12200 const int *ci=_mesh->getNodalConnectivityIndex()->begin();
12201 if(_cell_id<_nb_cell)
12203 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[_cell_id]];
12204 int nbOfElems=(int)std::distance(ci+_cell_id,std::find_if(ci+_cell_id,ci+_nb_cell,MEDCouplingImpl::ConnReader(c,type)));
12205 int startId=_cell_id;
12206 _cell_id+=nbOfElems;
12207 return new MEDCouplingUMeshCellEntry(_mesh,type,_cell,startId,_cell_id);
12213 MEDCouplingUMeshCell::MEDCouplingUMeshCell(MEDCouplingUMesh *mesh):_conn(0),_conn_indx(0),_conn_lgth(NOTICABLE_FIRST_VAL)
12217 _conn=mesh->getNodalConnectivity()->getPointer();
12218 _conn_indx=mesh->getNodalConnectivityIndex()->getPointer();
12222 void MEDCouplingUMeshCell::next()
12224 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
12229 _conn_lgth=_conn_indx[1]-_conn_indx[0];
12232 std::string MEDCouplingUMeshCell::repr() const
12234 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
12236 std::ostringstream oss; oss << "Cell Type " << INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)_conn[0]).getRepr();
12238 std::copy(_conn+1,_conn+_conn_lgth,std::ostream_iterator<int>(oss," "));
12242 return std::string("MEDCouplingUMeshCell::repr : Invalid pos");
12245 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCell::getType() const
12247 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
12248 return (INTERP_KERNEL::NormalizedCellType)_conn[0];
12250 return INTERP_KERNEL::NORM_ERROR;
12253 const int *MEDCouplingUMeshCell::getAllConn(int& lgth) const
12256 if(_conn_lgth!=NOTICABLE_FIRST_VAL)