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 (EDF R&D)
21 #include "MEDCouplingUMesh.hxx"
22 #include "MEDCouplingCMesh.hxx"
23 #include "MEDCoupling1GTUMesh.hxx"
24 #include "MEDCouplingFieldDouble.hxx"
25 #include "MEDCouplingSkyLineArray.hxx"
26 #include "CellModel.hxx"
27 #include "VolSurfUser.txx"
28 #include "InterpolationUtils.hxx"
29 #include "PointLocatorAlgos.txx"
31 #include "BBTreeDst.txx"
32 #include "SplitterTetra.hxx"
33 #include "DiameterCalculator.hxx"
34 #include "DirectedBoundingBox.hxx"
35 #include "InterpKernelMatrixTools.hxx"
36 #include "InterpKernelMeshQuality.hxx"
37 #include "InterpKernelCellSimplify.hxx"
38 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
39 #include "InterpKernelAutoPtr.hxx"
40 #include "InterpKernelGeo2DNode.hxx"
41 #include "InterpKernelGeo2DEdgeLin.hxx"
42 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
43 #include "InterpKernelGeo2DQuadraticPolygon.hxx"
44 #include "OrientationInverter.hxx"
45 #include "MEDCouplingUMesh_internal.hxx"
54 using namespace MEDCoupling;
56 double MEDCouplingUMesh::EPS_FOR_POLYH_ORIENTATION=1.e-14;
59 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_PENTA18, INTERP_KERNEL::NORM_HEXA20, INTERP_KERNEL::NORM_HEXA27, INTERP_KERNEL::NORM_POLYHED };
60 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,32,-1,25,42,36,4};
63 MEDCouplingUMesh *MEDCouplingUMesh::New()
65 return new MEDCouplingUMesh;
68 MEDCouplingUMesh *MEDCouplingUMesh::New(const std::string& meshName, int meshDim)
70 MEDCouplingUMesh *ret=new MEDCouplingUMesh;
71 ret->setName(meshName);
72 ret->setMeshDimension(meshDim);
77 * Returns a new MEDCouplingUMesh which is a full copy of \a this one. No data is shared
78 * between \a this and the new mesh.
79 * \return MEDCouplingUMesh * - a new instance of MEDCouplingMesh. The caller is to
80 * delete this mesh using decrRef() as it is no more needed.
82 MEDCouplingUMesh *MEDCouplingUMesh::deepCopy() const
89 * Returns a new MEDCouplingUMesh which is a copy of \a this one.
90 * \param [in] recDeepCpy - if \a true, the copy is deep, else all data arrays of \a
91 * this mesh are shared by the new mesh.
92 * \return MEDCouplingUMesh * - a new instance of MEDCouplingMesh. The caller is to
93 * delete this mesh using decrRef() as it is no more needed.
95 MEDCouplingUMesh *MEDCouplingUMesh::clone(bool recDeepCpy) const
97 return new MEDCouplingUMesh(*this,recDeepCpy);
101 * This method behaves mostly like MEDCouplingUMesh::deepCopy method, except that only nodal connectivity arrays are deeply copied.
102 * The coordinates are shared between \a this and the returned instance.
104 * \return MEDCouplingUMesh * - A new object instance holding the copy of \a this (deep for connectivity, shallow for coordiantes)
105 * \sa MEDCouplingUMesh::deepCopy
107 MEDCouplingUMesh *MEDCouplingUMesh::deepCopyConnectivityOnly() const
109 checkConnectivityFullyDefined();
110 MCAuto<MEDCouplingUMesh> ret=clone(false);
111 MCAuto<DataArrayInt> c(getNodalConnectivity()->deepCopy()),ci(getNodalConnectivityIndex()->deepCopy());
112 ret->setConnectivity(c,ci);
116 void MEDCouplingUMesh::shallowCopyConnectivityFrom(const MEDCouplingPointSet *other)
119 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is null !");
120 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
122 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is not an MEDCouplingUMesh instance !");
123 MEDCouplingUMesh *otherC2=const_cast<MEDCouplingUMesh *>(otherC);//sorry :(
124 setConnectivity(otherC2->getNodalConnectivity(),otherC2->getNodalConnectivityIndex(),true);
127 std::size_t MEDCouplingUMesh::getHeapMemorySizeWithoutChildren() const
129 std::size_t ret(MEDCouplingPointSet::getHeapMemorySizeWithoutChildren());
133 std::vector<const BigMemoryObject *> MEDCouplingUMesh::getDirectChildrenWithNull() const
135 std::vector<const BigMemoryObject *> ret(MEDCouplingPointSet::getDirectChildrenWithNull());
136 ret.push_back(_nodal_connec);
137 ret.push_back(_nodal_connec_index);
141 void MEDCouplingUMesh::updateTime() const
143 MEDCouplingPointSet::updateTime();
146 updateTimeWith(*_nodal_connec);
148 if(_nodal_connec_index)
150 updateTimeWith(*_nodal_connec_index);
154 MEDCouplingUMesh::MEDCouplingUMesh():_mesh_dim(-2),_nodal_connec(0),_nodal_connec_index(0)
159 * Checks if \a this mesh is well defined. If no exception is thrown by this method,
160 * then \a this mesh is most probably is writable, exchangeable and available for most
161 * of algorithms. When a mesh is constructed from scratch, it is a good habit to call
162 * this method to check that all is in order with \a this mesh.
163 * \throw If the mesh dimension is not set.
164 * \throw If the coordinates array is not set (if mesh dimension != -1 ).
165 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
166 * \throw If the connectivity data array has more than one component.
167 * \throw If the connectivity data array has a named component.
168 * \throw If the connectivity index data array has more than one component.
169 * \throw If the connectivity index data array has a named component.
171 void MEDCouplingUMesh::checkConsistencyLight() const
174 throw INTERP_KERNEL::Exception("No mesh dimension specified !");
176 MEDCouplingPointSet::checkConsistencyLight();
177 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
179 if((int)INTERP_KERNEL::CellModel::GetCellModel(*iter).getDimension()!=_mesh_dim)
181 std::ostringstream message;
182 message << "Mesh invalid because dimension is " << _mesh_dim << " and there is presence of cell(s) with type " << (*iter);
183 throw INTERP_KERNEL::Exception(message.str().c_str());
188 if(_nodal_connec->getNumberOfComponents()!=1)
189 throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to be with number of components set to one !");
190 if(_nodal_connec->getInfoOnComponent(0)!="")
191 throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to have no info on its single component !");
195 throw INTERP_KERNEL::Exception("Nodal connectivity array is not defined !");
196 if(_nodal_connec_index)
198 if(_nodal_connec_index->getNumberOfComponents()!=1)
199 throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to be with number of components set to one !");
200 if(_nodal_connec_index->getInfoOnComponent(0)!="")
201 throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to have no info on its single component !");
205 throw INTERP_KERNEL::Exception("Nodal connectivity index array is not defined !");
209 * Checks if \a this mesh is well defined. If no exception is thrown by this method,
210 * then \a this mesh is most probably is writable, exchangeable and available for all
211 * algorithms. <br> In addition to the checks performed by checkConsistencyLight(), this
212 * method thoroughly checks the nodal connectivity.
213 * \param [in] eps - a not used parameter.
214 * \throw If the mesh dimension is not set.
215 * \throw If the coordinates array is not set (if mesh dimension != -1 ).
216 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
217 * \throw If the connectivity data array has more than one component.
218 * \throw If the connectivity data array has a named component.
219 * \throw If the connectivity index data array has more than one component.
220 * \throw If the connectivity index data array has a named component.
221 * \throw If number of nodes defining an element does not correspond to the type of element.
222 * \throw If the nodal connectivity includes an invalid node id.
224 void MEDCouplingUMesh::checkConsistency(double eps) const
226 checkConsistencyLight();
229 int meshDim=getMeshDimension();
230 int nbOfNodes=getNumberOfNodes();
231 int nbOfCells=getNumberOfCells();
232 const int *ptr=_nodal_connec->getConstPointer();
233 const int *ptrI=_nodal_connec_index->getConstPointer();
234 for(int i=0;i<nbOfCells;i++)
236 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)ptr[ptrI[i]]);
237 if((int)cm.getDimension()!=meshDim)
239 std::ostringstream oss;
240 oss << "MEDCouplingUMesh::checkConsistency : cell << #" << i<< " with type Type " << cm.getRepr() << " in 'this' whereas meshdim == " << meshDim << " !";
241 throw INTERP_KERNEL::Exception(oss.str());
243 int nbOfNodesInCell=ptrI[i+1]-ptrI[i]-1;
245 if(nbOfNodesInCell!=(int)cm.getNumberOfNodes())
247 std::ostringstream oss;
248 oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with static Type '" << cm.getRepr() << "' has " << cm.getNumberOfNodes();
249 oss << " nodes whereas in connectivity there is " << nbOfNodesInCell << " nodes ! Looks very bad !";
250 throw INTERP_KERNEL::Exception(oss.str());
252 if(cm.isQuadratic() && cm.isDynamic() && meshDim == 2)
253 if (nbOfNodesInCell % 2 || nbOfNodesInCell < 4)
255 std::ostringstream oss;
256 oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with quadratic type '" << cm.getRepr() << "' has " << nbOfNodesInCell;
257 oss << " nodes. This should be even, and greater or equal than 4!! Looks very bad!";
258 throw INTERP_KERNEL::Exception(oss.str());
260 for(const int *w=ptr+ptrI[i]+1;w!=ptr+ptrI[i+1];w++)
265 if(nodeId>=nbOfNodes)
267 std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " whereas there are only " << nbOfNodes << " nodes in the mesh !";
268 throw INTERP_KERNEL::Exception(oss.str());
273 std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " in connectivity ! sounds bad !";
274 throw INTERP_KERNEL::Exception(oss.str());
278 if((INTERP_KERNEL::NormalizedCellType)(ptr[ptrI[i]])!=INTERP_KERNEL::NORM_POLYHED)
280 std::ostringstream oss; oss << "Cell #" << i << " is built with node #-1 in connectivity ! sounds bad !";
281 throw INTERP_KERNEL::Exception(oss.str());
289 * Sets dimension of \a this mesh. The mesh dimension in general depends on types of
290 * elements contained in the mesh. For more info on the mesh dimension see
291 * \ref MEDCouplingUMeshPage.
292 * \param [in] meshDim - a new mesh dimension.
293 * \throw If \a meshDim is invalid. A valid range is <em> -1 <= meshDim <= 3</em>.
295 void MEDCouplingUMesh::setMeshDimension(int meshDim)
297 if(meshDim<-1 || meshDim>3)
298 throw INTERP_KERNEL::Exception("Invalid meshDim specified ! Must be greater or equal to -1 and lower or equal to 3 !");
304 * Allocates memory to store an estimation of the given number of cells. The closer is the estimation to the number of cells effectively inserted,
305 * 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.
306 * If a nodal connectivity previouly existed before the call of this method, it will be reset.
308 * \param [in] nbOfCells - estimation of the number of cell \a this mesh will contain.
310 * \if ENABLE_EXAMPLES
311 * \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
312 * \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
315 void MEDCouplingUMesh::allocateCells(int nbOfCells)
318 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::allocateCells : the input number of cells should be >= 0 !");
319 if(_nodal_connec_index)
321 _nodal_connec_index->decrRef();
325 _nodal_connec->decrRef();
327 _nodal_connec_index=DataArrayInt::New();
328 _nodal_connec_index->reserve(nbOfCells+1);
329 _nodal_connec_index->pushBackSilent(0);
330 _nodal_connec=DataArrayInt::New();
331 _nodal_connec->reserve(2*nbOfCells);
337 * Appends a cell to the connectivity array. For deeper understanding what is
338 * happening see \ref MEDCouplingUMeshNodalConnectivity.
339 * \param [in] type - type of cell to add.
340 * \param [in] size - number of nodes constituting this cell.
341 * \param [in] nodalConnOfCell - the connectivity of the cell to add.
343 * \if ENABLE_EXAMPLES
344 * \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
345 * \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
348 void MEDCouplingUMesh::insertNextCell(INTERP_KERNEL::NormalizedCellType type, int size, const int *nodalConnOfCell)
350 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
351 if(_nodal_connec_index==0)
352 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::insertNextCell : nodal connectivity not set ! invoke allocateCells before calling insertNextCell !");
353 if((int)cm.getDimension()==_mesh_dim)
356 if(size!=(int)cm.getNumberOfNodes())
358 std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : Trying to push a " << cm.getRepr() << " cell with a size of " << size;
359 oss << " ! Expecting " << cm.getNumberOfNodes() << " !";
360 throw INTERP_KERNEL::Exception(oss.str());
362 int idx=_nodal_connec_index->back();
364 _nodal_connec_index->pushBackSilent(val);
365 _nodal_connec->writeOnPlace(idx,type,nodalConnOfCell,size);
370 std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : cell type " << cm.getRepr() << " has a dimension " << cm.getDimension();
371 oss << " whereas Mesh Dimension of current UMesh instance is set to " << _mesh_dim << " ! Please invoke \"setMeshDimension\" method before or invoke ";
372 oss << "\"MEDCouplingUMesh::New\" static method with 2 parameters name and meshDimension !";
373 throw INTERP_KERNEL::Exception(oss.str());
378 * Compacts data arrays to release unused memory. This method is to be called after
379 * finishing cell insertion using \a this->insertNextCell().
381 * \if ENABLE_EXAMPLES
382 * \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
383 * \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
386 void MEDCouplingUMesh::finishInsertingCells()
388 _nodal_connec->pack();
389 _nodal_connec_index->pack();
390 _nodal_connec->declareAsNew();
391 _nodal_connec_index->declareAsNew();
396 * Entry point for iteration over cells of this. Warning the returned cell iterator should be deallocated.
397 * Useful for python users.
399 MEDCouplingUMeshCellIterator *MEDCouplingUMesh::cellIterator()
401 return new MEDCouplingUMeshCellIterator(this);
405 * Entry point for iteration over cells groups geo types per geotypes. Warning the returned cell iterator should be deallocated.
406 * If \a this is not so that that cells are grouped by geo types this method will throw an exception.
407 * In this case MEDCouplingUMesh::sortCellsInMEDFileFrmt or MEDCouplingUMesh::rearrange2ConsecutiveCellTypes methods for example can be called before invoking this method.
408 * Useful for python users.
410 MEDCouplingUMeshCellByTypeEntry *MEDCouplingUMesh::cellsByType()
412 if(!checkConsecutiveCellTypes())
413 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::cellsByType : this mesh is not sorted by type !");
414 return new MEDCouplingUMeshCellByTypeEntry(this);
418 * Returns a set of all cell types available in \a this mesh.
419 * \return std::set<INTERP_KERNEL::NormalizedCellType> - the set of cell types.
420 * \warning this method does not throw any exception even if \a this is not defined.
421 * \sa MEDCouplingUMesh::getAllGeoTypesSorted
423 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypes() const
429 * This method returns the sorted list of geometric types in \a this.
430 * 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
431 * having the same geometric type. So a same geometric type can appear more than once if the cells are not sorted per geometric type.
433 * \throw if connectivity in \a this is not correctly defined.
435 * \sa MEDCouplingMesh::getAllGeoTypes
437 std::vector<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypesSorted() const
439 std::vector<INTERP_KERNEL::NormalizedCellType> ret;
440 checkConnectivityFullyDefined();
441 int nbOfCells(getNumberOfCells());
444 if(getNodalConnectivityArrayLen()<1)
445 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAllGeoTypesSorted : the connectivity in this seems invalid !");
446 const int *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin());
447 ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci++]);
448 for(int i=1;i<nbOfCells;i++,ci++)
449 if(ret.back()!=((INTERP_KERNEL::NormalizedCellType)c[*ci]))
450 ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci]);
455 * This method is a method that compares \a this and \a other.
456 * This method compares \b all attributes, even names and component names.
458 bool MEDCouplingUMesh::isEqualIfNotWhy(const MEDCouplingMesh *other, double prec, std::string& reason) const
461 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isEqualIfNotWhy : input other pointer is null !");
462 std::ostringstream oss; oss.precision(15);
463 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
466 reason="mesh given in input is not castable in MEDCouplingUMesh !";
469 if(!MEDCouplingPointSet::isEqualIfNotWhy(other,prec,reason))
471 if(_mesh_dim!=otherC->_mesh_dim)
473 oss << "umesh dimension mismatch : this mesh dimension=" << _mesh_dim << " other mesh dimension=" << otherC->_mesh_dim;
477 if(_types!=otherC->_types)
479 oss << "umesh geometric type mismatch :\nThis geometric types are :";
480 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
481 { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
482 oss << "\nOther geometric types are :";
483 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=otherC->_types.begin();iter!=otherC->_types.end();iter++)
484 { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
488 if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
489 if(_nodal_connec==0 || otherC->_nodal_connec==0)
491 reason="Only one UMesh between the two this and other has its nodal connectivity DataArrayInt defined !";
494 if(_nodal_connec!=otherC->_nodal_connec)
495 if(!_nodal_connec->isEqualIfNotWhy(*otherC->_nodal_connec,reason))
497 reason.insert(0,"Nodal connectivity DataArrayInt differ : ");
500 if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
501 if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
503 reason="Only one UMesh between the two this and other has its nodal connectivity index DataArrayInt defined !";
506 if(_nodal_connec_index!=otherC->_nodal_connec_index)
507 if(!_nodal_connec_index->isEqualIfNotWhy(*otherC->_nodal_connec_index,reason))
509 reason.insert(0,"Nodal connectivity index DataArrayInt differ : ");
516 * Checks if data arrays of this mesh (node coordinates, nodal
517 * connectivity of cells, etc) of two meshes are same. Textual data like name etc. are
519 * \param [in] other - the mesh to compare with.
520 * \param [in] prec - precision value used to compare node coordinates.
521 * \return bool - \a true if the two meshes are same.
523 bool MEDCouplingUMesh::isEqualWithoutConsideringStr(const MEDCouplingMesh *other, double prec) const
525 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
528 if(!MEDCouplingPointSet::isEqualWithoutConsideringStr(other,prec))
530 if(_mesh_dim!=otherC->_mesh_dim)
532 if(_types!=otherC->_types)
534 if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
535 if(_nodal_connec==0 || otherC->_nodal_connec==0)
537 if(_nodal_connec!=otherC->_nodal_connec)
538 if(!_nodal_connec->isEqualWithoutConsideringStr(*otherC->_nodal_connec))
540 if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
541 if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
543 if(_nodal_connec_index!=otherC->_nodal_connec_index)
544 if(!_nodal_connec_index->isEqualWithoutConsideringStr(*otherC->_nodal_connec_index))
550 * Checks if \a this and \a other meshes are geometrically equivalent with high
551 * probability, else an exception is thrown. The meshes are considered equivalent if
552 * (1) meshes contain the same number of nodes and the same number of elements of the
553 * same types (2) three cells of the two meshes (first, last and middle) are based
554 * on coincident nodes (with a specified precision).
555 * \param [in] other - the mesh to compare with.
556 * \param [in] prec - the precision used to compare nodes of the two meshes.
557 * \throw If the two meshes do not match.
559 void MEDCouplingUMesh::checkFastEquivalWith(const MEDCouplingMesh *other, double prec) const
561 MEDCouplingPointSet::checkFastEquivalWith(other,prec);
562 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
564 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkFastEquivalWith : Two meshes are not not unstructured !");
568 * Returns the reverse nodal connectivity. The reverse nodal connectivity enumerates
569 * cells each node belongs to.
570 * \warning For speed reasons, this method does not check if node ids in the nodal
571 * connectivity correspond to the size of node coordinates array.
572 * \param [in,out] revNodal - an array holding ids of cells sharing each node.
573 * \param [in,out] revNodalIndx - an array, of length \a this->getNumberOfNodes() + 1,
574 * dividing cell ids in \a revNodal into groups each referring to one
575 * node. Its every element (except the last one) is an index pointing to the
576 * first id of a group of cells. For example cells sharing the node #1 are
577 * described by following range of indices:
578 * [ \a revNodalIndx[1], \a revNodalIndx[2] ) and the cell ids are
579 * \a revNodal[ \a revNodalIndx[1] ], \a revNodal[ \a revNodalIndx[1] + 1], ...
580 * Number of cells sharing the *i*-th node is
581 * \a revNodalIndx[ *i*+1 ] - \a revNodalIndx[ *i* ].
582 * \throw If the coordinates array is not set.
583 * \throw If the nodal connectivity of cells is not defined.
585 * \if ENABLE_EXAMPLES
586 * \ref cpp_mcumesh_getReverseNodalConnectivity "Here is a C++ example".<br>
587 * \ref py_mcumesh_getReverseNodalConnectivity "Here is a Python example".
590 void MEDCouplingUMesh::getReverseNodalConnectivity(DataArrayInt *revNodal, DataArrayInt *revNodalIndx) const
593 int nbOfNodes(getNumberOfNodes());
594 int *revNodalIndxPtr=(int *)malloc((nbOfNodes+1)*sizeof(int));
595 revNodalIndx->useArray(revNodalIndxPtr,true,C_DEALLOC,nbOfNodes+1,1);
596 std::fill(revNodalIndxPtr,revNodalIndxPtr+nbOfNodes+1,0);
597 const int *conn(_nodal_connec->begin()),*connIndex(_nodal_connec_index->begin());
598 int nbOfCells(getNumberOfCells()),nbOfEltsInRevNodal(0);
599 for(int eltId=0;eltId<nbOfCells;eltId++)
601 const int *strtNdlConnOfCurCell(conn+connIndex[eltId]+1),*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;
624 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
625 * this->getMeshDimension(), that bound cells of \a this mesh. In addition arrays
626 * describing correspondence between cells of \a this and the result meshes are
627 * returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending connectivity,
628 * i.e. enumerate cells of the result mesh bounding each cell of \a this mesh. The
629 * arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
630 * i.e. enumerate cells of \a this mesh bounded by each cell of the result mesh.
631 * \warning For speed reasons, this method does not check if node ids in the nodal
632 * connectivity correspond to the size of node coordinates array.
633 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
634 * to write this mesh to the MED file, its cells must be sorted using
635 * sortCellsInMEDFileFrmt().
636 * \param [in,out] desc - the array containing cell ids of the result mesh bounding
637 * each cell of \a this mesh.
638 * \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
639 * dividing cell ids in \a desc into groups each referring to one
640 * cell of \a this mesh. Its every element (except the last one) is an index
641 * pointing to the first id of a group of cells. For example cells of the
642 * result mesh bounding the cell #1 of \a this mesh are described by following
644 * [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
645 * \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
646 * Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
647 * \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
648 * \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
649 * by each cell of the result mesh.
650 * \param [in,out] revDescIndx - the array, of length one more than number of cells
651 * in the result mesh,
652 * dividing cell ids in \a revDesc into groups each referring to one
653 * cell of the result mesh the same way as \a descIndx divides \a desc.
654 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is to
655 * delete this mesh using decrRef() as it is no more needed.
656 * \throw If the coordinates array is not set.
657 * \throw If the nodal connectivity of cells is node defined.
658 * \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
659 * revDescIndx == NULL.
661 * \if ENABLE_EXAMPLES
662 * \ref cpp_mcumesh_buildDescendingConnectivity "Here is a C++ example".<br>
663 * \ref py_mcumesh_buildDescendingConnectivity "Here is a Python example".
665 * \sa buildDescendingConnectivity2()
667 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
669 return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
673 * \a this has to have a mesh dimension equal to 3. If it is not the case an INTERP_KERNEL::Exception will be thrown.
674 * This behaves exactly as MEDCouplingUMesh::buildDescendingConnectivity does except that this method compute directly the transition from mesh dimension 3 to sub edges (dimension 1)
675 * in one shot. That is to say that this method is equivalent to 2 successive calls to MEDCouplingUMesh::buildDescendingConnectivity.
676 * This method returns 4 arrays and a mesh as MEDCouplingUMesh::buildDescendingConnectivity does.
677 * \sa MEDCouplingUMesh::buildDescendingConnectivity
679 MEDCouplingUMesh *MEDCouplingUMesh::explode3DMeshTo1D(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
682 if(getMeshDimension()!=3)
683 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explode3DMeshTo1D : This has to have a mesh dimension to 3 !");
684 return buildDescendingConnectivityGen<MinusTwoSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
688 * 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.
689 * This method works for both meshes with mesh dimenstion equal to 2 or 3. Dynamical cells are not supported (polygons, polyhedrons...)
691 * \sa explode3DMeshTo1D, buildDescendingConnectiviy
693 MEDCouplingUMesh *MEDCouplingUMesh::explodeMeshIntoMicroEdges(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
696 switch(getMeshDimension())
699 return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
701 return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
703 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explodeMeshIntoMicroEdges : Only 2D and 3D supported !");
708 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
709 * this->getMeshDimension(), that bound cells of \a this mesh. In
710 * addition arrays describing correspondence between cells of \a this and the result
711 * meshes are returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending
712 * connectivity, i.e. enumerate cells of the result mesh bounding each cell of \a this
713 * mesh. This method differs from buildDescendingConnectivity() in that apart
714 * from cell ids, \a desc returns mutual orientation of cells in \a this and the
715 * result meshes. So a positive id means that order of nodes in corresponding cells
716 * of two meshes is same, and a negative id means a reverse order of nodes. Since a
717 * cell with id #0 can't be negative, the array \a desc returns ids in FORTRAN mode,
718 * i.e. cell ids are one-based.
719 * Arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
720 * i.e. enumerate cells of \a this mesh bounded by each cell of the result mesh.
721 * \warning For speed reasons, this method does not check if node ids in the nodal
722 * connectivity correspond to the size of node coordinates array.
723 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
724 * to write this mesh to the MED file, its cells must be sorted using
725 * sortCellsInMEDFileFrmt().
726 * \param [in,out] desc - the array containing cell ids of the result mesh bounding
727 * each cell of \a this mesh.
728 * \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
729 * dividing cell ids in \a desc into groups each referring to one
730 * cell of \a this mesh. Its every element (except the last one) is an index
731 * pointing to the first id of a group of cells. For example cells of the
732 * result mesh bounding the cell #1 of \a this mesh are described by following
734 * [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
735 * \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
736 * Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
737 * \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
738 * \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
739 * by each cell of the result mesh.
740 * \param [in,out] revDescIndx - the array, of length one more than number of cells
741 * in the result mesh,
742 * dividing cell ids in \a revDesc into groups each referring to one
743 * cell of the result mesh the same way as \a descIndx divides \a desc.
744 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This result mesh
745 * shares the node coordinates array with \a this mesh. The caller is to
746 * delete this mesh using decrRef() as it is no more needed.
747 * \throw If the coordinates array is not set.
748 * \throw If the nodal connectivity of cells is node defined.
749 * \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
750 * revDescIndx == NULL.
752 * \if ENABLE_EXAMPLES
753 * \ref cpp_mcumesh_buildDescendingConnectivity2 "Here is a C++ example".<br>
754 * \ref py_mcumesh_buildDescendingConnectivity2 "Here is a Python example".
756 * \sa buildDescendingConnectivity()
758 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity2(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
760 return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingOrientationSensitiveNbrer);
764 * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
765 * For speed reasons no check of this will be done. This method calls
766 * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
767 * This method lists cell by cell in \b this which are its neighbors. To compute the result
768 * only connectivities are considered.
769 * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
770 * The format of return is hence \ref numbering-indirect.
772 * \param [out] neighbors is an array storing all the neighbors of all cells in \b this. This array is newly
773 * allocated and should be dealt by the caller. \b neighborsIndx 2nd output
774 * parameter allows to select the right part in this array (\ref numbering-indirect). The number of tuples
775 * is equal to the last values in \b neighborsIndx.
776 * \param [out] neighborsIndx is an array of size this->getNumberOfCells()+1 newly allocated and should be
777 * dealt by the caller. This arrays allow to use the first output parameter \b neighbors (\ref numbering-indirect).
779 void MEDCouplingUMesh::computeNeighborsOfCells(DataArrayInt *&neighbors, DataArrayInt *&neighborsIndx) const
781 MCAuto<DataArrayInt> desc=DataArrayInt::New();
782 MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
783 MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
784 MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
785 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
787 ComputeNeighborsOfCellsAdv(desc,descIndx,revDesc,revDescIndx,neighbors,neighborsIndx);
790 void MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne(const DataArrayInt *nodeNeigh, const DataArrayInt *nodeNeighI, MCAuto<DataArrayInt>& cellNeigh, MCAuto<DataArrayInt>& cellNeighIndex) const
792 if(!nodeNeigh || !nodeNeighI)
793 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : null pointer !");
794 checkConsistencyLight();
795 nodeNeigh->checkAllocated(); nodeNeighI->checkAllocated();
796 nodeNeigh->checkNbOfComps(1,"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : node neigh");
797 nodeNeighI->checkNbOfComps(1,"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : node neigh index");
798 nodeNeighI->checkNbOfTuples(1+getNumberOfNodes(),"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : invalid length");
799 int nbCells(getNumberOfCells());
800 const int *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin()),*ne(nodeNeigh->begin()),*nei(nodeNeighI->begin());
801 cellNeigh=DataArrayInt::New(); cellNeigh->alloc(0,1); cellNeighIndex=DataArrayInt::New(); cellNeighIndex->alloc(1,1); cellNeighIndex->setIJ(0,0,0);
802 for(int i=0;i<nbCells;i++)
805 for(const int *it=c+ci[i]+1;it!=c+ci[i+1];it++)
807 s.insert(ne+nei[*it],ne+nei[*it+1]);
809 cellNeigh->insertAtTheEnd(s.begin(),s.end());
810 cellNeighIndex->pushBackSilent(cellNeigh->getNumberOfTuples());
815 * This method is called by MEDCouplingUMesh::computeNeighborsOfCells. This methods performs the algorithm
816 * of MEDCouplingUMesh::computeNeighborsOfCells.
817 * This method is useful for users that want to reduce along a criterion the set of neighbours cell. This is
818 * typically the case to extract a set a neighbours,
819 * excluding a set of meshdim-1 cells in input descending connectivity.
820 * Typically \b desc, \b descIndx, \b revDesc and \b revDescIndx (\ref numbering-indirect) input params are
821 * the result of MEDCouplingUMesh::buildDescendingConnectivity.
822 * This method lists cell by cell in \b this which are its neighbors. To compute the result only connectivities
824 * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
826 * \param [in] desc descending connectivity array.
827 * \param [in] descIndx descending connectivity index array used to walk through \b desc (\ref numbering-indirect).
828 * \param [in] revDesc reverse descending connectivity array.
829 * \param [in] revDescIndx reverse descending connectivity index array used to walk through \b revDesc (\ref numbering-indirect).
830 * \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
831 * parameter allows to select the right part in this array. The number of tuples is equal to the last values in \b neighborsIndx.
832 * \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.
834 void MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(const DataArrayInt *desc, const DataArrayInt *descIndx, const DataArrayInt *revDesc, const DataArrayInt *revDescIndx,
835 DataArrayInt *&neighbors, DataArrayInt *&neighborsIndx)
837 if(!desc || !descIndx || !revDesc || !revDescIndx)
838 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeNeighborsOfCellsAdv some input array is empty !");
839 const int *descPtr=desc->begin();
840 const int *descIPtr=descIndx->begin();
841 const int *revDescPtr=revDesc->begin();
842 const int *revDescIPtr=revDescIndx->begin();
844 int nbCells=descIndx->getNumberOfTuples()-1;
845 MCAuto<DataArrayInt> out0=DataArrayInt::New();
846 MCAuto<DataArrayInt> out1=DataArrayInt::New(); out1->alloc(nbCells+1,1);
847 int *out1Ptr=out1->getPointer();
849 out0->reserve(desc->getNumberOfTuples());
850 for(int i=0;i<nbCells;i++,descIPtr++,out1Ptr++)
852 for(const int *w1=descPtr+descIPtr[0];w1!=descPtr+descIPtr[1];w1++)
854 std::set<int> s(revDescPtr+revDescIPtr[*w1],revDescPtr+revDescIPtr[(*w1)+1]);
856 out0->insertAtTheEnd(s.begin(),s.end());
858 *out1Ptr=out0->getNumberOfTuples();
860 neighbors=out0.retn();
861 neighborsIndx=out1.retn();
865 * Explodes \a this into edges whatever its dimension.
867 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::explodeIntoEdges(MCAuto<DataArrayInt>& desc, MCAuto<DataArrayInt>& descIndex, MCAuto<DataArrayInt>& revDesc, MCAuto<DataArrayInt>& revDescIndx) const
870 int mdim(getMeshDimension());
871 desc=DataArrayInt::New(); descIndex=DataArrayInt::New(); revDesc=DataArrayInt::New(); revDescIndx=DataArrayInt::New();
872 MCAuto<MEDCouplingUMesh> mesh1D;
877 mesh1D=explode3DMeshTo1D(desc,descIndex,revDesc,revDescIndx);
882 mesh1D=buildDescendingConnectivity(desc,descIndex,revDesc,revDescIndx);
887 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2] !");
894 * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
895 * For speed reasons no check of this will be done. This method calls
896 * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
897 * This method lists node by node in \b this which are its neighbors. To compute the result
898 * only connectivities are considered.
899 * The neighbor nodes of node having id 'nodeId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
901 * \param [out] neighbors is an array storing all the neighbors of all nodes in \b this. This array
902 * is newly allocated and should be dealt by the caller. \b neighborsIndx 2nd output
903 * parameter allows to select the right part in this array (\ref numbering-indirect).
904 * The number of tuples is equal to the last values in \b neighborsIndx.
905 * \param [out] neighborsIdx is an array of size this->getNumberOfCells()+1 newly allocated and should
906 * be dealt by the caller. This arrays allow to use the first output parameter \b neighbors.
908 * \sa MEDCouplingUMesh::computeEnlargedNeighborsOfNodes
910 void MEDCouplingUMesh::computeNeighborsOfNodes(DataArrayInt *&neighbors, DataArrayInt *&neighborsIdx) const
913 int mdim(getMeshDimension()),nbNodes(getNumberOfNodes());
914 MCAuto<DataArrayInt> desc(DataArrayInt::New()),descIndx(DataArrayInt::New()),revDesc(DataArrayInt::New()),revDescIndx(DataArrayInt::New());
915 MCConstAuto<MEDCouplingUMesh> mesh1D;
920 mesh1D=explode3DMeshTo1D(desc,descIndx,revDesc,revDescIndx);
925 mesh1D=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
930 mesh1D.takeRef(this);
935 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2,1] !");
938 desc=DataArrayInt::New(); descIndx=DataArrayInt::New(); revDesc=0; revDescIndx=0;
939 mesh1D->getReverseNodalConnectivity(desc,descIndx);
940 MCAuto<DataArrayInt> ret0(DataArrayInt::New());
941 ret0->alloc(desc->getNumberOfTuples(),1);
942 int *r0Pt(ret0->getPointer());
943 const int *c1DPtr(mesh1D->getNodalConnectivity()->begin()),*rn(desc->begin()),*rni(descIndx->begin());
944 for(int i=0;i<nbNodes;i++,rni++)
946 for(const int *oneDCellIt=rn+rni[0];oneDCellIt!=rn+rni[1];oneDCellIt++)
947 *r0Pt++=c1DPtr[3*(*oneDCellIt)+1]==i?c1DPtr[3*(*oneDCellIt)+2]:c1DPtr[3*(*oneDCellIt)+1];
949 neighbors=ret0.retn();
950 neighborsIdx=descIndx.retn();
954 * Computes enlarged neighbors for each nodes in \a this. The behavior of this method is close to MEDCouplingUMesh::computeNeighborsOfNodes except that the neighborhood of each node is wider here.
955 * A node j is considered to be in the neighborhood of i if and only if there is a cell in \a this containing in its nodal connectivity both i and j.
956 * This method is useful to find ghost cells of a part of a mesh with a code based on fields on nodes.
958 * \sa MEDCouplingUMesh::computeNeighborsOfNodes
960 void MEDCouplingUMesh::computeEnlargedNeighborsOfNodes(MCAuto<DataArrayInt> &neighbors, MCAuto<DataArrayInt>& neighborsIdx) const
963 int nbOfNodes(getNumberOfNodes());
964 const int *conn(_nodal_connec->begin()),*connIndex(_nodal_connec_index->begin());
965 int nbOfCells(getNumberOfCells());
966 std::vector< std::set<int> > st0(nbOfNodes);
967 for(int eltId=0;eltId<nbOfCells;eltId++)
969 const int *strtNdlConnOfCurCell(conn+connIndex[eltId]+1),*endNdlConnOfCurCell(conn+connIndex[eltId+1]);
970 std::set<int> s(strtNdlConnOfCurCell,endNdlConnOfCurCell); s.erase(-1); //for polyhedrons
971 for(std::set<int>::const_iterator iter2=s.begin();iter2!=s.end();iter2++)
972 st0[*iter2].insert(s.begin(),s.end());
974 neighborsIdx=DataArrayInt::New(); neighborsIdx->alloc(nbOfNodes+1,1); neighborsIdx->setIJ(0,0,0);
976 int *neighIdx(neighborsIdx->getPointer());
977 for(std::vector< std::set<int> >::const_iterator it=st0.begin();it!=st0.end();it++,neighIdx++)
978 neighIdx[1]=neighIdx[0]+(*it).size()-1;
980 neighbors=DataArrayInt::New(); neighbors->alloc(neighborsIdx->back(),1);
982 const int *neighIdx(neighborsIdx->begin());
983 int *neigh(neighbors->getPointer()),nodeId(0);
984 for(std::vector< std::set<int> >::const_iterator it=st0.begin();it!=st0.end();it++,neighIdx++,nodeId++)
986 std::set<int> s(*it); s.erase(nodeId);
987 std::copy(s.begin(),s.end(),neigh+*neighIdx);
993 * Converts specified cells to either polygons (if \a this is a 2D mesh) or
994 * polyhedrons (if \a this is a 3D mesh). The cells to convert are specified by an
995 * array of cell ids. Pay attention that after conversion all algorithms work slower
996 * with \a this mesh than before conversion. <br> If an exception is thrown during the
997 * conversion due presence of invalid ids in the array of cells to convert, as a
998 * result \a this mesh contains some already converted elements. In this case the 2D
999 * mesh remains valid but 3D mesh becomes \b inconsistent!
1000 * \warning This method can significantly modify the order of geometric types in \a this,
1001 * hence, to write this mesh to the MED file, its cells must be sorted using
1002 * sortCellsInMEDFileFrmt().
1003 * \param [in] cellIdsToConvertBg - the array holding ids of cells to convert.
1004 * \param [in] cellIdsToConvertEnd - a pointer to the last-plus-one-th element of \a
1005 * cellIdsToConvertBg.
1006 * \throw If the coordinates array is not set.
1007 * \throw If the nodal connectivity of cells is node defined.
1008 * \throw If dimension of \a this mesh is not either 2 or 3.
1010 * \if ENABLE_EXAMPLES
1011 * \ref cpp_mcumesh_convertToPolyTypes "Here is a C++ example".<br>
1012 * \ref py_mcumesh_convertToPolyTypes "Here is a Python example".
1015 void MEDCouplingUMesh::convertToPolyTypes(const int *cellIdsToConvertBg, const int *cellIdsToConvertEnd)
1017 checkFullyDefined();
1018 int dim=getMeshDimension();
1020 throw INTERP_KERNEL::Exception("Invalid mesh dimension : must be 2 or 3 !");
1021 int nbOfCells(getNumberOfCells());
1024 const int *connIndex=_nodal_connec_index->begin();
1025 int *conn=_nodal_connec->getPointer();
1026 for(const int *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1028 if(*iter>=0 && *iter<nbOfCells)
1030 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*iter]]);
1031 if(!cm.isQuadratic())
1032 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_POLYGON;
1034 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_QPOLYG;
1038 std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1039 oss << " in range [0," << nbOfCells << ") !";
1040 throw INTERP_KERNEL::Exception(oss.str());
1046 int *connIndex(_nodal_connec_index->getPointer());
1047 const int *connOld(_nodal_connec->getConstPointer());
1048 MCAuto<DataArrayInt> connNew(DataArrayInt::New()),connNewI(DataArrayInt::New()); connNew->alloc(0,1); connNewI->alloc(1,1); connNewI->setIJ(0,0,0);
1049 std::vector<bool> toBeDone(nbOfCells,false);
1050 for(const int *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1052 if(*iter>=0 && *iter<nbOfCells)
1053 toBeDone[*iter]=true;
1056 std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1057 oss << " in range [0," << nbOfCells << ") !";
1058 throw INTERP_KERNEL::Exception(oss.str());
1061 for(int cellId=0;cellId<nbOfCells;cellId++)
1063 int pos(connIndex[cellId]),posP1(connIndex[cellId+1]);
1064 int lgthOld(posP1-pos-1);
1065 if(toBeDone[cellId])
1067 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connOld[pos]);
1068 unsigned nbOfFaces(cm.getNumberOfSons2(connOld+pos+1,lgthOld));
1069 int *tmp(new int[nbOfFaces*lgthOld+1]);
1070 int *work=tmp; *work++=INTERP_KERNEL::NORM_POLYHED;
1071 for(unsigned j=0;j<nbOfFaces;j++)
1073 INTERP_KERNEL::NormalizedCellType type;
1074 unsigned offset=cm.fillSonCellNodalConnectivity2(j,connOld+pos+1,lgthOld,work,type);
1078 std::size_t newLgth(std::distance(tmp,work)-1);//-1 for last -1
1079 connNew->pushBackValsSilent(tmp,tmp+newLgth);
1080 connNewI->pushBackSilent(connNewI->back()+(int)newLgth);
1085 connNew->pushBackValsSilent(connOld+pos,connOld+posP1);
1086 connNewI->pushBackSilent(connNewI->back()+posP1-pos);
1089 setConnectivity(connNew,connNewI,false);//false because computeTypes called just behind.
1095 * Converts all cells to either polygons (if \a this is a 2D mesh) or
1096 * polyhedrons (if \a this is a 3D mesh).
1097 * \warning As this method is purely for user-friendliness and no optimization is
1098 * done to avoid construction of a useless vector, this method can be costly
1100 * \throw If the coordinates array is not set.
1101 * \throw If the nodal connectivity of cells is node defined.
1102 * \throw If dimension of \a this mesh is not either 2 or 3.
1104 void MEDCouplingUMesh::convertAllToPoly()
1106 int nbOfCells=getNumberOfCells();
1107 std::vector<int> cellIds(nbOfCells);
1108 for(int i=0;i<nbOfCells;i++)
1110 convertToPolyTypes(&cellIds[0],&cellIds[0]+cellIds.size());
1114 * Fixes nodal connectivity of invalid cells of type NORM_POLYHED. This method
1115 * expects that all NORM_POLYHED cells have connectivity similar to that of prismatic
1116 * volumes like NORM_HEXA8, NORM_PENTA6 etc., i.e. the first half of nodes describes a
1117 * base facet of the volume and the second half of nodes describes an opposite facet
1118 * having the same number of nodes as the base one. This method converts such
1119 * connectivity to a valid polyhedral format where connectivity of each facet is
1120 * explicitly described and connectivity of facets are separated by -1. If \a this mesh
1121 * contains a NORM_POLYHED cell with a valid connectivity, or an invalid connectivity is
1122 * not as expected, an exception is thrown and the mesh remains unchanged. Care of
1123 * a correct orientation of the first facet of a polyhedron, else orientation of a
1124 * corrected cell is reverse.<br>
1125 * This method is useful to build an extruded unstructured mesh with polyhedrons as
1126 * it releases the user from boring description of polyhedra connectivity in the valid
1128 * \throw If \a this->getMeshDimension() != 3.
1129 * \throw If \a this->getSpaceDimension() != 3.
1130 * \throw If the nodal connectivity of cells is not defined.
1131 * \throw If the coordinates array is not set.
1132 * \throw If \a this mesh contains polyhedrons with the valid connectivity.
1133 * \throw If \a this mesh contains polyhedrons with odd number of nodes.
1135 * \if ENABLE_EXAMPLES
1136 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
1137 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
1140 void MEDCouplingUMesh::convertExtrudedPolyhedra()
1142 checkFullyDefined();
1143 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1144 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertExtrudedPolyhedra works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
1145 int nbOfCells=getNumberOfCells();
1146 MCAuto<DataArrayInt> newCi=DataArrayInt::New();
1147 newCi->alloc(nbOfCells+1,1);
1148 int *newci=newCi->getPointer();
1149 const int *ci=_nodal_connec_index->getConstPointer();
1150 const int *c=_nodal_connec->getConstPointer();
1152 for(int i=0;i<nbOfCells;i++)
1154 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1155 if(type==INTERP_KERNEL::NORM_POLYHED)
1157 if(std::count(c+ci[i]+1,c+ci[i+1],-1)!=0)
1159 std::ostringstream oss; oss << "MEDCouplingUMesh::convertExtrudedPolyhedra : cell # " << i << " is a polhedron BUT it has NOT exactly 1 face !";
1160 throw INTERP_KERNEL::Exception(oss.str());
1162 std::size_t n2=std::distance(c+ci[i]+1,c+ci[i+1]);
1165 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 !";
1166 throw INTERP_KERNEL::Exception(oss.str());
1169 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)
1172 newci[i+1]=(ci[i+1]-ci[i])+newci[i];
1174 MCAuto<DataArrayInt> newC=DataArrayInt::New();
1175 newC->alloc(newci[nbOfCells],1);
1176 int *newc=newC->getPointer();
1177 for(int i=0;i<nbOfCells;i++)
1179 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1180 if(type==INTERP_KERNEL::NORM_POLYHED)
1182 std::size_t n1=std::distance(c+ci[i]+1,c+ci[i+1])/2;
1183 newc=std::copy(c+ci[i],c+ci[i]+n1+1,newc);
1185 for(std::size_t j=0;j<n1;j++)
1187 newc[j]=c[ci[i]+1+n1+(n1-j)%n1];
1189 newc[n1+5*j+1]=c[ci[i]+1+j];
1190 newc[n1+5*j+2]=c[ci[i]+1+j+n1];
1191 newc[n1+5*j+3]=c[ci[i]+1+(j+1)%n1+n1];
1192 newc[n1+5*j+4]=c[ci[i]+1+(j+1)%n1];
1197 newc=std::copy(c+ci[i],c+ci[i+1],newc);
1199 _nodal_connec_index->decrRef(); _nodal_connec_index=newCi.retn();
1200 _nodal_connec->decrRef(); _nodal_connec=newC.retn();
1205 * Converts all polygons (if \a this is a 2D mesh) or polyhedrons (if \a this is a 3D
1206 * mesh) to cells of classical types. This method is opposite to convertToPolyTypes().
1207 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
1208 * to write this mesh to the MED file, its cells must be sorted using
1209 * sortCellsInMEDFileFrmt().
1210 * \warning Cells (and most notably polyhedrons) must be correctly oriented for this to work
1211 * properly. See orientCorrectlyPolyhedrons() and arePolyhedronsNotCorrectlyOriented().
1212 * \return \c true if at least one cell has been converted, \c false else. In the
1213 * last case the nodal connectivity remains unchanged.
1214 * \throw If the coordinates array is not set.
1215 * \throw If the nodal connectivity of cells is not defined.
1216 * \throw If \a this->getMeshDimension() < 0.
1218 bool MEDCouplingUMesh::unPolyze()
1220 checkFullyDefined();
1221 int mdim=getMeshDimension();
1223 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::unPolyze works on umeshes with meshdim equals to 0, 1 2 or 3 !");
1226 int nbOfCells=getNumberOfCells();
1229 int initMeshLgth=getNodalConnectivityArrayLen();
1230 int *conn=_nodal_connec->getPointer();
1231 int *index=_nodal_connec_index->getPointer();
1236 for(int i=0;i<nbOfCells;i++)
1238 lgthOfCurCell=index[i+1]-posOfCurCell;
1239 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
1240 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
1241 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::NORM_ERROR;
1245 switch(cm.getDimension())
1249 INTERP_KERNEL::AutoPtr<int> tmp=new int[lgthOfCurCell-1];
1250 std::copy(conn+posOfCurCell+1,conn+posOfCurCell+lgthOfCurCell,(int *)tmp);
1251 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly2D(cm.isQuadratic(),tmp,lgthOfCurCell-1,conn+newPos+1,newLgth);
1256 int nbOfFaces,lgthOfPolyhConn;
1257 INTERP_KERNEL::AutoPtr<int> zipFullReprOfPolyh=INTERP_KERNEL::CellSimplify::getFullPolyh3DCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,nbOfFaces,lgthOfPolyhConn);
1258 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly3D(zipFullReprOfPolyh,nbOfFaces,lgthOfPolyhConn,conn+newPos+1,newLgth);
1263 newType=(lgthOfCurCell==3)?INTERP_KERNEL::NORM_SEG2:INTERP_KERNEL::NORM_POLYL;
1267 ret=ret || (newType!=type);
1268 conn[newPos]=newType;
1270 posOfCurCell=index[i+1];
1275 std::copy(conn+posOfCurCell,conn+posOfCurCell+lgthOfCurCell,conn+newPos);
1276 newPos+=lgthOfCurCell;
1277 posOfCurCell+=lgthOfCurCell;
1281 if(newPos!=initMeshLgth)
1282 _nodal_connec->reAlloc(newPos);
1289 * This method expects that spaceDimension is equal to 3 and meshDimension equal to 3.
1290 * This method performs operation only on polyhedrons in \b this. If no polyhedrons exists in \b this, \b this remains unchanged.
1291 * This method allows to merge if any coplanar 3DSurf cells that may appear in some polyhedrons cells.
1293 * \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
1296 void MEDCouplingUMesh::simplifyPolyhedra(double eps)
1298 checkFullyDefined();
1299 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1300 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplifyPolyhedra : works on meshdimension 3 and spaceDimension 3 !");
1301 MCAuto<DataArrayDouble> coords=getCoords()->deepCopy();
1302 coords->recenterForMaxPrecision(eps);
1304 int nbOfCells=getNumberOfCells();
1305 const int *conn=_nodal_connec->getConstPointer();
1306 const int *index=_nodal_connec_index->getConstPointer();
1307 MCAuto<DataArrayInt> connINew=DataArrayInt::New();
1308 connINew->alloc(nbOfCells+1,1);
1309 int *connINewPtr=connINew->getPointer(); *connINewPtr++=0;
1310 MCAuto<DataArrayInt> connNew=DataArrayInt::New(); connNew->alloc(0,1);
1311 MCAuto<DataArrayInt> E_Fi(DataArrayInt::New()), E_F(DataArrayInt::New()), F_Ei(DataArrayInt::New()), F_E(DataArrayInt::New());
1312 MCAuto<MEDCouplingUMesh> m_faces(buildDescendingConnectivity(E_F, E_Fi, F_E, F_Ei));
1314 for(int i=0;i<nbOfCells;i++,connINewPtr++)
1316 if(conn[index[i]]==(int)INTERP_KERNEL::NORM_POLYHED)
1318 SimplifyPolyhedronCell(eps,coords, i,connNew, m_faces, E_Fi, E_F, F_Ei, F_E);
1322 connNew->insertAtTheEnd(conn+index[i],conn+index[i+1]);
1323 *connINewPtr=connNew->getNumberOfTuples();
1326 setConnectivity(connNew,connINew,false);
1330 * This method returns all node ids used in the connectivity of \b this. The data array returned has to be dealt by the caller.
1331 * The returned node ids are sorted ascendingly. This method is close to MEDCouplingUMesh::getNodeIdsInUse except
1332 * the format of the returned DataArrayInt instance.
1334 * \return a newly allocated DataArrayInt sorted ascendingly of fetched node ids.
1335 * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1337 DataArrayInt *MEDCouplingUMesh::computeFetchedNodeIds() const
1339 checkConnectivityFullyDefined();
1340 const int *maxEltPt(std::max_element(_nodal_connec->begin(),_nodal_connec->end()));
1341 int maxElt(maxEltPt==_nodal_connec->end()?0:std::abs(*maxEltPt)+1);
1342 std::vector<bool> retS(maxElt,false);
1343 computeNodeIdsAlg(retS);
1344 return DataArrayInt::BuildListOfSwitchedOn(retS);
1348 * \param [in,out] nodeIdsInUse an array of size typically equal to nbOfNodes.
1349 * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1351 void MEDCouplingUMesh::computeNodeIdsAlg(std::vector<bool>& nodeIdsInUse) const
1353 int nbOfNodes((int)nodeIdsInUse.size()),nbOfCells(getNumberOfCells());
1354 const int *connIndex(_nodal_connec_index->getConstPointer()),*conn(_nodal_connec->getConstPointer());
1355 for(int i=0;i<nbOfCells;i++)
1356 for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1359 if(conn[j]<nbOfNodes)
1360 nodeIdsInUse[conn[j]]=true;
1363 std::ostringstream oss; oss << "MEDCouplingUMesh::computeNodeIdsAlg : In cell #" << i << " presence of node id " << conn[j] << " not in [0," << nbOfNodes << ") !";
1364 throw INTERP_KERNEL::Exception(oss.str());
1371 struct MEDCouplingAccVisit
1373 MEDCouplingAccVisit():_new_nb_of_nodes(0) { }
1374 int operator()(int val) { if(val!=-1) return _new_nb_of_nodes++; else return -1; }
1375 int _new_nb_of_nodes;
1381 * Finds nodes not used in any cell and returns an array giving a new id to every node
1382 * by excluding the unused nodes, for which the array holds -1. The result array is
1383 * a mapping in "Old to New" mode.
1384 * \param [out] nbrOfNodesInUse - number of node ids present in the nodal connectivity.
1385 * \return DataArrayInt * - a new instance of DataArrayInt. Its length is \a
1386 * this->getNumberOfNodes(). It holds for each node of \a this mesh either -1
1387 * if the node is unused or a new id else. The caller is to delete this
1388 * array using decrRef() as it is no more needed.
1389 * \throw If the coordinates array is not set.
1390 * \throw If the nodal connectivity of cells is not defined.
1391 * \throw If the nodal connectivity includes an invalid id.
1393 * \if ENABLE_EXAMPLES
1394 * \ref cpp_mcumesh_getNodeIdsInUse "Here is a C++ example".<br>
1395 * \ref py_mcumesh_getNodeIdsInUse "Here is a Python example".
1397 * \sa computeFetchedNodeIds, computeNodeIdsAlg()
1399 DataArrayInt *MEDCouplingUMesh::getNodeIdsInUse(int& nbrOfNodesInUse) const
1402 int nbOfNodes(getNumberOfNodes());
1403 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1404 ret->alloc(nbOfNodes,1);
1405 int *traducer=ret->getPointer();
1406 std::fill(traducer,traducer+nbOfNodes,-1);
1407 int nbOfCells=getNumberOfCells();
1408 const int *connIndex=_nodal_connec_index->getConstPointer();
1409 const int *conn=_nodal_connec->getConstPointer();
1410 for(int i=0;i<nbOfCells;i++)
1411 for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1414 if(conn[j]<nbOfNodes)
1415 traducer[conn[j]]=1;
1418 std::ostringstream oss; oss << "MEDCouplingUMesh::getNodeIdsInUse : In cell #" << i << " presence of node id " << conn[j] << " not in [0," << nbOfNodes << ") !";
1419 throw INTERP_KERNEL::Exception(oss.str());
1422 nbrOfNodesInUse=(int)std::count(traducer,traducer+nbOfNodes,1);
1423 std::transform(traducer,traducer+nbOfNodes,traducer,MEDCouplingAccVisit());
1428 * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1429 * For each cell in \b this the number of nodes constituting cell is computed.
1430 * For each polyhedron cell, the sum of the number of nodes of each face constituting polyhedron cell is returned.
1431 * So for pohyhedrons some nodes can be counted several times in the returned result.
1433 * \return a newly allocated array
1434 * \sa MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell
1436 DataArrayInt *MEDCouplingUMesh::computeNbOfNodesPerCell() const
1438 checkConnectivityFullyDefined();
1439 int nbOfCells=getNumberOfCells();
1440 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1441 ret->alloc(nbOfCells,1);
1442 int *retPtr=ret->getPointer();
1443 const int *conn=getNodalConnectivity()->getConstPointer();
1444 const int *connI=getNodalConnectivityIndex()->getConstPointer();
1445 for(int i=0;i<nbOfCells;i++,retPtr++)
1447 if(conn[connI[i]]!=(int)INTERP_KERNEL::NORM_POLYHED)
1448 *retPtr=connI[i+1]-connI[i]-1;
1450 *retPtr=connI[i+1]-connI[i]-1-std::count(conn+connI[i]+1,conn+connI[i+1],-1);
1456 * This method computes effective number of nodes per cell. That is to say nodes appearing several times in nodal connectivity of a cell,
1457 * will be counted only once here whereas it will be counted several times in MEDCouplingUMesh::computeNbOfNodesPerCell method.
1459 * \return DataArrayInt * - new object to be deallocated by the caller.
1460 * \sa MEDCouplingUMesh::computeNbOfNodesPerCell
1462 DataArrayInt *MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell() const
1464 checkConnectivityFullyDefined();
1465 int nbOfCells=getNumberOfCells();
1466 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1467 ret->alloc(nbOfCells,1);
1468 int *retPtr=ret->getPointer();
1469 const int *conn=getNodalConnectivity()->getConstPointer();
1470 const int *connI=getNodalConnectivityIndex()->getConstPointer();
1471 for(int i=0;i<nbOfCells;i++,retPtr++)
1473 std::set<int> s(conn+connI[i]+1,conn+connI[i+1]);
1474 if(conn[connI[i]]!=(int)INTERP_KERNEL::NORM_POLYHED)
1475 *retPtr=(int)s.size();
1479 *retPtr=(int)s.size();
1486 * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1487 * For each cell in \b this the number of faces constituting (entity of dimension this->getMeshDimension()-1) cell is computed.
1489 * \return a newly allocated array
1491 DataArrayInt *MEDCouplingUMesh::computeNbOfFacesPerCell() const
1493 checkConnectivityFullyDefined();
1494 int nbOfCells=getNumberOfCells();
1495 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1496 ret->alloc(nbOfCells,1);
1497 int *retPtr=ret->getPointer();
1498 const int *conn=getNodalConnectivity()->getConstPointer();
1499 const int *connI=getNodalConnectivityIndex()->getConstPointer();
1500 for(int i=0;i<nbOfCells;i++,retPtr++,connI++)
1502 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]);
1503 *retPtr=cm.getNumberOfSons2(conn+connI[0]+1,connI[1]-connI[0]-1);
1509 * Removes unused nodes (the node coordinates array is shorten) and returns an array
1510 * mapping between new and old node ids in "Old to New" mode. -1 values in the returned
1511 * array mean that the corresponding old node is no more used.
1512 * \return DataArrayInt * - a new instance of DataArrayInt of length \a
1513 * this->getNumberOfNodes() before call of this method. The caller is to
1514 * delete this array using decrRef() as it is no more needed.
1515 * \throw If the coordinates array is not set.
1516 * \throw If the nodal connectivity of cells is not defined.
1517 * \throw If the nodal connectivity includes an invalid id.
1518 * \sa areAllNodesFetched
1520 * \if ENABLE_EXAMPLES
1521 * \ref cpp_mcumesh_zipCoordsTraducer "Here is a C++ example".<br>
1522 * \ref py_mcumesh_zipCoordsTraducer "Here is a Python example".
1525 DataArrayInt *MEDCouplingUMesh::zipCoordsTraducer()
1527 return MEDCouplingPointSet::zipCoordsTraducer();
1531 * This method stands if 'cell1' and 'cell2' are equals regarding 'compType' policy.
1532 * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1534 int MEDCouplingUMesh::AreCellsEqual(const int *conn, const int *connI, int cell1, int cell2, int compType)
1539 return AreCellsEqualPolicy0(conn,connI,cell1,cell2);
1541 return AreCellsEqualPolicy1(conn,connI,cell1,cell2);
1543 return AreCellsEqualPolicy2(conn,connI,cell1,cell2);
1545 return AreCellsEqualPolicy2NoType(conn,connI,cell1,cell2);
1547 return AreCellsEqualPolicy7(conn,connI,cell1,cell2);
1549 throw INTERP_KERNEL::Exception("Unknown comparison asked ! Must be in 0,1,2,3 or 7.");
1553 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 0.
1555 int MEDCouplingUMesh::AreCellsEqualPolicy0(const int *conn, const int *connI, int cell1, int cell2)
1557 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1558 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;
1563 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 1.
1565 int MEDCouplingUMesh::AreCellsEqualPolicy1(const int *conn, const int *connI, int cell1, int cell2)
1567 int sz=connI[cell1+1]-connI[cell1];
1568 if(sz==connI[cell2+1]-connI[cell2])
1570 if(conn[connI[cell1]]==conn[connI[cell2]])
1572 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1573 unsigned dim=cm.getDimension();
1579 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz1];
1580 int *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(int *)tmp);
1581 std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1582 work=std::search((int *)tmp,(int *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1583 return work!=tmp+sz1?1:0;
1586 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;//case of SEG2 and SEG3
1589 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy1 : not implemented yet for meshdim == 3 !");
1596 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 2.
1598 int MEDCouplingUMesh::AreCellsEqualPolicy2(const int *conn, const int *connI, int cell1, int cell2)
1600 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1602 if(conn[connI[cell1]]==conn[connI[cell2]])
1604 std::set<int> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1605 std::set<int> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1613 * This method is less restrictive than AreCellsEqualPolicy2. Here the geometric type is absolutely not taken into account !
1615 int MEDCouplingUMesh::AreCellsEqualPolicy2NoType(const int *conn, const int *connI, int cell1, int cell2)
1617 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1619 std::set<int> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1620 std::set<int> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1627 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 7.
1629 int MEDCouplingUMesh::AreCellsEqualPolicy7(const int *conn, const int *connI, int cell1, int cell2)
1631 int sz=connI[cell1+1]-connI[cell1];
1632 if(sz==connI[cell2+1]-connI[cell2])
1634 if(conn[connI[cell1]]==conn[connI[cell2]])
1636 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1637 unsigned dim=cm.getDimension();
1643 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz1];
1644 int *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(int *)tmp);
1645 std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1646 work=std::search((int *)tmp,(int *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1651 std::reverse_iterator<int *> it1((int *)tmp+sz1);
1652 std::reverse_iterator<int *> it2((int *)tmp);
1653 if(std::search(it1,it2,conn+connI[cell2]+1,conn+connI[cell2+1])!=it2)
1659 return work!=tmp+sz1?1:0;
1662 {//case of SEG2 and SEG3
1663 if(std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1))
1665 if(!cm.isQuadratic())
1667 std::reverse_iterator<const int *> it1(conn+connI[cell1+1]);
1668 std::reverse_iterator<const int *> it2(conn+connI[cell1]+1);
1669 if(std::equal(it1,it2,conn+connI[cell2]+1))
1675 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])
1682 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy7 : not implemented yet for meshdim == 3 !");
1690 * This method find cells that are equal (regarding \a compType) in \a this. The comparison is specified
1692 * This method keeps the coordiantes of \a this. This method is time consuming.
1694 * \param [in] compType input specifying the technique used to compare cells each other.
1695 * - 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.
1696 * - 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)
1697 * and their type equal. For 1D mesh the policy 1 is equivalent to 0.
1698 * - 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
1699 * can be used for users not sensitive to orientation of cell
1700 * \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.
1701 * \param [out] commonCellsArr common cells ids (\ref numbering-indirect)
1702 * \param [out] commonCellsIArr common cells ids (\ref numbering-indirect)
1703 * \return the correspondance array old to new in a newly allocated array.
1706 void MEDCouplingUMesh::findCommonCells(int compType, int startCellId, DataArrayInt *& commonCellsArr, DataArrayInt *& commonCellsIArr) const
1708 MCAuto<DataArrayInt> revNodal=DataArrayInt::New(),revNodalI=DataArrayInt::New();
1709 getReverseNodalConnectivity(revNodal,revNodalI);
1710 FindCommonCellsAlg(compType,startCellId,_nodal_connec,_nodal_connec_index,revNodal,revNodalI,commonCellsArr,commonCellsIArr);
1713 void MEDCouplingUMesh::FindCommonCellsAlg(int compType, int startCellId, const DataArrayInt *nodal, const DataArrayInt *nodalI, const DataArrayInt *revNodal, const DataArrayInt *revNodalI,
1714 DataArrayInt *& commonCellsArr, DataArrayInt *& commonCellsIArr)
1716 MCAuto<DataArrayInt> commonCells=DataArrayInt::New(),commonCellsI=DataArrayInt::New(); commonCells->alloc(0,1);
1717 int nbOfCells=nodalI->getNumberOfTuples()-1;
1718 commonCellsI->reserve(1); commonCellsI->pushBackSilent(0);
1719 const int *revNodalPtr=revNodal->getConstPointer(),*revNodalIPtr=revNodalI->getConstPointer();
1720 const int *connPtr=nodal->getConstPointer(),*connIPtr=nodalI->getConstPointer();
1721 std::vector<bool> isFetched(nbOfCells,false);
1724 for(int i=0;i<nbOfCells;i++)
1728 const int *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind2nd(std::not_equal_to<int>(),-1));
1729 std::vector<int> v,v2;
1730 if(connOfNode!=connPtr+connIPtr[i+1])
1732 const int *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1733 v2.insert(v2.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1]);
1736 for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1740 const int *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1741 std::vector<int>::iterator it=std::set_intersection(v.begin(),v.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1742 v2.resize(std::distance(v2.begin(),it));
1746 if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1748 int pos=commonCellsI->back();
1749 commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1750 for(const int *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1751 isFetched[*it]=true;
1759 for(int i=startCellId;i<nbOfCells;i++)
1763 const int *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind2nd(std::not_equal_to<int>(),-1));
1764 std::vector<int> v,v2;
1765 if(connOfNode!=connPtr+connIPtr[i+1])
1767 v2.insert(v2.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1]);
1770 for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1774 std::vector<int>::iterator it=std::set_intersection(v.begin(),v.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1775 v2.resize(std::distance(v2.begin(),it));
1779 if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1781 int pos=commonCellsI->back();
1782 commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1783 for(const int *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1784 isFetched[*it]=true;
1790 commonCellsArr=commonCells.retn();
1791 commonCellsIArr=commonCellsI.retn();
1795 * Checks if \a this mesh includes all cells of an \a other mesh, and returns an array
1796 * giving for each cell of the \a other an id of a cell in \a this mesh. A value larger
1797 * than \a this->getNumberOfCells() in the returned array means that there is no
1798 * corresponding cell in \a this mesh.
1799 * It is expected that \a this and \a other meshes share the same node coordinates
1800 * array, if it is not so an exception is thrown.
1801 * \param [in] other - the mesh to compare with.
1802 * \param [in] compType - specifies a cell comparison technique. For meaning of its
1803 * valid values [0,1,2], see zipConnectivityTraducer().
1804 * \param [out] arr - a new instance of DataArrayInt returning correspondence
1805 * between cells of the two meshes. It contains \a other->getNumberOfCells()
1806 * values. The caller is to delete this array using
1807 * decrRef() as it is no more needed.
1808 * \return bool - \c true if all cells of \a other mesh are present in the \a this
1811 * \if ENABLE_EXAMPLES
1812 * \ref cpp_mcumesh_areCellsIncludedIn "Here is a C++ example".<br>
1813 * \ref py_mcumesh_areCellsIncludedIn "Here is a Python example".
1815 * \sa checkDeepEquivalOnSameNodesWith()
1816 * \sa checkGeoEquivalWith()
1818 bool MEDCouplingUMesh::areCellsIncludedIn(const MEDCouplingUMesh *other, int compType, DataArrayInt *& arr) const
1820 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1821 int nbOfCells=getNumberOfCells();
1822 static const int possibleCompType[]={0,1,2};
1823 if(std::find(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),compType)==possibleCompType+sizeof(possibleCompType)/sizeof(int))
1825 std::ostringstream oss; oss << "MEDCouplingUMesh::areCellsIncludedIn : only following policies are possible : ";
1826 std::copy(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),std::ostream_iterator<int>(oss," "));
1828 throw INTERP_KERNEL::Exception(oss.str());
1830 MCAuto<DataArrayInt> o2n=mesh->zipConnectivityTraducer(compType,nbOfCells);
1831 arr=o2n->subArray(nbOfCells);
1832 arr->setName(other->getName());
1834 if(other->getNumberOfCells()==0)
1836 return arr->getMaxValue(tmp)<nbOfCells;
1840 * This method makes the assumption that \a this and \a other share the same coords. If not an exception will be thrown !
1841 * This method tries to determine if \b other is fully included in \b this.
1842 * The main difference is that this method is not expected to throw exception.
1843 * This method has two outputs :
1845 * \param other other mesh
1846 * \param arr is an output parameter that returns a \b newly created instance. This array is of size 'other->getNumberOfCells()'.
1847 * \return If \a other is fully included in 'this 'true is returned. If not false is returned.
1849 bool MEDCouplingUMesh::areCellsIncludedInPolicy7(const MEDCouplingUMesh *other, DataArrayInt *& arr) const
1851 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1852 DataArrayInt *commonCells=0,*commonCellsI=0;
1853 int thisNbCells=getNumberOfCells();
1854 mesh->findCommonCells(7,thisNbCells,commonCells,commonCellsI);
1855 MCAuto<DataArrayInt> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1856 const int *commonCellsPtr=commonCells->getConstPointer(),*commonCellsIPtr=commonCellsI->getConstPointer();
1857 int otherNbCells=other->getNumberOfCells();
1858 MCAuto<DataArrayInt> arr2=DataArrayInt::New();
1859 arr2->alloc(otherNbCells,1);
1860 arr2->fillWithZero();
1861 int *arr2Ptr=arr2->getPointer();
1862 int nbOfCommon=commonCellsI->getNumberOfTuples()-1;
1863 for(int i=0;i<nbOfCommon;i++)
1865 int start=commonCellsPtr[commonCellsIPtr[i]];
1866 if(start<thisNbCells)
1868 for(int j=commonCellsIPtr[i]+1;j!=commonCellsIPtr[i+1];j++)
1870 int sig=commonCellsPtr[j]>0?1:-1;
1871 int val=std::abs(commonCellsPtr[j])-1;
1872 if(val>=thisNbCells)
1873 arr2Ptr[val-thisNbCells]=sig*(start+1);
1877 arr2->setName(other->getName());
1878 if(arr2->presenceOfValue(0))
1884 MEDCouplingUMesh *MEDCouplingUMesh::mergeMyselfWithOnSameCoords(const MEDCouplingPointSet *other) const
1887 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : input other is null !");
1888 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
1890 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : the input other mesh is not of type unstructured !");
1891 std::vector<const MEDCouplingUMesh *> ms(2);
1894 return MergeUMeshesOnSameCoords(ms);
1898 * Build a sub part of \b this lying or not on the same coordinates than \b this (regarding value of \b keepCoords).
1899 * By default coordinates are kept. This method is close to MEDCouplingUMesh::buildPartOfMySelf except that here input
1900 * cellIds is not given explicitely but by a range python like.
1905 * \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.
1906 * \return a newly allocated
1908 * \warning This method modifies can generate an unstructured mesh whose cells are not sorted by geometric type order.
1909 * In view of the MED file writing, a renumbering of cells of returned unstructured mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
1911 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfSlice(int start, int end, int step, bool keepCoords) const
1913 if(getMeshDimension()!=-1)
1914 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelfSlice(start,end,step,keepCoords));
1917 int newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfSlice for -1 dimension mesh ");
1919 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
1921 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
1923 return const_cast<MEDCouplingUMesh *>(this);
1928 * Creates a new MEDCouplingUMesh containing specified cells of \a this mesh.
1929 * The result mesh shares or not the node coordinates array with \a this mesh depending
1930 * on \a keepCoords parameter.
1931 * \warning Cells of the result mesh can be \b not sorted by geometric type, hence,
1932 * to write this mesh to the MED file, its cells must be sorted using
1933 * sortCellsInMEDFileFrmt().
1934 * \param [in] begin - an array of cell ids to include to the new mesh.
1935 * \param [in] end - a pointer to last-plus-one-th element of \a begin.
1936 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
1937 * array of \a this mesh, else "free" nodes are removed from the result mesh
1938 * by calling zipCoords().
1939 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
1940 * to delete this mesh using decrRef() as it is no more needed.
1941 * \throw If the coordinates array is not set.
1942 * \throw If the nodal connectivity of cells is not defined.
1943 * \throw If any cell id in the array \a begin is not valid.
1945 * \if ENABLE_EXAMPLES
1946 * \ref cpp_mcumesh_buildPartOfMySelf "Here is a C++ example".<br>
1947 * \ref py_mcumesh_buildPartOfMySelf "Here is a Python example".
1950 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelf(const int *begin, const int *end, bool keepCoords) const
1952 if(getMeshDimension()!=-1)
1953 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelf(begin,end,keepCoords));
1957 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
1959 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
1961 return const_cast<MEDCouplingUMesh *>(this);
1966 * This method operates only on nodal connectivity on \b this. Coordinates of \b this is completely ignored here.
1968 * 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.
1969 * Size of [ \b cellIdsBg, \b cellIdsEnd ) ) must be equal to the number of cells of otherOnSameCoordsThanThis.
1970 * The number of cells of \b this will remain the same with this method.
1972 * \param [in] cellIdsBg begin of cell ids (included) of cells in this to assign
1973 * \param [in] cellIdsEnd end of cell ids (excluded) of cells in this to assign
1974 * \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 ).
1975 * Coordinate pointer of \b this and those of \b otherOnSameCoordsThanThis must be the same
1977 void MEDCouplingUMesh::setPartOfMySelf(const int *cellIdsBg, const int *cellIdsEnd, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
1979 checkConnectivityFullyDefined();
1980 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
1981 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
1982 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelf : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
1983 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
1985 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
1986 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
1987 throw INTERP_KERNEL::Exception(oss.str());
1989 std::size_t nbOfCellsToModify(std::distance(cellIdsBg,cellIdsEnd));
1990 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
1992 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
1993 throw INTERP_KERNEL::Exception(oss.str());
1995 std::size_t nbOfCells(getNumberOfCells());
1996 bool easyAssign(true);
1997 const int *connI(_nodal_connec_index->begin());
1998 const int *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->begin();
1999 for(const int *it=cellIdsBg;it!=cellIdsEnd && easyAssign;it++,connIOther++)
2001 if(*it>=0 && *it<(int)nbOfCells)
2003 easyAssign=(connIOther[1]-connIOther[0])==(connI[*it+1]-connI[*it]);
2007 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : On pos #" << std::distance(cellIdsBg,it) << " id is equal to " << *it << " which is not in [0," << nbOfCells << ") !";
2008 throw INTERP_KERNEL::Exception(oss.str());
2013 MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2018 DataArrayInt *arrOut=0,*arrIOut=0;
2019 MEDCouplingUMesh::SetPartOfIndexedArrays(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2021 MCAuto<DataArrayInt> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2022 setConnectivity(arrOut,arrIOut,true);
2026 void MEDCouplingUMesh::setPartOfMySelfSlice(int start, int end, int step, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2028 checkConnectivityFullyDefined();
2029 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2030 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2031 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelfSlice : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2032 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2034 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2035 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2036 throw INTERP_KERNEL::Exception(oss.str());
2038 int nbOfCellsToModify=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::setPartOfMySelfSlice : ");
2039 if(nbOfCellsToModify!=(int)otherOnSameCoordsThanThis.getNumberOfCells())
2041 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2042 throw INTERP_KERNEL::Exception(oss.str());
2044 int nbOfCells=getNumberOfCells();
2045 bool easyAssign=true;
2046 const int *connI=_nodal_connec_index->getConstPointer();
2047 const int *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2049 for(int i=0;i<nbOfCellsToModify && easyAssign;i++,it+=step,connIOther++)
2051 if(it>=0 && it<nbOfCells)
2053 easyAssign=(connIOther[1]-connIOther[0])==(connI[it+1]-connI[it]);
2057 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : On pos #" << i << " id is equal to " << it << " which is not in [0," << nbOfCells << ") !";
2058 throw INTERP_KERNEL::Exception(oss.str());
2063 MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2068 DataArrayInt *arrOut=0,*arrIOut=0;
2069 MEDCouplingUMesh::SetPartOfIndexedArraysSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2071 MCAuto<DataArrayInt> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2072 setConnectivity(arrOut,arrIOut,true);
2078 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2079 * this->getMeshDimension(), that bound some cells of \a this mesh.
2080 * The cells of lower dimension to include to the result mesh are selected basing on
2081 * specified node ids and the value of \a fullyIn parameter. If \a fullyIn ==\c true, a
2082 * cell is copied if its all nodes are in the array \a begin of node ids. If \a fullyIn
2083 * ==\c false, a cell is copied if any its node is in the array of node ids. The
2084 * created mesh shares the node coordinates array with \a this mesh.
2085 * \param [in] begin - the array of node ids.
2086 * \param [in] end - a pointer to the (last+1)-th element of \a begin.
2087 * \param [in] fullyIn - if \c true, then cells whose all nodes are in the
2088 * array \a begin are added, else cells whose any node is in the
2089 * array \a begin are added.
2090 * \return MEDCouplingUMesh * - new instance of MEDCouplingUMesh. The caller is
2091 * to delete this mesh using decrRef() as it is no more needed.
2092 * \throw If the coordinates array is not set.
2093 * \throw If the nodal connectivity of cells is not defined.
2094 * \throw If any node id in \a begin is not valid.
2096 * \if ENABLE_EXAMPLES
2097 * \ref cpp_mcumesh_buildFacePartOfMySelfNode "Here is a C++ example".<br>
2098 * \ref py_mcumesh_buildFacePartOfMySelfNode "Here is a Python example".
2101 MEDCouplingUMesh *MEDCouplingUMesh::buildFacePartOfMySelfNode(const int *begin, const int *end, bool fullyIn) const
2103 MCAuto<DataArrayInt> desc,descIndx,revDesc,revDescIndx;
2104 desc=DataArrayInt::New(); descIndx=DataArrayInt::New(); revDesc=DataArrayInt::New(); revDescIndx=DataArrayInt::New();
2105 MCAuto<MEDCouplingUMesh> subMesh=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2106 desc=0; descIndx=0; revDesc=0; revDescIndx=0;
2107 return static_cast<MEDCouplingUMesh*>(subMesh->buildPartOfMySelfNode(begin,end,fullyIn));
2111 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2112 * this->getMeshDimension(), which bound only one cell of \a this mesh.
2113 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2114 * array of \a this mesh, else "free" nodes are removed from the result mesh
2115 * by calling zipCoords().
2116 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2117 * to delete this mesh using decrRef() as it is no more needed.
2118 * \throw If the coordinates array is not set.
2119 * \throw If the nodal connectivity of cells is not defined.
2121 * \if ENABLE_EXAMPLES
2122 * \ref cpp_mcumesh_buildBoundaryMesh "Here is a C++ example".<br>
2123 * \ref py_mcumesh_buildBoundaryMesh "Here is a Python example".
2126 MEDCouplingUMesh *MEDCouplingUMesh::buildBoundaryMesh(bool keepCoords) const
2128 DataArrayInt *desc=DataArrayInt::New();
2129 DataArrayInt *descIndx=DataArrayInt::New();
2130 DataArrayInt *revDesc=DataArrayInt::New();
2131 DataArrayInt *revDescIndx=DataArrayInt::New();
2133 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2136 descIndx->decrRef();
2137 int nbOfCells=meshDM1->getNumberOfCells();
2138 const int *revDescIndxC=revDescIndx->getConstPointer();
2139 std::vector<int> boundaryCells;
2140 for(int i=0;i<nbOfCells;i++)
2141 if(revDescIndxC[i+1]-revDescIndxC[i]==1)
2142 boundaryCells.push_back(i);
2143 revDescIndx->decrRef();
2144 MEDCouplingUMesh *ret=meshDM1->buildPartOfMySelf(&boundaryCells[0],&boundaryCells[0]+boundaryCells.size(),keepCoords);
2149 * This method returns a newly created DataArrayInt instance containing ids of cells located in boundary.
2150 * A cell is detected to be on boundary if it contains one or more than one face having only one father.
2151 * This method makes the assumption that \a this is fully defined (coords,connectivity). If not an exception will be thrown.
2153 DataArrayInt *MEDCouplingUMesh::findCellIdsOnBoundary() const
2155 checkFullyDefined();
2156 MCAuto<DataArrayInt> desc=DataArrayInt::New();
2157 MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
2158 MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
2159 MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
2161 buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx)->decrRef();
2162 desc=(DataArrayInt*)0; descIndx=(DataArrayInt*)0;
2164 MCAuto<DataArrayInt> tmp=revDescIndx->deltaShiftIndex();
2165 MCAuto<DataArrayInt> faceIds=tmp->findIdsEqual(1); tmp=(DataArrayInt*)0;
2166 const int *revDescPtr=revDesc->getConstPointer();
2167 const int *revDescIndxPtr=revDescIndx->getConstPointer();
2168 int nbOfCells=getNumberOfCells();
2169 std::vector<bool> ret1(nbOfCells,false);
2171 for(const int *pt=faceIds->begin();pt!=faceIds->end();pt++)
2172 if(!ret1[revDescPtr[revDescIndxPtr[*pt]]])
2173 { ret1[revDescPtr[revDescIndxPtr[*pt]]]=true; sz++; }
2175 DataArrayInt *ret2=DataArrayInt::New();
2177 int *ret2Ptr=ret2->getPointer();
2179 for(std::vector<bool>::const_iterator it=ret1.begin();it!=ret1.end();it++,sz++)
2182 ret2->setName("BoundaryCells");
2187 * This method finds in \b this the cell ids that lie on mesh \b otherDimM1OnSameCoords.
2188 * \b this and \b otherDimM1OnSameCoords have to lie on the same coordinate array pointer. The coherency of that coords array with connectivity
2189 * of \b this and \b otherDimM1OnSameCoords is not important here because this method works only on connectivity.
2190 * this->getMeshDimension() - 1 must be equal to otherDimM1OnSameCoords.getMeshDimension()
2192 * s0 is the cell ids set in \b this lying on at least one node in the fetched nodes in \b otherDimM1OnSameCoords.
2193 * 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
2194 * equals a cell in \b otherDimM1OnSameCoords.
2196 * \throw if \b otherDimM1OnSameCoords is not part of constituent of \b this, or if coordinate pointer of \b this and \b otherDimM1OnSameCoords
2197 * are not same, or if this->getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension()
2199 * \param [in] otherDimM1OnSameCoords
2200 * \param [out] cellIdsRk0 a newly allocated array containing the cell ids of s0 (which are cell ids of \b this) in the above algorithm.
2201 * \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
2202 * cellIdsRk1->transformWithIndArr(cellIdsRk0->begin(),cellIdsRk0->end());
2204 void MEDCouplingUMesh::findCellIdsLyingOn(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayInt *&cellIdsRk0, DataArrayInt *&cellIdsRk1) const
2206 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2207 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : coordinates pointer are not the same ! Use tryToShareSameCoords method !");
2208 checkConnectivityFullyDefined();
2209 otherDimM1OnSameCoords.checkConnectivityFullyDefined();
2210 if(getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension())
2211 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : invalid mesh dimension of input mesh regarding meshdimesion of this !");
2212 MCAuto<DataArrayInt> fetchedNodeIds1=otherDimM1OnSameCoords.computeFetchedNodeIds();
2213 MCAuto<DataArrayInt> s0arr=getCellIdsLyingOnNodes(fetchedNodeIds1->begin(),fetchedNodeIds1->end(),false);
2214 MCAuto<MEDCouplingUMesh> thisPart=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(s0arr->begin(),s0arr->end(),true));
2215 MCAuto<DataArrayInt> descThisPart=DataArrayInt::New(),descIThisPart=DataArrayInt::New(),revDescThisPart=DataArrayInt::New(),revDescIThisPart=DataArrayInt::New();
2216 MCAuto<MEDCouplingUMesh> thisPartConsti=thisPart->buildDescendingConnectivity(descThisPart,descIThisPart,revDescThisPart,revDescIThisPart);
2217 const int *revDescThisPartPtr=revDescThisPart->getConstPointer(),*revDescIThisPartPtr=revDescIThisPart->getConstPointer();
2218 DataArrayInt *idsOtherInConsti=0;
2219 bool b=thisPartConsti->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsOtherInConsti);
2220 MCAuto<DataArrayInt> idsOtherInConstiAuto(idsOtherInConsti);
2222 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : the given mdim-1 mesh in other is not a constituent of this !");
2224 for(const int *idOther=idsOtherInConsti->begin();idOther!=idsOtherInConsti->end();idOther++)
2225 s1.insert(revDescThisPartPtr+revDescIThisPartPtr[*idOther],revDescThisPartPtr+revDescIThisPartPtr[*idOther+1]);
2226 MCAuto<DataArrayInt> s1arr_renum1=DataArrayInt::New(); s1arr_renum1->alloc((int)s1.size(),1); std::copy(s1.begin(),s1.end(),s1arr_renum1->getPointer());
2227 s1arr_renum1->sort();
2228 cellIdsRk0=s0arr.retn();
2229 //cellIdsRk1=s_renum1.retn();
2230 cellIdsRk1=s1arr_renum1.retn();
2234 * 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
2235 * returned. This subpart of meshdim-1 mesh is built using meshdim-1 cells in it shared only one cell in \b this.
2237 * \return a newly allocated mesh lying on the same coordinates than \b this. The caller has to deal with returned mesh.
2239 MEDCouplingUMesh *MEDCouplingUMesh::computeSkin() const
2241 MCAuto<DataArrayInt> desc=DataArrayInt::New();
2242 MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
2243 MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
2244 MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
2246 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2247 revDesc=0; desc=0; descIndx=0;
2248 MCAuto<DataArrayInt> revDescIndx2=revDescIndx->deltaShiftIndex();
2249 MCAuto<DataArrayInt> part=revDescIndx2->findIdsEqual(1);
2250 return static_cast<MEDCouplingUMesh *>(meshDM1->buildPartOfMySelf(part->begin(),part->end(),true));
2254 * Finds nodes lying on the boundary of \a this mesh.
2255 * \return DataArrayInt * - a new instance of DataArrayInt holding ids of found
2256 * nodes. The caller is to delete this array using decrRef() as it is no
2258 * \throw If the coordinates array is not set.
2259 * \throw If the nodal connectivity of cells is node defined.
2261 * \if ENABLE_EXAMPLES
2262 * \ref cpp_mcumesh_findBoundaryNodes "Here is a C++ example".<br>
2263 * \ref py_mcumesh_findBoundaryNodes "Here is a Python example".
2266 DataArrayInt *MEDCouplingUMesh::findBoundaryNodes() const
2268 MCAuto<MEDCouplingUMesh> skin=computeSkin();
2269 return skin->computeFetchedNodeIds();
2272 MEDCouplingUMesh *MEDCouplingUMesh::buildUnstructured() const
2275 return const_cast<MEDCouplingUMesh *>(this);
2279 * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2280 * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2281 * 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.
2282 * 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.
2283 * 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.
2285 * \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
2286 * parameter is altered during the call.
2287 * \param [out] nodeIdsToDuplicate node ids needed to be duplicated following the algorithm explain above.
2288 * \param [out] cellIdsNeededToBeRenum cell ids in \b this in which the renumber of nodes should be performed.
2289 * \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.
2291 * \warning This method modifies param \b otherDimM1OnSameCoords (for speed reasons).
2293 void MEDCouplingUMesh::findNodesToDuplicate(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayInt *& nodeIdsToDuplicate,
2294 DataArrayInt *& cellIdsNeededToBeRenum, DataArrayInt *& cellIdsNotModified) const
2296 typedef MCAuto<DataArrayInt> DAInt;
2297 typedef MCAuto<MEDCouplingUMesh> MCUMesh;
2299 checkFullyDefined();
2300 otherDimM1OnSameCoords.checkFullyDefined();
2301 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2302 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : meshes do not share the same coords array !");
2303 if(otherDimM1OnSameCoords.getMeshDimension()!=getMeshDimension()-1)
2304 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the mesh given in other parameter must have this->getMeshDimension()-1 !");
2306 // Checking star-shaped M1 group:
2307 DAInt dt0=DataArrayInt::New(),dit0=DataArrayInt::New(),rdt0=DataArrayInt::New(),rdit0=DataArrayInt::New();
2308 MCUMesh meshM2 = otherDimM1OnSameCoords.buildDescendingConnectivity(dt0, dit0, rdt0, rdit0);
2309 DAInt dsi = rdit0->deltaShiftIndex();
2310 DAInt idsTmp0 = dsi->findIdsNotInRange(-1, 3);
2311 if(idsTmp0->getNumberOfTuples())
2312 throw INTERP_KERNEL::Exception("MEDFileUMesh::buildInnerBoundaryAlongM1Group: group is too complex: some points (or edges) have more than two connected segments (or faces)!");
2313 dt0=0; dit0=0; rdt0=0; rdit0=0; idsTmp0=0;
2315 // Get extreme nodes from the group (they won't be duplicated), ie nodes belonging to boundary cells of M1
2316 DAInt xtremIdsM2 = dsi->findIdsEqual(1); dsi = 0;
2317 MCUMesh meshM2Part = static_cast<MEDCouplingUMesh *>(meshM2->buildPartOfMySelf(xtremIdsM2->begin(), xtremIdsM2->end(),true));
2318 DAInt xtrem = meshM2Part->computeFetchedNodeIds();
2319 // Remove from the list points on the boundary of the M0 mesh (those need duplication!)
2320 dt0=DataArrayInt::New(),dit0=DataArrayInt::New(),rdt0=DataArrayInt::New(),rdit0=DataArrayInt::New();
2321 MCUMesh m0desc = buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); dt0=0; dit0=0; rdt0=0;
2322 dsi = rdit0->deltaShiftIndex();
2323 DAInt boundSegs = dsi->findIdsEqual(1); // boundary segs/faces of the M0 mesh
2324 MCUMesh m0descSkin = static_cast<MEDCouplingUMesh *>(m0desc->buildPartOfMySelf(boundSegs->begin(),boundSegs->end(), true));
2325 DAInt fNodes = m0descSkin->computeFetchedNodeIds();
2326 // In 3D, some points on the boundary of M0 still need duplication:
2328 if (getMeshDimension() == 3)
2330 DAInt dnu1=DataArrayInt::New(), dnu2=DataArrayInt::New(), dnu3=DataArrayInt::New(), dnu4=DataArrayInt::New();
2331 MCUMesh m0descSkinDesc = m0descSkin->buildDescendingConnectivity(dnu1, dnu2, dnu3, dnu4);
2332 dnu1=0;dnu2=0;dnu3=0;dnu4=0;
2333 DataArrayInt * corresp=0;
2334 meshM2->areCellsIncludedIn(m0descSkinDesc,2,corresp);
2335 DAInt validIds = corresp->findIdsInRange(0, meshM2->getNumberOfCells());
2337 if (validIds->getNumberOfTuples())
2339 MCUMesh m1IntersecSkin = static_cast<MEDCouplingUMesh *>(m0descSkinDesc->buildPartOfMySelf(validIds->begin(), validIds->end(), true));
2340 DAInt notDuplSkin = m1IntersecSkin->findBoundaryNodes();
2341 DAInt fNodes1 = fNodes->buildSubstraction(notDuplSkin);
2342 notDup = xtrem->buildSubstraction(fNodes1);
2345 notDup = xtrem->buildSubstraction(fNodes);
2348 notDup = xtrem->buildSubstraction(fNodes);
2350 // Now compute cells around group (i.e. cells where we will do the propagation to identify the two sub-sets delimited by the group)
2351 DAInt m1Nodes = otherDimM1OnSameCoords.computeFetchedNodeIds();
2352 DAInt dupl = m1Nodes->buildSubstraction(notDup);
2353 DAInt cellsAroundGroup = getCellIdsLyingOnNodes(dupl->begin(), dupl->end(), false); // false= take cell in, even if not all nodes are in notDup
2356 MCUMesh m0Part2=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(cellsAroundGroup->begin(),cellsAroundGroup->end(),true));
2357 int nCells2 = m0Part2->getNumberOfCells();
2358 DAInt desc00=DataArrayInt::New(),descI00=DataArrayInt::New(),revDesc00=DataArrayInt::New(),revDescI00=DataArrayInt::New();
2359 MCUMesh m01=m0Part2->buildDescendingConnectivity(desc00,descI00,revDesc00,revDescI00);
2361 // Neighbor information of the mesh without considering the crack (serves to count how many connex pieces it is made of)
2362 DataArrayInt *tmp00=0,*tmp11=0;
2363 MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00, tmp00, tmp11);
2364 DAInt neighInit00(tmp00);
2365 DAInt neighIInit00(tmp11);
2366 // Neighbor information of the mesh WITH the crack (some neighbors are removed):
2367 DataArrayInt *idsTmp=0;
2368 m01->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsTmp);
2370 // In the neighbor information remove the connection between high dimension cells and its low level constituents which are part
2371 // of the frontier given in parameter (i.e. the cells of low dimension from the group delimiting the crack):
2372 MEDCouplingUMesh::RemoveIdsFromIndexedArrays(ids->begin(),ids->end(),desc00,descI00);
2373 DataArrayInt *tmp0=0,*tmp1=0;
2374 // Compute the neighbor of each cell in m0Part2, taking into account the broken link above. Two
2375 // cells on either side of the crack (defined by the mesh of low dimension) are not neighbor anymore.
2376 ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00,tmp0,tmp1);
2377 DAInt neigh00(tmp0);
2378 DAInt neighI00(tmp1);
2380 // For each initial connex part of the sub-mesh (or said differently for each independent crack):
2381 int seed = 0, nIter = 0;
2382 int nIterMax = nCells2+1; // Safety net for the loop
2383 DAInt hitCells = DataArrayInt::New(); hitCells->alloc(nCells2);
2384 hitCells->fillWithValue(-1);
2385 DAInt cellsToModifyConn0_torenum = DataArrayInt::New();
2386 cellsToModifyConn0_torenum->alloc(0,1);
2387 while (nIter < nIterMax)
2389 DAInt t = hitCells->findIdsEqual(-1);
2390 if (!t->getNumberOfTuples())
2392 // Connex zone without the crack (to compute the next seed really)
2394 DAInt connexCheck = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neighInit00,neighIInit00, -1, dnu);
2396 for (int * ptr = connexCheck->getPointer(); cnt < connexCheck->getNumberOfTuples(); ptr++, cnt++)
2397 hitCells->setIJ(*ptr,0,1);
2398 // Connex zone WITH the crack (to identify cells lying on either part of the crack)
2399 DAInt spreadZone = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neigh00,neighI00, -1, dnu);
2400 cellsToModifyConn0_torenum = DataArrayInt::Aggregate(cellsToModifyConn0_torenum, spreadZone, 0);
2401 // Compute next seed, i.e. a cell in another connex part, which was not covered by the previous iterations
2402 DAInt comple = cellsToModifyConn0_torenum->buildComplement(nCells2);
2403 DAInt nonHitCells = hitCells->findIdsEqual(-1);
2404 DAInt intersec = nonHitCells->buildIntersection(comple);
2405 if (intersec->getNumberOfTuples())
2406 { seed = intersec->getIJ(0,0); }
2411 if (nIter >= nIterMax)
2412 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate(): internal error - too many iterations.");
2414 DAInt cellsToModifyConn1_torenum=cellsToModifyConn0_torenum->buildComplement(neighI00->getNumberOfTuples()-1);
2415 cellsToModifyConn0_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2416 cellsToModifyConn1_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2418 cellIdsNeededToBeRenum=cellsToModifyConn0_torenum.retn();
2419 cellIdsNotModified=cellsToModifyConn1_torenum.retn();
2420 nodeIdsToDuplicate=dupl.retn();
2424 * This method operates a modification of the connectivity and coords in \b this.
2425 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2426 * its ids will be modified to id this->getNumberOfNodes()+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2427 * 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
2428 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id this->getNumberOfNodes()+0, node id nodeIdsToDuplicateBg[1] will have id this->getNumberOfNodes()+1,
2429 * node id nodeIdsToDuplicateBg[2] will have id this->getNumberOfNodes()+2...
2431 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2433 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2434 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2436 void MEDCouplingUMesh::duplicateNodes(const int *nodeIdsToDuplicateBg, const int *nodeIdsToDuplicateEnd)
2438 int nbOfNodes=getNumberOfNodes();
2439 duplicateNodesInCoords(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd);
2440 duplicateNodesInConn(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,nbOfNodes);
2444 * This method renumbers only nodal connectivity in \a this. The renumbering is only an offset applied. So this method is a specialization of
2445 * \a renumberNodesInConn. \b WARNING, this method does not check that the resulting node ids in the nodal connectivity is in a valid range !
2447 * \param [in] offset - specifies the offset to be applied on each element of connectivity.
2449 * \sa renumberNodesInConn
2451 void MEDCouplingUMesh::renumberNodesWithOffsetInConn(int offset)
2453 checkConnectivityFullyDefined();
2454 int *conn(getNodalConnectivity()->getPointer());
2455 const int *connIndex(getNodalConnectivityIndex()->getConstPointer());
2456 int nbOfCells(getNumberOfCells());
2457 for(int i=0;i<nbOfCells;i++)
2458 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2460 int& node=conn[iconn];
2461 if(node>=0)//avoid polyhedron separator
2466 _nodal_connec->declareAsNew();
2471 * Same than renumberNodesInConn(const int *) except that here the format of old-to-new traducer is using map instead
2472 * 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
2475 void MEDCouplingUMesh::renumberNodesInConn(const INTERP_KERNEL::HashMap<int,int>& newNodeNumbersO2N)
2477 checkConnectivityFullyDefined();
2478 int *conn(getNodalConnectivity()->getPointer());
2479 const int *connIndex(getNodalConnectivityIndex()->getConstPointer());
2480 int nbOfCells(getNumberOfCells());
2481 for(int i=0;i<nbOfCells;i++)
2482 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2484 int& node=conn[iconn];
2485 if(node>=0)//avoid polyhedron separator
2487 INTERP_KERNEL::HashMap<int,int>::const_iterator it(newNodeNumbersO2N.find(node));
2488 if(it!=newNodeNumbersO2N.end())
2494 std::ostringstream oss; oss << "MEDCouplingUMesh::renumberNodesInConn(map) : presence in connectivity for cell #" << i << " of node #" << node << " : Not in map !";
2495 throw INTERP_KERNEL::Exception(oss.str());
2499 _nodal_connec->declareAsNew();
2504 * Changes ids of nodes within the nodal connectivity arrays according to a permutation
2505 * array in "Old to New" mode. The node coordinates array is \b not changed by this method.
2506 * This method is a generalization of shiftNodeNumbersInConn().
2507 * \warning This method performs no check of validity of new ids. **Use it with care !**
2508 * \param [in] newNodeNumbersO2N - a permutation array, of length \a
2509 * this->getNumberOfNodes(), in "Old to New" mode.
2510 * See \ref numbering for more info on renumbering modes.
2511 * \throw If the nodal connectivity of cells is not defined.
2513 * \if ENABLE_EXAMPLES
2514 * \ref cpp_mcumesh_renumberNodesInConn "Here is a C++ example".<br>
2515 * \ref py_mcumesh_renumberNodesInConn "Here is a Python example".
2518 void MEDCouplingUMesh::renumberNodesInConn(const int *newNodeNumbersO2N)
2520 checkConnectivityFullyDefined();
2521 int *conn=getNodalConnectivity()->getPointer();
2522 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2523 int nbOfCells(getNumberOfCells());
2524 for(int i=0;i<nbOfCells;i++)
2525 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2527 int& node=conn[iconn];
2528 if(node>=0)//avoid polyhedron separator
2530 node=newNodeNumbersO2N[node];
2533 _nodal_connec->declareAsNew();
2538 * This method renumbers nodes \b in \b connectivity \b only \b without \b any \b reference \b to \b coords.
2539 * This method performs no check on the fact that new coordinate ids are valid. \b Use \b it \b with \b care !
2540 * This method is an specialization of \ref MEDCoupling::MEDCouplingUMesh::renumberNodesInConn "renumberNodesInConn method".
2542 * \param [in] delta specifies the shift size applied to nodeId in nodal connectivity in \b this.
2544 void MEDCouplingUMesh::shiftNodeNumbersInConn(int delta)
2546 checkConnectivityFullyDefined();
2547 int *conn=getNodalConnectivity()->getPointer();
2548 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2549 int nbOfCells=getNumberOfCells();
2550 for(int i=0;i<nbOfCells;i++)
2551 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2553 int& node=conn[iconn];
2554 if(node>=0)//avoid polyhedron separator
2559 _nodal_connec->declareAsNew();
2564 * This method operates a modification of the connectivity in \b this.
2565 * 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.
2566 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2567 * its ids will be modified to id offset+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2568 * 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
2569 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id offset+0, node id nodeIdsToDuplicateBg[1] will have id offset+1,
2570 * node id nodeIdsToDuplicateBg[2] will have id offset+2...
2572 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2573 * As an another consequense after the call of this method \b this can be transiently non cohrent.
2575 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2576 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2577 * \param [in] offset the offset applied to all node ids in connectivity that are in [ \a nodeIdsToDuplicateBg, \a nodeIdsToDuplicateEnd ).
2579 void MEDCouplingUMesh::duplicateNodesInConn(const int *nodeIdsToDuplicateBg, const int *nodeIdsToDuplicateEnd, int offset)
2581 checkConnectivityFullyDefined();
2582 std::map<int,int> m;
2584 for(const int *work=nodeIdsToDuplicateBg;work!=nodeIdsToDuplicateEnd;work++,val++)
2586 int *conn=getNodalConnectivity()->getPointer();
2587 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2588 int nbOfCells=getNumberOfCells();
2589 for(int i=0;i<nbOfCells;i++)
2590 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2592 int& node=conn[iconn];
2593 if(node>=0)//avoid polyhedron separator
2595 std::map<int,int>::iterator it=m.find(node);
2604 * This method renumbers cells of \a this using the array specified by [old2NewBg;old2NewBg+getNumberOfCells())
2606 * Contrary to MEDCouplingPointSet::renumberNodes, this method makes a permutation without any fuse of cell.
2607 * After the call of this method the number of cells remains the same as before.
2609 * If 'check' equals true the method will check that any elements in [ \a old2NewBg; \a old2NewEnd ) is unique ; if not
2610 * an INTERP_KERNEL::Exception will be thrown. When 'check' equals true [ \a old2NewBg ; \a old2NewEnd ) is not expected to
2611 * be strictly in [0;this->getNumberOfCells()).
2613 * If 'check' equals false the method will not check the content of [ \a old2NewBg ; \a old2NewEnd ).
2614 * To avoid any throw of SIGSEGV when 'check' equals false, the elements in [ \a old2NewBg ; \a old2NewEnd ) should be unique and
2615 * should be contained in[0;this->getNumberOfCells()).
2617 * \param [in] old2NewBg is expected to be a dynamically allocated pointer of size at least equal to this->getNumberOfCells()
2620 void MEDCouplingUMesh::renumberCells(const int *old2NewBg, bool check)
2622 checkConnectivityFullyDefined();
2623 int nbCells=getNumberOfCells();
2624 const int *array=old2NewBg;
2626 array=DataArrayInt::CheckAndPreparePermutation(old2NewBg,old2NewBg+nbCells);
2628 const int *conn=_nodal_connec->getConstPointer();
2629 const int *connI=_nodal_connec_index->getConstPointer();
2630 MCAuto<DataArrayInt> o2n=DataArrayInt::New(); o2n->useArray(array,false,C_DEALLOC,nbCells,1);
2631 MCAuto<DataArrayInt> n2o=o2n->invertArrayO2N2N2O(nbCells);
2632 const int *n2oPtr=n2o->begin();
2633 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
2634 newConn->alloc(_nodal_connec->getNumberOfTuples(),_nodal_connec->getNumberOfComponents());
2635 newConn->copyStringInfoFrom(*_nodal_connec);
2636 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
2637 newConnI->alloc(_nodal_connec_index->getNumberOfTuples(),_nodal_connec_index->getNumberOfComponents());
2638 newConnI->copyStringInfoFrom(*_nodal_connec_index);
2640 int *newC=newConn->getPointer();
2641 int *newCI=newConnI->getPointer();
2644 for(int i=0;i<nbCells;i++)
2647 int nbOfElts=connI[pos+1]-connI[pos];
2648 newC=std::copy(conn+connI[pos],conn+connI[pos+1],newC);
2653 setConnectivity(newConn,newConnI);
2655 free(const_cast<int *>(array));
2659 * Finds cells whose bounding boxes intersect a given bounding box.
2660 * \param [in] bbox - an array defining the bounding box via coordinates of its
2661 * extremum points in "no interlace" mode, i.e. xMin, xMax, yMin, yMax, zMin,
2663 * \param [in] eps - a factor used to increase size of the bounding box of cell
2664 * before comparing it with \a bbox. This factor is multiplied by the maximal
2665 * extent of the bounding box of cell to produce an addition to this bounding box.
2666 * \return DataArrayInt * - a new instance of DataArrayInt holding ids for found
2667 * cells. The caller is to delete this array using decrRef() as it is no more
2669 * \throw If the coordinates array is not set.
2670 * \throw If the nodal connectivity of cells is not defined.
2672 * \if ENABLE_EXAMPLES
2673 * \ref cpp_mcumesh_getCellsInBoundingBox "Here is a C++ example".<br>
2674 * \ref py_mcumesh_getCellsInBoundingBox "Here is a Python example".
2677 DataArrayInt *MEDCouplingUMesh::getCellsInBoundingBox(const double *bbox, double eps) const
2679 MCAuto<DataArrayInt> elems=DataArrayInt::New(); elems->alloc(0,1);
2680 if(getMeshDimension()==-1)
2682 elems->pushBackSilent(0);
2683 return elems.retn();
2685 int dim=getSpaceDimension();
2686 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2687 const int* conn = getNodalConnectivity()->getConstPointer();
2688 const int* conn_index= getNodalConnectivityIndex()->getConstPointer();
2689 const double* coords = getCoords()->getConstPointer();
2690 int nbOfCells=getNumberOfCells();
2691 for ( int ielem=0; ielem<nbOfCells;ielem++ )
2693 for (int i=0; i<dim; i++)
2695 elem_bb[i*2]=std::numeric_limits<double>::max();
2696 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2699 for (int inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2701 int node= conn[inode];
2702 if(node>=0)//avoid polyhedron separator
2704 for (int idim=0; idim<dim; idim++)
2706 if ( coords[node*dim+idim] < elem_bb[idim*2] )
2708 elem_bb[idim*2] = coords[node*dim+idim] ;
2710 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2712 elem_bb[idim*2+1] = coords[node*dim+idim] ;
2717 if (intersectsBoundingBox(elem_bb, bbox, dim, eps))
2718 elems->pushBackSilent(ielem);
2720 return elems.retn();
2724 * Given a boundary box 'bbox' returns elements 'elems' contained in this 'bbox' or touching 'bbox' (within 'eps' distance).
2725 * Warning 'elems' is incremented during the call so if elems is not empty before call returned elements will be
2726 * added in 'elems' parameter.
2728 DataArrayInt *MEDCouplingUMesh::getCellsInBoundingBox(const INTERP_KERNEL::DirectedBoundingBox& bbox, double eps)
2730 MCAuto<DataArrayInt> elems=DataArrayInt::New(); elems->alloc(0,1);
2731 if(getMeshDimension()==-1)
2733 elems->pushBackSilent(0);
2734 return elems.retn();
2736 int dim=getSpaceDimension();
2737 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2738 const int* conn = getNodalConnectivity()->getConstPointer();
2739 const int* conn_index= getNodalConnectivityIndex()->getConstPointer();
2740 const double* coords = getCoords()->getConstPointer();
2741 int nbOfCells=getNumberOfCells();
2742 for ( int ielem=0; ielem<nbOfCells;ielem++ )
2744 for (int i=0; i<dim; i++)
2746 elem_bb[i*2]=std::numeric_limits<double>::max();
2747 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2750 for (int inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2752 int node= conn[inode];
2753 if(node>=0)//avoid polyhedron separator
2755 for (int idim=0; idim<dim; idim++)
2757 if ( coords[node*dim+idim] < elem_bb[idim*2] )
2759 elem_bb[idim*2] = coords[node*dim+idim] ;
2761 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2763 elem_bb[idim*2+1] = coords[node*dim+idim] ;
2768 if(intersectsBoundingBox(bbox, elem_bb, dim, eps))
2769 elems->pushBackSilent(ielem);
2771 return elems.retn();
2775 * Returns a type of a cell by its id.
2776 * \param [in] cellId - the id of the cell of interest.
2777 * \return INTERP_KERNEL::NormalizedCellType - enumeration item describing the cell type.
2778 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2780 INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::getTypeOfCell(std::size_t cellId) const
2782 const int *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
2783 if(cellId<_nodal_connec_index->getNbOfElems()-1)
2784 return (INTERP_KERNEL::NormalizedCellType) pt[ptI[cellId]];
2787 std::ostringstream oss; oss << "MEDCouplingUMesh::getTypeOfCell : Requesting type of cell #" << cellId << " but it should be in [0," << _nodal_connec_index->getNbOfElems()-1 << ") !";
2788 throw INTERP_KERNEL::Exception(oss.str());
2793 * This method returns a newly allocated array containing cell ids (ascendingly sorted) whose geometric type are equal to type.
2794 * This method does not throw exception if geometric type \a type is not in \a this.
2795 * This method throws an INTERP_KERNEL::Exception if meshdimension of \b this is not equal to those of \b type.
2796 * The coordinates array is not considered here.
2798 * \param [in] type the geometric type
2799 * \return cell ids in this having geometric type \a type.
2801 DataArrayInt *MEDCouplingUMesh::giveCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2804 MCAuto<DataArrayInt> ret=DataArrayInt::New();
2806 checkConnectivityFullyDefined();
2807 int nbCells=getNumberOfCells();
2808 int mdim=getMeshDimension();
2809 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
2810 if(mdim!=(int)cm.getDimension())
2811 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::giveCellsWithType : Mismatch between mesh dimension and dimension of the cell !");
2812 const int *ptI=_nodal_connec_index->getConstPointer();
2813 const int *pt=_nodal_connec->getConstPointer();
2814 for(int i=0;i<nbCells;i++)
2816 if((INTERP_KERNEL::NormalizedCellType)pt[ptI[i]]==type)
2817 ret->pushBackSilent(i);
2823 * Returns nb of cells having the geometric type \a type. No throw if no cells in \a this has the geometric type \a type.
2825 std::size_t MEDCouplingUMesh::getNumberOfCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2827 const int *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
2828 std::size_t nbOfCells(getNumberOfCells()),ret(0);
2829 for(std::size_t i=0;i<nbOfCells;i++)
2830 if((INTERP_KERNEL::NormalizedCellType) pt[ptI[i]]==type)
2836 * Returns the nodal connectivity of a given cell.
2837 * The separator of faces within polyhedron connectivity (-1) is not returned, thus
2838 * all returned node ids can be used in getCoordinatesOfNode().
2839 * \param [in] cellId - an id of the cell of interest.
2840 * \param [in,out] conn - a vector where the node ids are appended. It is not
2841 * cleared before the appending.
2842 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2844 void MEDCouplingUMesh::getNodeIdsOfCell(std::size_t cellId, std::vector<int>& conn) const
2846 const int *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
2847 for(const int *w=pt+ptI[cellId]+1;w!=pt+ptI[cellId+1];w++)
2852 std::string MEDCouplingUMesh::simpleRepr() const
2854 static const char msg0[]="No coordinates specified !";
2855 std::ostringstream ret;
2856 ret << "Unstructured mesh with name : \"" << getName() << "\"\n";
2857 ret << "Description of mesh : \"" << getDescription() << "\"\n";
2859 double tt=getTime(tmpp1,tmpp2);
2860 ret << "Time attached to the mesh [unit] : " << tt << " [" << getTimeUnit() << "]\n";
2861 ret << "Iteration : " << tmpp1 << " Order : " << tmpp2 << "\n";
2863 { ret << "Mesh dimension : " << _mesh_dim << "\nSpace dimension : "; }
2865 { ret << " Mesh dimension has not been set or is invalid !"; }
2868 const int spaceDim=getSpaceDimension();
2869 ret << spaceDim << "\nInfo attached on space dimension : ";
2870 for(int i=0;i<spaceDim;i++)
2871 ret << "\"" << _coords->getInfoOnComponent(i) << "\" ";
2875 ret << msg0 << "\n";
2876 ret << "Number of nodes : ";
2878 ret << getNumberOfNodes() << "\n";
2880 ret << msg0 << "\n";
2881 ret << "Number of cells : ";
2882 if(_nodal_connec!=0 && _nodal_connec_index!=0)
2883 ret << getNumberOfCells() << "\n";
2885 ret << "No connectivity specified !" << "\n";
2886 ret << "Cell types present : ";
2887 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
2889 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter);
2890 ret << cm.getRepr() << " ";
2896 std::string MEDCouplingUMesh::advancedRepr() const
2898 std::ostringstream ret;
2899 ret << simpleRepr();
2900 ret << "\nCoordinates array : \n___________________\n\n";
2902 _coords->reprWithoutNameStream(ret);
2904 ret << "No array set !\n";
2905 ret << "\n\nConnectivity arrays : \n_____________________\n\n";
2906 reprConnectivityOfThisLL(ret);
2911 * This method returns a C++ code that is a dump of \a this.
2912 * This method will throw if this is not fully defined.
2914 std::string MEDCouplingUMesh::cppRepr() const
2916 static const char coordsName[]="coords";
2917 static const char connName[]="conn";
2918 static const char connIName[]="connI";
2919 checkFullyDefined();
2920 std::ostringstream ret; ret << "// coordinates" << std::endl;
2921 _coords->reprCppStream(coordsName,ret); ret << std::endl << "// connectivity" << std::endl;
2922 _nodal_connec->reprCppStream(connName,ret); ret << std::endl;
2923 _nodal_connec_index->reprCppStream(connIName,ret); ret << std::endl;
2924 ret << "MEDCouplingUMesh *mesh=MEDCouplingUMesh::New(\"" << getName() << "\"," << getMeshDimension() << ");" << std::endl;
2925 ret << "mesh->setCoords(" << coordsName << ");" << std::endl;
2926 ret << "mesh->setConnectivity(" << connName << "," << connIName << ",true);" << std::endl;
2927 ret << coordsName << "->decrRef(); " << connName << "->decrRef(); " << connIName << "->decrRef();" << std::endl;
2931 std::string MEDCouplingUMesh::reprConnectivityOfThis() const
2933 std::ostringstream ret;
2934 reprConnectivityOfThisLL(ret);
2939 * This method builds a newly allocated instance (with the same name than \a this) that the caller has the responsability to deal with.
2940 * This method returns an instance with all arrays allocated (connectivity, connectivity index, coordinates)
2941 * but with length of these arrays set to 0. It allows to define an "empty" mesh (with nor cells nor nodes but compliant with
2944 * This method expects that \a this has a mesh dimension set and higher or equal to 0. If not an exception will be thrown.
2945 * 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
2946 * with number of tuples set to 0, if not the array is taken as this in the returned instance.
2948 MEDCouplingUMesh *MEDCouplingUMesh::buildSetInstanceFromThis(int spaceDim) const
2950 int mdim=getMeshDimension();
2952 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSetInstanceFromThis : invalid mesh dimension ! Should be >= 0 !");
2953 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
2954 MCAuto<DataArrayInt> tmp1,tmp2;
2955 bool needToCpyCT=true;
2958 tmp1=DataArrayInt::New(); tmp1->alloc(0,1);
2966 if(!_nodal_connec_index)
2968 tmp2=DataArrayInt::New(); tmp2->alloc(1,1); tmp2->setIJ(0,0,0);
2973 tmp2=_nodal_connec_index;
2976 ret->setConnectivity(tmp1,tmp2,false);
2981 MCAuto<DataArrayDouble> coords=DataArrayDouble::New(); coords->alloc(0,spaceDim);
2982 ret->setCoords(coords);
2985 ret->setCoords(_coords);
2989 int MEDCouplingUMesh::getNumberOfNodesInCell(int cellId) const
2991 const int *ptI=_nodal_connec_index->getConstPointer();
2992 const int *pt=_nodal_connec->getConstPointer();
2993 if(pt[ptI[cellId]]!=INTERP_KERNEL::NORM_POLYHED)
2994 return ptI[cellId+1]-ptI[cellId]-1;
2996 return (int)std::count_if(pt+ptI[cellId]+1,pt+ptI[cellId+1],std::bind2nd(std::not_equal_to<int>(),-1));
3000 * Returns types of cells of the specified part of \a this mesh.
3001 * This method avoids computing sub-mesh explicitely to get its types.
3002 * \param [in] begin - an array of cell ids of interest.
3003 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3004 * \return std::set<INTERP_KERNEL::NormalizedCellType> - a set of enumeration items
3005 * describing the cell types.
3006 * \throw If the coordinates array is not set.
3007 * \throw If the nodal connectivity of cells is not defined.
3008 * \sa getAllGeoTypes()
3010 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getTypesOfPart(const int *begin, const int *end) const
3012 checkFullyDefined();
3013 std::set<INTERP_KERNEL::NormalizedCellType> ret;
3014 const int *conn=_nodal_connec->getConstPointer();
3015 const int *connIndex=_nodal_connec_index->getConstPointer();
3016 for(const int *w=begin;w!=end;w++)
3017 ret.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]);
3022 * Defines the nodal connectivity using given connectivity arrays in \ref numbering-indirect format.
3023 * Optionally updates
3024 * a set of types of cells constituting \a this mesh.
3025 * This method is for advanced users having prepared their connectivity before. For
3026 * more info on using this method see \ref MEDCouplingUMeshAdvBuild.
3027 * \param [in] conn - the nodal connectivity array.
3028 * \param [in] connIndex - the nodal connectivity index array.
3029 * \param [in] isComputingTypes - if \c true, the set of types constituting \a this
3032 void MEDCouplingUMesh::setConnectivity(DataArrayInt *conn, DataArrayInt *connIndex, bool isComputingTypes)
3034 DataArrayInt::SetArrayIn(conn,_nodal_connec);
3035 DataArrayInt::SetArrayIn(connIndex,_nodal_connec_index);
3036 if(isComputingTypes)
3042 * Copy constructor. If 'deepCopy' is false \a this is a shallow copy of other.
3043 * If 'deeCpy' is true all arrays (coordinates and connectivities) are deeply copied.
3045 MEDCouplingUMesh::MEDCouplingUMesh(const MEDCouplingUMesh& other, bool deepCpy):MEDCouplingPointSet(other,deepCpy),_mesh_dim(other._mesh_dim),
3046 _nodal_connec(0),_nodal_connec_index(0),
3047 _types(other._types)
3049 if(other._nodal_connec)
3050 _nodal_connec=other._nodal_connec->performCopyOrIncrRef(deepCpy);
3051 if(other._nodal_connec_index)
3052 _nodal_connec_index=other._nodal_connec_index->performCopyOrIncrRef(deepCpy);
3055 MEDCouplingUMesh::~MEDCouplingUMesh()
3058 _nodal_connec->decrRef();
3059 if(_nodal_connec_index)
3060 _nodal_connec_index->decrRef();
3064 * Recomputes a set of cell types of \a this mesh. For more info see
3065 * \ref MEDCouplingUMeshNodalConnectivity.
3067 void MEDCouplingUMesh::computeTypes()
3069 ComputeAllTypesInternal(_types,_nodal_connec,_nodal_connec_index);
3074 * Returns a number of cells constituting \a this mesh.
3075 * \return int - the number of cells in \a this mesh.
3076 * \throw If the nodal connectivity of cells is not defined.
3078 std::size_t MEDCouplingUMesh::getNumberOfCells() const
3080 if(_nodal_connec_index)
3081 return _nodal_connec_index->getNumberOfTuples()-1;
3086 throw INTERP_KERNEL::Exception("Unable to get number of cells because no connectivity specified !");
3090 * Returns a dimension of \a this mesh, i.e. a dimension of cells constituting \a this
3091 * mesh. For more info see \ref meshes.
3092 * \return int - the dimension of \a this mesh.
3093 * \throw If the mesh dimension is not defined using setMeshDimension().
3095 int MEDCouplingUMesh::getMeshDimension() const
3098 throw INTERP_KERNEL::Exception("No mesh dimension specified !");
3103 * Returns a length of the nodal connectivity array.
3104 * This method is for test reason. Normally the integer returned is not useable by
3105 * user. For more info see \ref MEDCouplingUMeshNodalConnectivity.
3106 * \return int - the length of the nodal connectivity array.
3108 int MEDCouplingUMesh::getNodalConnectivityArrayLen() const
3110 return _nodal_connec->getNbOfElems();
3114 * First step of serialization process. Used by ParaMEDMEM and MEDCouplingCorba to transfert data between process.
3116 void MEDCouplingUMesh::getTinySerializationInformation(std::vector<double>& tinyInfoD, std::vector<int>& tinyInfo, std::vector<std::string>& littleStrings) const
3118 MEDCouplingPointSet::getTinySerializationInformation(tinyInfoD,tinyInfo,littleStrings);
3119 tinyInfo.push_back(getMeshDimension());
3120 tinyInfo.push_back(getNumberOfCells());
3122 tinyInfo.push_back(getNodalConnectivityArrayLen());
3124 tinyInfo.push_back(-1);
3128 * First step of unserialization process.
3130 bool MEDCouplingUMesh::isEmptyMesh(const std::vector<int>& tinyInfo) const
3132 return tinyInfo[6]<=0;
3136 * Second step of serialization process.
3137 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3140 * \param littleStrings
3142 void MEDCouplingUMesh::resizeForUnserialization(const std::vector<int>& tinyInfo, DataArrayInt *a1, DataArrayDouble *a2, std::vector<std::string>& littleStrings) const
3144 MEDCouplingPointSet::resizeForUnserialization(tinyInfo,a1,a2,littleStrings);
3146 a1->alloc(tinyInfo[7]+tinyInfo[6]+1,1);
3150 * Third and final step of serialization process.
3152 void MEDCouplingUMesh::serialize(DataArrayInt *&a1, DataArrayDouble *&a2) const
3154 MEDCouplingPointSet::serialize(a1,a2);
3155 if(getMeshDimension()>-1)
3157 a1=DataArrayInt::New();
3158 a1->alloc(getNodalConnectivityArrayLen()+getNumberOfCells()+1,1);
3159 int *ptA1=a1->getPointer();
3160 const int *conn=getNodalConnectivity()->getConstPointer();
3161 const int *index=getNodalConnectivityIndex()->getConstPointer();
3162 ptA1=std::copy(index,index+getNumberOfCells()+1,ptA1);
3163 std::copy(conn,conn+getNodalConnectivityArrayLen(),ptA1);
3170 * Second and final unserialization process.
3171 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3173 void MEDCouplingUMesh::unserialization(const std::vector<double>& tinyInfoD, const std::vector<int>& tinyInfo, const DataArrayInt *a1, DataArrayDouble *a2, const std::vector<std::string>& littleStrings)
3175 MEDCouplingPointSet::unserialization(tinyInfoD,tinyInfo,a1,a2,littleStrings);
3176 setMeshDimension(tinyInfo[5]);
3180 const int *recvBuffer=a1->getConstPointer();
3181 MCAuto<DataArrayInt> myConnecIndex=DataArrayInt::New();
3182 myConnecIndex->alloc(tinyInfo[6]+1,1);
3183 std::copy(recvBuffer,recvBuffer+tinyInfo[6]+1,myConnecIndex->getPointer());
3184 MCAuto<DataArrayInt> myConnec=DataArrayInt::New();
3185 myConnec->alloc(tinyInfo[7],1);
3186 std::copy(recvBuffer+tinyInfo[6]+1,recvBuffer+tinyInfo[6]+1+tinyInfo[7],myConnec->getPointer());
3187 setConnectivity(myConnec, myConnecIndex);
3194 * Returns a new MEDCouplingFieldDouble containing volumes of cells constituting \a this
3196 * For 1D cells, the returned field contains lengths.<br>
3197 * For 2D cells, the returned field contains areas.<br>
3198 * For 3D cells, the returned field contains volumes.
3199 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3200 * orientation, i.e. the volume is always positive.
3201 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on cells
3202 * and one time . The caller is to delete this field using decrRef() as it is no
3205 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureField(bool isAbs) const
3207 std::string name="MeasureOfMesh_";
3209 int nbelem=getNumberOfCells();
3210 MCAuto<MEDCouplingFieldDouble> field=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3211 field->setName(name);
3212 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3213 array->alloc(nbelem,1);
3214 double *area_vol=array->getPointer();
3215 field->setArray(array) ; array=0;
3216 field->setMesh(const_cast<MEDCouplingUMesh *>(this));
3217 field->synchronizeTimeWithMesh();
3218 if(getMeshDimension()!=-1)
3221 INTERP_KERNEL::NormalizedCellType type;
3222 int dim_space=getSpaceDimension();
3223 const double *coords=getCoords()->getConstPointer();
3224 const int *connec=getNodalConnectivity()->getConstPointer();
3225 const int *connec_index=getNodalConnectivityIndex()->getConstPointer();
3226 for(int iel=0;iel<nbelem;iel++)
3228 ipt=connec_index[iel];
3229 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3230 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);
3233 std::transform(area_vol,area_vol+nbelem,area_vol,std::ptr_fun<double,double>(fabs));
3237 area_vol[0]=std::numeric_limits<double>::max();
3239 return field.retn();
3243 * Returns a new DataArrayDouble containing volumes of specified cells of \a this
3245 * For 1D cells, the returned array contains lengths.<br>
3246 * For 2D cells, the returned array contains areas.<br>
3247 * For 3D cells, the returned array contains volumes.
3248 * This method avoids building explicitly a part of \a this mesh to perform the work.
3249 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3250 * orientation, i.e. the volume is always positive.
3251 * \param [in] begin - an array of cell ids of interest.
3252 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3253 * \return DataArrayDouble * - a new instance of DataArrayDouble. The caller is to
3254 * delete this array using decrRef() as it is no more needed.
3256 * \if ENABLE_EXAMPLES
3257 * \ref cpp_mcumesh_getPartMeasureField "Here is a C++ example".<br>
3258 * \ref py_mcumesh_getPartMeasureField "Here is a Python example".
3260 * \sa getMeasureField()
3262 DataArrayDouble *MEDCouplingUMesh::getPartMeasureField(bool isAbs, const int *begin, const int *end) const
3264 std::string name="PartMeasureOfMesh_";
3266 int nbelem=(int)std::distance(begin,end);
3267 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3268 array->setName(name);
3269 array->alloc(nbelem,1);
3270 double *area_vol=array->getPointer();
3271 if(getMeshDimension()!=-1)
3274 INTERP_KERNEL::NormalizedCellType type;
3275 int dim_space=getSpaceDimension();
3276 const double *coords=getCoords()->getConstPointer();
3277 const int *connec=getNodalConnectivity()->getConstPointer();
3278 const int *connec_index=getNodalConnectivityIndex()->getConstPointer();
3279 for(const int *iel=begin;iel!=end;iel++)
3281 ipt=connec_index[*iel];
3282 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3283 *area_vol++=INTERP_KERNEL::computeVolSurfOfCell2<int,INTERP_KERNEL::ALL_C_MODE>(type,connec+ipt+1,connec_index[*iel+1]-ipt-1,coords,dim_space);
3286 std::transform(array->getPointer(),area_vol,array->getPointer(),std::ptr_fun<double,double>(fabs));
3290 area_vol[0]=std::numeric_limits<double>::max();
3292 return array.retn();
3296 * Returns a new MEDCouplingFieldDouble containing volumes of cells of a dual mesh of
3297 * \a this one. The returned field contains the dual cell volume for each corresponding
3298 * node in \a this mesh. In other words, the field returns the getMeasureField() of
3299 * the dual mesh in P1 sens of \a this.<br>
3300 * For 1D cells, the returned field contains lengths.<br>
3301 * For 2D cells, the returned field contains areas.<br>
3302 * For 3D cells, the returned field contains volumes.
3303 * This method is useful to check "P1*" conservative interpolators.
3304 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3305 * orientation, i.e. the volume is always positive.
3306 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3307 * nodes and one time. The caller is to delete this array using decrRef() as
3308 * it is no more needed.
3310 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureFieldOnNode(bool isAbs) const
3312 MCAuto<MEDCouplingFieldDouble> tmp=getMeasureField(isAbs);
3313 std::string name="MeasureOnNodeOfMesh_";
3315 int nbNodes=getNumberOfNodes();
3316 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_NODES);
3317 double cst=1./((double)getMeshDimension()+1.);
3318 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3319 array->alloc(nbNodes,1);
3320 double *valsToFill=array->getPointer();
3321 std::fill(valsToFill,valsToFill+nbNodes,0.);
3322 const double *values=tmp->getArray()->getConstPointer();
3323 MCAuto<DataArrayInt> da=DataArrayInt::New();
3324 MCAuto<DataArrayInt> daInd=DataArrayInt::New();
3325 getReverseNodalConnectivity(da,daInd);
3326 const int *daPtr=da->getConstPointer();
3327 const int *daIPtr=daInd->getConstPointer();
3328 for(int i=0;i<nbNodes;i++)
3329 for(const int *cell=daPtr+daIPtr[i];cell!=daPtr+daIPtr[i+1];cell++)
3330 valsToFill[i]+=cst*values[*cell];
3332 ret->setArray(array);
3337 * Returns a new MEDCouplingFieldDouble holding normal vectors to cells of \a this
3338 * mesh. The returned normal vectors to each cell have a norm2 equal to 1.
3339 * The computed vectors have <em> this->getMeshDimension()+1 </em> components
3340 * and are normalized.
3341 * <br> \a this can be either
3342 * - a 2D mesh in 2D or 3D space or
3343 * - an 1D mesh in 2D space.
3345 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3346 * cells and one time. The caller is to delete this field using decrRef() as
3347 * it is no more needed.
3348 * \throw If the nodal connectivity of cells is not defined.
3349 * \throw If the coordinates array is not set.
3350 * \throw If the mesh dimension is not set.
3351 * \throw If the mesh and space dimension is not as specified above.
3353 MEDCouplingFieldDouble *MEDCouplingUMesh::buildOrthogonalField() const
3355 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3356 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3357 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3358 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3359 int nbOfCells=getNumberOfCells();
3360 int nbComp=getMeshDimension()+1;
3361 array->alloc(nbOfCells,nbComp);
3362 double *vals=array->getPointer();
3363 const int *connI=_nodal_connec_index->getConstPointer();
3364 const int *conn=_nodal_connec->getConstPointer();
3365 const double *coords=_coords->getConstPointer();
3366 if(getMeshDimension()==2)
3368 if(getSpaceDimension()==3)
3370 MCAuto<DataArrayDouble> loc=computeCellCenterOfMass();
3371 const double *locPtr=loc->getConstPointer();
3372 for(int i=0;i<nbOfCells;i++,vals+=3)
3374 int offset=connI[i];
3375 INTERP_KERNEL::crossprod<3>(locPtr+3*i,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3376 double n=INTERP_KERNEL::norm<3>(vals);
3377 std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3382 MCAuto<MEDCouplingFieldDouble> isAbs=getMeasureField(false);
3383 const double *isAbsPtr=isAbs->getArray()->begin();
3384 for(int i=0;i<nbOfCells;i++,isAbsPtr++)
3385 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=*isAbsPtr>0.?1.:-1.; }
3388 else//meshdimension==1
3391 for(int i=0;i<nbOfCells;i++)
3393 int offset=connI[i];
3394 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3395 double n=INTERP_KERNEL::norm<2>(tmp);
3396 std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3401 ret->setArray(array);
3403 ret->synchronizeTimeWithSupport();
3408 * Returns a new MEDCouplingFieldDouble holding normal vectors to specified cells of
3409 * \a this mesh. The computed vectors have <em> this->getMeshDimension()+1 </em> components
3410 * and are normalized.
3411 * <br> \a this can be either
3412 * - a 2D mesh in 2D or 3D space or
3413 * - an 1D mesh in 2D space.
3415 * This method avoids building explicitly a part of \a this mesh to perform the work.
3416 * \param [in] begin - an array of cell ids of interest.
3417 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3418 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3419 * cells and one time. The caller is to delete this field using decrRef() as
3420 * it is no more needed.
3421 * \throw If the nodal connectivity of cells is not defined.
3422 * \throw If the coordinates array is not set.
3423 * \throw If the mesh dimension is not set.
3424 * \throw If the mesh and space dimension is not as specified above.
3425 * \sa buildOrthogonalField()
3427 * \if ENABLE_EXAMPLES
3428 * \ref cpp_mcumesh_buildPartOrthogonalField "Here is a C++ example".<br>
3429 * \ref py_mcumesh_buildPartOrthogonalField "Here is a Python example".
3432 MEDCouplingFieldDouble *MEDCouplingUMesh::buildPartOrthogonalField(const int *begin, const int *end) const
3434 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3435 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3436 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3437 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3438 std::size_t nbelems=std::distance(begin,end);
3439 int nbComp=getMeshDimension()+1;
3440 array->alloc((int)nbelems,nbComp);
3441 double *vals=array->getPointer();
3442 const int *connI=_nodal_connec_index->getConstPointer();
3443 const int *conn=_nodal_connec->getConstPointer();
3444 const double *coords=_coords->getConstPointer();
3445 if(getMeshDimension()==2)
3447 if(getSpaceDimension()==3)
3449 MCAuto<DataArrayDouble> loc=getPartBarycenterAndOwner(begin,end);
3450 const double *locPtr=loc->getConstPointer();
3451 for(const int *i=begin;i!=end;i++,vals+=3,locPtr+=3)
3453 int offset=connI[*i];
3454 INTERP_KERNEL::crossprod<3>(locPtr,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3455 double n=INTERP_KERNEL::norm<3>(vals);
3456 std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3461 for(std::size_t i=0;i<nbelems;i++)
3462 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=1.; }
3465 else//meshdimension==1
3468 for(const int *i=begin;i!=end;i++)
3470 int offset=connI[*i];
3471 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3472 double n=INTERP_KERNEL::norm<2>(tmp);
3473 std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3478 ret->setArray(array);
3480 ret->synchronizeTimeWithSupport();
3485 * Returns a new MEDCouplingFieldDouble holding a direction vector for each SEG2 in \a
3486 * this 1D mesh. The computed vectors have <em> this->getSpaceDimension() </em> components
3487 * and are \b not normalized.
3488 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3489 * cells and one time. The caller is to delete this field using decrRef() as
3490 * it is no more needed.
3491 * \throw If the nodal connectivity of cells is not defined.
3492 * \throw If the coordinates array is not set.
3493 * \throw If \a this->getMeshDimension() != 1.
3494 * \throw If \a this mesh includes cells of type other than SEG2.
3496 MEDCouplingFieldDouble *MEDCouplingUMesh::buildDirectionVectorField() const
3498 if(getMeshDimension()!=1)
3499 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for buildDirectionVectorField !");
3500 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3501 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for buildDirectionVectorField !");
3502 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3503 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3504 int nbOfCells=getNumberOfCells();
3505 int spaceDim=getSpaceDimension();
3506 array->alloc(nbOfCells,spaceDim);
3507 double *pt=array->getPointer();
3508 const double *coo=getCoords()->getConstPointer();
3509 std::vector<int> conn;
3511 for(int i=0;i<nbOfCells;i++)
3514 getNodeIdsOfCell(i,conn);
3515 pt=std::transform(coo+conn[1]*spaceDim,coo+(conn[1]+1)*spaceDim,coo+conn[0]*spaceDim,pt,std::minus<double>());
3517 ret->setArray(array);
3519 ret->synchronizeTimeWithSupport();
3524 * Creates a 2D mesh by cutting \a this 3D mesh with a plane. In addition to the mesh,
3525 * returns a new DataArrayInt, of length equal to the number of 2D cells in the result
3526 * mesh, holding, for each cell in the result mesh, an id of a 3D cell it comes
3527 * from. If a result face is shared by two 3D cells, then the face in included twice in
3529 * \param [in] origin - 3 components of a point defining location of the plane.
3530 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3531 * must be greater than 1e-6.
3532 * \param [in] eps - half-thickness of the plane.
3533 * \param [out] cellIds - a new instance of DataArrayInt holding ids of 3D cells
3534 * producing correspondent 2D cells. The caller is to delete this array
3535 * using decrRef() as it is no more needed.
3536 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This mesh does
3537 * not share the node coordinates array with \a this mesh. The caller is to
3538 * delete this mesh using decrRef() as it is no more needed.
3539 * \throw If the coordinates array is not set.
3540 * \throw If the nodal connectivity of cells is not defined.
3541 * \throw If \a this->getMeshDimension() != 3 or \a this->getSpaceDimension() != 3.
3542 * \throw If magnitude of \a vec is less than 1e-6.
3543 * \throw If the plane does not intersect any 3D cell of \a this mesh.
3544 * \throw If \a this includes quadratic cells.
3546 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3D(const double *origin, const double *vec, double eps, DataArrayInt *&cellIds) const
3548 checkFullyDefined();
3549 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3550 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3551 MCAuto<DataArrayInt> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3552 if(candidates->empty())
3553 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane considering bounding boxes !");
3554 std::vector<int> nodes;
3555 DataArrayInt *cellIds1D=0;
3556 MCAuto<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3557 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3558 MCAuto<DataArrayInt> desc1=DataArrayInt::New(),desc2=DataArrayInt::New();
3559 MCAuto<DataArrayInt> descIndx1=DataArrayInt::New(),descIndx2=DataArrayInt::New();
3560 MCAuto<DataArrayInt> revDesc1=DataArrayInt::New(),revDesc2=DataArrayInt::New();
3561 MCAuto<DataArrayInt> revDescIndx1=DataArrayInt::New(),revDescIndx2=DataArrayInt::New();
3562 MCAuto<MEDCouplingUMesh> mDesc2=subMesh->buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2);//meshDim==2 spaceDim==3
3563 revDesc2=0; revDescIndx2=0;
3564 MCAuto<MEDCouplingUMesh> mDesc1=mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3565 revDesc1=0; revDescIndx1=0;
3566 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3567 MCAuto<DataArrayInt> cellIds1DTmp(cellIds1D);
3569 std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3570 for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3572 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3573 std::vector< std::pair<int,int> > cut3DSurf(mDesc2->getNumberOfCells());
3574 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->getConstPointer(),mDesc2->getNodalConnectivityIndex()->getConstPointer(),
3575 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3576 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3577 MCAuto<DataArrayInt> conn(DataArrayInt::New()),connI(DataArrayInt::New()),cellIds2(DataArrayInt::New());
3578 connI->pushBackSilent(0); conn->alloc(0,1); cellIds2->alloc(0,1);
3579 subMesh->assemblyForSplitFrom3DSurf(cut3DSurf,desc2->getConstPointer(),descIndx2->getConstPointer(),conn,connI,cellIds2);
3580 if(cellIds2->empty())
3581 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3582 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3D",2);
3583 ret->setCoords(mDesc1->getCoords());
3584 ret->setConnectivity(conn,connI,true);
3585 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3590 * Creates an 1D mesh by cutting \a this 2D mesh in 3D space with a plane. In
3591 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
3592 from. If a result segment is shared by two 2D cells, then the segment in included twice in
3594 * \param [in] origin - 3 components of a point defining location of the plane.
3595 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3596 * must be greater than 1e-6.
3597 * \param [in] eps - half-thickness of the plane.
3598 * \param [out] cellIds - a new instance of DataArrayInt holding ids of faces
3599 * producing correspondent segments. The caller is to delete this array
3600 * using decrRef() as it is no more needed.
3601 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This is an 1D
3602 * mesh in 3D space. This mesh does not share the node coordinates array with
3603 * \a this mesh. The caller is to delete this mesh using decrRef() as it is
3605 * \throw If the coordinates array is not set.
3606 * \throw If the nodal connectivity of cells is not defined.
3607 * \throw If \a this->getMeshDimension() != 2 or \a this->getSpaceDimension() != 3.
3608 * \throw If magnitude of \a vec is less than 1e-6.
3609 * \throw If the plane does not intersect any 2D cell of \a this mesh.
3610 * \throw If \a this includes quadratic cells.
3612 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3DSurf(const double *origin, const double *vec, double eps, DataArrayInt *&cellIds) const
3614 checkFullyDefined();
3615 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
3616 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf works on umeshes with meshdim equal to 2 and spaceDim equal to 3 !");
3617 MCAuto<DataArrayInt> candidates(getCellIdsCrossingPlane(origin,vec,eps));
3618 if(candidates->empty())
3619 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3D surf cells in this intercepts the specified plane considering bounding boxes !");
3620 std::vector<int> nodes;
3621 DataArrayInt *cellIds1D(0);
3622 MCAuto<MEDCouplingUMesh> subMesh(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3623 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3624 MCAuto<DataArrayInt> desc1(DataArrayInt::New()),descIndx1(DataArrayInt::New()),revDesc1(DataArrayInt::New()),revDescIndx1(DataArrayInt::New());
3625 MCAuto<MEDCouplingUMesh> mDesc1(subMesh->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3626 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3627 MCAuto<DataArrayInt> cellIds1DTmp(cellIds1D);
3629 std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3630 for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3632 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3633 int ncellsSub=subMesh->getNumberOfCells();
3634 std::vector< std::pair<int,int> > cut3DSurf(ncellsSub);
3635 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,subMesh->getNodalConnectivity()->getConstPointer(),subMesh->getNodalConnectivityIndex()->getConstPointer(),
3636 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3637 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3638 MCAuto<DataArrayInt> conn(DataArrayInt::New()),connI(DataArrayInt::New()),cellIds2(DataArrayInt::New()); connI->pushBackSilent(0);
3640 const int *nodal=subMesh->getNodalConnectivity()->getConstPointer();
3641 const int *nodalI=subMesh->getNodalConnectivityIndex()->getConstPointer();
3642 for(int i=0;i<ncellsSub;i++)
3644 if(cut3DSurf[i].first!=-1 && cut3DSurf[i].second!=-1)
3646 if(cut3DSurf[i].first!=-2)
3648 conn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG2); conn->pushBackSilent(cut3DSurf[i].first); conn->pushBackSilent(cut3DSurf[i].second);
3649 connI->pushBackSilent(conn->getNumberOfTuples());
3650 cellIds2->pushBackSilent(i);
3654 int cellId3DSurf=cut3DSurf[i].second;
3655 int offset=nodalI[cellId3DSurf]+1;
3656 int nbOfEdges=nodalI[cellId3DSurf+1]-offset;
3657 for(int j=0;j<nbOfEdges;j++)
3659 conn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG2); conn->pushBackSilent(nodal[offset+j]); conn->pushBackSilent(nodal[offset+(j+1)%nbOfEdges]);
3660 connI->pushBackSilent(conn->getNumberOfTuples());
3661 cellIds2->pushBackSilent(cellId3DSurf);
3666 if(cellIds2->empty())
3667 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3DSurf cells in this intercepts the specified plane !");
3668 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3DSurf",1);
3669 ret->setCoords(mDesc1->getCoords());
3670 ret->setConnectivity(conn,connI,true);
3671 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3675 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::clipSingle3DCellByPlane(const double origin[3], const double vec[3], double eps) const
3677 checkFullyDefined();
3678 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3679 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3680 if(getNumberOfCells()!=1)
3681 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works only on mesh containing exactly one cell !");
3683 std::vector<int> nodes;
3684 findNodesOnPlane(origin,vec,eps,nodes);
3685 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());
3686 MCAuto<MEDCouplingUMesh> mDesc2(buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2));//meshDim==2 spaceDim==3
3687 revDesc2=0; revDescIndx2=0;
3688 MCAuto<MEDCouplingUMesh> mDesc1(mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3689 revDesc1=0; revDescIndx1=0;
3690 DataArrayInt *cellIds1D(0);
3691 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3692 MCAuto<DataArrayInt> cellIds1DTmp(cellIds1D);
3693 std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3694 for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3698 int oldNbNodes(mDesc1->getNumberOfNodes());
3699 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3700 sameNbNodes=(mDesc1->getNumberOfNodes()==oldNbNodes);
3702 std::vector< std::pair<int,int> > cut3DSurf(mDesc2->getNumberOfCells());
3703 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->begin(),mDesc2->getNodalConnectivityIndex()->begin(),
3704 mDesc1->getNodalConnectivity()->begin(),mDesc1->getNodalConnectivityIndex()->begin(),
3705 desc1->begin(),descIndx1->begin(),cut3DSurf);
3706 MCAuto<DataArrayInt> conn(DataArrayInt::New()),connI(DataArrayInt::New());
3707 connI->pushBackSilent(0); conn->alloc(0,1);
3709 MCAuto<DataArrayInt> cellIds2(DataArrayInt::New()); cellIds2->alloc(0,1);
3710 assemblyForSplitFrom3DSurf(cut3DSurf,desc2->begin(),descIndx2->begin(),conn,connI,cellIds2);
3711 if(cellIds2->empty())
3712 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3714 std::vector<std::vector<int> > res;
3715 buildSubCellsFromCut(cut3DSurf,desc2->begin(),descIndx2->begin(),mDesc1->getCoords()->begin(),eps,res);
3716 std::size_t sz(res.size());
3717 if(res.size()==mDesc1->getNumberOfCells() && sameNbNodes)
3718 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane : cell is not clipped !");
3719 for(std::size_t i=0;i<sz;i++)
3721 conn->pushBackSilent((int)INTERP_KERNEL::NORM_POLYGON);
3722 conn->insertAtTheEnd(res[i].begin(),res[i].end());
3723 connI->pushBackSilent(conn->getNumberOfTuples());
3725 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
3726 ret->setCoords(mDesc1->getCoords());
3727 ret->setConnectivity(conn,connI,true);
3728 int nbCellsRet(ret->getNumberOfCells());
3730 MCAuto<DataArrayDouble> vec2(DataArrayDouble::New()); vec2->alloc(1,3); std::copy(vec,vec+3,vec2->getPointer());
3731 MCAuto<MEDCouplingFieldDouble> ortho(ret->buildOrthogonalField());
3732 MCAuto<DataArrayDouble> ortho2(ortho->getArray()->selectByTupleIdSafeSlice(0,1,1));
3733 MCAuto<DataArrayDouble> dott(DataArrayDouble::Dot(ortho2,vec2));
3734 MCAuto<DataArrayDouble> ccm(ret->computeCellCenterOfMass());
3735 MCAuto<DataArrayDouble> occm;
3737 MCAuto<DataArrayDouble> pt(DataArrayDouble::New()); pt->alloc(1,3); std::copy(origin,origin+3,pt->getPointer());
3738 occm=DataArrayDouble::Substract(ccm,pt);
3740 vec2=DataArrayDouble::New(); vec2->alloc(nbCellsRet,3);
3741 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);
3742 MCAuto<DataArrayDouble> dott2(DataArrayDouble::Dot(occm,vec2));
3744 const int *cPtr(ret->getNodalConnectivity()->begin()),*ciPtr(ret->getNodalConnectivityIndex()->begin());
3745 MCAuto<MEDCouplingUMesh> ret2(MEDCouplingUMesh::New("Clip3D",3));
3746 ret2->setCoords(mDesc1->getCoords());
3747 MCAuto<DataArrayInt> conn2(DataArrayInt::New()),conn2I(DataArrayInt::New());
3748 conn2I->pushBackSilent(0); conn2->alloc(0,1);
3749 std::vector<int> cell0(1,(int)INTERP_KERNEL::NORM_POLYHED);
3750 std::vector<int> cell1(1,(int)INTERP_KERNEL::NORM_POLYHED);
3751 if(dott->getIJ(0,0)>0)
3753 cell0.insert(cell0.end(),cPtr+1,cPtr+ciPtr[1]);
3754 std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell1,cell1.end()));
3758 cell1.insert(cell1.end(),cPtr+1,cPtr+ciPtr[1]);
3759 std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell0,cell0.end()));
3761 for(int i=1;i<nbCellsRet;i++)
3763 if(dott2->getIJ(i,0)<0)
3765 if(ciPtr[i+1]-ciPtr[i]>=4)
3767 cell0.push_back(-1);
3768 cell0.insert(cell0.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
3773 if(ciPtr[i+1]-ciPtr[i]>=4)
3775 cell1.push_back(-1);
3776 cell1.insert(cell1.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
3780 conn2->insertAtTheEnd(cell0.begin(),cell0.end());
3781 conn2I->pushBackSilent(conn2->getNumberOfTuples());
3782 conn2->insertAtTheEnd(cell1.begin(),cell1.end());
3783 conn2I->pushBackSilent(conn2->getNumberOfTuples());
3784 ret2->setConnectivity(conn2,conn2I,true);
3785 ret2->checkConsistencyLight();
3786 ret2->orientCorrectlyPolyhedrons();
3791 * Finds cells whose bounding boxes intersect a given plane.
3792 * \param [in] origin - 3 components of a point defining location of the plane.
3793 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3794 * must be greater than 1e-6.
3795 * \param [in] eps - half-thickness of the plane.
3796 * \return DataArrayInt * - a new instance of DataArrayInt holding ids of the found
3797 * cells. The caller is to delete this array using decrRef() as it is no more
3799 * \throw If the coordinates array is not set.
3800 * \throw If the nodal connectivity of cells is not defined.
3801 * \throw If \a this->getSpaceDimension() != 3.
3802 * \throw If magnitude of \a vec is less than 1e-6.
3803 * \sa buildSlice3D()
3805 DataArrayInt *MEDCouplingUMesh::getCellIdsCrossingPlane(const double *origin, const double *vec, double eps) const
3807 checkFullyDefined();
3808 if(getSpaceDimension()!=3)
3809 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with spaceDim equal to 3 !");
3810 double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
3812 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellIdsCrossingPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
3814 vec2[0]=vec[1]; vec2[1]=-vec[0]; vec2[2]=0.;//vec2 is the result of cross product of vec with (0,0,1)
3815 double angle=acos(vec[2]/normm);
3816 MCAuto<DataArrayInt> cellIds;
3820 MCAuto<DataArrayDouble> coo=_coords->deepCopy();
3821 double normm2(sqrt(vec2[0]*vec2[0]+vec2[1]*vec2[1]+vec2[2]*vec2[2]));
3822 if(normm2/normm>1e-6)
3823 DataArrayDouble::Rotate3DAlg(origin,vec2,angle,coo->getNumberOfTuples(),coo->getPointer(),coo->getPointer());
3824 MCAuto<MEDCouplingUMesh> mw=clone(false);//false -> shallow copy
3826 mw->getBoundingBox(bbox);
3827 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3828 cellIds=mw->getCellsInBoundingBox(bbox,eps);
3832 getBoundingBox(bbox);
3833 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3834 cellIds=getCellsInBoundingBox(bbox,eps);
3836 return cellIds.retn();
3840 * This method checks that \a this is a contiguous mesh. The user is expected to call this method on a mesh with meshdim==1.
3841 * If not an exception will thrown. If this is an empty mesh with no cell an exception will be thrown too.
3842 * No consideration of coordinate is done by this method.
3843 * 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)
3844 * If not false is returned. In case that false is returned a call to MEDCoupling::MEDCouplingUMesh::mergeNodes could be usefull.
3846 bool MEDCouplingUMesh::isContiguous1D() const
3848 if(getMeshDimension()!=1)
3849 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense only for 1D mesh !");
3850 int nbCells=getNumberOfCells();
3852 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense for non empty mesh !");
3853 const int *connI(_nodal_connec_index->begin()),*conn(_nodal_connec->begin());
3854 int ref=conn[connI[0]+2];
3855 for(int i=1;i<nbCells;i++)
3857 if(conn[connI[i]+1]!=ref)
3859 ref=conn[connI[i]+2];
3865 * This method is only callable on mesh with meshdim == 1 containing only SEG2 and spaceDim==3.
3866 * This method projects this on the 3D line defined by (pt,v). This methods first checks that all SEG2 are along v vector.
3867 * \param pt reference point of the line
3868 * \param v normalized director vector of the line
3869 * \param eps max precision before throwing an exception
3870 * \param res output of size this->getNumberOfCells
3872 void MEDCouplingUMesh::project1D(const double *pt, const double *v, double eps, double *res) const
3874 if(getMeshDimension()!=1)
3875 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for project1D !");
3876 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3877 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for project1D !");
3878 if(getSpaceDimension()!=3)
3879 throw INTERP_KERNEL::Exception("Expected a umesh with spaceDim==3 for project1D !");
3880 MCAuto<MEDCouplingFieldDouble> f=buildDirectionVectorField();
3881 const double *fPtr=f->getArray()->getConstPointer();
3883 for(std::size_t i=0;i<getNumberOfCells();i++)
3885 const double *tmp1=fPtr+3*i;
3886 tmp[0]=tmp1[1]*v[2]-tmp1[2]*v[1];
3887 tmp[1]=tmp1[2]*v[0]-tmp1[0]*v[2];
3888 tmp[2]=tmp1[0]*v[1]-tmp1[1]*v[0];
3889 double n1=INTERP_KERNEL::norm<3>(tmp);
3890 n1/=INTERP_KERNEL::norm<3>(tmp1);
3892 throw INTERP_KERNEL::Exception("UMesh::Projection 1D failed !");
3894 const double *coo=getCoords()->getConstPointer();
3895 for(int i=0;i<getNumberOfNodes();i++)
3897 std::transform(coo+i*3,coo+i*3+3,pt,tmp,std::minus<double>());
3898 std::transform(tmp,tmp+3,v,tmp,std::multiplies<double>());
3899 res[i]=std::accumulate(tmp,tmp+3,0.);
3904 * 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.
3905 * \a this is expected to be a mesh so that its space dimension is equal to its
3906 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
3907 * 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).
3909 * 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
3910 * 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).
3911 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
3913 * So this method is more accurate (so, more costly) than simply searching for the closest point in \a this.
3914 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
3916 * \param [in] ptBg the start pointer (included) of the coordinates of the point
3917 * \param [in] ptEnd the end pointer (not included) of the coordinates of the point
3918 * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
3919 * \return the positive value of the distance.
3920 * \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
3922 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoints
3924 double MEDCouplingUMesh::distanceToPoint(const double *ptBg, const double *ptEnd, int& cellId) const
3926 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
3927 if(meshDim!=spaceDim-1)
3928 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint works only for spaceDim=meshDim+1 !");
3929 if(meshDim!=2 && meshDim!=1)
3930 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint : only mesh dimension 2 and 1 are implemented !");
3931 checkFullyDefined();
3932 if((int)std::distance(ptBg,ptEnd)!=spaceDim)
3933 { 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()); }
3934 DataArrayInt *ret1=0;
3935 MCAuto<DataArrayDouble> pts=DataArrayDouble::New(); pts->useArray(ptBg,false,C_DEALLOC,1,spaceDim);
3936 MCAuto<DataArrayDouble> ret0=distanceToPoints(pts,ret1);
3937 MCAuto<DataArrayInt> ret1Safe(ret1);
3938 cellId=*ret1Safe->begin();
3939 return *ret0->begin();
3943 * This method computes the distance from each point of points serie \a pts (stored in a DataArrayDouble in which each tuple represents a point)
3944 * to \a this and the first \a cellId in \a this corresponding to the returned distance.
3945 * 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
3946 * 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).
3947 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
3949 * \a this is expected to be a mesh so that its space dimension is equal to its
3950 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
3951 * 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).
3953 * So this method is more accurate (so, more costly) than simply searching for each point in \a pts the closest point in \a this.
3954 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
3956 * \param [in] pts the list of points in which each tuple represents a point
3957 * \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.
3958 * \return a newly allocated object to be dealed by the caller that tells for each point in \a pts the distance to \a this.
3959 * \throw if number of components of \a pts is not equal to the space dimension.
3960 * \throw if mesh dimension of \a this is not equal to space dimension - 1.
3961 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoint
3963 DataArrayDouble *MEDCouplingUMesh::distanceToPoints(const DataArrayDouble *pts, DataArrayInt *& cellIds) const
3966 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : input points pointer is NULL !");
3967 pts->checkAllocated();
3968 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
3969 if(meshDim!=spaceDim-1)
3970 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints works only for spaceDim=meshDim+1 !");
3971 if(meshDim!=2 && meshDim!=1)
3972 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only mesh dimension 2 and 1 are implemented !");
3973 if((int)pts->getNumberOfComponents()!=spaceDim)
3975 std::ostringstream oss; oss << "MEDCouplingUMesh::distanceToPoints : input pts DataArrayDouble has " << pts->getNumberOfComponents() << " components whereas it should be equal to " << spaceDim << " (mesh spaceDimension) !";
3976 throw INTERP_KERNEL::Exception(oss.str());
3978 checkFullyDefined();
3979 int nbCells=getNumberOfCells();
3981 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : no cells in this !");
3982 int nbOfPts=pts->getNumberOfTuples();
3983 MCAuto<DataArrayDouble> ret0=DataArrayDouble::New(); ret0->alloc(nbOfPts,1);
3984 MCAuto<DataArrayInt> ret1=DataArrayInt::New(); ret1->alloc(nbOfPts,1);
3985 const int *nc=_nodal_connec->begin(),*ncI=_nodal_connec_index->begin(); const double *coords=_coords->begin();
3986 double *ret0Ptr=ret0->getPointer(); int *ret1Ptr=ret1->getPointer(); const double *ptsPtr=pts->begin();
3987 MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree());
3988 const double *bbox(bboxArr->begin());
3993 BBTreeDst<3> myTree(bbox,0,0,nbCells);
3994 for(int i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=3)
3996 double x=std::numeric_limits<double>::max();
3997 std::vector<int> elems;
3998 myTree.getMinDistanceOfMax(ptsPtr,x);
3999 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4000 DistanceToPoint3DSurfAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4006 BBTreeDst<2> myTree(bbox,0,0,nbCells);
4007 for(int i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=2)
4009 double x=std::numeric_limits<double>::max();
4010 std::vector<int> elems;
4011 myTree.getMinDistanceOfMax(ptsPtr,x);
4012 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4013 DistanceToPoint2DCurveAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4018 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only spacedim 2 and 3 supported !");
4020 cellIds=ret1.retn();
4029 * Finds cells in contact with a ball (i.e. a point with precision).
4030 * 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.
4031 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4033 * \warning This method is suitable if the caller intends to evaluate only one
4034 * point, for more points getCellsContainingPoints() is recommended as it is
4036 * \param [in] pos - array of coordinates of the ball central point.
4037 * \param [in] eps - ball radius.
4038 * \return int - a smallest id of cells being in contact with the ball, -1 in case
4039 * if there are no such cells.
4040 * \throw If the coordinates array is not set.
4041 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4043 int MEDCouplingUMesh::getCellContainingPoint(const double *pos, double eps) const
4045 std::vector<int> elts;
4046 getCellsContainingPoint(pos,eps,elts);
4049 return elts.front();
4053 * Finds cells in contact with a ball (i.e. a point with precision).
4054 * 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.
4055 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4056 * \warning This method is suitable if the caller intends to evaluate only one
4057 * point, for more points getCellsContainingPoints() is recommended as it is
4059 * \param [in] pos - array of coordinates of the ball central point.
4060 * \param [in] eps - ball radius.
4061 * \param [out] elts - vector returning ids of the found cells. It is cleared
4062 * before inserting ids.
4063 * \throw If the coordinates array is not set.
4064 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4066 * \if ENABLE_EXAMPLES
4067 * \ref cpp_mcumesh_getCellsContainingPoint "Here is a C++ example".<br>
4068 * \ref py_mcumesh_getCellsContainingPoint "Here is a Python example".
4071 void MEDCouplingUMesh::getCellsContainingPoint(const double *pos, double eps, std::vector<int>& elts) const
4073 MCAuto<DataArrayInt> eltsUg,eltsIndexUg;
4074 getCellsContainingPoints(pos,1,eps,eltsUg,eltsIndexUg);
4075 elts.clear(); elts.insert(elts.end(),eltsUg->begin(),eltsUg->end());
4079 * Finds cells in contact with several balls (i.e. points with precision).
4080 * This method is an extension of getCellContainingPoint() and
4081 * getCellsContainingPoint() for the case of multiple points.
4082 * 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.
4083 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4084 * \param [in] pos - an array of coordinates of points in full interlace mode :
4085 * X0,Y0,Z0,X1,Y1,Z1,... Size of the array must be \a
4086 * this->getSpaceDimension() * \a nbOfPoints
4087 * \param [in] nbOfPoints - number of points to locate within \a this mesh.
4088 * \param [in] eps - radius of balls (i.e. the precision).
4089 * \param [out] elts - vector returning ids of found cells.
4090 * \param [out] eltsIndex - an array, of length \a nbOfPoints + 1,
4091 * dividing cell ids in \a elts into groups each referring to one
4092 * point. Its every element (except the last one) is an index pointing to the
4093 * first id of a group of cells. For example cells in contact with the *i*-th
4094 * point are described by following range of indices:
4095 * [ \a eltsIndex[ *i* ], \a eltsIndex[ *i*+1 ] ) and the cell ids are
4096 * \a elts[ \a eltsIndex[ *i* ]], \a elts[ \a eltsIndex[ *i* ] + 1 ], ...
4097 * Number of cells in contact with the *i*-th point is
4098 * \a eltsIndex[ *i*+1 ] - \a eltsIndex[ *i* ].
4099 * \throw If the coordinates array is not set.
4100 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4102 * \if ENABLE_EXAMPLES
4103 * \ref cpp_mcumesh_getCellsContainingPoints "Here is a C++ example".<br>
4104 * \ref py_mcumesh_getCellsContainingPoints "Here is a Python example".
4107 void MEDCouplingUMesh::getCellsContainingPoints(const double *pos, int nbOfPoints, double eps,
4108 MCAuto<DataArrayInt>& elts, MCAuto<DataArrayInt>& eltsIndex) const
4110 int spaceDim=getSpaceDimension();
4111 int mDim=getMeshDimension();
4116 const double *coords=_coords->getConstPointer();
4117 getCellsContainingPointsAlg<3>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4124 throw INTERP_KERNEL::Exception("For spaceDim==3 only meshDim==3 implemented for getelementscontainingpoints !");
4126 else if(spaceDim==2)
4130 const double *coords=_coords->getConstPointer();
4131 getCellsContainingPointsAlg<2>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4134 throw INTERP_KERNEL::Exception("For spaceDim==2 only meshDim==2 implemented for getelementscontainingpoints !");
4136 else if(spaceDim==1)
4140 const double *coords=_coords->getConstPointer();
4141 getCellsContainingPointsAlg<1>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4144 throw INTERP_KERNEL::Exception("For spaceDim==1 only meshDim==1 implemented for getelementscontainingpoints !");
4147 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPoints : not managed for mdim not in [1,2,3] !");
4151 * Finds butterfly cells in \a this mesh. A 2D cell is considered to be butterfly if at
4152 * least two its edges intersect each other anywhere except their extremities. An
4153 * INTERP_KERNEL::NORM_NORI3 cell can \b not be butterfly.
4154 * \param [in,out] cells - a vector returning ids of the found cells. It is not
4155 * cleared before filling in.
4156 * \param [in] eps - precision.
4157 * \throw If \a this->getMeshDimension() != 2.
4158 * \throw If \a this->getSpaceDimension() != 2 && \a this->getSpaceDimension() != 3.
4160 void MEDCouplingUMesh::checkButterflyCells(std::vector<int>& cells, double eps) const
4162 const char msg[]="Butterfly detection work only for 2D cells with spaceDim==2 or 3!";
4163 if(getMeshDimension()!=2)
4164 throw INTERP_KERNEL::Exception(msg);
4165 int spaceDim=getSpaceDimension();
4166 if(spaceDim!=2 && spaceDim!=3)
4167 throw INTERP_KERNEL::Exception(msg);
4168 const int *conn=_nodal_connec->getConstPointer();
4169 const int *connI=_nodal_connec_index->getConstPointer();
4170 int nbOfCells=getNumberOfCells();
4171 std::vector<double> cell2DinS2;
4172 for(int i=0;i<nbOfCells;i++)
4174 int offset=connI[i];
4175 int nbOfNodesForCell=connI[i+1]-offset-1;
4176 if(nbOfNodesForCell<=3)
4178 bool isQuad=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[offset]).isQuadratic();
4179 project2DCellOnXY(conn+offset+1,conn+connI[i+1],cell2DinS2);
4180 if(isButterfly2DCell(cell2DinS2,isQuad,eps))
4187 * This method is typically requested to unbutterfly 2D linear cells in \b this.
4189 * 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.
4190 * 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.
4192 * For each 2D linear cell in \b this, this method builds the convex envelop (or the convex hull) of the current cell.
4193 * This convex envelop is computed using Jarvis march algorithm.
4194 * The coordinates and the number of cells of \b this remain unchanged on invocation of this method.
4195 * 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)
4196 * 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.
4198 * \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.
4199 * \sa MEDCouplingUMesh::colinearize2D
4201 DataArrayInt *MEDCouplingUMesh::convexEnvelop2D()
4203 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
4204 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convexEnvelop2D works only for meshDim=2 and spaceDim=2 !");
4205 checkFullyDefined();
4206 const double *coords=getCoords()->getConstPointer();
4207 int nbOfCells=getNumberOfCells();
4208 MCAuto<DataArrayInt> nodalConnecIndexOut=DataArrayInt::New();
4209 nodalConnecIndexOut->alloc(nbOfCells+1,1);
4210 MCAuto<DataArrayInt> nodalConnecOut(DataArrayInt::New());
4211 int *workIndexOut=nodalConnecIndexOut->getPointer();
4213 const int *nodalConnecIn=_nodal_connec->getConstPointer();
4214 const int *nodalConnecIndexIn=_nodal_connec_index->getConstPointer();
4215 std::set<INTERP_KERNEL::NormalizedCellType> types;
4216 MCAuto<DataArrayInt> isChanged(DataArrayInt::New());
4217 isChanged->alloc(0,1);
4218 for(int i=0;i<nbOfCells;i++,workIndexOut++)
4220 int pos=nodalConnecOut->getNumberOfTuples();
4221 if(BuildConvexEnvelopOf2DCellJarvis(coords,nodalConnecIn+nodalConnecIndexIn[i],nodalConnecIn+nodalConnecIndexIn[i+1],nodalConnecOut))
4222 isChanged->pushBackSilent(i);
4223 types.insert((INTERP_KERNEL::NormalizedCellType)nodalConnecOut->getIJ(pos,0));
4224 workIndexOut[1]=nodalConnecOut->getNumberOfTuples();
4226 if(isChanged->empty())
4228 setConnectivity(nodalConnecOut,nodalConnecIndexOut,false);
4230 return isChanged.retn();
4234 * This method is \b NOT const because it can modify \a this.
4235 * \a this is expected to be an unstructured mesh with meshDim==2 and spaceDim==3. If not an exception will be thrown.
4236 * \param mesh1D is an unstructured mesh with MeshDim==1 and spaceDim==3. If not an exception will be thrown.
4237 * \param policy specifies the type of extrusion chosen:
4238 * - \b 0 for translation only (most simple): the cells of the 1D mesh represent the vectors along which the 2D mesh
4239 * will be repeated to build each level
4240 * - \b 1 for translation and rotation: the translation is done as above. For each level, an arc of circle is fitted on
4241 * 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
4242 * 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
4244 * \return an unstructured mesh with meshDim==3 and spaceDim==3. The returned mesh has the same coords than \a this.
4246 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMesh(const MEDCouplingUMesh *mesh1D, int policy)
4248 checkFullyDefined();
4249 mesh1D->checkFullyDefined();
4250 if(!mesh1D->isContiguous1D())
4251 throw INTERP_KERNEL::Exception("buildExtrudedMesh : 1D mesh passed in parameter is not contiguous !");
4252 if(getSpaceDimension()!=mesh1D->getSpaceDimension())
4253 throw INTERP_KERNEL::Exception("Invalid call to buildExtrudedMesh this and mesh1D must have same space dimension !");
4254 if((getMeshDimension()!=2 || getSpaceDimension()!=3) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
4255 throw INTERP_KERNEL::Exception("Invalid 'this' for buildExtrudedMesh method : must be (meshDim==2 and spaceDim==3) or (meshDim==1 and spaceDim==2) !");
4256 if(mesh1D->getMeshDimension()!=1)
4257 throw INTERP_KERNEL::Exception("Invalid 'mesh1D' for buildExtrudedMesh method : must be meshDim==1 !");
4259 if(isPresenceOfQuadratic())
4261 if(mesh1D->isFullyQuadratic())
4264 throw INTERP_KERNEL::Exception("Invalid 2D mesh and 1D mesh because 2D mesh has quadratic cells and 1D is not fully quadratic !");
4266 int oldNbOfNodes(getNumberOfNodes());
4267 MCAuto<DataArrayDouble> newCoords;
4272 newCoords=fillExtCoordsUsingTranslation(mesh1D,isQuad);
4277 newCoords=fillExtCoordsUsingTranslAndAutoRotation(mesh1D,isQuad);
4281 throw INTERP_KERNEL::Exception("Not implemented extrusion policy : must be in (0) !");
4283 setCoords(newCoords);
4284 MCAuto<MEDCouplingUMesh> ret(buildExtrudedMeshFromThisLowLev(oldNbOfNodes,isQuad));
4291 * Checks if \a this mesh is constituted by only quadratic cells.
4292 * \return bool - \c true if there are only quadratic cells in \a this mesh.
4293 * \throw If the coordinates array is not set.
4294 * \throw If the nodal connectivity of cells is not defined.
4296 bool MEDCouplingUMesh::isFullyQuadratic() const
4298 checkFullyDefined();
4300 int nbOfCells=getNumberOfCells();
4301 for(int i=0;i<nbOfCells && ret;i++)
4303 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4304 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4305 ret=cm.isQuadratic();
4311 * Checks if \a this mesh includes any quadratic cell.
4312 * \return bool - \c true if there is at least one quadratic cells in \a this mesh.
4313 * \throw If the coordinates array is not set.
4314 * \throw If the nodal connectivity of cells is not defined.
4316 bool MEDCouplingUMesh::isPresenceOfQuadratic() const
4318 checkFullyDefined();
4320 int nbOfCells=getNumberOfCells();
4321 for(int i=0;i<nbOfCells && !ret;i++)
4323 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4324 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4325 ret=cm.isQuadratic();
4331 * Converts all quadratic cells to linear ones. If there are no quadratic cells in \a
4332 * this mesh, it remains unchanged.
4333 * \throw If the coordinates array is not set.
4334 * \throw If the nodal connectivity of cells is not defined.
4336 void MEDCouplingUMesh::convertQuadraticCellsToLinear()
4338 checkFullyDefined();
4339 int nbOfCells(getNumberOfCells());
4341 const int *iciptr=_nodal_connec_index->begin();
4342 for(int i=0;i<nbOfCells;i++)
4344 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4345 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4346 if(cm.isQuadratic())
4348 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4349 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4350 if(!cml.isDynamic())
4351 delta+=cm.getNumberOfNodes()-cml.getNumberOfNodes();
4353 delta+=(iciptr[i+1]-iciptr[i]-1)/2;
4358 MCAuto<DataArrayInt> newConn(DataArrayInt::New()),newConnI(DataArrayInt::New());
4359 const int *icptr(_nodal_connec->begin());
4360 newConn->alloc(getNodalConnectivityArrayLen()-delta,1);
4361 newConnI->alloc(nbOfCells+1,1);
4362 int *ocptr(newConn->getPointer()),*ociptr(newConnI->getPointer());
4365 for(int i=0;i<nbOfCells;i++,ociptr++)
4367 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)icptr[iciptr[i]];
4368 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4369 if(!cm.isQuadratic())
4371 _types.insert(type);
4372 ocptr=std::copy(icptr+iciptr[i],icptr+iciptr[i+1],ocptr);
4373 ociptr[1]=ociptr[0]+iciptr[i+1]-iciptr[i];
4377 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4378 _types.insert(typel);
4379 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4380 int newNbOfNodes=cml.getNumberOfNodes();
4382 newNbOfNodes=(iciptr[i+1]-iciptr[i]-1)/2;
4383 *ocptr++=(int)typel;
4384 ocptr=std::copy(icptr+iciptr[i]+1,icptr+iciptr[i]+newNbOfNodes+1,ocptr);
4385 ociptr[1]=ociptr[0]+newNbOfNodes+1;
4388 setConnectivity(newConn,newConnI,false);
4392 * This method converts all linear cell in \a this to quadratic one.
4393 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, here it is needed to specify the target
4394 * 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)
4395 * 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.
4396 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, the coordinates in \a this can be become bigger. All created nodes will be put at the
4397 * end of the existing coordinates.
4399 * \param [in] conversionType specifies the type of conversion expected. Only 0 (default) and 1 are supported presently. 0 those that creates the 'most' simple
4400 * corresponding quadratic cells. 1 is those creating the 'most' complex.
4401 * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
4403 * \throw if \a this is not fully defined. It throws too if \a conversionType is not in [0,1].
4405 * \sa MEDCouplingUMesh::convertQuadraticCellsToLinear
4407 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic(int conversionType)
4409 DataArrayInt *conn=0,*connI=0;
4410 DataArrayDouble *coords=0;
4411 std::set<INTERP_KERNEL::NormalizedCellType> types;
4412 checkFullyDefined();
4413 MCAuto<DataArrayInt> ret,connSafe,connISafe;
4414 MCAuto<DataArrayDouble> coordsSafe;
4415 int meshDim=getMeshDimension();
4416 switch(conversionType)
4422 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);
4423 connSafe=conn; connISafe=connI; coordsSafe=coords;
4426 ret=convertLinearCellsToQuadratic2D0(conn,connI,coords,types);
4427 connSafe=conn; connISafe=connI; coordsSafe=coords;
4430 ret=convertLinearCellsToQuadratic3D0(conn,connI,coords,types);
4431 connSafe=conn; connISafe=connI; coordsSafe=coords;
4434 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 0 mesh dimensions available are [1,2,3] !");
4442 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);//it is not a bug. In 1D policy 0 and 1 are equals
4443 connSafe=conn; connISafe=connI; coordsSafe=coords;
4446 ret=convertLinearCellsToQuadratic2D1(conn,connI,coords,types);
4447 connSafe=conn; connISafe=connI; coordsSafe=coords;
4450 ret=convertLinearCellsToQuadratic3D1(conn,connI,coords,types);
4451 connSafe=conn; connISafe=connI; coordsSafe=coords;
4454 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 1 mesh dimensions available are [1,2,3] !");
4459 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion type available are 0 (default, the simplest) and 1 (the most complex) !");
4461 setConnectivity(connSafe,connISafe,false);
4463 setCoords(coordsSafe);
4468 * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
4469 * so that the number of cells remains the same. Quadratic faces are converted to
4470 * polygons. This method works only for 2D meshes in
4471 * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
4472 * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
4473 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
4474 * \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
4475 * a polylinized edge constituting the input polygon.
4476 * \throw If the coordinates array is not set.
4477 * \throw If the nodal connectivity of cells is not defined.
4478 * \throw If \a this->getMeshDimension() != 2.
4479 * \throw If \a this->getSpaceDimension() != 2.
4481 void MEDCouplingUMesh::tessellate2D(double eps)
4483 int meshDim(getMeshDimension()),spaceDim(getSpaceDimension());
4485 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : works only with space dimension equal to 2 !");
4489 return tessellate2DCurveInternal(eps);
4491 return tessellate2DInternal(eps);
4493 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : mesh dimension must be in [1,2] !");
4497 * Tessellates \a this 1D mesh in 2D space by dividing not straight quadratic edges.
4498 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
4499 * \param [in] eps - specifies the maximal angle (in radian) between 2 sub-edges of
4500 * a sub-divided edge.
4501 * \throw If the coordinates array is not set.
4502 * \throw If the nodal connectivity of cells is not defined.
4503 * \throw If \a this->getMeshDimension() != 1.
4504 * \throw If \a this->getSpaceDimension() != 2.
4509 * This method only works if \a this has spaceDimension equal to 2 and meshDimension also equal to 2.
4510 * This method allows to modify connectivity of cells in \a this that shares some edges in \a edgeIdsToBeSplit.
4511 * The nodes to be added in those 2D cells are defined by the pair of \a nodeIdsToAdd and \a nodeIdsIndexToAdd.
4512 * Length of \a nodeIdsIndexToAdd is expected to equal to length of \a edgeIdsToBeSplit + 1.
4513 * The node ids in \a nodeIdsToAdd should be valid. Those nodes have to be sorted exactly following exactly the direction of the edge.
4514 * This method can be seen as the opposite method of colinearize2D.
4515 * 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
4516 * to avoid to modify the numbering of existing nodes.
4518 * \param [in] nodeIdsToAdd - the list of node ids to be added (\a nodeIdsIndexToAdd array allows to walk on this array)
4519 * \param [in] nodeIdsIndexToAdd - the entry point of \a nodeIdsToAdd to point to the corresponding nodes to be added.
4520 * \param [in] mesh1Desc - 1st output of buildDescendingConnectivity2 on \a this.
4521 * \param [in] desc - 2nd output of buildDescendingConnectivity2 on \a this.
4522 * \param [in] descI - 3rd output of buildDescendingConnectivity2 on \a this.
4523 * \param [in] revDesc - 4th output of buildDescendingConnectivity2 on \a this.
4524 * \param [in] revDescI - 5th output of buildDescendingConnectivity2 on \a this.
4526 * \sa buildDescendingConnectivity2
4528 void MEDCouplingUMesh::splitSomeEdgesOf2DMesh(const DataArrayInt *nodeIdsToAdd, const DataArrayInt *nodeIdsIndexToAdd, const DataArrayInt *edgeIdsToBeSplit,
4529 const MEDCouplingUMesh *mesh1Desc, const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *revDesc, const DataArrayInt *revDescI)
4531 if(!nodeIdsToAdd || !nodeIdsIndexToAdd || !edgeIdsToBeSplit || !mesh1Desc || !desc || !descI || !revDesc || !revDescI)
4532 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : input pointers must be not NULL !");
4533 nodeIdsToAdd->checkAllocated(); nodeIdsIndexToAdd->checkAllocated(); edgeIdsToBeSplit->checkAllocated(); desc->checkAllocated(); descI->checkAllocated(); revDesc->checkAllocated(); revDescI->checkAllocated();
4534 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
4535 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : this must have spacedim=meshdim=2 !");
4536 if(mesh1Desc->getSpaceDimension()!=2 || mesh1Desc->getMeshDimension()!=1)
4537 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : mesh1Desc must be the explosion of this with spaceDim=2 and meshDim = 1 !");
4538 //DataArrayInt *out0(0),*outi0(0);
4539 //MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
4540 //MCAuto<DataArrayInt> out0s(out0),outi0s(outi0);
4541 //out0s=out0s->buildUnique(); out0s->sort(true);
4547 * Divides every cell of \a this mesh into simplices (triangles in 2D and tetrahedra in 3D).
4548 * In addition, returns an array mapping new cells to old ones. <br>
4549 * This method typically increases the number of cells in \a this mesh
4550 * but the number of nodes remains \b unchanged.
4551 * That's why the 3D splitting policies
4552 * INTERP_KERNEL::GENERAL_24 and INTERP_KERNEL::GENERAL_48 are not available here.
4553 * \param [in] policy - specifies a pattern used for splitting.
4554 * The semantic of \a policy is:
4555 * - 0 - to split QUAD4 by cutting it along 0-2 diagonal (for 2D mesh only).
4556 * - 1 - to split QUAD4 by cutting it along 1-3 diagonal (for 2D mesh only).
4557 * - INTERP_KERNEL::PLANAR_FACE_5 - to split HEXA8 into 5 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4558 * - INTERP_KERNEL::PLANAR_FACE_6 - to split HEXA8 into 6 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4561 * \return DataArrayInt * - a new instance of DataArrayInt holding, for each new cell,
4562 * an id of old cell producing it. The caller is to delete this array using
4563 * decrRef() as it is no more needed.
4565 * \throw If \a policy is 0 or 1 and \a this->getMeshDimension() != 2.
4566 * \throw If \a policy is INTERP_KERNEL::PLANAR_FACE_5 or INTERP_KERNEL::PLANAR_FACE_6
4567 * and \a this->getMeshDimension() != 3.
4568 * \throw If \a policy is not one of the four discussed above.
4569 * \throw If the nodal connectivity of cells is not defined.
4570 * \sa MEDCouplingUMesh::tetrahedrize, MEDCoupling1SGTUMesh::sortHexa8EachOther
4572 DataArrayInt *MEDCouplingUMesh::simplexize(int policy)
4577 return simplexizePol0();
4579 return simplexizePol1();
4580 case (int) INTERP_KERNEL::PLANAR_FACE_5:
4581 return simplexizePlanarFace5();
4582 case (int) INTERP_KERNEL::PLANAR_FACE_6:
4583 return simplexizePlanarFace6();
4585 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)");
4590 * Checks if \a this mesh is constituted by simplex cells only. Simplex cells are:
4591 * - 1D: INTERP_KERNEL::NORM_SEG2
4592 * - 2D: INTERP_KERNEL::NORM_TRI3
4593 * - 3D: INTERP_KERNEL::NORM_TETRA4.
4595 * This method is useful for users that need to use P1 field services as
4596 * MEDCouplingFieldDouble::getValueOn(), MEDCouplingField::buildMeasureField() etc.
4597 * All these methods need mesh support containing only simplex cells.
4598 * \return bool - \c true if there are only simplex cells in \a this mesh.
4599 * \throw If the coordinates array is not set.
4600 * \throw If the nodal connectivity of cells is not defined.
4601 * \throw If \a this->getMeshDimension() < 1.
4603 bool MEDCouplingUMesh::areOnlySimplexCells() const
4605 checkFullyDefined();
4606 int mdim=getMeshDimension();
4607 if(mdim<1 || mdim>3)
4608 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::areOnlySimplexCells : only available with meshes having a meshdim 1, 2 or 3 !");
4609 int nbCells=getNumberOfCells();
4610 const int *conn=_nodal_connec->begin();
4611 const int *connI=_nodal_connec_index->begin();
4612 for(int i=0;i<nbCells;i++)
4614 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4624 * Converts degenerated 2D or 3D linear cells of \a this mesh into cells of simpler
4625 * type. For example an INTERP_KERNEL::NORM_QUAD4 cell having only three unique nodes in
4626 * its connectivity is transformed into an INTERP_KERNEL::NORM_TRI3 cell. This method
4627 * does \b not perform geometrical checks and checks only nodal connectivity of cells,
4628 * so it can be useful to call mergeNodes() before calling this method.
4629 * \throw If \a this->getMeshDimension() <= 1.
4630 * \throw If the coordinates array is not set.
4631 * \throw If the nodal connectivity of cells is not defined.
4633 void MEDCouplingUMesh::convertDegeneratedCells()
4635 checkFullyDefined();
4636 if(getMeshDimension()<=1)
4637 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4638 int nbOfCells=getNumberOfCells();
4641 int initMeshLgth=getNodalConnectivityArrayLen();
4642 int *conn=_nodal_connec->getPointer();
4643 int *index=_nodal_connec_index->getPointer();
4647 for(int i=0;i<nbOfCells;i++)
4649 lgthOfCurCell=index[i+1]-posOfCurCell;
4650 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4652 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
4653 conn+newPos+1,newLgth);
4654 conn[newPos]=newType;
4656 posOfCurCell=index[i+1];
4659 if(newPos!=initMeshLgth)
4660 _nodal_connec->reAlloc(newPos);
4665 * Finds incorrectly oriented cells of this 2D mesh in 3D space.
4666 * A cell is considered to be oriented correctly if an angle between its
4667 * normal vector and a given vector is less than \c PI / \c 2.
4668 * \param [in] vec - 3 components of the vector specifying the correct orientation of
4670 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
4672 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
4673 * is not cleared before filling in.
4674 * \throw If \a this->getMeshDimension() != 2.
4675 * \throw If \a this->getSpaceDimension() != 3.
4677 * \if ENABLE_EXAMPLES
4678 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
4679 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
4682 void MEDCouplingUMesh::are2DCellsNotCorrectlyOriented(const double *vec, bool polyOnly, std::vector<int>& cells) const
4684 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
4685 throw INTERP_KERNEL::Exception("Invalid mesh to apply are2DCellsNotCorrectlyOriented on it : must be meshDim==2 and spaceDim==3 !");
4686 int nbOfCells=getNumberOfCells();
4687 const int *conn=_nodal_connec->begin();
4688 const int *connI=_nodal_connec_index->begin();
4689 const double *coordsPtr=_coords->begin();
4690 for(int i=0;i<nbOfCells;i++)
4692 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4693 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
4695 bool isQuadratic=INTERP_KERNEL::CellModel::GetCellModel(type).isQuadratic();
4696 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4703 * Reverse connectivity of 2D cells whose orientation is not correct. A cell is
4704 * considered to be oriented correctly if an angle between its normal vector and a
4705 * given vector is less than \c PI / \c 2.
4706 * \param [in] vec - 3 components of the vector specifying the correct orientation of
4708 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
4710 * \throw If \a this->getMeshDimension() != 2.
4711 * \throw If \a this->getSpaceDimension() != 3.
4713 * \if ENABLE_EXAMPLES
4714 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
4715 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
4718 * \sa changeOrientationOfCells
4720 void MEDCouplingUMesh::orientCorrectly2DCells(const double *vec, bool polyOnly)
4722 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
4723 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectly2DCells on it : must be meshDim==2 and spaceDim==3 !");
4724 int nbOfCells(getNumberOfCells()),*conn(_nodal_connec->getPointer());
4725 const int *connI(_nodal_connec_index->begin());
4726 const double *coordsPtr(_coords->begin());
4727 bool isModified(false);
4728 for(int i=0;i<nbOfCells;i++)
4730 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4731 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
4733 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
4734 bool isQuadratic(cm.isQuadratic());
4735 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4738 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
4743 _nodal_connec->declareAsNew();
4748 * This method change the orientation of cells in \a this without any consideration of coordinates. Only connectivity is impacted.
4750 * \sa orientCorrectly2DCells
4752 void MEDCouplingUMesh::changeOrientationOfCells()
4754 int mdim(getMeshDimension());
4755 if(mdim!=2 && mdim!=1)
4756 throw INTERP_KERNEL::Exception("Invalid mesh to apply changeOrientationOfCells on it : must be meshDim==2 or meshDim==1 !");
4757 int nbOfCells(getNumberOfCells()),*conn(_nodal_connec->getPointer());
4758 const int *connI(_nodal_connec_index->begin());
4761 for(int i=0;i<nbOfCells;i++)
4763 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4764 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
4765 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
4770 for(int i=0;i<nbOfCells;i++)
4772 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4773 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
4774 cm.changeOrientationOf1D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
4780 * Finds incorrectly oriented polyhedral cells, i.e. polyhedrons having correctly
4781 * oriented facets. The normal vector of the facet should point out of the cell.
4782 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
4783 * is not cleared before filling in.
4784 * \throw If \a this->getMeshDimension() != 3.
4785 * \throw If \a this->getSpaceDimension() != 3.
4786 * \throw If the coordinates array is not set.
4787 * \throw If the nodal connectivity of cells is not defined.
4789 * \if ENABLE_EXAMPLES
4790 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
4791 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
4794 void MEDCouplingUMesh::arePolyhedronsNotCorrectlyOriented(std::vector<int>& cells) const
4796 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
4797 throw INTERP_KERNEL::Exception("Invalid mesh to apply arePolyhedronsNotCorrectlyOriented on it : must be meshDim==3 and spaceDim==3 !");
4798 int nbOfCells=getNumberOfCells();
4799 const int *conn=_nodal_connec->begin();
4800 const int *connI=_nodal_connec_index->begin();
4801 const double *coordsPtr=_coords->begin();
4802 for(int i=0;i<nbOfCells;i++)
4804 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4805 if(type==INTERP_KERNEL::NORM_POLYHED)
4807 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4814 * Tries to fix connectivity of polyhedra, so that normal vector of all facets to point
4816 * \throw If \a this->getMeshDimension() != 3.
4817 * \throw If \a this->getSpaceDimension() != 3.
4818 * \throw If the coordinates array is not set.
4819 * \throw If the nodal connectivity of cells is not defined.
4820 * \throw If the reparation fails.
4822 * \if ENABLE_EXAMPLES
4823 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
4824 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
4826 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
4828 void MEDCouplingUMesh::orientCorrectlyPolyhedrons()
4830 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
4831 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectlyPolyhedrons on it : must be meshDim==3 and spaceDim==3 !");
4832 int nbOfCells=getNumberOfCells();
4833 int *conn=_nodal_connec->getPointer();
4834 const int *connI=_nodal_connec_index->begin();
4835 const double *coordsPtr=_coords->begin();
4836 for(int i=0;i<nbOfCells;i++)
4838 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4839 if(type==INTERP_KERNEL::NORM_POLYHED)
4843 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4844 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
4846 catch(INTERP_KERNEL::Exception& e)
4848 std::ostringstream oss; oss << "Something wrong in polyhedron #" << i << " : " << e.what();
4849 throw INTERP_KERNEL::Exception(oss.str());
4857 * This method invert orientation of all cells in \a this.
4858 * After calling this method the absolute value of measure of cells in \a this are the same than before calling.
4859 * This method only operates on the connectivity so coordinates are not touched at all.
4861 void MEDCouplingUMesh::invertOrientationOfAllCells()
4863 checkConnectivityFullyDefined();
4864 std::set<INTERP_KERNEL::NormalizedCellType> gts(getAllGeoTypes());
4865 int *conn(_nodal_connec->getPointer());
4866 const int *conni(_nodal_connec_index->begin());
4867 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator gt=gts.begin();gt!=gts.end();gt++)
4869 INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::OrientationInverter> oi(INTERP_KERNEL::OrientationInverter::BuildInstanceFrom(*gt));
4870 MCAuto<DataArrayInt> cwt(giveCellsWithType(*gt));
4871 for(const int *it=cwt->begin();it!=cwt->end();it++)
4872 oi->operate(conn+conni[*it]+1,conn+conni[*it+1]);
4878 * Finds and fixes incorrectly oriented linear extruded volumes (INTERP_KERNEL::NORM_HEXA8,
4879 * INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXGP12 etc) to respect the MED convention
4880 * according to which the first facet of the cell should be oriented to have the normal vector
4881 * pointing out of cell.
4882 * \return DataArrayInt * - a new instance of DataArrayInt holding ids of fixed
4883 * cells. The caller is to delete this array using decrRef() as it is no more
4885 * \throw If \a this->getMeshDimension() != 3.
4886 * \throw If \a this->getSpaceDimension() != 3.
4887 * \throw If the coordinates array is not set.
4888 * \throw If the nodal connectivity of cells is not defined.
4890 * \if ENABLE_EXAMPLES
4891 * \ref cpp_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a C++ example".<br>
4892 * \ref py_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a Python example".
4894 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
4896 DataArrayInt *MEDCouplingUMesh::findAndCorrectBadOriented3DExtrudedCells()
4898 const char msg[]="check3DCellsWellOriented detection works only for 3D cells !";
4899 if(getMeshDimension()!=3)
4900 throw INTERP_KERNEL::Exception(msg);
4901 int spaceDim=getSpaceDimension();
4903 throw INTERP_KERNEL::Exception(msg);
4905 int nbOfCells=getNumberOfCells();
4906 int *conn=_nodal_connec->getPointer();
4907 const int *connI=_nodal_connec_index->begin();
4908 const double *coo=getCoords()->begin();
4909 MCAuto<DataArrayInt> cells(DataArrayInt::New()); cells->alloc(0,1);
4910 for(int i=0;i<nbOfCells;i++)
4912 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4913 if(cm.isExtruded() && !cm.isDynamic() && !cm.isQuadratic())
4915 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coo))
4917 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
4918 cells->pushBackSilent(i);
4922 return cells.retn();
4926 * This method is a faster method to correct orientation of all 3D cells in \a this.
4927 * 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.
4928 * This method makes the hypothesis that \a this a coherent that is to say MEDCouplingUMesh::checkConsistency should throw no exception.
4930 * \return a newly allocated int array with one components containing cell ids renumbered to fit the convention of MED (MED file and MEDCoupling)
4931 * \sa MEDCouplingUMesh::orientCorrectlyPolyhedrons,
4933 DataArrayInt *MEDCouplingUMesh::findAndCorrectBadOriented3DCells()
4935 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
4936 throw INTERP_KERNEL::Exception("Invalid mesh to apply findAndCorrectBadOriented3DCells on it : must be meshDim==3 and spaceDim==3 !");
4937 int nbOfCells=getNumberOfCells();
4938 int *conn=_nodal_connec->getPointer();
4939 const int *connI=_nodal_connec_index->begin();
4940 const double *coordsPtr=_coords->begin();
4941 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
4942 for(int i=0;i<nbOfCells;i++)
4944 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4947 case INTERP_KERNEL::NORM_TETRA4:
4949 if(!IsTetra4WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4951 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+3));
4952 ret->pushBackSilent(i);
4956 case INTERP_KERNEL::NORM_PYRA5:
4958 if(!IsPyra5WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4960 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+4));
4961 ret->pushBackSilent(i);
4965 case INTERP_KERNEL::NORM_PENTA6:
4966 case INTERP_KERNEL::NORM_HEXA8:
4967 case INTERP_KERNEL::NORM_HEXGP12:
4969 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4971 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
4972 ret->pushBackSilent(i);
4976 case INTERP_KERNEL::NORM_POLYHED:
4978 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4980 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
4981 ret->pushBackSilent(i);
4986 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 !");
4994 * This method has a sense for meshes with spaceDim==3 and meshDim==2.
4995 * If it is not the case an exception will be thrown.
4996 * This method is fast because the first cell of \a this is used to compute the plane.
4997 * \param vec output of size at least 3 used to store the normal vector (with norm equal to Area ) of searched plane.
4998 * \param pos output of size at least 3 used to store a point owned of searched plane.
5000 void MEDCouplingUMesh::getFastAveragePlaneOfThis(double *vec, double *pos) const
5002 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
5003 throw INTERP_KERNEL::Exception("Invalid mesh to apply getFastAveragePlaneOfThis on it : must be meshDim==2 and spaceDim==3 !");
5004 const int *conn=_nodal_connec->begin();
5005 const int *connI=_nodal_connec_index->begin();
5006 const double *coordsPtr=_coords->begin();
5007 INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(conn+1,connI[1]-connI[0]-1,coordsPtr,vec);
5008 std::copy(coordsPtr+3*conn[1],coordsPtr+3*conn[1]+3,pos);
5012 * Creates a new MEDCouplingFieldDouble holding Edge Ratio values of all
5013 * cells. Currently cells of the following types are treated:
5014 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5015 * For a cell of other type an exception is thrown.
5016 * Space dimension of a 2D mesh can be either 2 or 3.
5017 * The Edge Ratio of a cell \f$t\f$ is:
5018 * \f$\frac{|t|_\infty}{|t|_0}\f$,
5019 * where \f$|t|_\infty\f$ and \f$|t|_0\f$ respectively denote the greatest and
5020 * the smallest edge lengths of \f$t\f$.
5021 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5022 * cells and one time, lying on \a this mesh. The caller is to delete this
5023 * field using decrRef() as it is no more needed.
5024 * \throw If the coordinates array is not set.
5025 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5026 * \throw If the connectivity data array has more than one component.
5027 * \throw If the connectivity data array has a named component.
5028 * \throw If the connectivity index data array has more than one component.
5029 * \throw If the connectivity index data array has a named component.
5030 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
5031 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5032 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5034 MEDCouplingFieldDouble *MEDCouplingUMesh::getEdgeRatioField() const
5036 checkConsistencyLight();
5037 int spaceDim=getSpaceDimension();
5038 int meshDim=getMeshDimension();
5039 if(spaceDim!=2 && spaceDim!=3)
5040 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : SpaceDimension must be equal to 2 or 3 !");
5041 if(meshDim!=2 && meshDim!=3)
5042 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : MeshDimension must be equal to 2 or 3 !");
5043 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5045 int nbOfCells=getNumberOfCells();
5046 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5047 arr->alloc(nbOfCells,1);
5048 double *pt=arr->getPointer();
5049 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5050 const int *conn=_nodal_connec->begin();
5051 const int *connI=_nodal_connec_index->begin();
5052 const double *coo=_coords->begin();
5054 for(int i=0;i<nbOfCells;i++,pt++)
5056 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5059 case INTERP_KERNEL::NORM_TRI3:
5061 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5062 *pt=INTERP_KERNEL::triEdgeRatio(tmp);
5065 case INTERP_KERNEL::NORM_QUAD4:
5067 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5068 *pt=INTERP_KERNEL::quadEdgeRatio(tmp);
5071 case INTERP_KERNEL::NORM_TETRA4:
5073 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5074 *pt=INTERP_KERNEL::tetraEdgeRatio(tmp);
5078 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5080 conn+=connI[i+1]-connI[i];
5082 ret->setName("EdgeRatio");
5083 ret->synchronizeTimeWithSupport();
5088 * Creates a new MEDCouplingFieldDouble holding Aspect Ratio values of all
5089 * cells. Currently cells of the following types are treated:
5090 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5091 * For a cell of other type an exception is thrown.
5092 * Space dimension of a 2D mesh can be either 2 or 3.
5093 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5094 * cells and one time, lying on \a this mesh. The caller is to delete this
5095 * field using decrRef() as it is no more needed.
5096 * \throw If the coordinates array is not set.
5097 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5098 * \throw If the connectivity data array has more than one component.
5099 * \throw If the connectivity data array has a named component.
5100 * \throw If the connectivity index data array has more than one component.
5101 * \throw If the connectivity index data array has a named component.
5102 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
5103 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5104 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5106 MEDCouplingFieldDouble *MEDCouplingUMesh::getAspectRatioField() const
5108 checkConsistencyLight();
5109 int spaceDim=getSpaceDimension();
5110 int meshDim=getMeshDimension();
5111 if(spaceDim!=2 && spaceDim!=3)
5112 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : SpaceDimension must be equal to 2 or 3 !");
5113 if(meshDim!=2 && meshDim!=3)
5114 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : MeshDimension must be equal to 2 or 3 !");
5115 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5117 int nbOfCells=getNumberOfCells();
5118 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5119 arr->alloc(nbOfCells,1);
5120 double *pt=arr->getPointer();
5121 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5122 const int *conn=_nodal_connec->begin();
5123 const int *connI=_nodal_connec_index->begin();
5124 const double *coo=_coords->begin();
5126 for(int i=0;i<nbOfCells;i++,pt++)
5128 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5131 case INTERP_KERNEL::NORM_TRI3:
5133 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5134 *pt=INTERP_KERNEL::triAspectRatio(tmp);
5137 case INTERP_KERNEL::NORM_QUAD4:
5139 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5140 *pt=INTERP_KERNEL::quadAspectRatio(tmp);
5143 case INTERP_KERNEL::NORM_TETRA4:
5145 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5146 *pt=INTERP_KERNEL::tetraAspectRatio(tmp);
5150 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5152 conn+=connI[i+1]-connI[i];
5154 ret->setName("AspectRatio");
5155 ret->synchronizeTimeWithSupport();
5160 * Creates a new MEDCouplingFieldDouble holding Warping factor values of all
5161 * cells of \a this 2D mesh in 3D space. It is a measure of the "planarity" of 2D cell
5162 * in 3D space. Currently only cells of the following types are
5163 * treated: INTERP_KERNEL::NORM_QUAD4.
5164 * For a cell of other type an exception is thrown.
5165 * The warp field is computed as follows: let (a,b,c,d) be the points of the quad.
5167 * \f$t=\vec{da}\times\vec{ab}\f$,
5168 * \f$u=\vec{ab}\times\vec{bc}\f$
5169 * \f$v=\vec{bc}\times\vec{cd}\f$
5170 * \f$w=\vec{cd}\times\vec{da}\f$, the warp is defined as \f$W^3\f$ with
5172 * W=min(\frac{t}{|t|}\cdot\frac{v}{|v|}, \frac{u}{|u|}\cdot\frac{w}{|w|})
5174 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5175 * cells and one time, lying on \a this mesh. The caller is to delete this
5176 * field using decrRef() as it is no more needed.
5177 * \throw If the coordinates array is not set.
5178 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5179 * \throw If the connectivity data array has more than one component.
5180 * \throw If the connectivity data array has a named component.
5181 * \throw If the connectivity index data array has more than one component.
5182 * \throw If the connectivity index data array has a named component.
5183 * \throw If \a this->getMeshDimension() != 2.
5184 * \throw If \a this->getSpaceDimension() != 3.
5185 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5187 MEDCouplingFieldDouble *MEDCouplingUMesh::getWarpField() const
5189 checkConsistencyLight();
5190 int spaceDim=getSpaceDimension();
5191 int meshDim=getMeshDimension();
5193 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : SpaceDimension must be equal to 3 !");
5195 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : MeshDimension must be equal to 2 !");
5196 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5198 int nbOfCells=getNumberOfCells();
5199 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5200 arr->alloc(nbOfCells,1);
5201 double *pt=arr->getPointer();
5202 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5203 const int *conn=_nodal_connec->begin();
5204 const int *connI=_nodal_connec_index->begin();
5205 const double *coo=_coords->begin();
5207 for(int i=0;i<nbOfCells;i++,pt++)
5209 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5212 case INTERP_KERNEL::NORM_QUAD4:
5214 FillInCompact3DMode(3,4,conn+1,coo,tmp);
5215 *pt=INTERP_KERNEL::quadWarp(tmp);
5219 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : A cell with not manged type (NORM_QUAD4) has been detected !");
5221 conn+=connI[i+1]-connI[i];
5223 ret->setName("Warp");
5224 ret->synchronizeTimeWithSupport();
5230 * Creates a new MEDCouplingFieldDouble holding Skew factor values of all
5231 * cells of \a this 2D mesh in 3D space. Currently cells of the following types are
5232 * treated: INTERP_KERNEL::NORM_QUAD4.
5233 * The skew is computed as follow for a quad with points (a,b,c,d): let
5234 * \f$u=\vec{ab}+\vec{dc}\f$ and \f$v=\vec{ac}+\vec{bd}\f$
5235 * then the skew is computed as:
5237 * s=\frac{u}{|u|}\cdot\frac{v}{|v|}
5240 * For a cell of other type an exception is thrown.
5241 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5242 * cells and one time, lying on \a this mesh. The caller is to delete this
5243 * field using decrRef() as it is no more needed.
5244 * \throw If the coordinates array is not set.
5245 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5246 * \throw If the connectivity data array has more than one component.
5247 * \throw If the connectivity data array has a named component.
5248 * \throw If the connectivity index data array has more than one component.
5249 * \throw If the connectivity index data array has a named component.
5250 * \throw If \a this->getMeshDimension() != 2.
5251 * \throw If \a this->getSpaceDimension() != 3.
5252 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5254 MEDCouplingFieldDouble *MEDCouplingUMesh::getSkewField() const
5256 checkConsistencyLight();
5257 int spaceDim=getSpaceDimension();
5258 int meshDim=getMeshDimension();
5260 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : SpaceDimension must be equal to 3 !");
5262 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : MeshDimension must be equal to 2 !");
5263 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5265 int nbOfCells=getNumberOfCells();
5266 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5267 arr->alloc(nbOfCells,1);
5268 double *pt=arr->getPointer();
5269 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5270 const int *conn=_nodal_connec->begin();
5271 const int *connI=_nodal_connec_index->begin();
5272 const double *coo=_coords->begin();
5274 for(int i=0;i<nbOfCells;i++,pt++)
5276 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5279 case INTERP_KERNEL::NORM_QUAD4:
5281 FillInCompact3DMode(3,4,conn+1,coo,tmp);
5282 *pt=INTERP_KERNEL::quadSkew(tmp);
5286 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : A cell with not manged type (NORM_QUAD4) has been detected !");
5288 conn+=connI[i+1]-connI[i];
5290 ret->setName("Skew");
5291 ret->synchronizeTimeWithSupport();
5296 * 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.
5298 * \return a new instance of field containing the result. The returned instance has to be deallocated by the caller.
5300 * \sa getSkewField, getWarpField, getAspectRatioField, getEdgeRatioField
5302 MEDCouplingFieldDouble *MEDCouplingUMesh::computeDiameterField() const
5304 checkConsistencyLight();
5305 MCAuto<MEDCouplingFieldDouble> ret(MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME));
5307 std::set<INTERP_KERNEL::NormalizedCellType> types;
5308 ComputeAllTypesInternal(types,_nodal_connec,_nodal_connec_index);
5309 int spaceDim(getSpaceDimension()),nbCells(getNumberOfCells());
5310 MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
5311 arr->alloc(nbCells,1);
5312 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++)
5314 INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::DiameterCalculator> dc(INTERP_KERNEL::CellModel::GetCellModel(*it).buildInstanceOfDiameterCalulator(spaceDim));
5315 MCAuto<DataArrayInt> cellIds(giveCellsWithType(*it));
5316 dc->computeForListOfCellIdsUMeshFrmt(cellIds->begin(),cellIds->end(),_nodal_connec_index->begin(),_nodal_connec->begin(),getCoords()->begin(),arr->getPointer());
5319 ret->setName("Diameter");
5324 * This method aggregate the bbox of each cell and put it into bbox parameter (xmin,xmax,ymin,ymax,zmin,zmax).
5326 * \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)
5327 * For all other cases this input parameter is ignored.
5328 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5330 * \throw If \a this is not fully set (coordinates and connectivity).
5331 * \throw If a cell in \a this has no valid nodeId.
5332 * \sa MEDCouplingUMesh::getBoundingBoxForBBTreeFast, MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5334 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree(double arcDetEps) const
5336 int mDim(getMeshDimension()),sDim(getSpaceDimension());
5337 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.
5338 return getBoundingBoxForBBTreeFast();
5339 if((mDim==2 && sDim==2) || (mDim==1 && sDim==2))
5341 bool presenceOfQuadratic(false);
5342 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=_types.begin();it!=_types.end();it++)
5344 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(*it));
5345 if(cm.isQuadratic())
5346 presenceOfQuadratic=true;
5348 if(!presenceOfQuadratic)
5349 return getBoundingBoxForBBTreeFast();
5350 if(mDim==2 && sDim==2)
5351 return getBoundingBoxForBBTree2DQuadratic(arcDetEps);
5353 return getBoundingBoxForBBTree1DQuadratic(arcDetEps);
5355 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) !");
5359 * This method aggregate the bbox of each cell only considering the nodes constituting each cell and put it into bbox parameter.
5360 * So meshes having quadratic cells the computed bounding boxes can be invalid !
5362 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5364 * \throw If \a this is not fully set (coordinates and connectivity).
5365 * \throw If a cell in \a this has no valid nodeId.
5367 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTreeFast() const
5369 checkFullyDefined();
5370 int spaceDim(getSpaceDimension()),nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
5371 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5372 double *bbox(ret->getPointer());
5373 for(int i=0;i<nbOfCells*spaceDim;i++)
5375 bbox[2*i]=std::numeric_limits<double>::max();
5376 bbox[2*i+1]=-std::numeric_limits<double>::max();
5378 const double *coordsPtr(_coords->begin());
5379 const int *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5380 for(int i=0;i<nbOfCells;i++)
5382 int offset=connI[i]+1;
5383 int nbOfNodesForCell(connI[i+1]-offset),kk(0);
5384 for(int j=0;j<nbOfNodesForCell;j++)
5386 int nodeId=conn[offset+j];
5387 if(nodeId>=0 && nodeId<nbOfNodes)
5389 for(int k=0;k<spaceDim;k++)
5391 bbox[2*spaceDim*i+2*k]=std::min(bbox[2*spaceDim*i+2*k],coordsPtr[spaceDim*nodeId+k]);
5392 bbox[2*spaceDim*i+2*k+1]=std::max(bbox[2*spaceDim*i+2*k+1],coordsPtr[spaceDim*nodeId+k]);
5399 std::ostringstream oss; oss << "MEDCouplingUMesh::getBoundingBoxForBBTree : cell #" << i << " contains no valid nodeId !";
5400 throw INTERP_KERNEL::Exception(oss.str());
5407 * This method aggregates the bbox of each 2D cell in \a this considering the whole shape. This method is particularly
5408 * useful for 2D meshes having quadratic cells
5409 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5410 * the two extremities of the arc of circle).
5412 * \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)
5413 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5414 * \throw If \a this is not fully defined.
5415 * \throw If \a this is not a mesh with meshDimension equal to 2.
5416 * \throw If \a this is not a mesh with spaceDimension equal to 2.
5417 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic
5419 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic(double arcDetEps) const
5421 checkFullyDefined();
5422 INTERP_KERNEL::QuadraticPlanarArcDetectionPrecision arcPrec(arcDetEps);
5424 int spaceDim(getSpaceDimension()),mDim(getMeshDimension()),nbOfCells(getNumberOfCells());
5425 if(spaceDim!=2 || mDim!=2)
5426 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!");
5427 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5428 double *bbox(ret->getPointer());
5429 const double *coords(_coords->begin());
5430 const int *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5431 for(int i=0;i<nbOfCells;i++,bbox+=4,connI++)
5433 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5434 int sz(connI[1]-connI[0]-1);
5435 std::vector<INTERP_KERNEL::Node *> nodes(sz);
5436 INTERP_KERNEL::QuadraticPolygon *pol(0);
5437 for(int j=0;j<sz;j++)
5439 int nodeId(conn[*connI+1+j]);
5440 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5442 if(!cm.isQuadratic())
5443 pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
5445 pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
5446 INTERP_KERNEL::Bounds b; b.prepareForAggregation(); pol->fillBounds(b); delete pol;
5447 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax();
5453 * This method aggregates the bbox of each 1D cell in \a this considering the whole shape. This method is particularly
5454 * useful for 2D meshes having quadratic cells
5455 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5456 * the two extremities of the arc of circle).
5458 * \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)
5459 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5460 * \throw If \a this is not fully defined.
5461 * \throw If \a this is not a mesh with meshDimension equal to 1.
5462 * \throw If \a this is not a mesh with spaceDimension equal to 2.
5463 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5465 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic(double arcDetEps) const
5467 checkFullyDefined();
5468 int spaceDim(getSpaceDimension()),mDim(getMeshDimension()),nbOfCells(getNumberOfCells());
5469 if(spaceDim!=2 || mDim!=1)
5470 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!");
5471 INTERP_KERNEL::QuadraticPlanarArcDetectionPrecision arcPrec(arcDetEps);
5472 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5473 double *bbox(ret->getPointer());
5474 const double *coords(_coords->begin());
5475 const int *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5476 for(int i=0;i<nbOfCells;i++,bbox+=4,connI++)
5478 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5479 int sz(connI[1]-connI[0]-1);
5480 std::vector<INTERP_KERNEL::Node *> nodes(sz);
5481 INTERP_KERNEL::Edge *edge(0);
5482 for(int j=0;j<sz;j++)
5484 int nodeId(conn[*connI+1+j]);
5485 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5487 if(!cm.isQuadratic())
5488 edge=INTERP_KERNEL::QuadraticPolygon::BuildLinearEdge(nodes);
5490 edge=INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(nodes);
5491 const INTERP_KERNEL::Bounds& b(edge->getBounds());
5492 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax(); edge->decrRef();
5499 namespace MEDCouplingImpl
5504 ConnReader(const int *c, int val):_conn(c),_val(val) { }
5505 bool operator() (const int& pos) { return _conn[pos]!=_val; }
5514 ConnReader2(const int *c, int val):_conn(c),_val(val) { }
5515 bool operator() (const int& pos) { return _conn[pos]==_val; }
5525 * This method expects that \a this is sorted by types. If not an exception will be thrown.
5526 * This method returns in the same format as code (see MEDCouplingUMesh::checkTypeConsistencyAndContig or MEDCouplingUMesh::splitProfilePerType) how
5527 * \a this is composed in cell types.
5528 * The returned array is of size 3*n where n is the number of different types present in \a this.
5529 * For every k in [0,n] ret[3*k+2]==-1 because it has no sense here.
5530 * This parameter is kept only for compatibility with other methode listed above.
5532 std::vector<int> MEDCouplingUMesh::getDistributionOfTypes() const
5534 checkConnectivityFullyDefined();
5535 const int *conn=_nodal_connec->begin();
5536 const int *connI=_nodal_connec_index->begin();
5537 const int *work=connI;
5538 int nbOfCells=getNumberOfCells();
5539 std::size_t n=getAllGeoTypes().size();
5540 std::vector<int> ret(3*n,-1); //ret[3*k+2]==-1 because it has no sense here
5541 std::set<INTERP_KERNEL::NormalizedCellType> types;
5542 for(std::size_t i=0;work!=connI+nbOfCells;i++)
5544 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn[*work];
5545 if(types.find(typ)!=types.end())
5547 std::ostringstream oss; oss << "MEDCouplingUMesh::getDistributionOfTypes : Type " << INTERP_KERNEL::CellModel::GetCellModel(typ).getRepr();
5548 oss << " is not contiguous !";
5549 throw INTERP_KERNEL::Exception(oss.str());
5553 const int *work2=std::find_if(work+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,typ));
5554 ret[3*i+1]=(int)std::distance(work,work2);
5561 * This method is used to check that this has contiguous cell type in same order than described in \a code.
5562 * only for types cell, type node is not managed.
5563 * Format of \a code is the following. \a code should be of size 3*n and non empty. If not an exception is thrown.
5564 * foreach k in [0,n) on 3*k pos represent the geometric type and 3*k+1 number of elements of type 3*k.
5565 * 3*k+2 refers if different from -1 the pos in 'idsPerType' to get the corresponding array.
5566 * If 2 or more same geometric type is in \a code and exception is thrown too.
5568 * This method firstly checks
5569 * If it exists k so that 3*k geometric type is not in geometric types of this an exception will be thrown.
5570 * If it exists k so that 3*k geometric type exists but the number of consecutive cell types does not match,
5571 * an exception is thrown too.
5573 * If all geometric types in \a code are exactly those in \a this null pointer is returned.
5574 * If it exists a geometric type in \a this \b not in \a code \b no exception is thrown
5575 * and a DataArrayInt instance is returned that the user has the responsability to deallocate.
5577 DataArrayInt *MEDCouplingUMesh::checkTypeConsistencyAndContig(const std::vector<int>& code, const std::vector<const DataArrayInt *>& idsPerType) const
5580 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code is empty, should not !");
5581 std::size_t sz=code.size();
5584 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code size is NOT %3 !");
5585 std::vector<INTERP_KERNEL::NormalizedCellType> types;
5587 bool isNoPflUsed=true;
5588 for(std::size_t i=0;i<n;i++)
5589 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)code[3*i])==types.end())
5591 types.push_back((INTERP_KERNEL::NormalizedCellType)code[3*i]);
5593 if(_types.find((INTERP_KERNEL::NormalizedCellType)code[3*i])==_types.end())
5594 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : expected geo types not in this !");
5595 isNoPflUsed=isNoPflUsed && (code[3*i+2]==-1);
5598 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code contains duplication of types in unstructured mesh !");
5601 if(!checkConsecutiveCellTypesAndOrder(&types[0],&types[0]+types.size()))
5602 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : non contiguous type !");
5603 if(types.size()==_types.size())
5606 MCAuto<DataArrayInt> ret=DataArrayInt::New();
5608 int *retPtr=ret->getPointer();
5609 const int *connI=_nodal_connec_index->begin();
5610 const int *conn=_nodal_connec->begin();
5611 int nbOfCells=getNumberOfCells();
5614 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++,kk++)
5616 i=std::find_if(i,connI+nbOfCells,MEDCouplingImpl::ConnReader2(conn,(int)(*it)));
5617 int offset=(int)std::distance(connI,i);
5618 const int *j=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)(*it)));
5619 int nbOfCellsOfCurType=(int)std::distance(i,j);
5620 if(code[3*kk+2]==-1)
5621 for(int k=0;k<nbOfCellsOfCurType;k++)
5625 int idInIdsPerType=code[3*kk+2];
5626 if(idInIdsPerType>=0 && idInIdsPerType<(int)idsPerType.size())
5628 const DataArrayInt *zePfl=idsPerType[idInIdsPerType];
5631 zePfl->checkAllocated();
5632 if(zePfl->getNumberOfComponents()==1)
5634 for(const int *k=zePfl->begin();k!=zePfl->end();k++,retPtr++)
5636 if(*k>=0 && *k<nbOfCellsOfCurType)
5637 *retPtr=(*k)+offset;
5640 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : the section " << kk << " points to the profile #" << idInIdsPerType;
5641 oss << ", and this profile contains a value " << *k << " should be in [0," << nbOfCellsOfCurType << ") !";
5642 throw INTERP_KERNEL::Exception(oss.str());
5647 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of a profile with nb of compo != 1 !");
5650 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of null profile !");
5654 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : at section " << kk << " of code it points to the array #" << idInIdsPerType;
5655 oss << " should be in [0," << idsPerType.size() << ") !";
5656 throw INTERP_KERNEL::Exception(oss.str());
5665 * This method makes the hypothesis that \a this is sorted by type. If not an exception will be thrown.
5666 * 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.
5667 * 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.
5668 * This method has 1 input \a profile and 3 outputs \a code \a idsInPflPerType and \a idsPerType.
5670 * \param [in] profile
5671 * \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.
5672 * \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,
5673 * \a idsInPflPerType[i] stores the tuple ids in \a profile that correspond to the geometric type code[3*i+0]
5674 * \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.
5675 * This vector can be empty in case of all geometric type cells are fully covered in ascending in the given input \a profile.
5676 * \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
5678 void MEDCouplingUMesh::splitProfilePerType(const DataArrayInt *profile, std::vector<int>& code, std::vector<DataArrayInt *>& idsInPflPerType, std::vector<DataArrayInt *>& idsPerType) const
5681 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile is NULL !");
5682 if(profile->getNumberOfComponents()!=1)
5683 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile should have exactly one component !");
5684 checkConnectivityFullyDefined();
5685 const int *conn=_nodal_connec->begin();
5686 const int *connI=_nodal_connec_index->begin();
5687 int nbOfCells=getNumberOfCells();
5688 std::vector<INTERP_KERNEL::NormalizedCellType> types;
5689 std::vector<int> typeRangeVals(1);
5690 for(const int *i=connI;i!=connI+nbOfCells;)
5692 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5693 if(std::find(types.begin(),types.end(),curType)!=types.end())
5695 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : current mesh is not sorted by type !");
5697 types.push_back(curType);
5698 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
5699 typeRangeVals.push_back((int)std::distance(connI,i));
5702 DataArrayInt *castArr=0,*rankInsideCast=0,*castsPresent=0;
5703 profile->splitByValueRange(&typeRangeVals[0],&typeRangeVals[0]+typeRangeVals.size(),castArr,rankInsideCast,castsPresent);
5704 MCAuto<DataArrayInt> tmp0=castArr;
5705 MCAuto<DataArrayInt> tmp1=rankInsideCast;
5706 MCAuto<DataArrayInt> tmp2=castsPresent;
5708 int nbOfCastsFinal=castsPresent->getNumberOfTuples();
5709 code.resize(3*nbOfCastsFinal);
5710 std::vector< MCAuto<DataArrayInt> > idsInPflPerType2;
5711 std::vector< MCAuto<DataArrayInt> > idsPerType2;
5712 for(int i=0;i<nbOfCastsFinal;i++)
5714 int castId=castsPresent->getIJ(i,0);
5715 MCAuto<DataArrayInt> tmp3=castArr->findIdsEqual(castId);
5716 idsInPflPerType2.push_back(tmp3);
5717 code[3*i]=(int)types[castId];
5718 code[3*i+1]=tmp3->getNumberOfTuples();
5719 MCAuto<DataArrayInt> tmp4=rankInsideCast->selectByTupleId(tmp3->begin(),tmp3->begin()+tmp3->getNumberOfTuples());
5720 if(!tmp4->isIota(typeRangeVals[castId+1]-typeRangeVals[castId]))
5722 tmp4->copyStringInfoFrom(*profile);
5723 idsPerType2.push_back(tmp4);
5724 code[3*i+2]=(int)idsPerType2.size()-1;
5731 std::size_t sz2=idsInPflPerType2.size();
5732 idsInPflPerType.resize(sz2);
5733 for(std::size_t i=0;i<sz2;i++)
5735 DataArrayInt *locDa=idsInPflPerType2[i];
5737 idsInPflPerType[i]=locDa;
5739 std::size_t sz=idsPerType2.size();
5740 idsPerType.resize(sz);
5741 for(std::size_t i=0;i<sz;i++)
5743 DataArrayInt *locDa=idsPerType2[i];
5745 idsPerType[i]=locDa;
5750 * This method is here too emulate the MEDMEM behaviour on BDC (buildDescendingConnectivity). Hoping this method becomes deprecated very soon.
5751 * This method make the assumption that \a this and 'nM1LevMesh' mesh lyies on same coords (same pointer) as MED and MEDMEM does.
5752 * The following equality should be verified 'nM1LevMesh->getMeshDimension()==this->getMeshDimension()-1'
5753 * 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.
5755 MEDCouplingUMesh *MEDCouplingUMesh::emulateMEDMEMBDC(const MEDCouplingUMesh *nM1LevMesh, DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *&revDesc, DataArrayInt *&revDescIndx, DataArrayInt *& nM1LevMeshIds, DataArrayInt *&meshnM1Old2New) const
5757 checkFullyDefined();
5758 nM1LevMesh->checkFullyDefined();
5759 if(getMeshDimension()-1!=nM1LevMesh->getMeshDimension())
5760 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : The mesh passed as first argument should have a meshDim equal to this->getMeshDimension()-1 !" );
5761 if(_coords!=nM1LevMesh->getCoords())
5762 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : 'this' and mesh in first argument should share the same coords : Use tryToShareSameCoords method !");
5763 MCAuto<DataArrayInt> tmp0=DataArrayInt::New();
5764 MCAuto<DataArrayInt> tmp1=DataArrayInt::New();
5765 MCAuto<MEDCouplingUMesh> ret1=buildDescendingConnectivity(desc,descIndx,tmp0,tmp1);
5766 MCAuto<DataArrayInt> ret0=ret1->sortCellsInMEDFileFrmt();
5767 desc->transformWithIndArr(ret0->begin(),ret0->begin()+ret0->getNbOfElems());
5768 MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
5769 tmp->setConnectivity(tmp0,tmp1);
5770 tmp->renumberCells(ret0->begin(),false);
5771 revDesc=tmp->getNodalConnectivity();
5772 revDescIndx=tmp->getNodalConnectivityIndex();
5773 DataArrayInt *ret=0;
5774 if(!ret1->areCellsIncludedIn(nM1LevMesh,2,ret))
5777 ret->getMaxValue(tmp2);
5779 std::ostringstream oss; oss << "MEDCouplingUMesh::emulateMEDMEMBDC : input N-1 mesh present a cell not in descending mesh ... Id of cell is " << tmp2 << " !";
5780 throw INTERP_KERNEL::Exception(oss.str());
5785 revDescIndx->incrRef();
5788 meshnM1Old2New=ret0;
5793 * Permutes the nodal connectivity arrays so that the cells are sorted by type, which is
5794 * necessary for writing the mesh to MED file. Additionally returns a permutation array
5795 * in "Old to New" mode.
5796 * \return DataArrayInt * - a new instance of DataArrayInt. The caller is to delete
5797 * this array using decrRef() as it is no more needed.
5798 * \throw If the nodal connectivity of cells is not defined.
5800 DataArrayInt *MEDCouplingUMesh::sortCellsInMEDFileFrmt()
5802 checkConnectivityFullyDefined();
5803 MCAuto<DataArrayInt> ret=getRenumArrForMEDFileFrmt();
5804 renumberCells(ret->begin(),false);
5809 * This methods checks that cells are sorted by their types.
5810 * This method makes asumption (no check) that connectivity is correctly set before calling.
5812 bool MEDCouplingUMesh::checkConsecutiveCellTypes() const
5814 checkFullyDefined();
5815 const int *conn=_nodal_connec->begin();
5816 const int *connI=_nodal_connec_index->begin();
5817 int nbOfCells=getNumberOfCells();
5818 std::set<INTERP_KERNEL::NormalizedCellType> types;
5819 for(const int *i=connI;i!=connI+nbOfCells;)
5821 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5822 if(types.find(curType)!=types.end())
5824 types.insert(curType);
5825 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
5831 * This method is a specialization of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method that is called here.
5832 * The geometric type order is specified by MED file.
5834 * \sa MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder
5836 bool MEDCouplingUMesh::checkConsecutiveCellTypesForMEDFileFrmt() const
5838 return checkConsecutiveCellTypesAndOrder(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
5842 * This method performs the same job as checkConsecutiveCellTypes except that the order of types sequence is analyzed to check
5843 * that the order is specified in array defined by [ \a orderBg , \a orderEnd ).
5844 * If there is some geo types in \a this \b NOT in [ \a orderBg, \a orderEnd ) it is OK (return true) if contiguous.
5845 * If there is some geo types in [ \a orderBg, \a orderEnd ) \b NOT in \a this it is OK too (return true) if contiguous.
5847 bool MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
5849 checkFullyDefined();
5850 const int *conn=_nodal_connec->begin();
5851 const int *connI=_nodal_connec_index->begin();
5852 int nbOfCells=getNumberOfCells();
5856 std::set<INTERP_KERNEL::NormalizedCellType> sg;
5857 for(const int *i=connI;i!=connI+nbOfCells;)
5859 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5860 const INTERP_KERNEL::NormalizedCellType *isTypeExists=std::find(orderBg,orderEnd,curType);
5861 if(isTypeExists!=orderEnd)
5863 int pos=(int)std::distance(orderBg,isTypeExists);
5867 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
5871 if(sg.find(curType)==sg.end())
5873 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
5884 * This method returns 2 newly allocated DataArrayInt instances. The first is an array of size 'this->getNumberOfCells()' with one component,
5885 * 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
5886 * 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'.
5888 DataArrayInt *MEDCouplingUMesh::getLevArrPerCellTypes(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd, DataArrayInt *&nbPerType) const
5890 checkConnectivityFullyDefined();
5891 int nbOfCells=getNumberOfCells();
5892 const int *conn=_nodal_connec->begin();
5893 const int *connI=_nodal_connec_index->begin();
5894 MCAuto<DataArrayInt> tmpa=DataArrayInt::New();
5895 MCAuto<DataArrayInt> tmpb=DataArrayInt::New();
5896 tmpa->alloc(nbOfCells,1);
5897 tmpb->alloc((int)std::distance(orderBg,orderEnd),1);
5898 tmpb->fillWithZero();
5899 int *tmp=tmpa->getPointer();
5900 int *tmp2=tmpb->getPointer();
5901 for(const int *i=connI;i!=connI+nbOfCells;i++)
5903 const INTERP_KERNEL::NormalizedCellType *where=std::find(orderBg,orderEnd,(INTERP_KERNEL::NormalizedCellType)conn[*i]);
5906 int pos=(int)std::distance(orderBg,where);
5908 tmp[std::distance(connI,i)]=pos;
5912 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*i]);
5913 std::ostringstream oss; oss << "MEDCouplingUMesh::getLevArrPerCellTypes : Cell #" << std::distance(connI,i);
5914 oss << " has a type " << cm.getRepr() << " not in input array of type !";
5915 throw INTERP_KERNEL::Exception(oss.str());
5918 nbPerType=tmpb.retn();
5923 * This method behaves exactly as MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec but the order is those defined in MED file spec.
5925 * \return a new object containing the old to new correspondance.
5927 * \sa MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec, MEDCouplingUMesh::sortCellsInMEDFileFrmt.
5929 DataArrayInt *MEDCouplingUMesh::getRenumArrForMEDFileFrmt() const
5931 return getRenumArrForConsecutiveCellTypesSpec(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
5935 * 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.
5936 * This method returns an array of size getNumberOfCells() that gives a renumber array old2New that can be used as input of MEDCouplingMesh::renumberCells.
5937 * The mesh after this call to MEDCouplingMesh::renumberCells will pass the test of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder with the same inputs.
5938 * The returned array minimizes the permutations that is to say the order of cells inside same geometric type remains the same.
5940 DataArrayInt *MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
5942 DataArrayInt *nbPerType=0;
5943 MCAuto<DataArrayInt> tmpa=getLevArrPerCellTypes(orderBg,orderEnd,nbPerType);
5944 nbPerType->decrRef();
5945 return tmpa->buildPermArrPerLevel();
5949 * This method reorganize the cells of \a this so that the cells with same geometric types are put together.
5950 * The number of cells remains unchanged after the call of this method.
5951 * This method tries to minimizes the number of needed permutations. So, this method behaves not exactly as
5952 * MEDCouplingUMesh::sortCellsInMEDFileFrmt.
5954 * \return the array giving the correspondance old to new.
5956 DataArrayInt *MEDCouplingUMesh::rearrange2ConsecutiveCellTypes()
5958 checkFullyDefined();
5960 const int *conn=_nodal_connec->begin();
5961 const int *connI=_nodal_connec_index->begin();
5962 int nbOfCells=getNumberOfCells();
5963 std::vector<INTERP_KERNEL::NormalizedCellType> types;
5964 for(const int *i=connI;i!=connI+nbOfCells && (types.size()!=_types.size());)
5965 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)conn[*i])==types.end())
5967 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5968 types.push_back(curType);
5969 for(i++;i!=connI+nbOfCells && (INTERP_KERNEL::NormalizedCellType)conn[*i]==curType;i++);
5971 DataArrayInt *ret=DataArrayInt::New();
5972 ret->alloc(nbOfCells,1);
5973 int *retPtr=ret->getPointer();
5974 std::fill(retPtr,retPtr+nbOfCells,-1);
5976 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
5978 for(const int *i=connI;i!=connI+nbOfCells;i++)
5979 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
5980 retPtr[std::distance(connI,i)]=newCellId++;
5982 renumberCells(retPtr,false);
5987 * This method splits \a this into as mush as untructured meshes that consecutive set of same type cells.
5988 * So this method has typically a sense if MEDCouplingUMesh::checkConsecutiveCellTypes has a sense.
5989 * This method makes asumption that connectivity is correctly set before calling.
5991 std::vector<MEDCouplingUMesh *> MEDCouplingUMesh::splitByType() const
5993 checkConnectivityFullyDefined();
5994 const int *conn=_nodal_connec->begin();
5995 const int *connI=_nodal_connec_index->begin();
5996 int nbOfCells=getNumberOfCells();
5997 std::vector<MEDCouplingUMesh *> ret;
5998 for(const int *i=connI;i!=connI+nbOfCells;)
6000 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6001 int beginCellId=(int)std::distance(connI,i);
6002 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
6003 int endCellId=(int)std::distance(connI,i);
6004 int sz=endCellId-beginCellId;
6005 int *cells=new int[sz];
6006 for(int j=0;j<sz;j++)
6007 cells[j]=beginCellId+j;
6008 MEDCouplingUMesh *m=(MEDCouplingUMesh *)buildPartOfMySelf(cells,cells+sz,true);
6016 * This method performs the opposite operation than those in MEDCoupling1SGTUMesh::buildUnstructured.
6017 * If \a this is a single geometric type unstructured mesh, it will be converted into a more compact data structure,
6018 * MEDCoupling1GTUMesh instance. The returned instance will aggregate the same DataArrayDouble instance of coordinates than \a this.
6020 * \return a newly allocated instance, that the caller must manage.
6021 * \throw If \a this contains more than one geometric type.
6022 * \throw If the nodal connectivity of \a this is not fully defined.
6023 * \throw If the internal data is not coherent.
6025 MEDCoupling1GTUMesh *MEDCouplingUMesh::convertIntoSingleGeoTypeMesh() const
6027 checkConnectivityFullyDefined();
6028 if(_types.size()!=1)
6029 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6030 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6031 MCAuto<MEDCoupling1GTUMesh> ret=MEDCoupling1GTUMesh::New(getName(),typ);
6032 ret->setCoords(getCoords());
6033 MEDCoupling1SGTUMesh *retC=dynamic_cast<MEDCoupling1SGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6036 MCAuto<DataArrayInt> c=convertNodalConnectivityToStaticGeoTypeMesh();
6037 retC->setNodalConnectivity(c);
6041 MEDCoupling1DGTUMesh *retD=dynamic_cast<MEDCoupling1DGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6043 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : Internal error !");
6044 DataArrayInt *c=0,*ci=0;
6045 convertNodalConnectivityToDynamicGeoTypeMesh(c,ci);
6046 MCAuto<DataArrayInt> cs(c),cis(ci);
6047 retD->setNodalConnectivity(cs,cis);
6052 DataArrayInt *MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh() const
6054 checkConnectivityFullyDefined();
6055 if(_types.size()!=1)
6056 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6057 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6058 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6061 std::ostringstream oss; oss << "MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : this contains a single geo type (" << cm.getRepr() << ") but ";
6062 oss << "this type is dynamic ! Only static geometric type is possible for that type ! call convertNodalConnectivityToDynamicGeoTypeMesh instead !";
6063 throw INTERP_KERNEL::Exception(oss.str());
6065 int nbCells=getNumberOfCells();
6067 int nbNodesPerCell=(int)cm.getNumberOfNodes();
6068 MCAuto<DataArrayInt> connOut=DataArrayInt::New(); connOut->alloc(nbCells*nbNodesPerCell,1);
6069 int *outPtr=connOut->getPointer();
6070 const int *conn=_nodal_connec->begin();
6071 const int *connI=_nodal_connec_index->begin();
6073 for(int i=0;i<nbCells;i++,connI++)
6075 if(conn[connI[0]]==typi && connI[1]-connI[0]==nbNodesPerCell)
6076 outPtr=std::copy(conn+connI[0]+1,conn+connI[1],outPtr);
6079 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 << ") !";
6080 throw INTERP_KERNEL::Exception(oss.str());
6083 return connOut.retn();
6087 * Convert the nodal connectivity of the mesh so that all the cells are of dynamic types (polygon or quadratic
6088 * polygon). This returns the corresponding new nodal connectivity in \ref numbering-indirect format.
6092 void MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh(DataArrayInt *&nodalConn, DataArrayInt *&nodalConnIndex) const
6094 static const char msg0[]="MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : nodal connectivity in this are invalid ! Call checkConsistency !";
6095 checkConnectivityFullyDefined();
6096 if(_types.size()!=1)
6097 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6098 int nbCells=getNumberOfCells(),lgth=_nodal_connec->getNumberOfTuples();
6100 throw INTERP_KERNEL::Exception(msg0);
6101 MCAuto<DataArrayInt> c(DataArrayInt::New()),ci(DataArrayInt::New());
6102 c->alloc(lgth-nbCells,1); ci->alloc(nbCells+1,1);
6103 int *cp(c->getPointer()),*cip(ci->getPointer());
6104 const int *incp(_nodal_connec->begin()),*incip(_nodal_connec_index->begin());
6106 for(int i=0;i<nbCells;i++,cip++,incip++)
6108 int strt(incip[0]+1),stop(incip[1]);//+1 to skip geo type
6109 int delta(stop-strt);
6112 if((strt>=0 && strt<lgth) && (stop>=0 && stop<=lgth))
6113 cp=std::copy(incp+strt,incp+stop,cp);
6115 throw INTERP_KERNEL::Exception(msg0);
6118 throw INTERP_KERNEL::Exception(msg0);
6119 cip[1]=cip[0]+delta;
6121 nodalConn=c.retn(); nodalConnIndex=ci.retn();
6125 * This method takes in input a vector of MEDCouplingUMesh instances lying on the same coordinates with same mesh dimensions.
6126 * Each mesh in \b ms must be sorted by type with the same order (typically using MEDCouplingUMesh::sortCellsInMEDFileFrmt).
6127 * This method is particulary useful for MED file interaction. It allows to aggregate several meshes and keeping the type sorting
6128 * and the track of the permutation by chunk of same geotype cells to retrieve it. The traditional formats old2new and new2old
6129 * are not used here to avoid the build of big permutation array.
6131 * \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
6132 * those specified in MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6133 * \param [out] szOfCellGrpOfSameType is a newly allocated DataArrayInt instance whose number of tuples is equal to the number of chunks of same geotype
6134 * in all meshes in \b ms. The accumulation of all values of this array is equal to the number of cells of returned mesh.
6135 * \param [out] idInMsOfCellGrpOfSameType is a newly allocated DataArrayInt instance having the same size than \b szOfCellGrpOfSameType. This
6136 * output array gives for each chunck of same type the corresponding mesh id in \b ms.
6137 * \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
6138 * is sorted by type following the geo cell types order of MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6140 MEDCouplingUMesh *MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& ms,
6141 DataArrayInt *&szOfCellGrpOfSameType,
6142 DataArrayInt *&idInMsOfCellGrpOfSameType)
6144 std::vector<const MEDCouplingUMesh *> ms2;
6145 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms.begin();it!=ms.end();it++)
6148 (*it)->checkConnectivityFullyDefined();
6152 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : input vector is empty !");
6153 const DataArrayDouble *refCoo=ms2[0]->getCoords();
6154 int meshDim=ms2[0]->getMeshDimension();
6155 std::vector<const MEDCouplingUMesh *> m1ssm;
6156 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmAuto;
6158 std::vector<const MEDCouplingUMesh *> m1ssmSingle;
6159 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmSingleAuto;
6161 MCAuto<DataArrayInt> ret1(DataArrayInt::New()),ret2(DataArrayInt::New());
6162 ret1->alloc(0,1); ret2->alloc(0,1);
6163 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms2.begin();it!=ms2.end();it++,rk++)
6165 if(meshDim!=(*it)->getMeshDimension())
6166 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshdims mismatch !");
6167 if(refCoo!=(*it)->getCoords())
6168 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshes are not shared by a single coordinates coords !");
6169 std::vector<MEDCouplingUMesh *> sp=(*it)->splitByType();
6170 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<const MEDCouplingUMesh *> >(m1ssm));
6171 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<MCAuto<MEDCouplingUMesh> > >(m1ssmAuto));
6172 for(std::vector<MEDCouplingUMesh *>::const_iterator it2=sp.begin();it2!=sp.end();it2++)
6174 MEDCouplingUMesh *singleCell=static_cast<MEDCouplingUMesh *>((*it2)->buildPartOfMySelf(&fake,&fake+1,true));
6175 m1ssmSingleAuto.push_back(singleCell);
6176 m1ssmSingle.push_back(singleCell);
6177 ret1->pushBackSilent((*it2)->getNumberOfCells()); ret2->pushBackSilent(rk);
6180 MCAuto<MEDCouplingUMesh> m1ssmSingle2=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmSingle);
6181 MCAuto<DataArrayInt> renum=m1ssmSingle2->sortCellsInMEDFileFrmt();
6182 std::vector<const MEDCouplingUMesh *> m1ssmfinal(m1ssm.size());
6183 for(std::size_t i=0;i<m1ssm.size();i++)
6184 m1ssmfinal[renum->getIJ(i,0)]=m1ssm[i];
6185 MCAuto<MEDCouplingUMesh> ret0=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmfinal);
6186 szOfCellGrpOfSameType=ret1->renumber(renum->begin());
6187 idInMsOfCellGrpOfSameType=ret2->renumber(renum->begin());
6192 * This method returns a newly created DataArrayInt instance.
6193 * This method retrieves cell ids in [ \a begin, \a end ) that have the type \a type.
6195 DataArrayInt *MEDCouplingUMesh::keepCellIdsByType(INTERP_KERNEL::NormalizedCellType type, const int *begin, const int *end) const
6197 checkFullyDefined();
6198 const int *conn=_nodal_connec->begin();
6199 const int *connIndex=_nodal_connec_index->begin();
6200 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(0,1);
6201 for(const int *w=begin;w!=end;w++)
6202 if((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]==type)
6203 ret->pushBackSilent(*w);
6208 * This method makes the assumption that da->getNumberOfTuples()<this->getNumberOfCells(). This method makes the assumption that ids contained in 'da'
6209 * are in [0:getNumberOfCells())
6211 DataArrayInt *MEDCouplingUMesh::convertCellArrayPerGeoType(const DataArrayInt *da) const
6213 checkFullyDefined();
6214 const int *conn=_nodal_connec->begin();
6215 const int *connI=_nodal_connec_index->begin();
6216 int nbOfCells=getNumberOfCells();
6217 std::set<INTERP_KERNEL::NormalizedCellType> types(getAllGeoTypes());
6218 int *tmp=new int[nbOfCells];
6219 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
6222 for(const int *i=connI;i!=connI+nbOfCells;i++)
6223 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
6224 tmp[std::distance(connI,i)]=j++;
6226 DataArrayInt *ret=DataArrayInt::New();
6227 ret->alloc(da->getNumberOfTuples(),da->getNumberOfComponents());
6228 ret->copyStringInfoFrom(*da);
6229 int *retPtr=ret->getPointer();
6230 const int *daPtr=da->begin();
6231 int nbOfElems=da->getNbOfElems();
6232 for(int k=0;k<nbOfElems;k++)
6233 retPtr[k]=tmp[daPtr[k]];
6239 * This method reduced number of cells of this by keeping cells whose type is different from 'type' and if type=='type'
6240 * This method \b works \b for mesh sorted by type.
6241 * cells whose ids is in 'idsPerGeoType' array.
6242 * This method conserves coords and name of mesh.
6244 MEDCouplingUMesh *MEDCouplingUMesh::keepSpecifiedCells(INTERP_KERNEL::NormalizedCellType type, const int *idsPerGeoTypeBg, const int *idsPerGeoTypeEnd) const
6246 std::vector<int> code=getDistributionOfTypes();
6247 std::size_t nOfTypesInThis=code.size()/3;
6248 int sz=0,szOfType=0;
6249 for(std::size_t i=0;i<nOfTypesInThis;i++)
6254 szOfType=code[3*i+1];
6256 for(const int *work=idsPerGeoTypeBg;work!=idsPerGeoTypeEnd;work++)
6257 if(*work<0 || *work>=szOfType)
6259 std::ostringstream oss; oss << "MEDCouplingUMesh::keepSpecifiedCells : Request on type " << type << " at place #" << std::distance(idsPerGeoTypeBg,work) << " value " << *work;
6260 oss << ". It should be in [0," << szOfType << ") !";
6261 throw INTERP_KERNEL::Exception(oss.str());
6263 MCAuto<DataArrayInt> idsTokeep=DataArrayInt::New(); idsTokeep->alloc(sz+(int)std::distance(idsPerGeoTypeBg,idsPerGeoTypeEnd),1);
6264 int *idsPtr=idsTokeep->getPointer();
6266 for(std::size_t i=0;i<nOfTypesInThis;i++)
6269 for(int j=0;j<code[3*i+1];j++)
6272 idsPtr=std::transform(idsPerGeoTypeBg,idsPerGeoTypeEnd,idsPtr,std::bind2nd(std::plus<int>(),offset));
6273 offset+=code[3*i+1];
6275 MCAuto<MEDCouplingUMesh> ret=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(idsTokeep->begin(),idsTokeep->end(),true));
6276 ret->copyTinyInfoFrom(this);
6281 * This method returns a vector of size 'this->getNumberOfCells()'.
6282 * This method retrieves for each cell in \a this if it is linear (false) or quadratic(true).
6284 std::vector<bool> MEDCouplingUMesh::getQuadraticStatus() const
6286 int ncell=getNumberOfCells();
6287 std::vector<bool> ret(ncell);
6288 const int *cI=getNodalConnectivityIndex()->begin();
6289 const int *c=getNodalConnectivity()->begin();
6290 for(int i=0;i<ncell;i++)
6292 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[i]];
6293 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6294 ret[i]=cm.isQuadratic();
6300 * Returns a newly created mesh (with ref count ==1) that contains merge of \a this and \a other.
6302 MEDCouplingMesh *MEDCouplingUMesh::mergeMyselfWith(const MEDCouplingMesh *other) const
6304 if(other->getType()!=UNSTRUCTURED)
6305 throw INTERP_KERNEL::Exception("Merge of umesh only available with umesh each other !");
6306 const MEDCouplingUMesh *otherC=static_cast<const MEDCouplingUMesh *>(other);
6307 return MergeUMeshes(this,otherC);
6311 * Returns a new DataArrayDouble holding barycenters of all cells. The barycenter is
6312 * computed by averaging coordinates of cell nodes, so this method is not a right
6313 * choice for degnerated meshes (not well oriented, cells with measure close to zero).
6314 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
6315 * this->getNumberOfCells() tuples per \a this->getSpaceDimension()
6316 * components. The caller is to delete this array using decrRef() as it is
6318 * \throw If the coordinates array is not set.
6319 * \throw If the nodal connectivity of cells is not defined.
6320 * \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
6322 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMass() const
6324 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6325 int spaceDim=getSpaceDimension();
6326 int nbOfCells=getNumberOfCells();
6327 ret->alloc(nbOfCells,spaceDim);
6328 ret->copyStringInfoFrom(*getCoords());
6329 double *ptToFill=ret->getPointer();
6330 const int *nodal=_nodal_connec->begin();
6331 const int *nodalI=_nodal_connec_index->begin();
6332 const double *coor=_coords->begin();
6333 for(int i=0;i<nbOfCells;i++)
6335 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6336 INTERP_KERNEL::computeBarycenter2<int,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[i]+1,nodalI[i+1]-nodalI[i]-1,coor,spaceDim,ptToFill);
6343 * This method computes for each cell in \a this, the location of the iso barycenter of nodes constituting
6344 * the cell. Contrary to badly named MEDCouplingUMesh::computeCellCenterOfMass method that returns the center of inertia of the
6346 * \return a newly allocated DataArrayDouble instance that the caller has to deal with. The returned
6347 * DataArrayDouble instance will have \c this->getNumberOfCells() tuples and \c this->getSpaceDimension() components.
6349 * \sa MEDCouplingUMesh::computeCellCenterOfMass
6350 * \throw If \a this is not fully defined (coordinates and connectivity)
6351 * \throw If there is presence in nodal connectivity in \a this of node ids not in [0, \c this->getNumberOfNodes() )
6353 DataArrayDouble *MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell() const
6355 checkFullyDefined();
6356 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6357 int spaceDim=getSpaceDimension();
6358 int nbOfCells=getNumberOfCells();
6359 int nbOfNodes=getNumberOfNodes();
6360 ret->alloc(nbOfCells,spaceDim);
6361 double *ptToFill=ret->getPointer();
6362 const int *nodal=_nodal_connec->begin();
6363 const int *nodalI=_nodal_connec_index->begin();
6364 const double *coor=_coords->begin();
6365 for(int i=0;i<nbOfCells;i++,ptToFill+=spaceDim)
6367 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6368 std::fill(ptToFill,ptToFill+spaceDim,0.);
6369 if(type!=INTERP_KERNEL::NORM_POLYHED)
6371 for(const int *conn=nodal+nodalI[i]+1;conn!=nodal+nodalI[i+1];conn++)
6373 if(*conn>=0 && *conn<nbOfNodes)
6374 std::transform(coor+spaceDim*conn[0],coor+spaceDim*(conn[0]+1),ptToFill,ptToFill,std::plus<double>());
6377 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of nodeId #" << *conn << " should be in [0," << nbOfNodes << ") !";
6378 throw INTERP_KERNEL::Exception(oss.str());
6381 int nbOfNodesInCell=nodalI[i+1]-nodalI[i]-1;
6382 if(nbOfNodesInCell>0)
6383 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies<double>(),1./(double)nbOfNodesInCell));
6386 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of cell with no nodes !";
6387 throw INTERP_KERNEL::Exception(oss.str());
6392 std::set<int> s(nodal+nodalI[i]+1,nodal+nodalI[i+1]);
6394 for(std::set<int>::const_iterator it=s.begin();it!=s.end();it++)
6396 if(*it>=0 && *it<nbOfNodes)
6397 std::transform(coor+spaceDim*(*it),coor+spaceDim*((*it)+1),ptToFill,ptToFill,std::plus<double>());
6400 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell polyhedron cell #" << i << " presence of nodeId #" << *it << " should be in [0," << nbOfNodes << ") !";
6401 throw INTERP_KERNEL::Exception(oss.str());
6405 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies<double>(),1./(double)s.size()));
6408 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on polyhedron cell #" << i << " there are no nodes !";
6409 throw INTERP_KERNEL::Exception(oss.str());
6417 * Returns a new DataArrayDouble holding barycenters of specified cells. The
6418 * barycenter is computed by averaging coordinates of cell nodes. The cells to treat
6419 * are specified via an array of cell ids.
6420 * \warning Validity of the specified cell ids is not checked!
6421 * Valid range is [ 0, \a this->getNumberOfCells() ).
6422 * \param [in] begin - an array of cell ids of interest.
6423 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
6424 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size ( \a
6425 * end - \a begin ) tuples per \a this->getSpaceDimension() components. The
6426 * caller is to delete this array using decrRef() as it is no more needed.
6427 * \throw If the coordinates array is not set.
6428 * \throw If the nodal connectivity of cells is not defined.
6430 * \if ENABLE_EXAMPLES
6431 * \ref cpp_mcumesh_getPartBarycenterAndOwner "Here is a C++ example".<br>
6432 * \ref py_mcumesh_getPartBarycenterAndOwner "Here is a Python example".
6435 DataArrayDouble *MEDCouplingUMesh::getPartBarycenterAndOwner(const int *begin, const int *end) const
6437 DataArrayDouble *ret=DataArrayDouble::New();
6438 int spaceDim=getSpaceDimension();
6439 int nbOfTuple=(int)std::distance(begin,end);
6440 ret->alloc(nbOfTuple,spaceDim);
6441 double *ptToFill=ret->getPointer();
6442 double *tmp=new double[spaceDim];
6443 const int *nodal=_nodal_connec->begin();
6444 const int *nodalI=_nodal_connec_index->begin();
6445 const double *coor=_coords->begin();
6446 for(const int *w=begin;w!=end;w++)
6448 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[*w]];
6449 INTERP_KERNEL::computeBarycenter2<int,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[*w]+1,nodalI[*w+1]-nodalI[*w]-1,coor,spaceDim,ptToFill);
6457 * 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".
6458 * So the returned instance will have 4 components and \c this->getNumberOfCells() tuples.
6459 * So this method expects that \a this has a spaceDimension equal to 3 and meshDimension equal to 2.
6460 * The computation of the plane equation is done using each time the 3 first nodes of 2D cells.
6461 * This method is useful to detect 2D cells in 3D space that are not coplanar.
6463 * \return DataArrayDouble * - a new instance of DataArrayDouble having 4 components and a number of tuples equal to number of cells in \a this.
6464 * \throw If spaceDim!=3 or meshDim!=2.
6465 * \throw If connectivity of \a this is invalid.
6466 * \throw If connectivity of a cell in \a this points to an invalid node.
6468 DataArrayDouble *MEDCouplingUMesh::computePlaneEquationOf3DFaces() const
6470 MCAuto<DataArrayDouble> ret(DataArrayDouble::New());
6471 int nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
6472 if(getSpaceDimension()!=3 || getMeshDimension()!=2)
6473 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computePlaneEquationOf3DFaces : This method must be applied on a mesh having meshDimension equal 2 and a spaceDimension equal to 3 !");
6474 ret->alloc(nbOfCells,4);
6475 double *retPtr(ret->getPointer());
6476 const int *nodal(_nodal_connec->begin()),*nodalI(_nodal_connec_index->begin());
6477 const double *coor(_coords->begin());
6478 for(int i=0;i<nbOfCells;i++,nodalI++,retPtr+=4)
6480 double matrix[16]={0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,0},matrix2[16];
6481 if(nodalI[1]-nodalI[0]>=4)
6483 double aa[3]={coor[nodal[nodalI[0]+1+1]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6484 coor[nodal[nodalI[0]+1+1]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6485 coor[nodal[nodalI[0]+1+1]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]}
6486 ,bb[3]={coor[nodal[nodalI[0]+1+2]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6487 coor[nodal[nodalI[0]+1+2]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6488 coor[nodal[nodalI[0]+1+2]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]};
6489 double cc[3]={aa[1]*bb[2]-aa[2]*bb[1],aa[2]*bb[0]-aa[0]*bb[2],aa[0]*bb[1]-aa[1]*bb[0]};
6490 for(int j=0;j<3;j++)
6492 int nodeId(nodal[nodalI[0]+1+j]);
6493 if(nodeId>=0 && nodeId<nbOfNodes)
6494 std::copy(coor+nodeId*3,coor+(nodeId+1)*3,matrix+4*j);
6497 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! This cell points to an invalid nodeId : " << nodeId << " !";
6498 throw INTERP_KERNEL::Exception(oss.str());
6501 if(sqrt(cc[0]*cc[0]+cc[1]*cc[1]+cc[2]*cc[2])>1e-7)
6503 INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6504 retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6508 if(nodalI[1]-nodalI[0]==4)
6510 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : cell" << i << " : Presence of The 3 colinear points !";
6511 throw INTERP_KERNEL::Exception(oss.str());
6514 double dd[3]={0.,0.,0.};
6515 for(int offset=nodalI[0]+1;offset<nodalI[1];offset++)
6516 std::transform(coor+3*nodal[offset],coor+3*(nodal[offset]+1),dd,dd,std::plus<double>());
6517 int nbOfNodesInCell(nodalI[1]-nodalI[0]-1);
6518 std::transform(dd,dd+3,dd,std::bind2nd(std::multiplies<double>(),1./(double)nbOfNodesInCell));
6519 std::copy(dd,dd+3,matrix+4*2);
6520 INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6521 retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6526 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! Must be constitued by more than 3 nodes !";
6527 throw INTERP_KERNEL::Exception(oss.str());
6534 * This method expects as input a DataArrayDouble non nul instance 'da' that should be allocated. If not an exception is thrown.
6537 MEDCouplingUMesh *MEDCouplingUMesh::Build0DMeshFromCoords(DataArrayDouble *da)
6540 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build0DMeshFromCoords : instance of DataArrayDouble must be not null !");
6541 da->checkAllocated();
6542 std::string name(da->getName());
6543 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New(name,0));
6545 ret->setName("Mesh");
6547 int nbOfTuples(da->getNumberOfTuples());
6548 MCAuto<DataArrayInt> c(DataArrayInt::New()),cI(DataArrayInt::New());
6549 c->alloc(2*nbOfTuples,1);
6550 cI->alloc(nbOfTuples+1,1);
6551 int *cp(c->getPointer()),*cip(cI->getPointer());
6553 for(int i=0;i<nbOfTuples;i++)
6555 *cp++=INTERP_KERNEL::NORM_POINT1;
6559 ret->setConnectivity(c,cI,true);
6563 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::Build1DMeshFromCoords(DataArrayDouble *da)
6566 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build01MeshFromCoords : instance of DataArrayDouble must be not null !");
6567 da->checkAllocated();
6568 std::string name(da->getName());
6569 MCAuto<MEDCouplingUMesh> ret;
6571 MCAuto<MEDCouplingCMesh> tmp(MEDCouplingCMesh::New());
6572 MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
6573 arr->alloc(da->getNumberOfTuples());
6574 tmp->setCoordsAt(0,arr);
6575 ret=tmp->buildUnstructured();
6579 ret->setName("Mesh");
6586 * Creates a new MEDCouplingUMesh by concatenating two given meshes of the same dimension.
6587 * Cells and nodes of
6588 * the first mesh precede cells and nodes of the second mesh within the result mesh.
6589 * \param [in] mesh1 - the first mesh.
6590 * \param [in] mesh2 - the second mesh.
6591 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6592 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6593 * is no more needed.
6594 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
6595 * \throw If the coordinates array is not set in none of the meshes.
6596 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
6597 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
6599 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
6601 std::vector<const MEDCouplingUMesh *> tmp(2);
6602 tmp[0]=const_cast<MEDCouplingUMesh *>(mesh1); tmp[1]=const_cast<MEDCouplingUMesh *>(mesh2);
6603 return MergeUMeshes(tmp);
6607 * Creates a new MEDCouplingUMesh by concatenating all given meshes of the same dimension.
6608 * Cells and nodes of
6609 * the *i*-th mesh precede cells and nodes of the (*i*+1)-th mesh within the result mesh.
6610 * \param [in] a - a vector of meshes (MEDCouplingUMesh) to concatenate.
6611 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6612 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6613 * is no more needed.
6614 * \throw If \a a.size() == 0.
6615 * \throw If \a a[ *i* ] == NULL.
6616 * \throw If the coordinates array is not set in none of the meshes.
6617 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
6618 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
6620 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const std::vector<const MEDCouplingUMesh *>& a)
6622 std::size_t sz=a.size();
6624 return MergeUMeshesLL(a);
6625 for(std::size_t ii=0;ii<sz;ii++)
6628 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshes : item #" << ii << " in input array of size "<< sz << " is empty !";
6629 throw INTERP_KERNEL::Exception(oss.str());
6631 std::vector< MCAuto<MEDCouplingUMesh> > bb(sz);
6632 std::vector< const MEDCouplingUMesh * > aa(sz);
6634 for(std::size_t i=0;i<sz && spaceDim==-3;i++)
6636 const MEDCouplingUMesh *cur=a[i];
6637 const DataArrayDouble *coo=cur->getCoords();
6639 spaceDim=coo->getNumberOfComponents();
6642 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : no spaceDim specified ! unable to perform merge !");
6643 for(std::size_t i=0;i<sz;i++)
6645 bb[i]=a[i]->buildSetInstanceFromThis(spaceDim);
6648 return MergeUMeshesLL(aa);
6652 * Creates a new MEDCouplingUMesh by concatenating cells of two given meshes of same
6653 * dimension and sharing the node coordinates array.
6654 * All cells of the first mesh precede all cells of the second mesh
6655 * within the result mesh.
6656 * \param [in] mesh1 - the first mesh.
6657 * \param [in] mesh2 - the second mesh.
6658 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6659 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6660 * is no more needed.
6661 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
6662 * \throw If the meshes do not share the node coordinates array.
6663 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
6664 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
6666 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
6668 std::vector<const MEDCouplingUMesh *> tmp(2);
6669 tmp[0]=mesh1; tmp[1]=mesh2;
6670 return MergeUMeshesOnSameCoords(tmp);
6674 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
6675 * dimension and sharing the node coordinates array.
6676 * All cells of the *i*-th mesh precede all cells of the
6677 * (*i*+1)-th mesh within the result mesh.
6678 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
6679 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6680 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6681 * is no more needed.
6682 * \throw If \a a.size() == 0.
6683 * \throw If \a a[ *i* ] == NULL.
6684 * \throw If the meshes do not share the node coordinates array.
6685 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
6686 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
6688 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes)
6691 throw INTERP_KERNEL::Exception("meshes input parameter is expected to be non empty.");
6692 for(std::size_t ii=0;ii<meshes.size();ii++)
6695 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshesOnSameCoords : item #" << ii << " in input array of size "<< meshes.size() << " is empty !";
6696 throw INTERP_KERNEL::Exception(oss.str());
6698 const DataArrayDouble *coords=meshes.front()->getCoords();
6699 int meshDim=meshes.front()->getMeshDimension();
6700 std::vector<const MEDCouplingUMesh *>::const_iterator iter=meshes.begin();
6702 int meshIndexLgth=0;
6703 for(;iter!=meshes.end();iter++)
6705 if(coords!=(*iter)->getCoords())
6706 throw INTERP_KERNEL::Exception("meshes does not share the same coords ! Try using tryToShareSameCoords method !");
6707 if(meshDim!=(*iter)->getMeshDimension())
6708 throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, FuseUMeshesOnSameCoords impossible !");
6709 meshLgth+=(*iter)->getNodalConnectivityArrayLen();
6710 meshIndexLgth+=(*iter)->getNumberOfCells();
6712 MCAuto<DataArrayInt> nodal=DataArrayInt::New();
6713 nodal->alloc(meshLgth,1);
6714 int *nodalPtr=nodal->getPointer();
6715 MCAuto<DataArrayInt> nodalIndex=DataArrayInt::New();
6716 nodalIndex->alloc(meshIndexLgth+1,1);
6717 int *nodalIndexPtr=nodalIndex->getPointer();
6719 for(iter=meshes.begin();iter!=meshes.end();iter++)
6721 const int *nod=(*iter)->getNodalConnectivity()->begin();
6722 const int *index=(*iter)->getNodalConnectivityIndex()->begin();
6723 int nbOfCells=(*iter)->getNumberOfCells();
6724 int meshLgth2=(*iter)->getNodalConnectivityArrayLen();
6725 nodalPtr=std::copy(nod,nod+meshLgth2,nodalPtr);
6726 if(iter!=meshes.begin())
6727 nodalIndexPtr=std::transform(index+1,index+nbOfCells+1,nodalIndexPtr,std::bind2nd(std::plus<int>(),offset));
6729 nodalIndexPtr=std::copy(index,index+nbOfCells+1,nodalIndexPtr);
6732 MEDCouplingUMesh *ret=MEDCouplingUMesh::New();
6733 ret->setName("merge");
6734 ret->setMeshDimension(meshDim);
6735 ret->setConnectivity(nodal,nodalIndex,true);
6736 ret->setCoords(coords);
6741 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
6742 * dimension and sharing the node coordinates array. Cells of the *i*-th mesh precede
6743 * cells of the (*i*+1)-th mesh within the result mesh. Duplicates of cells are
6744 * removed from \a this mesh and arrays mapping between new and old cell ids in "Old to
6745 * New" mode are returned for each input mesh.
6746 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
6747 * \param [in] compType - specifies a cell comparison technique. For meaning of its
6748 * valid values [0,1,2], see zipConnectivityTraducer().
6749 * \param [in,out] corr - an array of DataArrayInt, of the same size as \a
6750 * meshes. The *i*-th array describes cell ids mapping for \a meshes[ *i* ]
6751 * mesh. The caller is to delete each of the arrays using decrRef() as it is
6753 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6754 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6755 * is no more needed.
6756 * \throw If \a meshes.size() == 0.
6757 * \throw If \a meshes[ *i* ] == NULL.
6758 * \throw If the meshes do not share the node coordinates array.
6759 * \throw If \a meshes[ *i* ]->getMeshDimension() < 0.
6760 * \throw If the \a meshes are of different dimension (getMeshDimension()).
6761 * \throw If the nodal connectivity of cells of any of \a meshes is not defined.
6762 * \throw If the nodal connectivity any of \a meshes includes an invalid id.
6764 MEDCouplingUMesh *MEDCouplingUMesh::FuseUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes, int compType, std::vector<DataArrayInt *>& corr)
6766 //All checks are delegated to MergeUMeshesOnSameCoords
6767 MCAuto<MEDCouplingUMesh> ret=MergeUMeshesOnSameCoords(meshes);
6768 MCAuto<DataArrayInt> o2n=ret->zipConnectivityTraducer(compType);
6769 corr.resize(meshes.size());
6770 std::size_t nbOfMeshes=meshes.size();
6772 const int *o2nPtr=o2n->begin();
6773 for(std::size_t i=0;i<nbOfMeshes;i++)
6775 DataArrayInt *tmp=DataArrayInt::New();
6776 int curNbOfCells=meshes[i]->getNumberOfCells();
6777 tmp->alloc(curNbOfCells,1);
6778 std::copy(o2nPtr+offset,o2nPtr+offset+curNbOfCells,tmp->getPointer());
6779 offset+=curNbOfCells;
6780 tmp->setName(meshes[i]->getName());
6787 * Makes all given meshes share the nodal connectivity array. The common connectivity
6788 * array is created by concatenating the connectivity arrays of all given meshes. All
6789 * the given meshes must be of the same space dimension but dimension of cells **can
6790 * differ**. This method is particulary useful in MEDLoader context to build a \ref
6791 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
6792 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
6793 * \param [in,out] meshes - a vector of meshes to update.
6794 * \throw If any of \a meshes is NULL.
6795 * \throw If the coordinates array is not set in any of \a meshes.
6796 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
6797 * \throw If \a meshes are of different space dimension.
6799 void MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords(const std::vector<MEDCouplingUMesh *>& meshes)
6801 std::size_t sz=meshes.size();
6804 std::vector< const DataArrayDouble * > coords(meshes.size());
6805 std::vector< const DataArrayDouble * >::iterator it2=coords.begin();
6806 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++,it2++)
6810 (*it)->checkConnectivityFullyDefined();
6811 const DataArrayDouble *coo=(*it)->getCoords();
6816 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
6817 oss << " has no coordinate array defined !";
6818 throw INTERP_KERNEL::Exception(oss.str());
6823 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
6824 oss << " is null !";
6825 throw INTERP_KERNEL::Exception(oss.str());
6828 MCAuto<DataArrayDouble> res=DataArrayDouble::Aggregate(coords);
6829 std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();
6830 int offset=(*it)->getNumberOfNodes();
6831 (*it++)->setCoords(res);
6832 for(;it!=meshes.end();it++)
6834 int oldNumberOfNodes=(*it)->getNumberOfNodes();
6835 (*it)->setCoords(res);
6836 (*it)->shiftNodeNumbersInConn(offset);
6837 offset+=oldNumberOfNodes;
6842 * Merges nodes coincident with a given precision within all given meshes that share
6843 * the nodal connectivity array. The given meshes **can be of different** mesh
6844 * dimension. This method is particulary useful in MEDLoader context to build a \ref
6845 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
6846 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
6847 * \param [in,out] meshes - a vector of meshes to update.
6848 * \param [in] eps - the precision used to detect coincident nodes (infinite norm).
6849 * \throw If any of \a meshes is NULL.
6850 * \throw If the \a meshes do not share the same node coordinates array.
6851 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
6853 void MEDCouplingUMesh::MergeNodesOnUMeshesSharingSameCoords(const std::vector<MEDCouplingUMesh *>& meshes, double eps)
6857 std::set<const DataArrayDouble *> s;
6858 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
6861 s.insert((*it)->getCoords());
6864 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 !";
6865 throw INTERP_KERNEL::Exception(oss.str());
6870 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 !";
6871 throw INTERP_KERNEL::Exception(oss.str());
6873 const DataArrayDouble *coo=*(s.begin());
6877 DataArrayInt *comm,*commI;
6878 coo->findCommonTuples(eps,-1,comm,commI);
6879 MCAuto<DataArrayInt> tmp1(comm),tmp2(commI);
6880 int oldNbOfNodes=coo->getNumberOfTuples();
6882 MCAuto<DataArrayInt> o2n=DataArrayInt::ConvertIndexArrayToO2N(oldNbOfNodes,comm->begin(),commI->begin(),commI->end(),newNbOfNodes);
6883 if(oldNbOfNodes==newNbOfNodes)
6885 MCAuto<DataArrayDouble> newCoords=coo->renumberAndReduce(o2n->begin(),newNbOfNodes);
6886 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
6888 (*it)->renumberNodesInConn(o2n->begin());
6889 (*it)->setCoords(newCoords);
6895 * This static operates only for coords in 3D. The polygon is specfied by its connectivity nodes in [ \a begin , \a end ).
6897 bool MEDCouplingUMesh::IsPolygonWellOriented(bool isQuadratic, const double *vec, const int *begin, const int *end, const double *coords)
6900 double v[3]={0.,0.,0.};
6901 std::size_t sz=std::distance(begin,end);
6906 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];
6907 v[1]+=coords[3*begin[i]+2]*coords[3*begin[(i+1)%sz]]-coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+2];
6908 v[2]+=coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+1]-coords[3*begin[i]+1]*coords[3*begin[(i+1)%sz]];
6910 double ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
6912 // Try using quadratic points if standard points are degenerated (for example a QPOLYG with two
6913 // SEG3 forming a circle):
6914 if (fabs(ret) < INTERP_KERNEL::DEFAULT_ABS_TOL && isQuadratic)
6916 v[0] = 0.0; v[1] = 0.0; v[2] = 0.0;
6917 for(std::size_t j=0;j<sz;j++)
6919 if (j%2) // current point i is quadratic, next point i+1 is standard
6922 ip1 = (j+1)%sz; // ip1 = "i+1"
6924 else // current point i is standard, next point i+1 is quadratic
6929 v[0]+=coords[3*begin[i]+1]*coords[3*begin[ip1]+2]-coords[3*begin[i]+2]*coords[3*begin[ip1]+1];
6930 v[1]+=coords[3*begin[i]+2]*coords[3*begin[ip1]]-coords[3*begin[i]]*coords[3*begin[ip1]+2];
6931 v[2]+=coords[3*begin[i]]*coords[3*begin[ip1]+1]-coords[3*begin[i]+1]*coords[3*begin[ip1]];
6933 ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
6939 * The polyhedron is specfied by its connectivity nodes in [ \a begin , \a end ).
6941 bool MEDCouplingUMesh::IsPolyhedronWellOriented(const int *begin, const int *end, const double *coords)
6943 std::vector<std::pair<int,int> > edges;
6944 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
6945 const int *bgFace=begin;
6946 for(std::size_t i=0;i<nbOfFaces;i++)
6948 const int *endFace=std::find(bgFace+1,end,-1);
6949 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
6950 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
6952 std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
6953 if(std::find(edges.begin(),edges.end(),p1)!=edges.end())
6955 edges.push_back(p1);
6959 return INTERP_KERNEL::calculateVolumeForPolyh2<int,INTERP_KERNEL::ALL_C_MODE>(begin,(int)std::distance(begin,end),coords)>-EPS_FOR_POLYH_ORIENTATION;
6963 * The 3D extruded static cell (PENTA6,HEXA8,HEXAGP12...) its connectivity nodes in [ \a begin , \a end ).
6965 bool MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented(const int *begin, const int *end, const double *coords)
6967 double vec0[3],vec1[3];
6968 std::size_t sz=std::distance(begin,end);
6970 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented : the length of nodal connectivity of extruded cell is not even !");
6971 int nbOfNodes=(int)sz/2;
6972 INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(begin,nbOfNodes,coords,vec0);
6973 const double *pt0=coords+3*begin[0];
6974 const double *pt1=coords+3*begin[nbOfNodes];
6975 vec1[0]=pt1[0]-pt0[0]; vec1[1]=pt1[1]-pt0[1]; vec1[2]=pt1[2]-pt0[2];
6976 return (vec0[0]*vec1[0]+vec0[1]*vec1[1]+vec0[2]*vec1[2])<0.;
6979 void MEDCouplingUMesh::CorrectExtrudedStaticCell(int *begin, int *end)
6981 std::size_t sz=std::distance(begin,end);
6982 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz];
6983 std::size_t nbOfNodes(sz/2);
6984 std::copy(begin,end,(int *)tmp);
6985 for(std::size_t j=1;j<nbOfNodes;j++)
6987 begin[j]=tmp[nbOfNodes-j];
6988 begin[j+nbOfNodes]=tmp[nbOfNodes+nbOfNodes-j];
6992 bool MEDCouplingUMesh::IsTetra4WellOriented(const int *begin, const int *end, const double *coords)
6994 std::size_t sz=std::distance(begin,end);
6996 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsTetra4WellOriented : Tetra4 cell with not 4 nodes ! Call checkConsistency !");
6997 double vec0[3],vec1[3];
6998 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[1],*pt2=coords+3*begin[2],*pt3=coords+3*begin[3];
6999 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];
7000 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;
7003 bool MEDCouplingUMesh::IsPyra5WellOriented(const int *begin, const int *end, const double *coords)
7005 std::size_t sz=std::distance(begin,end);
7007 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsPyra5WellOriented : Pyra5 cell with not 5 nodes ! Call checkConsistency !");
7009 INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(begin,4,coords,vec0);
7010 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[4];
7011 return (vec0[0]*(pt1[0]-pt0[0])+vec0[1]*(pt1[1]-pt0[1])+vec0[2]*(pt1[2]-pt0[2]))<0.;
7015 * 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 )
7016 * 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
7019 * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not.
7020 * \param [in] coords the coordinates with nb of components exactly equal to 3
7021 * \param [in] begin begin of the nodal connectivity (geometric type included) of a single polyhedron cell
7022 * \param [in] end end of nodal connectivity of a single polyhedron cell (excluded)
7023 * \param [out] res the result is put at the end of the vector without any alteration of the data.
7025 void MEDCouplingUMesh::SimplifyPolyhedronCell(double eps, const DataArrayDouble *coords, int index, DataArrayInt *res, MEDCouplingUMesh *faces,
7026 DataArrayInt *E_Fi, DataArrayInt *E_F, DataArrayInt *F_Ei, DataArrayInt *F_E)
7028 int nbFaces = E_Fi->getIJ(index + 1, 0) - E_Fi->getIJ(index, 0);
7029 MCAuto<DataArrayDouble> v=DataArrayDouble::New(); v->alloc(nbFaces,3);
7030 double *vPtr=v->getPointer();
7031 MCAuto<DataArrayDouble> p=DataArrayDouble::New(); p->alloc(nbFaces,2);
7032 double *pPtr=p->getPointer();
7033 int *e_fi = E_Fi->getPointer(), *e_f = E_F->getPointer(), *f_ei = F_Ei->getPointer(), *f_e = F_E->getPointer();
7034 const int *f_idx = faces->getNodalConnectivityIndex()->getPointer(), *f_cnn = faces->getNodalConnectivity()->getPointer();
7035 for(int i=0;i<nbFaces;i++,vPtr+=3,pPtr++)
7037 int face = e_f[e_fi[index] + i];
7038 ComputeVecAndPtOfFace(eps, coords->begin(), f_cnn + f_idx[face] + 1, f_cnn + f_idx[face + 1], vPtr, pPtr);
7039 // to differentiate faces going to different cells:
7041 for (int j = f_ei[face]; j < f_ei[face + 1]; j++)
7044 pPtr=p->getPointer(); vPtr=v->getPointer();
7045 DataArrayInt *comm1=0,*commI1=0;
7046 v->findCommonTuples(eps,-1,comm1,commI1);
7047 for (int i = 0; i < nbFaces; i++)
7048 if (comm1->findIdFirstEqual(i) < 0)
7050 comm1->pushBackSilent(i);
7051 commI1->pushBackSilent(comm1->getNumberOfTuples());
7053 MCAuto<DataArrayInt> comm1Auto(comm1),commI1Auto(commI1);
7054 const int *comm1Ptr=comm1->begin();
7055 const int *commI1Ptr=commI1->begin();
7056 int nbOfGrps1=commI1Auto->getNumberOfTuples()-1;
7057 res->pushBackSilent((int)INTERP_KERNEL::NORM_POLYHED);
7059 for(int i=0;i<nbOfGrps1;i++)
7061 int vecId=comm1Ptr[commI1Ptr[i]];
7062 MCAuto<DataArrayDouble> tmpgrp2=p->selectByTupleId(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7063 DataArrayInt *comm2=0,*commI2=0;
7064 tmpgrp2->findCommonTuples(eps,-1,comm2,commI2);
7065 for (int j = 0; j < commI1Ptr[i+1] - commI1Ptr[i]; j++)
7066 if (comm2->findIdFirstEqual(j) < 0)
7068 comm2->pushBackSilent(j);
7069 commI2->pushBackSilent(comm2->getNumberOfTuples());
7071 MCAuto<DataArrayInt> comm2Auto(comm2),commI2Auto(commI2);
7072 const int *comm2Ptr=comm2->begin();
7073 const int *commI2Ptr=commI2->begin();
7074 int nbOfGrps2=commI2Auto->getNumberOfTuples()-1;
7075 for(int j=0;j<nbOfGrps2;j++)
7077 if(commI2Ptr[j+1] == commI2Ptr[j] + 1)
7079 int face = e_f[e_fi[index] + comm1Ptr[commI1Ptr[i] + comm2Ptr[commI2Ptr[j]]]]; //hmmm
7080 res->insertAtTheEnd(f_cnn + f_idx[face] + 1, f_cnn + f_idx[face + 1]);
7081 res->pushBackSilent(-1);
7085 int pointId=comm1Ptr[commI1Ptr[i]+comm2Ptr[commI2Ptr[j]]];
7086 MCAuto<DataArrayInt> ids2=comm2->selectByTupleIdSafeSlice(commI2Ptr[j],commI2Ptr[j+1],1);
7087 ids2->transformWithIndArr(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7088 ids2->transformWithIndArr(e_f + e_fi[index], e_f + e_fi[index + 1]);
7089 MCAuto<MEDCouplingUMesh> mm3=static_cast<MEDCouplingUMesh *>(faces->buildPartOfMySelf(ids2->begin(),ids2->end(),true));
7090 MCAuto<DataArrayInt> idsNodeTmp=mm3->zipCoordsTraducer();
7091 MCAuto<DataArrayInt> idsNode=idsNodeTmp->invertArrayO2N2N2O(mm3->getNumberOfNodes());
7092 const int *idsNodePtr=idsNode->begin();
7093 double center[3]; center[0]=pPtr[2*pointId]*vPtr[3*vecId]; center[1]=pPtr[2*pointId]*vPtr[3*vecId+1]; center[2]=pPtr[2*pointId]*vPtr[3*vecId+2];
7094 double vec[3]; vec[0]=vPtr[3*vecId+1]; vec[1]=-vPtr[3*vecId]; vec[2]=0.;
7095 double norm=vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2];
7096 if(std::abs(norm)>eps)
7098 double angle=INTERP_KERNEL::EdgeArcCircle::SafeAsin(norm);
7099 mm3->rotate(center,vec,angle);
7101 mm3->changeSpaceDimension(2);
7102 MCAuto<MEDCouplingUMesh> mm4=mm3->buildSpreadZonesWithPoly();
7103 const int *conn4=mm4->getNodalConnectivity()->begin();
7104 const int *connI4=mm4->getNodalConnectivityIndex()->begin();
7105 int nbOfCells=mm4->getNumberOfCells();
7106 for(int k=0;k<nbOfCells;k++)
7109 for(const int *work=conn4+connI4[k]+1;work!=conn4+connI4[k+1];work++,l++)
7110 res->pushBackSilent(idsNodePtr[*work]);
7111 res->pushBackSilent(-1);
7116 res->popBackSilent();
7120 * 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
7121 * through origin. The plane is defined by its nodal connectivity [ \b begin, \b end ).
7123 * \param [in] eps below that value the dot product of 2 vectors is considered as colinears
7124 * \param [in] coords coordinates expected to have 3 components.
7125 * \param [in] begin start of the nodal connectivity of the face.
7126 * \param [in] end end of the nodal connectivity (excluded) of the face.
7127 * \param [out] v the normalized vector of size 3
7128 * \param [out] p the pos of plane
7130 void MEDCouplingUMesh::ComputeVecAndPtOfFace(double eps, const double *coords, const int *begin, const int *end, double *v, double *p)
7132 std::size_t nbPoints=std::distance(begin,end);
7134 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeVecAndPtOfFace : < of 3 points in face ! not able to find a plane on that face !");
7135 double vec[3]={0.,0.,0.};
7137 bool refFound=false;
7138 for(;j<nbPoints-1 && !refFound;j++)
7140 vec[0]=coords[3*begin[j+1]]-coords[3*begin[j]];
7141 vec[1]=coords[3*begin[j+1]+1]-coords[3*begin[j]+1];
7142 vec[2]=coords[3*begin[j+1]+2]-coords[3*begin[j]+2];
7143 double norm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
7147 vec[0]/=norm; vec[1]/=norm; vec[2]/=norm;
7150 for(std::size_t i=j;i<nbPoints-1;i++)
7153 curVec[0]=coords[3*begin[i+1]]-coords[3*begin[i]];
7154 curVec[1]=coords[3*begin[i+1]+1]-coords[3*begin[i]+1];
7155 curVec[2]=coords[3*begin[i+1]+2]-coords[3*begin[i]+2];
7156 double norm=sqrt(curVec[0]*curVec[0]+curVec[1]*curVec[1]+curVec[2]*curVec[2]);
7159 curVec[0]/=norm; curVec[1]/=norm; curVec[2]/=norm;
7160 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];
7161 norm=sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
7164 v[0]/=norm; v[1]/=norm; v[2]/=norm;
7165 *p=v[0]*coords[3*begin[i]]+v[1]*coords[3*begin[i]+1]+v[2]*coords[3*begin[i]+2];
7169 throw INTERP_KERNEL::Exception("Not able to find a normal vector of that 3D face !");
7173 * This method tries to obtain a well oriented polyhedron.
7174 * If the algorithm fails, an exception will be thrown.
7176 void MEDCouplingUMesh::TryToCorrectPolyhedronOrientation(int *begin, int *end, const double *coords)
7178 std::list< std::pair<int,int> > edgesOK,edgesFinished;
7179 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
7180 std::vector<bool> isPerm(nbOfFaces,false);//field on faces False: I don't know, True : oriented
7182 int *bgFace=begin,*endFace=std::find(begin+1,end,-1);
7183 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
7184 for(std::size_t l=0;l<nbOfEdgesInFace;l++) { std::pair<int,int> p1(bgFace[l],bgFace[(l+1)%nbOfEdgesInFace]); edgesOK.push_back(p1); }
7186 while(std::find(isPerm.begin(),isPerm.end(),false)!=isPerm.end())
7189 std::size_t smthChanged=0;
7190 for(std::size_t i=0;i<nbOfFaces;i++)
7192 endFace=std::find(bgFace+1,end,-1);
7193 nbOfEdgesInFace=std::distance(bgFace,endFace);
7197 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7199 std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7200 std::pair<int,int> p2(p1.second,p1.first);
7201 bool b1=std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end();
7202 bool b2=std::find(edgesOK.begin(),edgesOK.end(),p2)!=edgesOK.end();
7203 if(b1 || b2) { b=b2; isPerm[i]=true; smthChanged++; break; }
7208 std::reverse(bgFace+1,endFace);
7209 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7211 std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7212 std::pair<int,int> p2(p1.second,p1.first);
7213 if(std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end())
7214 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7215 if(std::find(edgesFinished.begin(),edgesFinished.end(),p1)!=edgesFinished.end() || std::find(edgesFinished.begin(),edgesFinished.end(),p2)!=edgesFinished.end())
7216 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7217 std::list< std::pair<int,int> >::iterator it=std::find(edgesOK.begin(),edgesOK.end(),p2);
7218 if(it!=edgesOK.end())
7221 edgesFinished.push_back(p1);
7224 edgesOK.push_back(p1);
7231 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired !"); }
7233 if(!edgesOK.empty())
7234 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired : Some edges are shared only once !"); }
7235 if(INTERP_KERNEL::calculateVolumeForPolyh2<int,INTERP_KERNEL::ALL_C_MODE>(begin,(int)std::distance(begin,end),coords)<-EPS_FOR_POLYH_ORIENTATION)
7236 {//not lucky ! The first face was not correctly oriented : reorient all faces...
7238 for(std::size_t i=0;i<nbOfFaces;i++)
7240 endFace=std::find(bgFace+1,end,-1);
7241 std::reverse(bgFace+1,endFace);
7249 * This method makes the assumption spacedimension == meshdimension == 2.
7250 * This method works only for linear cells.
7252 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYGON in pos#0)
7254 DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMesh() const
7256 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
7257 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : meshdimension, spacedimension must be equal to 2 !");
7258 MCAuto<MEDCouplingUMesh> skin(computeSkin());
7259 int oldNbOfNodes(skin->getNumberOfNodes());
7260 MCAuto<DataArrayInt> o2n(skin->zipCoordsTraducer());
7261 int nbOfNodesExpected(skin->getNumberOfNodes());
7262 MCAuto<DataArrayInt> n2o(o2n->invertArrayO2N2N2O(oldNbOfNodes));
7263 int nbCells(skin->getNumberOfCells());
7264 if(nbCells==nbOfNodesExpected)
7265 return buildUnionOf2DMeshLinear(skin,n2o);
7266 else if(2*nbCells==nbOfNodesExpected)
7267 return buildUnionOf2DMeshQuadratic(skin,n2o);
7269 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : the mesh 2D in input appears to be not in a single part of a 2D mesh !");
7273 * This method makes the assumption spacedimension == meshdimension == 3.
7274 * This method works only for linear cells.
7276 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYHED in pos#0)
7278 DataArrayInt *MEDCouplingUMesh::buildUnionOf3DMesh() const
7280 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
7281 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf3DMesh : meshdimension, spacedimension must be equal to 2 !");
7282 MCAuto<MEDCouplingUMesh> m=computeSkin();
7283 const int *conn=m->getNodalConnectivity()->begin();
7284 const int *connI=m->getNodalConnectivityIndex()->begin();
7285 int nbOfCells=m->getNumberOfCells();
7286 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(m->getNodalConnectivity()->getNumberOfTuples(),1);
7287 int *work=ret->getPointer(); *work++=INTERP_KERNEL::NORM_POLYHED;
7290 work=std::copy(conn+connI[0]+1,conn+connI[1],work);
7291 for(int i=1;i<nbOfCells;i++)
7294 work=std::copy(conn+connI[i]+1,conn+connI[i+1],work);
7300 * \brief Creates a graph of cell neighbors
7301 * \return MEDCouplingSkyLineArray * - an sky line array the user should delete.
7302 * In the sky line array, graph arcs are stored in terms of (index,value) notation.
7304 * - index: 0 3 5 6 6
7305 * - value: 1 2 3 2 3 3
7306 * means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7307 * Arcs are not doubled but reflexive (1,1) arcs are present for each cell
7309 MEDCouplingSkyLineArray* MEDCouplingUMesh::generateGraph() const
7311 checkConnectivityFullyDefined();
7313 int meshDim = this->getMeshDimension();
7314 MEDCoupling::DataArrayInt* indexr=MEDCoupling::DataArrayInt::New();
7315 MEDCoupling::DataArrayInt* revConn=MEDCoupling::DataArrayInt::New();
7316 this->getReverseNodalConnectivity(revConn,indexr);
7317 const int* indexr_ptr=indexr->begin();
7318 const int* revConn_ptr=revConn->begin();
7320 const MEDCoupling::DataArrayInt* index;
7321 const MEDCoupling::DataArrayInt* conn;
7322 conn=this->getNodalConnectivity(); // it includes a type as the 1st element!!!
7323 index=this->getNodalConnectivityIndex();
7324 int nbCells=this->getNumberOfCells();
7325 const int* index_ptr=index->begin();
7326 const int* conn_ptr=conn->begin();
7328 //creating graph arcs (cell to cell relations)
7329 //arcs are stored in terms of (index,value) notation
7332 // means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7333 // in present version arcs are not doubled but reflexive (1,1) arcs are present for each cell
7335 //warning here one node have less than or equal effective number of cell with it
7336 //but cell could have more than effective nodes
7337 //because other equals nodes in other domain (with other global inode)
7338 std::vector <int> cell2cell_index(nbCells+1,0);
7339 std::vector <int> cell2cell;
7340 cell2cell.reserve(3*nbCells);
7342 for (int icell=0; icell<nbCells;icell++)
7344 std::map<int,int > counter;
7345 for (int iconn=index_ptr[icell]+1; iconn<index_ptr[icell+1];iconn++)
7347 int inode=conn_ptr[iconn];
7348 for (int iconnr=indexr_ptr[inode]; iconnr<indexr_ptr[inode+1];iconnr++)
7350 int icell2=revConn_ptr[iconnr];
7351 std::map<int,int>::iterator iter=counter.find(icell2);
7352 if (iter!=counter.end()) (iter->second)++;
7353 else counter.insert(std::make_pair(icell2,1));
7356 for (std::map<int,int>::const_iterator iter=counter.begin();
7357 iter!=counter.end(); iter++)
7358 if (iter->second >= meshDim)
7360 cell2cell_index[icell+1]++;
7361 cell2cell.push_back(iter->first);
7366 cell2cell_index[0]=0;
7367 for (int icell=0; icell<nbCells;icell++)
7368 cell2cell_index[icell+1]=cell2cell_index[icell]+cell2cell_index[icell+1];
7370 //filling up index and value to create skylinearray structure
7371 MEDCouplingSkyLineArray * array(MEDCouplingSkyLineArray::New(cell2cell_index,cell2cell));
7376 void MEDCouplingUMesh::writeVTKLL(std::ostream& ofs, const std::string& cellData, const std::string& pointData, DataArrayByte *byteData) const
7378 int nbOfCells=getNumberOfCells();
7380 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::writeVTK : the unstructured mesh has no cells !");
7381 ofs << " <" << getVTKDataSetType() << ">\n";
7382 ofs << " <Piece NumberOfPoints=\"" << getNumberOfNodes() << "\" NumberOfCells=\"" << nbOfCells << "\">\n";
7383 ofs << " <PointData>\n" << pointData << std::endl;
7384 ofs << " </PointData>\n";
7385 ofs << " <CellData>\n" << cellData << std::endl;
7386 ofs << " </CellData>\n";
7387 ofs << " <Points>\n";
7388 if(getSpaceDimension()==3)
7389 _coords->writeVTK(ofs,8,"Points",byteData);
7392 MCAuto<DataArrayDouble> coo=_coords->changeNbOfComponents(3,0.);
7393 coo->writeVTK(ofs,8,"Points",byteData);
7395 ofs << " </Points>\n";
7396 ofs << " <Cells>\n";
7397 const int *cPtr=_nodal_connec->begin();
7398 const int *cIPtr=_nodal_connec_index->begin();
7399 MCAuto<DataArrayInt> faceoffsets=DataArrayInt::New(); faceoffsets->alloc(nbOfCells,1);
7400 MCAuto<DataArrayInt> types=DataArrayInt::New(); types->alloc(nbOfCells,1);
7401 MCAuto<DataArrayInt> offsets=DataArrayInt::New(); offsets->alloc(nbOfCells,1);
7402 MCAuto<DataArrayInt> connectivity=DataArrayInt::New(); connectivity->alloc(_nodal_connec->getNumberOfTuples()-nbOfCells,1);
7403 int *w1=faceoffsets->getPointer(),*w2=types->getPointer(),*w3=offsets->getPointer(),*w4=connectivity->getPointer();
7404 int szFaceOffsets=0,szConn=0;
7405 for(int i=0;i<nbOfCells;i++,w1++,w2++,w3++)
7408 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]!=INTERP_KERNEL::NORM_POLYHED)
7411 *w3=szConn+cIPtr[i+1]-cIPtr[i]-1; szConn+=cIPtr[i+1]-cIPtr[i]-1;
7412 w4=std::copy(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],w4);
7416 int deltaFaceOffset=cIPtr[i+1]-cIPtr[i]+1;
7417 *w1=szFaceOffsets+deltaFaceOffset; szFaceOffsets+=deltaFaceOffset;
7418 std::set<int> c(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1]); c.erase(-1);
7419 *w3=szConn+(int)c.size(); szConn+=(int)c.size();
7420 w4=std::copy(c.begin(),c.end(),w4);
7423 types->transformWithIndArr(MEDCOUPLING2VTKTYPETRADUCER,MEDCOUPLING2VTKTYPETRADUCER+INTERP_KERNEL::NORM_MAXTYPE+1);
7424 types->writeVTK(ofs,8,"UInt8","types",byteData);
7425 offsets->writeVTK(ofs,8,"Int32","offsets",byteData);
7426 if(szFaceOffsets!=0)
7427 {//presence of Polyhedra
7428 connectivity->reAlloc(szConn);
7429 faceoffsets->writeVTK(ofs,8,"Int32","faceoffsets",byteData);
7430 MCAuto<DataArrayInt> faces=DataArrayInt::New(); faces->alloc(szFaceOffsets,1);
7431 w1=faces->getPointer();
7432 for(int i=0;i<nbOfCells;i++)
7433 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]==INTERP_KERNEL::NORM_POLYHED)
7435 int nbFaces=std::count(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],-1)+1;
7437 const int *w6=cPtr+cIPtr[i]+1,*w5=0;
7438 for(int j=0;j<nbFaces;j++)
7440 w5=std::find(w6,cPtr+cIPtr[i+1],-1);
7441 *w1++=(int)std::distance(w6,w5);
7442 w1=std::copy(w6,w5,w1);
7446 faces->writeVTK(ofs,8,"Int32","faces",byteData);
7448 connectivity->writeVTK(ofs,8,"Int32","connectivity",byteData);
7449 ofs << " </Cells>\n";
7450 ofs << " </Piece>\n";
7451 ofs << " </" << getVTKDataSetType() << ">\n";
7454 void MEDCouplingUMesh::reprQuickOverview(std::ostream& stream) const
7456 stream << "MEDCouplingUMesh C++ instance at " << this << ". Name : \"" << getName() << "\".";
7458 { stream << " Not set !"; return ; }
7459 stream << " Mesh dimension : " << _mesh_dim << ".";
7463 { stream << " No coordinates set !"; return ; }
7464 if(!_coords->isAllocated())
7465 { stream << " Coordinates set but not allocated !"; return ; }
7466 stream << " Space dimension : " << _coords->getNumberOfComponents() << "." << std::endl;
7467 stream << "Number of nodes : " << _coords->getNumberOfTuples() << ".";
7468 if(!_nodal_connec_index)
7469 { stream << std::endl << "Nodal connectivity NOT set !"; return ; }
7470 if(!_nodal_connec_index->isAllocated())
7471 { stream << std::endl << "Nodal connectivity set but not allocated !"; return ; }
7472 int lgth=_nodal_connec_index->getNumberOfTuples();
7473 int cpt=_nodal_connec_index->getNumberOfComponents();
7474 if(cpt!=1 || lgth<1)
7476 stream << std::endl << "Number of cells : " << lgth-1 << ".";
7479 std::string MEDCouplingUMesh::getVTKDataSetType() const
7481 return std::string("UnstructuredGrid");
7484 std::string MEDCouplingUMesh::getVTKFileExtension() const
7486 return std::string("vtu");
7492 * Provides a renumbering of the cells of this (which has to be a piecewise connected 1D line), so that
7493 * the segments of the line are indexed in consecutive order (i.e. cells \a i and \a i+1 are neighbors).
7494 * This doesn't modify the mesh. This method only works using nodal connectivity consideration. Coordinates of nodes are ignored here.
7495 * The caller is to deal with the resulting DataArrayInt.
7496 * \throw If the coordinate array is not set.
7497 * \throw If the nodal connectivity of the cells is not defined.
7498 * \throw If m1 is not a mesh of dimension 2, or m1 is not a mesh of dimension 1
7499 * \throw If m2 is not a (piecewise) line (i.e. if a point has more than 2 adjacent segments)
7501 * \sa DataArrayInt::sortEachPairToMakeALinkedList
7503 DataArrayInt *MEDCouplingUMesh::orderConsecutiveCells1D() const
7505 checkFullyDefined();
7506 if(getMeshDimension()!=1)
7507 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D works on unstructured mesh with meshdim = 1 !");
7509 // Check that this is a line (and not a more complex 1D mesh) - each point is used at most by 2 segments:
7510 MCAuto<DataArrayInt> _d(DataArrayInt::New()),_dI(DataArrayInt::New());
7511 MCAuto<DataArrayInt> _rD(DataArrayInt::New()),_rDI(DataArrayInt::New());
7512 MCAuto<MEDCouplingUMesh> m_points(buildDescendingConnectivity(_d, _dI, _rD, _rDI));
7513 const int *d(_d->begin()), *dI(_dI->begin());
7514 const int *rD(_rD->begin()), *rDI(_rDI->begin());
7515 MCAuto<DataArrayInt> _dsi(_rDI->deltaShiftIndex());
7516 const int * dsi(_dsi->begin());
7517 MCAuto<DataArrayInt> dsii = _dsi->findIdsNotInRange(0,3);
7519 if (dsii->getNumberOfTuples())
7520 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D only work with a mesh being a (piecewise) connected line!");
7522 int nc(getNumberOfCells());
7523 MCAuto<DataArrayInt> result(DataArrayInt::New());
7524 result->alloc(nc,1);
7526 // set of edges not used so far
7527 std::set<int> edgeSet;
7528 for (int i=0; i<nc; edgeSet.insert(i), i++);
7532 // while we have points with only one neighbor segments
7535 std::list<int> linePiece;
7536 // fills a list of consecutive segment linked to startSeg. This can go forward or backward.
7537 for (int direction=0;direction<2;direction++) // direction=0 --> forward, direction=1 --> backward
7539 // Fill the list forward (resp. backward) from the start segment:
7540 int activeSeg = startSeg;
7541 int prevPointId = -20;
7543 while (!edgeSet.empty())
7545 if (!(direction == 1 && prevPointId==-20)) // prevent adding twice startSeg
7548 linePiece.push_back(activeSeg);
7550 linePiece.push_front(activeSeg);
7551 edgeSet.erase(activeSeg);
7554 int ptId1 = d[dI[activeSeg]], ptId2 = d[dI[activeSeg]+1];
7555 ptId = direction ? (ptId1 == prevPointId ? ptId2 : ptId1) : (ptId2 == prevPointId ? ptId1 : ptId2);
7556 if (dsi[ptId] == 1) // hitting the end of the line
7559 int seg1 = rD[rDI[ptId]], seg2 = rD[rDI[ptId]+1];
7560 activeSeg = (seg1 == activeSeg) ? seg2 : seg1;
7563 // Done, save final piece into DA:
7564 std::copy(linePiece.begin(), linePiece.end(), result->getPointer()+newIdx);
7565 newIdx += linePiece.size();
7567 // identify next valid start segment (one which is not consumed)
7568 if(!edgeSet.empty())
7569 startSeg = *(edgeSet.begin());
7571 while (!edgeSet.empty());
7572 return result.retn();
7576 * This method split some of edges of 2D cells in \a this. The edges to be split are specified in \a subNodesInSeg
7577 * and in \a subNodesInSegI using \ref numbering-indirect storage mode.
7578 * To do the work this method can optionally needs information about middle of subedges for quadratic cases if
7579 * a minimal creation of new nodes is wanted.
7580 * So this method try to reduce at most the number of new nodes. The only case that can lead this method to add
7581 * nodes if a SEG3 is split without information of middle.
7582 * \b WARNING : is returned value is different from 0 a call to MEDCouplingUMesh::mergeNodes is necessary to
7583 * avoid to have a non conform mesh.
7585 * \return int - the number of new nodes created (in most of cases 0).
7587 * \throw If \a this is not coherent.
7588 * \throw If \a this has not spaceDim equal to 2.
7589 * \throw If \a this has not meshDim equal to 2.
7590 * \throw If some subcells needed to be split are orphan.
7591 * \sa MEDCouplingUMesh::conformize2D
7593 int MEDCouplingUMesh::split2DCells(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI, const DataArrayInt *midOpt, const DataArrayInt *midOptI)
7595 if(!desc || !descI || !subNodesInSeg || !subNodesInSegI)
7596 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : the 4 first arrays must be not null !");
7597 desc->checkAllocated(); descI->checkAllocated(); subNodesInSeg->checkAllocated(); subNodesInSegI->checkAllocated();
7598 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
7599 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : This method only works for meshes with spaceDim=2 and meshDim=2 !");
7600 if(midOpt==0 && midOptI==0)
7602 split2DCellsLinear(desc,descI,subNodesInSeg,subNodesInSegI);
7605 else if(midOpt!=0 && midOptI!=0)
7606 return split2DCellsQuadratic(desc,descI,subNodesInSeg,subNodesInSegI,midOpt,midOptI);
7608 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : middle parameters must be set to null for all or not null for all.");
7612 * 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
7613 * 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
7614 * the geometric cell type set to INTERP_KERNEL::NORM_POLYGON.
7615 * 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
7616 * 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.
7618 * \return false if the input connectivity represents already the convex hull, true if the input cell needs to be reordered.
7620 bool MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis(const double *coords, const int *nodalConnBg, const int *nodalConnEnd, DataArrayInt *nodalConnecOut)
7622 std::size_t sz=std::distance(nodalConnBg,nodalConnEnd);
7625 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)*nodalConnBg);
7626 if(cm.getDimension()==2)
7628 const int *node=nodalConnBg+1;
7629 int startNode=*node++;
7630 double refX=coords[2*startNode];
7631 for(;node!=nodalConnEnd;node++)
7633 if(coords[2*(*node)]<refX)
7636 refX=coords[2*startNode];
7639 std::vector<int> tmpOut; tmpOut.reserve(sz); tmpOut.push_back(startNode);
7643 double angle0=-M_PI/2;
7648 double angleNext=0.;
7649 while(nextNode!=startNode)
7653 for(node=nodalConnBg+1;node!=nodalConnEnd;node++)
7655 if(*node!=tmpOut.back() && *node!=prevNode)
7657 tmp2[0]=coords[2*(*node)]-coords[2*tmpOut.back()]; tmp2[1]=coords[2*(*node)+1]-coords[2*tmpOut.back()+1];
7658 double angleM=INTERP_KERNEL::EdgeArcCircle::GetAbsoluteAngle(tmp2,tmp1);
7663 res=angle0-angleM+2.*M_PI;
7672 if(nextNode!=startNode)
7674 angle0=angleNext-M_PI;
7677 prevNode=tmpOut.back();
7678 tmpOut.push_back(nextNode);
7681 std::vector<int> tmp3(2*(sz-1));
7682 std::vector<int>::iterator it=std::copy(nodalConnBg+1,nodalConnEnd,tmp3.begin());
7683 std::copy(nodalConnBg+1,nodalConnEnd,it);
7684 if(std::search(tmp3.begin(),tmp3.end(),tmpOut.begin(),tmpOut.end())!=tmp3.end())
7686 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
7689 if(std::search(tmp3.rbegin(),tmp3.rend(),tmpOut.begin(),tmpOut.end())!=tmp3.rend())
7691 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
7696 nodalConnecOut->pushBackSilent((int)INTERP_KERNEL::NORM_POLYGON);
7697 nodalConnecOut->insertAtTheEnd(tmpOut.begin(),tmpOut.end());
7702 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
7705 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
7709 * This method works on an input pair (\b arr, \b arrIndx) where \b arr indexes is in \b arrIndx.
7710 * 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.
7712 * \param [in] idsToRemoveBg begin of set of ids to remove in \b arr (included)
7713 * \param [in] idsToRemoveEnd end of set of ids to remove in \b arr (excluded)
7714 * \param [in,out] arr array in which the remove operation will be done.
7715 * \param [in,out] arrIndx array in the remove operation will modify
7716 * \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])
7717 * \return true if \b arr and \b arrIndx have been modified, false if not.
7719 bool MEDCouplingUMesh::RemoveIdsFromIndexedArrays(const int *idsToRemoveBg, const int *idsToRemoveEnd, DataArrayInt *arr, DataArrayInt *arrIndx, int offsetForRemoval)
7721 if(!arrIndx || !arr)
7722 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::RemoveIdsFromIndexedArrays : some input arrays are empty !");
7723 if(offsetForRemoval<0)
7724 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::RemoveIdsFromIndexedArrays : offsetForRemoval should be >=0 !");
7725 std::set<int> s(idsToRemoveBg,idsToRemoveEnd);
7726 int nbOfGrps=arrIndx->getNumberOfTuples()-1;
7727 int *arrIPtr=arrIndx->getPointer();
7730 const int *arrPtr=arr->begin();
7731 std::vector<int> arrOut;//no utility to switch to DataArrayInt because copy always needed
7732 for(int i=0;i<nbOfGrps;i++,arrIPtr++)
7734 if(*arrIPtr-previousArrI>offsetForRemoval)
7736 for(const int *work=arrPtr+previousArrI+offsetForRemoval;work!=arrPtr+*arrIPtr;work++)
7738 if(s.find(*work)==s.end())
7739 arrOut.push_back(*work);
7742 previousArrI=*arrIPtr;
7743 *arrIPtr=(int)arrOut.size();
7745 if(arr->getNumberOfTuples()==arrOut.size())
7747 arr->alloc((int)arrOut.size(),1);
7748 std::copy(arrOut.begin(),arrOut.end(),arr->getPointer());
7753 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn
7754 * (\ref numbering-indirect).
7755 * This method returns the result of the extraction ( specified by a set of ids in [\b idsOfSelectBg , \b idsOfSelectEnd ) ).
7756 * The selection of extraction is done standardly in new2old format.
7757 * This method returns indexed arrays (\ref numbering-indirect) using 2 arrays (arrOut,arrIndexOut).
7759 * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
7760 * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
7761 * \param [in] arrIn arr origin array from which the extraction will be done.
7762 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7763 * \param [out] arrOut the resulting array
7764 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
7765 * \sa MEDCouplingUMesh::ExtractFromIndexedArraysSlice
7767 void MEDCouplingUMesh::ExtractFromIndexedArrays(const int *idsOfSelectBg, const int *idsOfSelectEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
7768 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
7770 if(!arrIn || !arrIndxIn)
7771 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : input pointer is NULL !");
7772 arrIn->checkAllocated(); arrIndxIn->checkAllocated();
7773 if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1)
7774 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : input arrays must have exactly one component !");
7775 std::size_t sz=std::distance(idsOfSelectBg,idsOfSelectEnd);
7776 const int *arrInPtr=arrIn->begin();
7777 const int *arrIndxPtr=arrIndxIn->begin();
7778 int nbOfGrps=arrIndxIn->getNumberOfTuples()-1;
7780 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : The format of \"arrIndxIn\" is invalid ! Its nb of tuples should be >=1 !");
7781 int maxSizeOfArr=arrIn->getNumberOfTuples();
7782 MCAuto<DataArrayInt> arro=DataArrayInt::New();
7783 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
7784 arrIo->alloc((int)(sz+1),1);
7785 const int *idsIt=idsOfSelectBg;
7786 int *work=arrIo->getPointer();
7789 for(std::size_t i=0;i<sz;i++,work++,idsIt++)
7791 if(*idsIt>=0 && *idsIt<nbOfGrps)
7792 lgth+=arrIndxPtr[*idsIt+1]-arrIndxPtr[*idsIt];
7795 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " ! Must be in [0," << nbOfGrps << ") !";
7796 throw INTERP_KERNEL::Exception(oss.str());
7802 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " and at this pos arrIndxIn[" << *idsIt;
7803 oss << "+1]-arrIndxIn[" << *idsIt << "] < 0 ! The input index array is bugged !";
7804 throw INTERP_KERNEL::Exception(oss.str());
7807 arro->alloc(lgth,1);
7808 work=arro->getPointer();
7809 idsIt=idsOfSelectBg;
7810 for(std::size_t i=0;i<sz;i++,idsIt++)
7812 if(arrIndxPtr[*idsIt]>=0 && arrIndxPtr[*idsIt+1]<=maxSizeOfArr)
7813 work=std::copy(arrInPtr+arrIndxPtr[*idsIt],arrInPtr+arrIndxPtr[*idsIt+1],work);
7816 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " arrIndx[" << *idsIt << "] must be >= 0 and arrIndx[";
7817 oss << *idsIt << "+1] <= " << maxSizeOfArr << " (the size of arrIn)!";
7818 throw INTERP_KERNEL::Exception(oss.str());
7822 arrIndexOut=arrIo.retn();
7826 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn
7827 * (\ref numbering-indirect).
7828 * 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 ).
7829 * The selection of extraction is done standardly in new2old format.
7830 * This method returns indexed arrays (\ref numbering-indirect) using 2 arrays (arrOut,arrIndexOut).
7832 * \param [in] idsOfSelectStart begin of set of ids of the input extraction (included)
7833 * \param [in] idsOfSelectStop end of set of ids of the input extraction (excluded)
7834 * \param [in] idsOfSelectStep
7835 * \param [in] arrIn arr origin array from which the extraction will be done.
7836 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7837 * \param [out] arrOut the resulting array
7838 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
7839 * \sa MEDCouplingUMesh::ExtractFromIndexedArrays
7841 void MEDCouplingUMesh::ExtractFromIndexedArraysSlice(int idsOfSelectStart, int idsOfSelectStop, int idsOfSelectStep, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
7842 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
7844 if(!arrIn || !arrIndxIn)
7845 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : input pointer is NULL !");
7846 arrIn->checkAllocated(); arrIndxIn->checkAllocated();
7847 if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1)
7848 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : input arrays must have exactly one component !");
7849 int sz=DataArrayInt::GetNumberOfItemGivenBESRelative(idsOfSelectStart,idsOfSelectStop,idsOfSelectStep,"MEDCouplingUMesh::ExtractFromIndexedArraysSlice : Input slice ");
7850 const int *arrInPtr=arrIn->begin();
7851 const int *arrIndxPtr=arrIndxIn->begin();
7852 int nbOfGrps=arrIndxIn->getNumberOfTuples()-1;
7854 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : The format of \"arrIndxIn\" is invalid ! Its nb of tuples should be >=1 !");
7855 int maxSizeOfArr=arrIn->getNumberOfTuples();
7856 MCAuto<DataArrayInt> arro=DataArrayInt::New();
7857 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
7858 arrIo->alloc((int)(sz+1),1);
7859 int idsIt=idsOfSelectStart;
7860 int *work=arrIo->getPointer();
7863 for(int i=0;i<sz;i++,work++,idsIt+=idsOfSelectStep)
7865 if(idsIt>=0 && idsIt<nbOfGrps)
7866 lgth+=arrIndxPtr[idsIt+1]-arrIndxPtr[idsIt];
7869 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " ! Must be in [0," << nbOfGrps << ") !";
7870 throw INTERP_KERNEL::Exception(oss.str());
7876 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " and at this pos arrIndxIn[" << idsIt;
7877 oss << "+1]-arrIndxIn[" << idsIt << "] < 0 ! The input index array is bugged !";
7878 throw INTERP_KERNEL::Exception(oss.str());
7881 arro->alloc(lgth,1);
7882 work=arro->getPointer();
7883 idsIt=idsOfSelectStart;
7884 for(int i=0;i<sz;i++,idsIt+=idsOfSelectStep)
7886 if(arrIndxPtr[idsIt]>=0 && arrIndxPtr[idsIt+1]<=maxSizeOfArr)
7887 work=std::copy(arrInPtr+arrIndxPtr[idsIt],arrInPtr+arrIndxPtr[idsIt+1],work);
7890 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " arrIndx[" << idsIt << "] must be >= 0 and arrIndx[";
7891 oss << idsIt << "+1] <= " << maxSizeOfArr << " (the size of arrIn)!";
7892 throw INTERP_KERNEL::Exception(oss.str());
7896 arrIndexOut=arrIo.retn();
7900 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
7901 * 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
7902 * cellIds \b in [ \b idsOfSelectBg , \b idsOfSelectEnd ) a copy coming from the corresponding values in input pair (\b srcArr, \b srcArrIndex).
7903 * This method is an generalization of MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx that performs the same thing but by without building explicitely a result output arrays.
7905 * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
7906 * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
7907 * \param [in] arrIn arr origin array from which the extraction will be done.
7908 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7909 * \param [in] srcArr input array that will be used as source of copy for ids in [ \b idsOfSelectBg, \b idsOfSelectEnd )
7910 * \param [in] srcArrIndex index array of \b srcArr
7911 * \param [out] arrOut the resulting array
7912 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
7914 * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx
7916 void MEDCouplingUMesh::SetPartOfIndexedArrays(const int *idsOfSelectBg, const int *idsOfSelectEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
7917 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex,
7918 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
7920 if(arrIn==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
7921 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArrays : presence of null pointer in input parameter !");
7922 MCAuto<DataArrayInt> arro=DataArrayInt::New();
7923 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
7924 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
7925 std::vector<bool> v(nbOfTuples,true);
7927 const int *arrIndxInPtr=arrIndxIn->begin();
7928 const int *srcArrIndexPtr=srcArrIndex->begin();
7929 for(const int *it=idsOfSelectBg;it!=idsOfSelectEnd;it++,srcArrIndexPtr++)
7931 if(*it>=0 && *it<nbOfTuples)
7934 offset+=(srcArrIndexPtr[1]-srcArrIndexPtr[0])-(arrIndxInPtr[*it+1]-arrIndxInPtr[*it]);
7938 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArrays : On pos #" << std::distance(idsOfSelectBg,it) << " value is " << *it << " not in [0," << nbOfTuples << ") !";
7939 throw INTERP_KERNEL::Exception(oss.str());
7942 srcArrIndexPtr=srcArrIndex->begin();
7943 arrIo->alloc(nbOfTuples+1,1);
7944 arro->alloc(arrIn->getNumberOfTuples()+offset,1);
7945 const int *arrInPtr=arrIn->begin();
7946 const int *srcArrPtr=srcArr->begin();
7947 int *arrIoPtr=arrIo->getPointer(); *arrIoPtr++=0;
7948 int *arroPtr=arro->getPointer();
7949 for(int ii=0;ii<nbOfTuples;ii++,arrIoPtr++)
7953 arroPtr=std::copy(arrInPtr+arrIndxInPtr[ii],arrInPtr+arrIndxInPtr[ii+1],arroPtr);
7954 *arrIoPtr=arrIoPtr[-1]+(arrIndxInPtr[ii+1]-arrIndxInPtr[ii]);
7958 std::size_t pos=std::distance(idsOfSelectBg,std::find(idsOfSelectBg,idsOfSelectEnd,ii));
7959 arroPtr=std::copy(srcArrPtr+srcArrIndexPtr[pos],srcArrPtr+srcArrIndexPtr[pos+1],arroPtr);
7960 *arrIoPtr=arrIoPtr[-1]+(srcArrIndexPtr[pos+1]-srcArrIndexPtr[pos]);
7964 arrIndexOut=arrIo.retn();
7968 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
7969 * This method is an specialization of MEDCouplingUMesh::SetPartOfIndexedArrays in the case of assignement do not modify the index in \b arrIndxIn.
7971 * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
7972 * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
7973 * \param [in,out] arrInOut arr origin array from which the extraction will be done.
7974 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7975 * \param [in] srcArr input array that will be used as source of copy for ids in [ \b idsOfSelectBg , \b idsOfSelectEnd )
7976 * \param [in] srcArrIndex index array of \b srcArr
7978 * \sa MEDCouplingUMesh::SetPartOfIndexedArrays
7980 void MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx(const int *idsOfSelectBg, const int *idsOfSelectEnd, DataArrayInt *arrInOut, const DataArrayInt *arrIndxIn,
7981 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex)
7983 if(arrInOut==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
7984 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx : presence of null pointer in input parameter !");
7985 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
7986 const int *arrIndxInPtr=arrIndxIn->begin();
7987 const int *srcArrIndexPtr=srcArrIndex->begin();
7988 int *arrInOutPtr=arrInOut->getPointer();
7989 const int *srcArrPtr=srcArr->begin();
7990 for(const int *it=idsOfSelectBg;it!=idsOfSelectEnd;it++,srcArrIndexPtr++)
7992 if(*it>=0 && *it<nbOfTuples)
7994 if(srcArrIndexPtr[1]-srcArrIndexPtr[0]==arrIndxInPtr[*it+1]-arrIndxInPtr[*it])
7995 std::copy(srcArrPtr+srcArrIndexPtr[0],srcArrPtr+srcArrIndexPtr[1],arrInOutPtr+arrIndxInPtr[*it]);
7998 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] !";
7999 throw INTERP_KERNEL::Exception(oss.str());
8004 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx : On pos #" << std::distance(idsOfSelectBg,it) << " value is " << *it << " not in [0," << nbOfTuples << ") !";
8005 throw INTERP_KERNEL::Exception(oss.str());
8011 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
8012 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
8013 * 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]].
8014 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
8015 * A negative value in \b arrIn means that it is ignored.
8016 * 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.
8018 * \param [in] arrIn arr origin array from which the extraction will be done.
8019 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
8020 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
8021 * \sa MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed, MEDCouplingUMesh::partitionBySpreadZone
8023 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGradually(const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn)
8025 int seed=0,nbOfDepthPeelingPerformed=0;
8026 return ComputeSpreadZoneGraduallyFromSeed(&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfDepthPeelingPerformed);
8030 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
8031 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
8032 * 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]].
8033 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
8034 * A negative value in \b arrIn means that it is ignored.
8035 * 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.
8036 * \param [in] seedBg the begin pointer (included) of an array containing the seed of the search zone
8037 * \param [in] seedEnd the end pointer (not included) of an array containing the seed of the search zone
8038 * \param [in] arrIn arr origin array from which the extraction will be done.
8039 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
8040 * \param [in] nbOfDepthPeeling the max number of peels requested in search. By default -1, that is to say, no limit.
8041 * \param [out] nbOfDepthPeelingPerformed the number of peels effectively performed. May be different from \a nbOfDepthPeeling
8042 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
8043 * \sa MEDCouplingUMesh::partitionBySpreadZone
8045 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(const int *seedBg, const int *seedEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn, int nbOfDepthPeeling, int& nbOfDepthPeelingPerformed)
8047 nbOfDepthPeelingPerformed=0;
8049 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed : arrIndxIn input pointer is NULL !");
8050 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
8053 DataArrayInt *ret=DataArrayInt::New(); ret->alloc(0,1);
8057 std::vector<bool> fetched(nbOfTuples,false);
8058 return ComputeSpreadZoneGraduallyFromSeedAlg(fetched,seedBg,seedEnd,arrIn,arrIndxIn,nbOfDepthPeeling,nbOfDepthPeelingPerformed);
8063 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
8064 * 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
8065 * cellIds \b in [\b idsOfSelectBg, \b idsOfSelectEnd) a copy coming from the corresponding values in input pair (\b srcArr, \b srcArrIndex).
8066 * This method is an generalization of MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx that performs the same thing but by without building explicitely a result output arrays.
8068 * \param [in] start begin of set of ids of the input extraction (included)
8069 * \param [in] end end of set of ids of the input extraction (excluded)
8070 * \param [in] step step of the set of ids in range mode.
8071 * \param [in] arrIn arr origin array from which the extraction will be done.
8072 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
8073 * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd)
8074 * \param [in] srcArrIndex index array of \b srcArr
8075 * \param [out] arrOut the resulting array
8076 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
8078 * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx MEDCouplingUMesh::SetPartOfIndexedArrays
8080 void MEDCouplingUMesh::SetPartOfIndexedArraysSlice(int start, int end, int step, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
8081 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex,
8082 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
8084 if(arrIn==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
8085 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSlice : presence of null pointer in input parameter !");
8086 MCAuto<DataArrayInt> arro=DataArrayInt::New();
8087 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
8088 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
8090 const int *arrIndxInPtr=arrIndxIn->begin();
8091 const int *srcArrIndexPtr=srcArrIndex->begin();
8092 int nbOfElemsToSet=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::SetPartOfIndexedArraysSlice : ");
8094 for(int i=0;i<nbOfElemsToSet;i++,srcArrIndexPtr++,it+=step)
8096 if(it>=0 && it<nbOfTuples)
8097 offset+=(srcArrIndexPtr[1]-srcArrIndexPtr[0])-(arrIndxInPtr[it+1]-arrIndxInPtr[it]);
8100 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSlice : On pos #" << i << " value is " << it << " not in [0," << nbOfTuples << ") !";
8101 throw INTERP_KERNEL::Exception(oss.str());
8104 srcArrIndexPtr=srcArrIndex->begin();
8105 arrIo->alloc(nbOfTuples+1,1);
8106 arro->alloc(arrIn->getNumberOfTuples()+offset,1);
8107 const int *arrInPtr=arrIn->begin();
8108 const int *srcArrPtr=srcArr->begin();
8109 int *arrIoPtr=arrIo->getPointer(); *arrIoPtr++=0;
8110 int *arroPtr=arro->getPointer();
8111 for(int ii=0;ii<nbOfTuples;ii++,arrIoPtr++)
8113 int pos=DataArray::GetPosOfItemGivenBESRelativeNoThrow(ii,start,end,step);
8116 arroPtr=std::copy(arrInPtr+arrIndxInPtr[ii],arrInPtr+arrIndxInPtr[ii+1],arroPtr);
8117 *arrIoPtr=arrIoPtr[-1]+(arrIndxInPtr[ii+1]-arrIndxInPtr[ii]);
8121 arroPtr=std::copy(srcArrPtr+srcArrIndexPtr[pos],srcArrPtr+srcArrIndexPtr[pos+1],arroPtr);
8122 *arrIoPtr=arrIoPtr[-1]+(srcArrIndexPtr[pos+1]-srcArrIndexPtr[pos]);
8126 arrIndexOut=arrIo.retn();
8130 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
8131 * This method is an specialization of MEDCouplingUMesh::SetPartOfIndexedArrays in the case of assignement do not modify the index in \b arrIndxIn.
8133 * \param [in] start begin of set of ids of the input extraction (included)
8134 * \param [in] end end of set of ids of the input extraction (excluded)
8135 * \param [in] step step of the set of ids in range mode.
8136 * \param [in,out] arrInOut arr origin array from which the extraction will be done.
8137 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
8138 * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd)
8139 * \param [in] srcArrIndex index array of \b srcArr
8141 * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSlice MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx
8143 void MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice(int start, int end, int step, DataArrayInt *arrInOut, const DataArrayInt *arrIndxIn,
8144 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex)
8146 if(arrInOut==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
8147 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : presence of null pointer in input parameter !");
8148 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
8149 const int *arrIndxInPtr=arrIndxIn->begin();
8150 const int *srcArrIndexPtr=srcArrIndex->begin();
8151 int *arrInOutPtr=arrInOut->getPointer();
8152 const int *srcArrPtr=srcArr->begin();
8153 int nbOfElemsToSet=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : ");
8155 for(int i=0;i<nbOfElemsToSet;i++,srcArrIndexPtr++,it+=step)
8157 if(it>=0 && it<nbOfTuples)
8159 if(srcArrIndexPtr[1]-srcArrIndexPtr[0]==arrIndxInPtr[it+1]-arrIndxInPtr[it])
8160 std::copy(srcArrPtr+srcArrIndexPtr[0],srcArrPtr+srcArrIndexPtr[1],arrInOutPtr+arrIndxInPtr[it]);
8163 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : On pos #" << i << " id (idsOfSelectBg[" << i << "]) is " << it << " arrIndxIn[id+1]-arrIndxIn[id]!=srcArrIndex[pos+1]-srcArrIndex[pos] !";
8164 throw INTERP_KERNEL::Exception(oss.str());
8169 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : On pos #" << i << " value is " << it << " not in [0," << nbOfTuples << ") !";
8170 throw INTERP_KERNEL::Exception(oss.str());
8176 * \b this is expected to be a mesh fully defined whose spaceDim==meshDim.
8177 * It returns a new allocated mesh having the same mesh dimension and lying on same coordinates.
8178 * The returned mesh contains as poly cells as number of contiguous zone (regarding connectivity).
8179 * A spread contiguous zone is built using poly cells (polyhedra in 3D, polygons in 2D and polyline in 1D).
8180 * The sum of measure field of returned mesh is equal to the sum of measure field of this.
8182 * \return a newly allocated mesh lying on the same coords than \b this with same meshdimension than \b this.
8184 MEDCouplingUMesh *MEDCouplingUMesh::buildSpreadZonesWithPoly() const
8186 checkFullyDefined();
8187 int mdim=getMeshDimension();
8188 int spaceDim=getSpaceDimension();
8190 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension and spacedimension do not match !");
8191 std::vector<DataArrayInt *> partition=partitionBySpreadZone();
8192 std::vector< MCAuto<DataArrayInt> > partitionAuto; partitionAuto.reserve(partition.size());
8193 std::copy(partition.begin(),partition.end(),std::back_insert_iterator<std::vector< MCAuto<DataArrayInt> > >(partitionAuto));
8194 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
8195 ret->setCoords(getCoords());
8196 ret->allocateCells((int)partition.size());
8198 for(std::vector<DataArrayInt *>::const_iterator it=partition.begin();it!=partition.end();it++)
8200 MCAuto<MEDCouplingUMesh> tmp=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf((*it)->begin(),(*it)->end(),true));
8201 MCAuto<DataArrayInt> cell;
8205 cell=tmp->buildUnionOf2DMesh();
8208 cell=tmp->buildUnionOf3DMesh();
8211 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension supported are [2,3] ! Not implemented yet for others !");
8214 ret->insertNextCell((INTERP_KERNEL::NormalizedCellType)cell->getIJSafe(0,0),cell->getNumberOfTuples()-1,cell->begin()+1);
8217 ret->finishInsertingCells();
8222 * This method partitions \b this into contiguous zone.
8223 * This method only needs a well defined connectivity. Coordinates are not considered here.
8224 * This method returns a vector of \b newly allocated arrays that the caller has to deal with.
8226 std::vector<DataArrayInt *> MEDCouplingUMesh::partitionBySpreadZone() const
8228 DataArrayInt *neigh=0,*neighI=0;
8229 computeNeighborsOfCells(neigh,neighI);
8230 MCAuto<DataArrayInt> neighAuto(neigh),neighIAuto(neighI);
8231 return PartitionBySpreadZone(neighAuto,neighIAuto);
8234 std::vector<DataArrayInt *> MEDCouplingUMesh::PartitionBySpreadZone(const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn)
8236 if(!arrIn || !arrIndxIn)
8237 throw INTERP_KERNEL::Exception("PartitionBySpreadZone : null input pointers !");
8238 arrIn->checkAllocated(); arrIndxIn->checkAllocated();
8239 int nbOfTuples(arrIndxIn->getNumberOfTuples());
8240 if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1 || nbOfTuples<1)
8241 throw INTERP_KERNEL::Exception("PartitionBySpreadZone : invalid arrays in input !");
8242 int nbOfCellsCur(nbOfTuples-1);
8243 std::vector<DataArrayInt *> ret;
8246 std::vector<bool> fetchedCells(nbOfCellsCur,false);
8247 std::vector< MCAuto<DataArrayInt> > ret2;
8249 while(seed<nbOfCellsCur)
8251 int nbOfPeelPerformed=0;
8252 ret2.push_back(ComputeSpreadZoneGraduallyFromSeedAlg(fetchedCells,&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfPeelPerformed));
8253 seed=(int)std::distance(fetchedCells.begin(),std::find(fetchedCells.begin()+seed,fetchedCells.end(),false));
8255 for(std::vector< MCAuto<DataArrayInt> >::iterator it=ret2.begin();it!=ret2.end();it++)
8256 ret.push_back((*it).retn());
8261 * This method returns given a distribution of cell type (returned for example by MEDCouplingUMesh::getDistributionOfTypes method and customized after) a
8262 * newly allocated DataArrayInt instance with 2 components ready to be interpreted as input of DataArrayInt::findRangeIdForEachTuple method.
8264 * \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.
8265 * \return a newly allocated DataArrayInt to be managed by the caller.
8266 * \throw In case of \a code has not the right format (typically of size 3*n)
8268 DataArrayInt *MEDCouplingUMesh::ComputeRangesFromTypeDistribution(const std::vector<int>& code)
8270 MCAuto<DataArrayInt> ret=DataArrayInt::New();
8271 std::size_t nb=code.size()/3;
8272 if(code.size()%3!=0)
8273 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeRangesFromTypeDistribution : invalid input code !");
8274 ret->alloc((int)nb,2);
8275 int *retPtr=ret->getPointer();
8276 for(std::size_t i=0;i<nb;i++,retPtr+=2)
8278 retPtr[0]=code[3*i+2];
8279 retPtr[1]=code[3*i+2]+code[3*i+1];
8285 * This method expects that \a this a 3D mesh (spaceDim=3 and meshDim=3) with all coordinates and connectivities set.
8286 * All cells in \a this are expected to be linear 3D cells.
8287 * This method will split **all** 3D cells in \a this into INTERP_KERNEL::NORM_TETRA4 cells and put them in the returned mesh.
8288 * It leads to an increase to number of cells.
8289 * This method contrary to MEDCouplingUMesh::simplexize can append coordinates in \a this to perform its work.
8290 * The \a nbOfAdditionalPoints returned value informs about it. If > 0, the coordinates array in returned mesh will have \a nbOfAdditionalPoints
8291 * more tuples (nodes) than in \a this. Anyway, all the nodes in \a this (with the same order) will be in the returned mesh.
8293 * \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.
8294 * For all other cells, the splitting policy will be ignored. See INTERP_KERNEL::SplittingPolicy for the images.
8295 * \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.
8296 * \param [out] n2oCells - A new instance of DataArrayInt holding, for each new cell,
8297 * an id of old cell producing it. The caller is to delete this array using
8298 * decrRef() as it is no more needed.
8299 * \return MEDCoupling1SGTUMesh * - the mesh containing only INTERP_KERNEL::NORM_TETRA4 cells.
8301 * \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
8302 * the policy PLANAR_FACE_6 should be used on a mesh sorted with MEDCoupling1SGTUMesh::sortHexa8EachOther.
8304 * \throw If \a this is not a 3D mesh (spaceDim==3 and meshDim==3).
8305 * \throw If \a this is not fully constituted with linear 3D cells.
8306 * \sa MEDCouplingUMesh::simplexize, MEDCoupling1SGTUMesh::sortHexa8EachOther
8308 MEDCoupling1SGTUMesh *MEDCouplingUMesh::tetrahedrize(int policy, DataArrayInt *& n2oCells, int& nbOfAdditionalPoints) const
8310 INTERP_KERNEL::SplittingPolicy pol((INTERP_KERNEL::SplittingPolicy)policy);
8311 checkConnectivityFullyDefined();
8312 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
8313 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tetrahedrize : only available for mesh with meshdim == 3 and spacedim == 3 !");
8314 int nbOfCells(getNumberOfCells()),nbNodes(getNumberOfNodes());
8315 MCAuto<MEDCoupling1SGTUMesh> ret0(MEDCoupling1SGTUMesh::New(getName(),INTERP_KERNEL::NORM_TETRA4));
8316 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(nbOfCells,1);
8317 int *retPt(ret->getPointer());
8318 MCAuto<DataArrayInt> newConn(DataArrayInt::New()); newConn->alloc(0,1);
8319 MCAuto<DataArrayDouble> addPts(DataArrayDouble::New()); addPts->alloc(0,1);
8320 const int *oldc(_nodal_connec->begin());
8321 const int *oldci(_nodal_connec_index->begin());
8322 const double *coords(_coords->begin());
8323 for(int i=0;i<nbOfCells;i++,oldci++,retPt++)
8325 std::vector<int> a; std::vector<double> b;
8326 INTERP_KERNEL::SplitIntoTetras(pol,(INTERP_KERNEL::NormalizedCellType)oldc[oldci[0]],oldc+oldci[0]+1,oldc+oldci[1],coords,a,b);
8327 std::size_t nbOfTet(a.size()/4); *retPt=(int)nbOfTet;
8328 const int *aa(&a[0]);
8331 for(std::vector<int>::iterator it=a.begin();it!=a.end();it++)
8333 *it=(-(*(it))-1+nbNodes);
8334 addPts->insertAtTheEnd(b.begin(),b.end());
8335 nbNodes+=(int)b.size()/3;
8337 for(std::size_t j=0;j<nbOfTet;j++,aa+=4)
8338 newConn->insertAtTheEnd(aa,aa+4);
8340 if(!addPts->empty())
8342 addPts->rearrange(3);
8343 nbOfAdditionalPoints=addPts->getNumberOfTuples();
8344 addPts=DataArrayDouble::Aggregate(getCoords(),addPts);
8345 ret0->setCoords(addPts);
8349 nbOfAdditionalPoints=0;
8350 ret0->setCoords(getCoords());
8352 ret0->setNodalConnectivity(newConn);
8354 ret->computeOffsetsFull();
8355 n2oCells=ret->buildExplicitArrOfSliceOnScaledArr(0,nbOfCells,1);
8359 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),
8360 _own_cell(true),_cell_id(-1),_nb_cell(0)
8365 _nb_cell=mesh->getNumberOfCells();
8369 MEDCouplingUMeshCellIterator::~MEDCouplingUMeshCellIterator()
8377 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh, MEDCouplingUMeshCell *itc, int bg, int end):_mesh(mesh),_cell(itc),
8378 _own_cell(false),_cell_id(bg-1),
8385 MEDCouplingUMeshCell *MEDCouplingUMeshCellIterator::nextt()
8388 if(_cell_id<_nb_cell)
8397 MEDCouplingUMeshCellByTypeEntry::MEDCouplingUMeshCellByTypeEntry(MEDCouplingUMesh *mesh):_mesh(mesh)
8403 MEDCouplingUMeshCellByTypeIterator *MEDCouplingUMeshCellByTypeEntry::iterator()
8405 return new MEDCouplingUMeshCellByTypeIterator(_mesh);
8408 MEDCouplingUMeshCellByTypeEntry::~MEDCouplingUMeshCellByTypeEntry()
8414 MEDCouplingUMeshCellEntry::MEDCouplingUMeshCellEntry(MEDCouplingUMesh *mesh, INTERP_KERNEL::NormalizedCellType type, MEDCouplingUMeshCell *itc, int bg, int end):_mesh(mesh),_type(type),
8422 MEDCouplingUMeshCellEntry::~MEDCouplingUMeshCellEntry()
8428 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCellEntry::getType() const
8433 int MEDCouplingUMeshCellEntry::getNumberOfElems() const
8438 MEDCouplingUMeshCellIterator *MEDCouplingUMeshCellEntry::iterator()
8440 return new MEDCouplingUMeshCellIterator(_mesh,_itc,_bg,_end);
8443 MEDCouplingUMeshCellByTypeIterator::MEDCouplingUMeshCellByTypeIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),_cell_id(0),_nb_cell(0)
8448 _nb_cell=mesh->getNumberOfCells();
8452 MEDCouplingUMeshCellByTypeIterator::~MEDCouplingUMeshCellByTypeIterator()
8459 MEDCouplingUMeshCellEntry *MEDCouplingUMeshCellByTypeIterator::nextt()
8461 const int *c=_mesh->getNodalConnectivity()->begin();
8462 const int *ci=_mesh->getNodalConnectivityIndex()->begin();
8463 if(_cell_id<_nb_cell)
8465 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[_cell_id]];
8466 int nbOfElems=(int)std::distance(ci+_cell_id,std::find_if(ci+_cell_id,ci+_nb_cell,MEDCouplingImpl::ConnReader(c,type)));
8467 int startId=_cell_id;
8468 _cell_id+=nbOfElems;
8469 return new MEDCouplingUMeshCellEntry(_mesh,type,_cell,startId,_cell_id);
8475 MEDCouplingUMeshCell::MEDCouplingUMeshCell(MEDCouplingUMesh *mesh):_conn(0),_conn_indx(0),_conn_lgth(NOTICABLE_FIRST_VAL)
8479 _conn=mesh->getNodalConnectivity()->getPointer();
8480 _conn_indx=mesh->getNodalConnectivityIndex()->getPointer();
8484 void MEDCouplingUMeshCell::next()
8486 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8491 _conn_lgth=_conn_indx[1]-_conn_indx[0];
8494 std::string MEDCouplingUMeshCell::repr() const
8496 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8498 std::ostringstream oss; oss << "Cell Type " << INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)_conn[0]).getRepr();
8500 std::copy(_conn+1,_conn+_conn_lgth,std::ostream_iterator<int>(oss," "));
8504 return std::string("MEDCouplingUMeshCell::repr : Invalid pos");
8507 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCell::getType() const
8509 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8510 return (INTERP_KERNEL::NormalizedCellType)_conn[0];
8512 return INTERP_KERNEL::NORM_ERROR;
8515 const int *MEDCouplingUMeshCell::getAllConn(int& lgth) const
8518 if(_conn_lgth!=NOTICABLE_FIRST_VAL)