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++)
980 neighIdx[1]=neighIdx[0];
982 neighIdx[1]=neighIdx[0]+(*it).size()-1;
985 neighbors=DataArrayInt::New(); neighbors->alloc(neighborsIdx->back(),1);
987 const int *neighIdx(neighborsIdx->begin());
988 int *neigh(neighbors->getPointer()),nodeId(0);
989 for(std::vector< std::set<int> >::const_iterator it=st0.begin();it!=st0.end();it++,neighIdx++,nodeId++)
991 std::set<int> s(*it); s.erase(nodeId);
992 std::copy(s.begin(),s.end(),neigh+*neighIdx);
998 * Converts specified cells to either polygons (if \a this is a 2D mesh) or
999 * polyhedrons (if \a this is a 3D mesh). The cells to convert are specified by an
1000 * array of cell ids. Pay attention that after conversion all algorithms work slower
1001 * with \a this mesh than before conversion. <br> If an exception is thrown during the
1002 * conversion due presence of invalid ids in the array of cells to convert, as a
1003 * result \a this mesh contains some already converted elements. In this case the 2D
1004 * mesh remains valid but 3D mesh becomes \b inconsistent!
1005 * \warning This method can significantly modify the order of geometric types in \a this,
1006 * hence, to write this mesh to the MED file, its cells must be sorted using
1007 * sortCellsInMEDFileFrmt().
1008 * \param [in] cellIdsToConvertBg - the array holding ids of cells to convert.
1009 * \param [in] cellIdsToConvertEnd - a pointer to the last-plus-one-th element of \a
1010 * cellIdsToConvertBg.
1011 * \throw If the coordinates array is not set.
1012 * \throw If the nodal connectivity of cells is node defined.
1013 * \throw If dimension of \a this mesh is not either 2 or 3.
1015 * \if ENABLE_EXAMPLES
1016 * \ref cpp_mcumesh_convertToPolyTypes "Here is a C++ example".<br>
1017 * \ref py_mcumesh_convertToPolyTypes "Here is a Python example".
1020 void MEDCouplingUMesh::convertToPolyTypes(const int *cellIdsToConvertBg, const int *cellIdsToConvertEnd)
1022 checkFullyDefined();
1023 int dim=getMeshDimension();
1025 throw INTERP_KERNEL::Exception("Invalid mesh dimension : must be 2 or 3 !");
1026 int nbOfCells(getNumberOfCells());
1029 const int *connIndex=_nodal_connec_index->begin();
1030 int *conn=_nodal_connec->getPointer();
1031 for(const int *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1033 if(*iter>=0 && *iter<nbOfCells)
1035 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*iter]]);
1036 if(!cm.isQuadratic())
1037 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_POLYGON;
1039 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_QPOLYG;
1043 std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1044 oss << " in range [0," << nbOfCells << ") !";
1045 throw INTERP_KERNEL::Exception(oss.str());
1051 int *connIndex(_nodal_connec_index->getPointer());
1052 const int *connOld(_nodal_connec->getConstPointer());
1053 MCAuto<DataArrayInt> connNew(DataArrayInt::New()),connNewI(DataArrayInt::New()); connNew->alloc(0,1); connNewI->alloc(1,1); connNewI->setIJ(0,0,0);
1054 std::vector<bool> toBeDone(nbOfCells,false);
1055 for(const int *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1057 if(*iter>=0 && *iter<nbOfCells)
1058 toBeDone[*iter]=true;
1061 std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1062 oss << " in range [0," << nbOfCells << ") !";
1063 throw INTERP_KERNEL::Exception(oss.str());
1066 for(int cellId=0;cellId<nbOfCells;cellId++)
1068 int pos(connIndex[cellId]),posP1(connIndex[cellId+1]);
1069 int lgthOld(posP1-pos-1);
1070 if(toBeDone[cellId])
1072 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connOld[pos]);
1073 unsigned nbOfFaces(cm.getNumberOfSons2(connOld+pos+1,lgthOld));
1074 int *tmp(new int[nbOfFaces*lgthOld+1]);
1075 int *work=tmp; *work++=INTERP_KERNEL::NORM_POLYHED;
1076 for(unsigned j=0;j<nbOfFaces;j++)
1078 INTERP_KERNEL::NormalizedCellType type;
1079 unsigned offset=cm.fillSonCellNodalConnectivity2(j,connOld+pos+1,lgthOld,work,type);
1083 std::size_t newLgth(std::distance(tmp,work)-1);//-1 for last -1
1084 connNew->pushBackValsSilent(tmp,tmp+newLgth);
1085 connNewI->pushBackSilent(connNewI->back()+(int)newLgth);
1090 connNew->pushBackValsSilent(connOld+pos,connOld+posP1);
1091 connNewI->pushBackSilent(connNewI->back()+posP1-pos);
1094 setConnectivity(connNew,connNewI,false);//false because computeTypes called just behind.
1100 * Converts all cells to either polygons (if \a this is a 2D mesh) or
1101 * polyhedrons (if \a this is a 3D mesh).
1102 * \warning As this method is purely for user-friendliness and no optimization is
1103 * done to avoid construction of a useless vector, this method can be costly
1105 * \throw If the coordinates array is not set.
1106 * \throw If the nodal connectivity of cells is node defined.
1107 * \throw If dimension of \a this mesh is not either 2 or 3.
1109 void MEDCouplingUMesh::convertAllToPoly()
1111 int nbOfCells=getNumberOfCells();
1112 std::vector<int> cellIds(nbOfCells);
1113 for(int i=0;i<nbOfCells;i++)
1115 convertToPolyTypes(&cellIds[0],&cellIds[0]+cellIds.size());
1119 * Fixes nodal connectivity of invalid cells of type NORM_POLYHED. This method
1120 * expects that all NORM_POLYHED cells have connectivity similar to that of prismatic
1121 * volumes like NORM_HEXA8, NORM_PENTA6 etc., i.e. the first half of nodes describes a
1122 * base facet of the volume and the second half of nodes describes an opposite facet
1123 * having the same number of nodes as the base one. This method converts such
1124 * connectivity to a valid polyhedral format where connectivity of each facet is
1125 * explicitly described and connectivity of facets are separated by -1. If \a this mesh
1126 * contains a NORM_POLYHED cell with a valid connectivity, or an invalid connectivity is
1127 * not as expected, an exception is thrown and the mesh remains unchanged. Care of
1128 * a correct orientation of the first facet of a polyhedron, else orientation of a
1129 * corrected cell is reverse.<br>
1130 * This method is useful to build an extruded unstructured mesh with polyhedrons as
1131 * it releases the user from boring description of polyhedra connectivity in the valid
1133 * \throw If \a this->getMeshDimension() != 3.
1134 * \throw If \a this->getSpaceDimension() != 3.
1135 * \throw If the nodal connectivity of cells is not defined.
1136 * \throw If the coordinates array is not set.
1137 * \throw If \a this mesh contains polyhedrons with the valid connectivity.
1138 * \throw If \a this mesh contains polyhedrons with odd number of nodes.
1140 * \if ENABLE_EXAMPLES
1141 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
1142 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
1145 void MEDCouplingUMesh::convertExtrudedPolyhedra()
1147 checkFullyDefined();
1148 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1149 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertExtrudedPolyhedra works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
1150 int nbOfCells=getNumberOfCells();
1151 MCAuto<DataArrayInt> newCi=DataArrayInt::New();
1152 newCi->alloc(nbOfCells+1,1);
1153 int *newci=newCi->getPointer();
1154 const int *ci=_nodal_connec_index->getConstPointer();
1155 const int *c=_nodal_connec->getConstPointer();
1157 for(int i=0;i<nbOfCells;i++)
1159 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1160 if(type==INTERP_KERNEL::NORM_POLYHED)
1162 if(std::count(c+ci[i]+1,c+ci[i+1],-1)!=0)
1164 std::ostringstream oss; oss << "MEDCouplingUMesh::convertExtrudedPolyhedra : cell # " << i << " is a polhedron BUT it has NOT exactly 1 face !";
1165 throw INTERP_KERNEL::Exception(oss.str());
1167 std::size_t n2=std::distance(c+ci[i]+1,c+ci[i+1]);
1170 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 !";
1171 throw INTERP_KERNEL::Exception(oss.str());
1174 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)
1177 newci[i+1]=(ci[i+1]-ci[i])+newci[i];
1179 MCAuto<DataArrayInt> newC=DataArrayInt::New();
1180 newC->alloc(newci[nbOfCells],1);
1181 int *newc=newC->getPointer();
1182 for(int i=0;i<nbOfCells;i++)
1184 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1185 if(type==INTERP_KERNEL::NORM_POLYHED)
1187 std::size_t n1=std::distance(c+ci[i]+1,c+ci[i+1])/2;
1188 newc=std::copy(c+ci[i],c+ci[i]+n1+1,newc);
1190 for(std::size_t j=0;j<n1;j++)
1192 newc[j]=c[ci[i]+1+n1+(n1-j)%n1];
1194 newc[n1+5*j+1]=c[ci[i]+1+j];
1195 newc[n1+5*j+2]=c[ci[i]+1+j+n1];
1196 newc[n1+5*j+3]=c[ci[i]+1+(j+1)%n1+n1];
1197 newc[n1+5*j+4]=c[ci[i]+1+(j+1)%n1];
1202 newc=std::copy(c+ci[i],c+ci[i+1],newc);
1204 _nodal_connec_index->decrRef(); _nodal_connec_index=newCi.retn();
1205 _nodal_connec->decrRef(); _nodal_connec=newC.retn();
1210 * Converts all polygons (if \a this is a 2D mesh) or polyhedrons (if \a this is a 3D
1211 * mesh) to cells of classical types. This method is opposite to convertToPolyTypes().
1212 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
1213 * to write this mesh to the MED file, its cells must be sorted using
1214 * sortCellsInMEDFileFrmt().
1215 * \warning Cells (and most notably polyhedrons) must be correctly oriented for this to work
1216 * properly. See orientCorrectlyPolyhedrons() and arePolyhedronsNotCorrectlyOriented().
1217 * \return \c true if at least one cell has been converted, \c false else. In the
1218 * last case the nodal connectivity remains unchanged.
1219 * \throw If the coordinates array is not set.
1220 * \throw If the nodal connectivity of cells is not defined.
1221 * \throw If \a this->getMeshDimension() < 0.
1223 bool MEDCouplingUMesh::unPolyze()
1225 checkFullyDefined();
1226 int mdim=getMeshDimension();
1228 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::unPolyze works on umeshes with meshdim equals to 0, 1 2 or 3 !");
1231 int nbOfCells=getNumberOfCells();
1234 int initMeshLgth=getNodalConnectivityArrayLen();
1235 int *conn=_nodal_connec->getPointer();
1236 int *index=_nodal_connec_index->getPointer();
1241 for(int i=0;i<nbOfCells;i++)
1243 lgthOfCurCell=index[i+1]-posOfCurCell;
1244 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
1245 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
1246 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::NORM_ERROR;
1250 switch(cm.getDimension())
1254 INTERP_KERNEL::AutoPtr<int> tmp=new int[lgthOfCurCell-1];
1255 std::copy(conn+posOfCurCell+1,conn+posOfCurCell+lgthOfCurCell,(int *)tmp);
1256 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly2D(cm.isQuadratic(),tmp,lgthOfCurCell-1,conn+newPos+1,newLgth);
1261 int nbOfFaces,lgthOfPolyhConn;
1262 INTERP_KERNEL::AutoPtr<int> zipFullReprOfPolyh=INTERP_KERNEL::CellSimplify::getFullPolyh3DCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,nbOfFaces,lgthOfPolyhConn);
1263 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly3D(zipFullReprOfPolyh,nbOfFaces,lgthOfPolyhConn,conn+newPos+1,newLgth);
1268 newType=(lgthOfCurCell==3)?INTERP_KERNEL::NORM_SEG2:INTERP_KERNEL::NORM_POLYL;
1272 ret=ret || (newType!=type);
1273 conn[newPos]=newType;
1275 posOfCurCell=index[i+1];
1280 std::copy(conn+posOfCurCell,conn+posOfCurCell+lgthOfCurCell,conn+newPos);
1281 newPos+=lgthOfCurCell;
1282 posOfCurCell+=lgthOfCurCell;
1286 if(newPos!=initMeshLgth)
1287 _nodal_connec->reAlloc(newPos);
1294 * This method expects that spaceDimension is equal to 3 and meshDimension equal to 3.
1295 * This method performs operation only on polyhedrons in \b this. If no polyhedrons exists in \b this, \b this remains unchanged.
1296 * This method allows to merge if any coplanar 3DSurf cells that may appear in some polyhedrons cells.
1298 * \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
1301 void MEDCouplingUMesh::simplifyPolyhedra(double eps)
1303 checkFullyDefined();
1304 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1305 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplifyPolyhedra : works on meshdimension 3 and spaceDimension 3 !");
1306 MCAuto<DataArrayDouble> coords=getCoords()->deepCopy();
1307 coords->recenterForMaxPrecision(eps);
1309 int nbOfCells=getNumberOfCells();
1310 const int *conn=_nodal_connec->getConstPointer();
1311 const int *index=_nodal_connec_index->getConstPointer();
1312 MCAuto<DataArrayInt> connINew=DataArrayInt::New();
1313 connINew->alloc(nbOfCells+1,1);
1314 int *connINewPtr=connINew->getPointer(); *connINewPtr++=0;
1315 MCAuto<DataArrayInt> connNew=DataArrayInt::New(); connNew->alloc(0,1);
1316 MCAuto<DataArrayInt> E_Fi(DataArrayInt::New()), E_F(DataArrayInt::New()), F_Ei(DataArrayInt::New()), F_E(DataArrayInt::New());
1317 MCAuto<MEDCouplingUMesh> m_faces(buildDescendingConnectivity(E_F, E_Fi, F_E, F_Ei));
1319 for(int i=0;i<nbOfCells;i++,connINewPtr++)
1321 if(conn[index[i]]==(int)INTERP_KERNEL::NORM_POLYHED)
1323 SimplifyPolyhedronCell(eps,coords, i,connNew, m_faces, E_Fi, E_F, F_Ei, F_E);
1327 connNew->insertAtTheEnd(conn+index[i],conn+index[i+1]);
1328 *connINewPtr=connNew->getNumberOfTuples();
1331 setConnectivity(connNew,connINew,false);
1335 * This method returns all node ids used in the connectivity of \b this. The data array returned has to be dealt by the caller.
1336 * The returned node ids are sorted ascendingly. This method is close to MEDCouplingUMesh::getNodeIdsInUse except
1337 * the format of the returned DataArrayInt instance.
1339 * \return a newly allocated DataArrayInt sorted ascendingly of fetched node ids.
1340 * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1342 DataArrayInt *MEDCouplingUMesh::computeFetchedNodeIds() const
1344 checkConnectivityFullyDefined();
1345 const int *maxEltPt(std::max_element(_nodal_connec->begin(),_nodal_connec->end()));
1346 int maxElt(maxEltPt==_nodal_connec->end()?0:std::abs(*maxEltPt)+1);
1347 std::vector<bool> retS(maxElt,false);
1348 computeNodeIdsAlg(retS);
1349 return DataArrayInt::BuildListOfSwitchedOn(retS);
1353 * \param [in,out] nodeIdsInUse an array of size typically equal to nbOfNodes.
1354 * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1356 void MEDCouplingUMesh::computeNodeIdsAlg(std::vector<bool>& nodeIdsInUse) const
1358 int nbOfNodes((int)nodeIdsInUse.size()),nbOfCells(getNumberOfCells());
1359 const int *connIndex(_nodal_connec_index->getConstPointer()),*conn(_nodal_connec->getConstPointer());
1360 for(int i=0;i<nbOfCells;i++)
1361 for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1364 if(conn[j]<nbOfNodes)
1365 nodeIdsInUse[conn[j]]=true;
1368 std::ostringstream oss; oss << "MEDCouplingUMesh::computeNodeIdsAlg : In cell #" << i << " presence of node id " << conn[j] << " not in [0," << nbOfNodes << ") !";
1369 throw INTERP_KERNEL::Exception(oss.str());
1376 struct MEDCouplingAccVisit
1378 MEDCouplingAccVisit():_new_nb_of_nodes(0) { }
1379 int operator()(int val) { if(val!=-1) return _new_nb_of_nodes++; else return -1; }
1380 int _new_nb_of_nodes;
1386 * Finds nodes not used in any cell and returns an array giving a new id to every node
1387 * by excluding the unused nodes, for which the array holds -1. The result array is
1388 * a mapping in "Old to New" mode.
1389 * \param [out] nbrOfNodesInUse - number of node ids present in the nodal connectivity.
1390 * \return DataArrayInt * - a new instance of DataArrayInt. Its length is \a
1391 * this->getNumberOfNodes(). It holds for each node of \a this mesh either -1
1392 * if the node is unused or a new id else. The caller is to delete this
1393 * array using decrRef() as it is no more needed.
1394 * \throw If the coordinates array is not set.
1395 * \throw If the nodal connectivity of cells is not defined.
1396 * \throw If the nodal connectivity includes an invalid id.
1398 * \if ENABLE_EXAMPLES
1399 * \ref cpp_mcumesh_getNodeIdsInUse "Here is a C++ example".<br>
1400 * \ref py_mcumesh_getNodeIdsInUse "Here is a Python example".
1402 * \sa computeFetchedNodeIds, computeNodeIdsAlg()
1404 DataArrayInt *MEDCouplingUMesh::getNodeIdsInUse(int& nbrOfNodesInUse) const
1407 int nbOfNodes(getNumberOfNodes());
1408 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1409 ret->alloc(nbOfNodes,1);
1410 int *traducer=ret->getPointer();
1411 std::fill(traducer,traducer+nbOfNodes,-1);
1412 int nbOfCells=getNumberOfCells();
1413 const int *connIndex=_nodal_connec_index->getConstPointer();
1414 const int *conn=_nodal_connec->getConstPointer();
1415 for(int i=0;i<nbOfCells;i++)
1416 for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1419 if(conn[j]<nbOfNodes)
1420 traducer[conn[j]]=1;
1423 std::ostringstream oss; oss << "MEDCouplingUMesh::getNodeIdsInUse : In cell #" << i << " presence of node id " << conn[j] << " not in [0," << nbOfNodes << ") !";
1424 throw INTERP_KERNEL::Exception(oss.str());
1427 nbrOfNodesInUse=(int)std::count(traducer,traducer+nbOfNodes,1);
1428 std::transform(traducer,traducer+nbOfNodes,traducer,MEDCouplingAccVisit());
1433 * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1434 * For each cell in \b this the number of nodes constituting cell is computed.
1435 * For each polyhedron cell, the sum of the number of nodes of each face constituting polyhedron cell is returned.
1436 * So for pohyhedrons some nodes can be counted several times in the returned result.
1438 * \return a newly allocated array
1439 * \sa MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell
1441 DataArrayInt *MEDCouplingUMesh::computeNbOfNodesPerCell() const
1443 checkConnectivityFullyDefined();
1444 int nbOfCells=getNumberOfCells();
1445 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1446 ret->alloc(nbOfCells,1);
1447 int *retPtr=ret->getPointer();
1448 const int *conn=getNodalConnectivity()->getConstPointer();
1449 const int *connI=getNodalConnectivityIndex()->getConstPointer();
1450 for(int i=0;i<nbOfCells;i++,retPtr++)
1452 if(conn[connI[i]]!=(int)INTERP_KERNEL::NORM_POLYHED)
1453 *retPtr=connI[i+1]-connI[i]-1;
1455 *retPtr=connI[i+1]-connI[i]-1-std::count(conn+connI[i]+1,conn+connI[i+1],-1);
1461 * This method computes effective number of nodes per cell. That is to say nodes appearing several times in nodal connectivity of a cell,
1462 * will be counted only once here whereas it will be counted several times in MEDCouplingUMesh::computeNbOfNodesPerCell method.
1464 * \return DataArrayInt * - new object to be deallocated by the caller.
1465 * \sa MEDCouplingUMesh::computeNbOfNodesPerCell
1467 DataArrayInt *MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell() const
1469 checkConnectivityFullyDefined();
1470 int nbOfCells=getNumberOfCells();
1471 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1472 ret->alloc(nbOfCells,1);
1473 int *retPtr=ret->getPointer();
1474 const int *conn=getNodalConnectivity()->getConstPointer();
1475 const int *connI=getNodalConnectivityIndex()->getConstPointer();
1476 for(int i=0;i<nbOfCells;i++,retPtr++)
1478 std::set<int> s(conn+connI[i]+1,conn+connI[i+1]);
1479 if(conn[connI[i]]!=(int)INTERP_KERNEL::NORM_POLYHED)
1480 *retPtr=(int)s.size();
1484 *retPtr=(int)s.size();
1491 * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1492 * For each cell in \b this the number of faces constituting (entity of dimension this->getMeshDimension()-1) cell is computed.
1494 * \return a newly allocated array
1496 DataArrayInt *MEDCouplingUMesh::computeNbOfFacesPerCell() const
1498 checkConnectivityFullyDefined();
1499 int nbOfCells=getNumberOfCells();
1500 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1501 ret->alloc(nbOfCells,1);
1502 int *retPtr=ret->getPointer();
1503 const int *conn=getNodalConnectivity()->getConstPointer();
1504 const int *connI=getNodalConnectivityIndex()->getConstPointer();
1505 for(int i=0;i<nbOfCells;i++,retPtr++,connI++)
1507 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]);
1508 *retPtr=cm.getNumberOfSons2(conn+connI[0]+1,connI[1]-connI[0]-1);
1514 * Removes unused nodes (the node coordinates array is shorten) and returns an array
1515 * mapping between new and old node ids in "Old to New" mode. -1 values in the returned
1516 * array mean that the corresponding old node is no more used.
1517 * \return DataArrayInt * - a new instance of DataArrayInt of length \a
1518 * this->getNumberOfNodes() before call of this method. The caller is to
1519 * delete this array using decrRef() as it is no more needed.
1520 * \throw If the coordinates array is not set.
1521 * \throw If the nodal connectivity of cells is not defined.
1522 * \throw If the nodal connectivity includes an invalid id.
1523 * \sa areAllNodesFetched
1525 * \if ENABLE_EXAMPLES
1526 * \ref cpp_mcumesh_zipCoordsTraducer "Here is a C++ example".<br>
1527 * \ref py_mcumesh_zipCoordsTraducer "Here is a Python example".
1530 DataArrayInt *MEDCouplingUMesh::zipCoordsTraducer()
1532 return MEDCouplingPointSet::zipCoordsTraducer();
1536 * This method stands if 'cell1' and 'cell2' are equals regarding 'compType' policy.
1537 * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1539 int MEDCouplingUMesh::AreCellsEqual(const int *conn, const int *connI, int cell1, int cell2, int compType)
1544 return AreCellsEqualPolicy0(conn,connI,cell1,cell2);
1546 return AreCellsEqualPolicy1(conn,connI,cell1,cell2);
1548 return AreCellsEqualPolicy2(conn,connI,cell1,cell2);
1550 return AreCellsEqualPolicy2NoType(conn,connI,cell1,cell2);
1552 return AreCellsEqualPolicy7(conn,connI,cell1,cell2);
1554 throw INTERP_KERNEL::Exception("Unknown comparison asked ! Must be in 0,1,2,3 or 7.");
1558 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 0.
1560 int MEDCouplingUMesh::AreCellsEqualPolicy0(const int *conn, const int *connI, int cell1, int cell2)
1562 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1563 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;
1568 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 1.
1570 int MEDCouplingUMesh::AreCellsEqualPolicy1(const int *conn, const int *connI, int cell1, int cell2)
1572 int sz=connI[cell1+1]-connI[cell1];
1573 if(sz==connI[cell2+1]-connI[cell2])
1575 if(conn[connI[cell1]]==conn[connI[cell2]])
1577 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1578 unsigned dim=cm.getDimension();
1584 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz1];
1585 int *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(int *)tmp);
1586 std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1587 work=std::search((int *)tmp,(int *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1588 return work!=tmp+sz1?1:0;
1591 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;//case of SEG2 and SEG3
1594 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy1 : not implemented yet for meshdim == 3 !");
1601 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 2.
1603 int MEDCouplingUMesh::AreCellsEqualPolicy2(const int *conn, const int *connI, int cell1, int cell2)
1605 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1607 if(conn[connI[cell1]]==conn[connI[cell2]])
1609 std::set<int> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1610 std::set<int> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1618 * This method is less restrictive than AreCellsEqualPolicy2. Here the geometric type is absolutely not taken into account !
1620 int MEDCouplingUMesh::AreCellsEqualPolicy2NoType(const int *conn, const int *connI, int cell1, int cell2)
1622 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1624 std::set<int> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1625 std::set<int> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1632 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 7.
1634 int MEDCouplingUMesh::AreCellsEqualPolicy7(const int *conn, const int *connI, int cell1, int cell2)
1636 int sz=connI[cell1+1]-connI[cell1];
1637 if(sz==connI[cell2+1]-connI[cell2])
1639 if(conn[connI[cell1]]==conn[connI[cell2]])
1641 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1642 unsigned dim=cm.getDimension();
1648 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz1];
1649 int *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(int *)tmp);
1650 std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1651 work=std::search((int *)tmp,(int *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1656 std::reverse_iterator<int *> it1((int *)tmp+sz1);
1657 std::reverse_iterator<int *> it2((int *)tmp);
1658 if(std::search(it1,it2,conn+connI[cell2]+1,conn+connI[cell2+1])!=it2)
1664 return work!=tmp+sz1?1:0;
1667 {//case of SEG2 and SEG3
1668 if(std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1))
1670 if(!cm.isQuadratic())
1672 std::reverse_iterator<const int *> it1(conn+connI[cell1+1]);
1673 std::reverse_iterator<const int *> it2(conn+connI[cell1]+1);
1674 if(std::equal(it1,it2,conn+connI[cell2]+1))
1680 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])
1687 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy7 : not implemented yet for meshdim == 3 !");
1695 * This method find cells that are equal (regarding \a compType) in \a this. The comparison is specified
1697 * This method keeps the coordiantes of \a this. This method is time consuming.
1699 * \param [in] compType input specifying the technique used to compare cells each other.
1700 * - 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.
1701 * - 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)
1702 * and their type equal. For 1D mesh the policy 1 is equivalent to 0.
1703 * - 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
1704 * can be used for users not sensitive to orientation of cell
1705 * \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.
1706 * \param [out] commonCellsArr common cells ids (\ref numbering-indirect)
1707 * \param [out] commonCellsIArr common cells ids (\ref numbering-indirect)
1708 * \return the correspondance array old to new in a newly allocated array.
1711 void MEDCouplingUMesh::findCommonCells(int compType, int startCellId, DataArrayInt *& commonCellsArr, DataArrayInt *& commonCellsIArr) const
1713 MCAuto<DataArrayInt> revNodal=DataArrayInt::New(),revNodalI=DataArrayInt::New();
1714 getReverseNodalConnectivity(revNodal,revNodalI);
1715 FindCommonCellsAlg(compType,startCellId,_nodal_connec,_nodal_connec_index,revNodal,revNodalI,commonCellsArr,commonCellsIArr);
1718 void MEDCouplingUMesh::FindCommonCellsAlg(int compType, int startCellId, const DataArrayInt *nodal, const DataArrayInt *nodalI, const DataArrayInt *revNodal, const DataArrayInt *revNodalI,
1719 DataArrayInt *& commonCellsArr, DataArrayInt *& commonCellsIArr)
1721 MCAuto<DataArrayInt> commonCells=DataArrayInt::New(),commonCellsI=DataArrayInt::New(); commonCells->alloc(0,1);
1722 int nbOfCells=nodalI->getNumberOfTuples()-1;
1723 commonCellsI->reserve(1); commonCellsI->pushBackSilent(0);
1724 const int *revNodalPtr=revNodal->getConstPointer(),*revNodalIPtr=revNodalI->getConstPointer();
1725 const int *connPtr=nodal->getConstPointer(),*connIPtr=nodalI->getConstPointer();
1726 std::vector<bool> isFetched(nbOfCells,false);
1729 for(int i=0;i<nbOfCells;i++)
1733 const int *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind2nd(std::not_equal_to<int>(),-1));
1734 std::vector<int> v,v2;
1735 if(connOfNode!=connPtr+connIPtr[i+1])
1737 const int *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1738 v2.insert(v2.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1]);
1741 for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1745 const int *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1746 std::vector<int>::iterator it=std::set_intersection(v.begin(),v.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1747 v2.resize(std::distance(v2.begin(),it));
1751 if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1753 int pos=commonCellsI->back();
1754 commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1755 for(const int *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1756 isFetched[*it]=true;
1764 for(int i=startCellId;i<nbOfCells;i++)
1768 const int *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind2nd(std::not_equal_to<int>(),-1));
1769 std::vector<int> v,v2;
1770 if(connOfNode!=connPtr+connIPtr[i+1])
1772 v2.insert(v2.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1]);
1775 for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1779 std::vector<int>::iterator it=std::set_intersection(v.begin(),v.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1780 v2.resize(std::distance(v2.begin(),it));
1784 if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1786 int pos=commonCellsI->back();
1787 commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1788 for(const int *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1789 isFetched[*it]=true;
1795 commonCellsArr=commonCells.retn();
1796 commonCellsIArr=commonCellsI.retn();
1800 * Checks if \a this mesh includes all cells of an \a other mesh, and returns an array
1801 * giving for each cell of the \a other an id of a cell in \a this mesh. A value larger
1802 * than \a this->getNumberOfCells() in the returned array means that there is no
1803 * corresponding cell in \a this mesh.
1804 * It is expected that \a this and \a other meshes share the same node coordinates
1805 * array, if it is not so an exception is thrown.
1806 * \param [in] other - the mesh to compare with.
1807 * \param [in] compType - specifies a cell comparison technique. For meaning of its
1808 * valid values [0,1,2], see zipConnectivityTraducer().
1809 * \param [out] arr - a new instance of DataArrayInt returning correspondence
1810 * between cells of the two meshes. It contains \a other->getNumberOfCells()
1811 * values. The caller is to delete this array using
1812 * decrRef() as it is no more needed.
1813 * \return bool - \c true if all cells of \a other mesh are present in the \a this
1816 * \if ENABLE_EXAMPLES
1817 * \ref cpp_mcumesh_areCellsIncludedIn "Here is a C++ example".<br>
1818 * \ref py_mcumesh_areCellsIncludedIn "Here is a Python example".
1820 * \sa checkDeepEquivalOnSameNodesWith()
1821 * \sa checkGeoEquivalWith()
1823 bool MEDCouplingUMesh::areCellsIncludedIn(const MEDCouplingUMesh *other, int compType, DataArrayInt *& arr) const
1825 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1826 int nbOfCells=getNumberOfCells();
1827 static const int possibleCompType[]={0,1,2};
1828 if(std::find(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),compType)==possibleCompType+sizeof(possibleCompType)/sizeof(int))
1830 std::ostringstream oss; oss << "MEDCouplingUMesh::areCellsIncludedIn : only following policies are possible : ";
1831 std::copy(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),std::ostream_iterator<int>(oss," "));
1833 throw INTERP_KERNEL::Exception(oss.str());
1835 MCAuto<DataArrayInt> o2n=mesh->zipConnectivityTraducer(compType,nbOfCells);
1836 arr=o2n->subArray(nbOfCells);
1837 arr->setName(other->getName());
1839 if(other->getNumberOfCells()==0)
1841 return arr->getMaxValue(tmp)<nbOfCells;
1845 * This method makes the assumption that \a this and \a other share the same coords. If not an exception will be thrown !
1846 * This method tries to determine if \b other is fully included in \b this.
1847 * The main difference is that this method is not expected to throw exception.
1848 * This method has two outputs :
1850 * \param other other mesh
1851 * \param arr is an output parameter that returns a \b newly created instance. This array is of size 'other->getNumberOfCells()'.
1852 * \return If \a other is fully included in 'this 'true is returned. If not false is returned.
1854 bool MEDCouplingUMesh::areCellsIncludedInPolicy7(const MEDCouplingUMesh *other, DataArrayInt *& arr) const
1856 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1857 DataArrayInt *commonCells=0,*commonCellsI=0;
1858 int thisNbCells=getNumberOfCells();
1859 mesh->findCommonCells(7,thisNbCells,commonCells,commonCellsI);
1860 MCAuto<DataArrayInt> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1861 const int *commonCellsPtr=commonCells->getConstPointer(),*commonCellsIPtr=commonCellsI->getConstPointer();
1862 int otherNbCells=other->getNumberOfCells();
1863 MCAuto<DataArrayInt> arr2=DataArrayInt::New();
1864 arr2->alloc(otherNbCells,1);
1865 arr2->fillWithZero();
1866 int *arr2Ptr=arr2->getPointer();
1867 int nbOfCommon=commonCellsI->getNumberOfTuples()-1;
1868 for(int i=0;i<nbOfCommon;i++)
1870 int start=commonCellsPtr[commonCellsIPtr[i]];
1871 if(start<thisNbCells)
1873 for(int j=commonCellsIPtr[i]+1;j!=commonCellsIPtr[i+1];j++)
1875 int sig=commonCellsPtr[j]>0?1:-1;
1876 int val=std::abs(commonCellsPtr[j])-1;
1877 if(val>=thisNbCells)
1878 arr2Ptr[val-thisNbCells]=sig*(start+1);
1882 arr2->setName(other->getName());
1883 if(arr2->presenceOfValue(0))
1889 MEDCouplingUMesh *MEDCouplingUMesh::mergeMyselfWithOnSameCoords(const MEDCouplingPointSet *other) const
1892 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : input other is null !");
1893 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
1895 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : the input other mesh is not of type unstructured !");
1896 std::vector<const MEDCouplingUMesh *> ms(2);
1899 return MergeUMeshesOnSameCoords(ms);
1903 * Build a sub part of \b this lying or not on the same coordinates than \b this (regarding value of \b keepCoords).
1904 * By default coordinates are kept. This method is close to MEDCouplingUMesh::buildPartOfMySelf except that here input
1905 * cellIds is not given explicitely but by a range python like.
1910 * \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.
1911 * \return a newly allocated
1913 * \warning This method modifies can generate an unstructured mesh whose cells are not sorted by geometric type order.
1914 * In view of the MED file writing, a renumbering of cells of returned unstructured mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
1916 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfSlice(int start, int end, int step, bool keepCoords) const
1918 if(getMeshDimension()!=-1)
1919 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelfSlice(start,end,step,keepCoords));
1922 int newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfSlice for -1 dimension mesh ");
1924 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
1926 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
1928 return const_cast<MEDCouplingUMesh *>(this);
1933 * Creates a new MEDCouplingUMesh containing specified cells of \a this mesh.
1934 * The result mesh shares or not the node coordinates array with \a this mesh depending
1935 * on \a keepCoords parameter.
1936 * \warning Cells of the result mesh can be \b not sorted by geometric type, hence,
1937 * to write this mesh to the MED file, its cells must be sorted using
1938 * sortCellsInMEDFileFrmt().
1939 * \param [in] begin - an array of cell ids to include to the new mesh.
1940 * \param [in] end - a pointer to last-plus-one-th element of \a begin.
1941 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
1942 * array of \a this mesh, else "free" nodes are removed from the result mesh
1943 * by calling zipCoords().
1944 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
1945 * to delete this mesh using decrRef() as it is no more needed.
1946 * \throw If the coordinates array is not set.
1947 * \throw If the nodal connectivity of cells is not defined.
1948 * \throw If any cell id in the array \a begin is not valid.
1950 * \if ENABLE_EXAMPLES
1951 * \ref cpp_mcumesh_buildPartOfMySelf "Here is a C++ example".<br>
1952 * \ref py_mcumesh_buildPartOfMySelf "Here is a Python example".
1955 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelf(const int *begin, const int *end, bool keepCoords) const
1957 if(getMeshDimension()!=-1)
1958 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelf(begin,end,keepCoords));
1962 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
1964 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
1966 return const_cast<MEDCouplingUMesh *>(this);
1971 * This method operates only on nodal connectivity on \b this. Coordinates of \b this is completely ignored here.
1973 * 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.
1974 * Size of [ \b cellIdsBg, \b cellIdsEnd ) ) must be equal to the number of cells of otherOnSameCoordsThanThis.
1975 * The number of cells of \b this will remain the same with this method.
1977 * \param [in] cellIdsBg begin of cell ids (included) of cells in this to assign
1978 * \param [in] cellIdsEnd end of cell ids (excluded) of cells in this to assign
1979 * \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 ).
1980 * Coordinate pointer of \b this and those of \b otherOnSameCoordsThanThis must be the same
1982 void MEDCouplingUMesh::setPartOfMySelf(const int *cellIdsBg, const int *cellIdsEnd, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
1984 checkConnectivityFullyDefined();
1985 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
1986 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
1987 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelf : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
1988 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
1990 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
1991 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
1992 throw INTERP_KERNEL::Exception(oss.str());
1994 std::size_t nbOfCellsToModify(std::distance(cellIdsBg,cellIdsEnd));
1995 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
1997 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
1998 throw INTERP_KERNEL::Exception(oss.str());
2000 std::size_t nbOfCells(getNumberOfCells());
2001 bool easyAssign(true);
2002 const int *connI(_nodal_connec_index->begin());
2003 const int *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->begin();
2004 for(const int *it=cellIdsBg;it!=cellIdsEnd && easyAssign;it++,connIOther++)
2006 if(*it>=0 && *it<(int)nbOfCells)
2008 easyAssign=(connIOther[1]-connIOther[0])==(connI[*it+1]-connI[*it]);
2012 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : On pos #" << std::distance(cellIdsBg,it) << " id is equal to " << *it << " which is not in [0," << nbOfCells << ") !";
2013 throw INTERP_KERNEL::Exception(oss.str());
2018 MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2023 DataArrayInt *arrOut=0,*arrIOut=0;
2024 MEDCouplingUMesh::SetPartOfIndexedArrays(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2026 MCAuto<DataArrayInt> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2027 setConnectivity(arrOut,arrIOut,true);
2031 void MEDCouplingUMesh::setPartOfMySelfSlice(int start, int end, int step, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2033 checkConnectivityFullyDefined();
2034 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2035 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2036 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelfSlice : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2037 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2039 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2040 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2041 throw INTERP_KERNEL::Exception(oss.str());
2043 int nbOfCellsToModify=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::setPartOfMySelfSlice : ");
2044 if(nbOfCellsToModify!=(int)otherOnSameCoordsThanThis.getNumberOfCells())
2046 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2047 throw INTERP_KERNEL::Exception(oss.str());
2049 int nbOfCells=getNumberOfCells();
2050 bool easyAssign=true;
2051 const int *connI=_nodal_connec_index->getConstPointer();
2052 const int *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2054 for(int i=0;i<nbOfCellsToModify && easyAssign;i++,it+=step,connIOther++)
2056 if(it>=0 && it<nbOfCells)
2058 easyAssign=(connIOther[1]-connIOther[0])==(connI[it+1]-connI[it]);
2062 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : On pos #" << i << " id is equal to " << it << " which is not in [0," << nbOfCells << ") !";
2063 throw INTERP_KERNEL::Exception(oss.str());
2068 MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2073 DataArrayInt *arrOut=0,*arrIOut=0;
2074 MEDCouplingUMesh::SetPartOfIndexedArraysSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2076 MCAuto<DataArrayInt> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2077 setConnectivity(arrOut,arrIOut,true);
2083 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2084 * this->getMeshDimension(), that bound some cells of \a this mesh.
2085 * The cells of lower dimension to include to the result mesh are selected basing on
2086 * specified node ids and the value of \a fullyIn parameter. If \a fullyIn ==\c true, a
2087 * cell is copied if its all nodes are in the array \a begin of node ids. If \a fullyIn
2088 * ==\c false, a cell is copied if any its node is in the array of node ids. The
2089 * created mesh shares the node coordinates array with \a this mesh.
2090 * \param [in] begin - the array of node ids.
2091 * \param [in] end - a pointer to the (last+1)-th element of \a begin.
2092 * \param [in] fullyIn - if \c true, then cells whose all nodes are in the
2093 * array \a begin are added, else cells whose any node is in the
2094 * array \a begin are added.
2095 * \return MEDCouplingUMesh * - new instance of MEDCouplingUMesh. The caller is
2096 * to delete this mesh using decrRef() as it is no more needed.
2097 * \throw If the coordinates array is not set.
2098 * \throw If the nodal connectivity of cells is not defined.
2099 * \throw If any node id in \a begin is not valid.
2101 * \if ENABLE_EXAMPLES
2102 * \ref cpp_mcumesh_buildFacePartOfMySelfNode "Here is a C++ example".<br>
2103 * \ref py_mcumesh_buildFacePartOfMySelfNode "Here is a Python example".
2106 MEDCouplingUMesh *MEDCouplingUMesh::buildFacePartOfMySelfNode(const int *begin, const int *end, bool fullyIn) const
2108 MCAuto<DataArrayInt> desc,descIndx,revDesc,revDescIndx;
2109 desc=DataArrayInt::New(); descIndx=DataArrayInt::New(); revDesc=DataArrayInt::New(); revDescIndx=DataArrayInt::New();
2110 MCAuto<MEDCouplingUMesh> subMesh=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2111 desc=0; descIndx=0; revDesc=0; revDescIndx=0;
2112 return static_cast<MEDCouplingUMesh*>(subMesh->buildPartOfMySelfNode(begin,end,fullyIn));
2116 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2117 * this->getMeshDimension(), which bound only one cell of \a this mesh.
2118 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2119 * array of \a this mesh, else "free" nodes are removed from the result mesh
2120 * by calling zipCoords().
2121 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2122 * to delete this mesh using decrRef() as it is no more needed.
2123 * \throw If the coordinates array is not set.
2124 * \throw If the nodal connectivity of cells is not defined.
2126 * \if ENABLE_EXAMPLES
2127 * \ref cpp_mcumesh_buildBoundaryMesh "Here is a C++ example".<br>
2128 * \ref py_mcumesh_buildBoundaryMesh "Here is a Python example".
2131 MEDCouplingUMesh *MEDCouplingUMesh::buildBoundaryMesh(bool keepCoords) const
2133 DataArrayInt *desc=DataArrayInt::New();
2134 DataArrayInt *descIndx=DataArrayInt::New();
2135 DataArrayInt *revDesc=DataArrayInt::New();
2136 DataArrayInt *revDescIndx=DataArrayInt::New();
2138 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2141 descIndx->decrRef();
2142 int nbOfCells=meshDM1->getNumberOfCells();
2143 const int *revDescIndxC=revDescIndx->getConstPointer();
2144 std::vector<int> boundaryCells;
2145 for(int i=0;i<nbOfCells;i++)
2146 if(revDescIndxC[i+1]-revDescIndxC[i]==1)
2147 boundaryCells.push_back(i);
2148 revDescIndx->decrRef();
2149 MEDCouplingUMesh *ret=meshDM1->buildPartOfMySelf(&boundaryCells[0],&boundaryCells[0]+boundaryCells.size(),keepCoords);
2154 * This method returns a newly created DataArrayInt instance containing ids of cells located in boundary.
2155 * A cell is detected to be on boundary if it contains one or more than one face having only one father.
2156 * This method makes the assumption that \a this is fully defined (coords,connectivity). If not an exception will be thrown.
2158 DataArrayInt *MEDCouplingUMesh::findCellIdsOnBoundary() const
2160 checkFullyDefined();
2161 MCAuto<DataArrayInt> desc=DataArrayInt::New();
2162 MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
2163 MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
2164 MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
2166 buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx)->decrRef();
2167 desc=(DataArrayInt*)0; descIndx=(DataArrayInt*)0;
2169 MCAuto<DataArrayInt> tmp=revDescIndx->deltaShiftIndex();
2170 MCAuto<DataArrayInt> faceIds=tmp->findIdsEqual(1); tmp=(DataArrayInt*)0;
2171 const int *revDescPtr=revDesc->getConstPointer();
2172 const int *revDescIndxPtr=revDescIndx->getConstPointer();
2173 int nbOfCells=getNumberOfCells();
2174 std::vector<bool> ret1(nbOfCells,false);
2176 for(const int *pt=faceIds->begin();pt!=faceIds->end();pt++)
2177 if(!ret1[revDescPtr[revDescIndxPtr[*pt]]])
2178 { ret1[revDescPtr[revDescIndxPtr[*pt]]]=true; sz++; }
2180 DataArrayInt *ret2=DataArrayInt::New();
2182 int *ret2Ptr=ret2->getPointer();
2184 for(std::vector<bool>::const_iterator it=ret1.begin();it!=ret1.end();it++,sz++)
2187 ret2->setName("BoundaryCells");
2192 * This method finds in \b this the cell ids that lie on mesh \b otherDimM1OnSameCoords.
2193 * \b this and \b otherDimM1OnSameCoords have to lie on the same coordinate array pointer. The coherency of that coords array with connectivity
2194 * of \b this and \b otherDimM1OnSameCoords is not important here because this method works only on connectivity.
2195 * this->getMeshDimension() - 1 must be equal to otherDimM1OnSameCoords.getMeshDimension()
2197 * s0 is the cell ids set in \b this lying on at least one node in the fetched nodes in \b otherDimM1OnSameCoords.
2198 * 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
2199 * equals a cell in \b otherDimM1OnSameCoords.
2201 * \throw if \b otherDimM1OnSameCoords is not part of constituent of \b this, or if coordinate pointer of \b this and \b otherDimM1OnSameCoords
2202 * are not same, or if this->getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension()
2204 * \param [in] otherDimM1OnSameCoords
2205 * \param [out] cellIdsRk0 a newly allocated array containing the cell ids of s0 (which are cell ids of \b this) in the above algorithm.
2206 * \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
2207 * cellIdsRk1->transformWithIndArr(cellIdsRk0->begin(),cellIdsRk0->end());
2209 void MEDCouplingUMesh::findCellIdsLyingOn(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayInt *&cellIdsRk0, DataArrayInt *&cellIdsRk1) const
2211 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2212 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : coordinates pointer are not the same ! Use tryToShareSameCoords method !");
2213 checkConnectivityFullyDefined();
2214 otherDimM1OnSameCoords.checkConnectivityFullyDefined();
2215 if(getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension())
2216 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : invalid mesh dimension of input mesh regarding meshdimesion of this !");
2217 MCAuto<DataArrayInt> fetchedNodeIds1=otherDimM1OnSameCoords.computeFetchedNodeIds();
2218 MCAuto<DataArrayInt> s0arr=getCellIdsLyingOnNodes(fetchedNodeIds1->begin(),fetchedNodeIds1->end(),false);
2219 MCAuto<MEDCouplingUMesh> thisPart=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(s0arr->begin(),s0arr->end(),true));
2220 MCAuto<DataArrayInt> descThisPart=DataArrayInt::New(),descIThisPart=DataArrayInt::New(),revDescThisPart=DataArrayInt::New(),revDescIThisPart=DataArrayInt::New();
2221 MCAuto<MEDCouplingUMesh> thisPartConsti=thisPart->buildDescendingConnectivity(descThisPart,descIThisPart,revDescThisPart,revDescIThisPart);
2222 const int *revDescThisPartPtr=revDescThisPart->getConstPointer(),*revDescIThisPartPtr=revDescIThisPart->getConstPointer();
2223 DataArrayInt *idsOtherInConsti=0;
2224 bool b=thisPartConsti->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsOtherInConsti);
2225 MCAuto<DataArrayInt> idsOtherInConstiAuto(idsOtherInConsti);
2227 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : the given mdim-1 mesh in other is not a constituent of this !");
2229 for(const int *idOther=idsOtherInConsti->begin();idOther!=idsOtherInConsti->end();idOther++)
2230 s1.insert(revDescThisPartPtr+revDescIThisPartPtr[*idOther],revDescThisPartPtr+revDescIThisPartPtr[*idOther+1]);
2231 MCAuto<DataArrayInt> s1arr_renum1=DataArrayInt::New(); s1arr_renum1->alloc((int)s1.size(),1); std::copy(s1.begin(),s1.end(),s1arr_renum1->getPointer());
2232 s1arr_renum1->sort();
2233 cellIdsRk0=s0arr.retn();
2234 //cellIdsRk1=s_renum1.retn();
2235 cellIdsRk1=s1arr_renum1.retn();
2239 * 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
2240 * returned. This subpart of meshdim-1 mesh is built using meshdim-1 cells in it shared only one cell in \b this.
2242 * \return a newly allocated mesh lying on the same coordinates than \b this. The caller has to deal with returned mesh.
2244 MEDCouplingUMesh *MEDCouplingUMesh::computeSkin() const
2246 MCAuto<DataArrayInt> desc=DataArrayInt::New();
2247 MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
2248 MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
2249 MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
2251 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2252 revDesc=0; desc=0; descIndx=0;
2253 MCAuto<DataArrayInt> revDescIndx2=revDescIndx->deltaShiftIndex();
2254 MCAuto<DataArrayInt> part=revDescIndx2->findIdsEqual(1);
2255 return static_cast<MEDCouplingUMesh *>(meshDM1->buildPartOfMySelf(part->begin(),part->end(),true));
2259 * Finds nodes lying on the boundary of \a this mesh.
2260 * \return DataArrayInt * - a new instance of DataArrayInt holding ids of found
2261 * nodes. The caller is to delete this array using decrRef() as it is no
2263 * \throw If the coordinates array is not set.
2264 * \throw If the nodal connectivity of cells is node defined.
2266 * \if ENABLE_EXAMPLES
2267 * \ref cpp_mcumesh_findBoundaryNodes "Here is a C++ example".<br>
2268 * \ref py_mcumesh_findBoundaryNodes "Here is a Python example".
2271 DataArrayInt *MEDCouplingUMesh::findBoundaryNodes() const
2273 MCAuto<MEDCouplingUMesh> skin=computeSkin();
2274 return skin->computeFetchedNodeIds();
2277 MEDCouplingUMesh *MEDCouplingUMesh::buildUnstructured() const
2280 return const_cast<MEDCouplingUMesh *>(this);
2284 * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2285 * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2286 * 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.
2287 * 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.
2288 * 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.
2290 * \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
2291 * parameter is altered during the call.
2292 * \param [out] nodeIdsToDuplicate node ids needed to be duplicated following the algorithm explain above.
2293 * \param [out] cellIdsNeededToBeRenum cell ids in \b this in which the renumber of nodes should be performed.
2294 * \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.
2296 * \warning This method modifies param \b otherDimM1OnSameCoords (for speed reasons).
2298 void MEDCouplingUMesh::findNodesToDuplicate(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayInt *& nodeIdsToDuplicate,
2299 DataArrayInt *& cellIdsNeededToBeRenum, DataArrayInt *& cellIdsNotModified) const
2301 typedef MCAuto<DataArrayInt> DAInt;
2302 typedef MCAuto<MEDCouplingUMesh> MCUMesh;
2304 checkFullyDefined();
2305 otherDimM1OnSameCoords.checkFullyDefined();
2306 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2307 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : meshes do not share the same coords array !");
2308 if(otherDimM1OnSameCoords.getMeshDimension()!=getMeshDimension()-1)
2309 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the mesh given in other parameter must have this->getMeshDimension()-1 !");
2311 // Checking star-shaped M1 group:
2312 DAInt dt0=DataArrayInt::New(),dit0=DataArrayInt::New(),rdt0=DataArrayInt::New(),rdit0=DataArrayInt::New();
2313 MCUMesh meshM2 = otherDimM1OnSameCoords.buildDescendingConnectivity(dt0, dit0, rdt0, rdit0);
2314 DAInt dsi = rdit0->deltaShiftIndex();
2315 DAInt idsTmp0 = dsi->findIdsNotInRange(-1, 3);
2316 if(idsTmp0->getNumberOfTuples())
2317 throw INTERP_KERNEL::Exception("MEDFileUMesh::buildInnerBoundaryAlongM1Group: group is too complex: some points (or edges) have more than two connected segments (or faces)!");
2318 dt0=0; dit0=0; rdt0=0; rdit0=0; idsTmp0=0;
2320 // Get extreme nodes from the group (they won't be duplicated), ie nodes belonging to boundary cells of M1
2321 DAInt xtremIdsM2 = dsi->findIdsEqual(1); dsi = 0;
2322 MCUMesh meshM2Part = static_cast<MEDCouplingUMesh *>(meshM2->buildPartOfMySelf(xtremIdsM2->begin(), xtremIdsM2->end(),true));
2323 DAInt xtrem = meshM2Part->computeFetchedNodeIds();
2324 // Remove from the list points on the boundary of the M0 mesh (those need duplication!)
2325 dt0=DataArrayInt::New(),dit0=DataArrayInt::New(),rdt0=DataArrayInt::New(),rdit0=DataArrayInt::New();
2326 MCUMesh m0desc = buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); dt0=0; dit0=0; rdt0=0;
2327 dsi = rdit0->deltaShiftIndex();
2328 DAInt boundSegs = dsi->findIdsEqual(1); // boundary segs/faces of the M0 mesh
2329 MCUMesh m0descSkin = static_cast<MEDCouplingUMesh *>(m0desc->buildPartOfMySelf(boundSegs->begin(),boundSegs->end(), true));
2330 DAInt fNodes = m0descSkin->computeFetchedNodeIds();
2331 // In 3D, some points on the boundary of M0 still need duplication:
2333 if (getMeshDimension() == 3)
2335 DAInt dnu1=DataArrayInt::New(), dnu2=DataArrayInt::New(), dnu3=DataArrayInt::New(), dnu4=DataArrayInt::New();
2336 MCUMesh m0descSkinDesc = m0descSkin->buildDescendingConnectivity(dnu1, dnu2, dnu3, dnu4);
2337 dnu1=0;dnu2=0;dnu3=0;dnu4=0;
2338 DataArrayInt * corresp=0;
2339 meshM2->areCellsIncludedIn(m0descSkinDesc,2,corresp);
2340 DAInt validIds = corresp->findIdsInRange(0, meshM2->getNumberOfCells());
2342 if (validIds->getNumberOfTuples())
2344 MCUMesh m1IntersecSkin = static_cast<MEDCouplingUMesh *>(m0descSkinDesc->buildPartOfMySelf(validIds->begin(), validIds->end(), true));
2345 DAInt notDuplSkin = m1IntersecSkin->findBoundaryNodes();
2346 DAInt fNodes1 = fNodes->buildSubstraction(notDuplSkin);
2347 notDup = xtrem->buildSubstraction(fNodes1);
2350 notDup = xtrem->buildSubstraction(fNodes);
2353 notDup = xtrem->buildSubstraction(fNodes);
2355 // Now compute cells around group (i.e. cells where we will do the propagation to identify the two sub-sets delimited by the group)
2356 DAInt m1Nodes = otherDimM1OnSameCoords.computeFetchedNodeIds();
2357 DAInt dupl = m1Nodes->buildSubstraction(notDup);
2358 DAInt cellsAroundGroup = getCellIdsLyingOnNodes(dupl->begin(), dupl->end(), false); // false= take cell in, even if not all nodes are in notDup
2361 MCUMesh m0Part2=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(cellsAroundGroup->begin(),cellsAroundGroup->end(),true));
2362 int nCells2 = m0Part2->getNumberOfCells();
2363 DAInt desc00=DataArrayInt::New(),descI00=DataArrayInt::New(),revDesc00=DataArrayInt::New(),revDescI00=DataArrayInt::New();
2364 MCUMesh m01=m0Part2->buildDescendingConnectivity(desc00,descI00,revDesc00,revDescI00);
2366 // Neighbor information of the mesh without considering the crack (serves to count how many connex pieces it is made of)
2367 DataArrayInt *tmp00=0,*tmp11=0;
2368 MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00, tmp00, tmp11);
2369 DAInt neighInit00(tmp00);
2370 DAInt neighIInit00(tmp11);
2371 // Neighbor information of the mesh WITH the crack (some neighbors are removed):
2372 DataArrayInt *idsTmp=0;
2373 m01->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsTmp);
2375 // In the neighbor information remove the connection between high dimension cells and its low level constituents which are part
2376 // of the frontier given in parameter (i.e. the cells of low dimension from the group delimiting the crack):
2377 MEDCouplingUMesh::RemoveIdsFromIndexedArrays(ids->begin(),ids->end(),desc00,descI00);
2378 DataArrayInt *tmp0=0,*tmp1=0;
2379 // Compute the neighbor of each cell in m0Part2, taking into account the broken link above. Two
2380 // cells on either side of the crack (defined by the mesh of low dimension) are not neighbor anymore.
2381 ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00,tmp0,tmp1);
2382 DAInt neigh00(tmp0);
2383 DAInt neighI00(tmp1);
2385 // For each initial connex part of the sub-mesh (or said differently for each independent crack):
2386 int seed = 0, nIter = 0;
2387 int nIterMax = nCells2+1; // Safety net for the loop
2388 DAInt hitCells = DataArrayInt::New(); hitCells->alloc(nCells2);
2389 hitCells->fillWithValue(-1);
2390 DAInt cellsToModifyConn0_torenum = DataArrayInt::New();
2391 cellsToModifyConn0_torenum->alloc(0,1);
2392 while (nIter < nIterMax)
2394 DAInt t = hitCells->findIdsEqual(-1);
2395 if (!t->getNumberOfTuples())
2397 // Connex zone without the crack (to compute the next seed really)
2399 DAInt connexCheck = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neighInit00,neighIInit00, -1, dnu);
2401 for (int * ptr = connexCheck->getPointer(); cnt < connexCheck->getNumberOfTuples(); ptr++, cnt++)
2402 hitCells->setIJ(*ptr,0,1);
2403 // Connex zone WITH the crack (to identify cells lying on either part of the crack)
2404 DAInt spreadZone = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neigh00,neighI00, -1, dnu);
2405 cellsToModifyConn0_torenum = DataArrayInt::Aggregate(cellsToModifyConn0_torenum, spreadZone, 0);
2406 // Compute next seed, i.e. a cell in another connex part, which was not covered by the previous iterations
2407 DAInt comple = cellsToModifyConn0_torenum->buildComplement(nCells2);
2408 DAInt nonHitCells = hitCells->findIdsEqual(-1);
2409 DAInt intersec = nonHitCells->buildIntersection(comple);
2410 if (intersec->getNumberOfTuples())
2411 { seed = intersec->getIJ(0,0); }
2416 if (nIter >= nIterMax)
2417 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate(): internal error - too many iterations.");
2419 DAInt cellsToModifyConn1_torenum=cellsToModifyConn0_torenum->buildComplement(neighI00->getNumberOfTuples()-1);
2420 cellsToModifyConn0_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2421 cellsToModifyConn1_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2423 cellIdsNeededToBeRenum=cellsToModifyConn0_torenum.retn();
2424 cellIdsNotModified=cellsToModifyConn1_torenum.retn();
2425 nodeIdsToDuplicate=dupl.retn();
2429 * This method operates a modification of the connectivity and coords in \b this.
2430 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2431 * its ids will be modified to id this->getNumberOfNodes()+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2432 * 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
2433 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id this->getNumberOfNodes()+0, node id nodeIdsToDuplicateBg[1] will have id this->getNumberOfNodes()+1,
2434 * node id nodeIdsToDuplicateBg[2] will have id this->getNumberOfNodes()+2...
2436 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2438 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2439 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2441 void MEDCouplingUMesh::duplicateNodes(const int *nodeIdsToDuplicateBg, const int *nodeIdsToDuplicateEnd)
2443 int nbOfNodes=getNumberOfNodes();
2444 duplicateNodesInCoords(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd);
2445 duplicateNodesInConn(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,nbOfNodes);
2449 * This method renumbers only nodal connectivity in \a this. The renumbering is only an offset applied. So this method is a specialization of
2450 * \a renumberNodesInConn. \b WARNING, this method does not check that the resulting node ids in the nodal connectivity is in a valid range !
2452 * \param [in] offset - specifies the offset to be applied on each element of connectivity.
2454 * \sa renumberNodesInConn
2456 void MEDCouplingUMesh::renumberNodesWithOffsetInConn(int offset)
2458 checkConnectivityFullyDefined();
2459 int *conn(getNodalConnectivity()->getPointer());
2460 const int *connIndex(getNodalConnectivityIndex()->getConstPointer());
2461 int nbOfCells(getNumberOfCells());
2462 for(int i=0;i<nbOfCells;i++)
2463 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2465 int& node=conn[iconn];
2466 if(node>=0)//avoid polyhedron separator
2471 _nodal_connec->declareAsNew();
2476 * Same than renumberNodesInConn(const int *) except that here the format of old-to-new traducer is using map instead
2477 * 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
2480 void MEDCouplingUMesh::renumberNodesInConn(const INTERP_KERNEL::HashMap<int,int>& newNodeNumbersO2N)
2482 checkConnectivityFullyDefined();
2483 int *conn(getNodalConnectivity()->getPointer());
2484 const int *connIndex(getNodalConnectivityIndex()->getConstPointer());
2485 int nbOfCells(getNumberOfCells());
2486 for(int i=0;i<nbOfCells;i++)
2487 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2489 int& node=conn[iconn];
2490 if(node>=0)//avoid polyhedron separator
2492 INTERP_KERNEL::HashMap<int,int>::const_iterator it(newNodeNumbersO2N.find(node));
2493 if(it!=newNodeNumbersO2N.end())
2499 std::ostringstream oss; oss << "MEDCouplingUMesh::renumberNodesInConn(map) : presence in connectivity for cell #" << i << " of node #" << node << " : Not in map !";
2500 throw INTERP_KERNEL::Exception(oss.str());
2504 _nodal_connec->declareAsNew();
2509 * Changes ids of nodes within the nodal connectivity arrays according to a permutation
2510 * array in "Old to New" mode. The node coordinates array is \b not changed by this method.
2511 * This method is a generalization of shiftNodeNumbersInConn().
2512 * \warning This method performs no check of validity of new ids. **Use it with care !**
2513 * \param [in] newNodeNumbersO2N - a permutation array, of length \a
2514 * this->getNumberOfNodes(), in "Old to New" mode.
2515 * See \ref numbering for more info on renumbering modes.
2516 * \throw If the nodal connectivity of cells is not defined.
2518 * \if ENABLE_EXAMPLES
2519 * \ref cpp_mcumesh_renumberNodesInConn "Here is a C++ example".<br>
2520 * \ref py_mcumesh_renumberNodesInConn "Here is a Python example".
2523 void MEDCouplingUMesh::renumberNodesInConn(const int *newNodeNumbersO2N)
2525 checkConnectivityFullyDefined();
2526 int *conn=getNodalConnectivity()->getPointer();
2527 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2528 int nbOfCells(getNumberOfCells());
2529 for(int i=0;i<nbOfCells;i++)
2530 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2532 int& node=conn[iconn];
2533 if(node>=0)//avoid polyhedron separator
2535 node=newNodeNumbersO2N[node];
2538 _nodal_connec->declareAsNew();
2543 * This method renumbers nodes \b in \b connectivity \b only \b without \b any \b reference \b to \b coords.
2544 * This method performs no check on the fact that new coordinate ids are valid. \b Use \b it \b with \b care !
2545 * This method is an specialization of \ref MEDCoupling::MEDCouplingUMesh::renumberNodesInConn "renumberNodesInConn method".
2547 * \param [in] delta specifies the shift size applied to nodeId in nodal connectivity in \b this.
2549 void MEDCouplingUMesh::shiftNodeNumbersInConn(int delta)
2551 checkConnectivityFullyDefined();
2552 int *conn=getNodalConnectivity()->getPointer();
2553 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2554 int nbOfCells=getNumberOfCells();
2555 for(int i=0;i<nbOfCells;i++)
2556 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2558 int& node=conn[iconn];
2559 if(node>=0)//avoid polyhedron separator
2564 _nodal_connec->declareAsNew();
2569 * This method operates a modification of the connectivity in \b this.
2570 * 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.
2571 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2572 * its ids will be modified to id offset+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2573 * 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
2574 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id offset+0, node id nodeIdsToDuplicateBg[1] will have id offset+1,
2575 * node id nodeIdsToDuplicateBg[2] will have id offset+2...
2577 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2578 * As an another consequense after the call of this method \b this can be transiently non cohrent.
2580 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2581 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2582 * \param [in] offset the offset applied to all node ids in connectivity that are in [ \a nodeIdsToDuplicateBg, \a nodeIdsToDuplicateEnd ).
2584 void MEDCouplingUMesh::duplicateNodesInConn(const int *nodeIdsToDuplicateBg, const int *nodeIdsToDuplicateEnd, int offset)
2586 checkConnectivityFullyDefined();
2587 std::map<int,int> m;
2589 for(const int *work=nodeIdsToDuplicateBg;work!=nodeIdsToDuplicateEnd;work++,val++)
2591 int *conn=getNodalConnectivity()->getPointer();
2592 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2593 int nbOfCells=getNumberOfCells();
2594 for(int i=0;i<nbOfCells;i++)
2595 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2597 int& node=conn[iconn];
2598 if(node>=0)//avoid polyhedron separator
2600 std::map<int,int>::iterator it=m.find(node);
2609 * This method renumbers cells of \a this using the array specified by [old2NewBg;old2NewBg+getNumberOfCells())
2611 * Contrary to MEDCouplingPointSet::renumberNodes, this method makes a permutation without any fuse of cell.
2612 * After the call of this method the number of cells remains the same as before.
2614 * If 'check' equals true the method will check that any elements in [ \a old2NewBg; \a old2NewEnd ) is unique ; if not
2615 * an INTERP_KERNEL::Exception will be thrown. When 'check' equals true [ \a old2NewBg ; \a old2NewEnd ) is not expected to
2616 * be strictly in [0;this->getNumberOfCells()).
2618 * If 'check' equals false the method will not check the content of [ \a old2NewBg ; \a old2NewEnd ).
2619 * To avoid any throw of SIGSEGV when 'check' equals false, the elements in [ \a old2NewBg ; \a old2NewEnd ) should be unique and
2620 * should be contained in[0;this->getNumberOfCells()).
2622 * \param [in] old2NewBg is expected to be a dynamically allocated pointer of size at least equal to this->getNumberOfCells()
2625 void MEDCouplingUMesh::renumberCells(const int *old2NewBg, bool check)
2627 checkConnectivityFullyDefined();
2628 int nbCells=getNumberOfCells();
2629 const int *array=old2NewBg;
2631 array=DataArrayInt::CheckAndPreparePermutation(old2NewBg,old2NewBg+nbCells);
2633 const int *conn=_nodal_connec->getConstPointer();
2634 const int *connI=_nodal_connec_index->getConstPointer();
2635 MCAuto<DataArrayInt> o2n=DataArrayInt::New(); o2n->useArray(array,false,C_DEALLOC,nbCells,1);
2636 MCAuto<DataArrayInt> n2o=o2n->invertArrayO2N2N2O(nbCells);
2637 const int *n2oPtr=n2o->begin();
2638 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
2639 newConn->alloc(_nodal_connec->getNumberOfTuples(),_nodal_connec->getNumberOfComponents());
2640 newConn->copyStringInfoFrom(*_nodal_connec);
2641 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
2642 newConnI->alloc(_nodal_connec_index->getNumberOfTuples(),_nodal_connec_index->getNumberOfComponents());
2643 newConnI->copyStringInfoFrom(*_nodal_connec_index);
2645 int *newC=newConn->getPointer();
2646 int *newCI=newConnI->getPointer();
2649 for(int i=0;i<nbCells;i++)
2652 int nbOfElts=connI[pos+1]-connI[pos];
2653 newC=std::copy(conn+connI[pos],conn+connI[pos+1],newC);
2658 setConnectivity(newConn,newConnI);
2660 free(const_cast<int *>(array));
2664 * Finds cells whose bounding boxes intersect a given bounding box.
2665 * \param [in] bbox - an array defining the bounding box via coordinates of its
2666 * extremum points in "no interlace" mode, i.e. xMin, xMax, yMin, yMax, zMin,
2668 * \param [in] eps - a factor used to increase size of the bounding box of cell
2669 * before comparing it with \a bbox. This factor is multiplied by the maximal
2670 * extent of the bounding box of cell to produce an addition to this bounding box.
2671 * \return DataArrayInt * - a new instance of DataArrayInt holding ids for found
2672 * cells. The caller is to delete this array using decrRef() as it is no more
2674 * \throw If the coordinates array is not set.
2675 * \throw If the nodal connectivity of cells is not defined.
2677 * \if ENABLE_EXAMPLES
2678 * \ref cpp_mcumesh_getCellsInBoundingBox "Here is a C++ example".<br>
2679 * \ref py_mcumesh_getCellsInBoundingBox "Here is a Python example".
2682 DataArrayInt *MEDCouplingUMesh::getCellsInBoundingBox(const double *bbox, double eps) const
2684 MCAuto<DataArrayInt> elems=DataArrayInt::New(); elems->alloc(0,1);
2685 if(getMeshDimension()==-1)
2687 elems->pushBackSilent(0);
2688 return elems.retn();
2690 int dim=getSpaceDimension();
2691 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2692 const int* conn = getNodalConnectivity()->getConstPointer();
2693 const int* conn_index= getNodalConnectivityIndex()->getConstPointer();
2694 const double* coords = getCoords()->getConstPointer();
2695 int nbOfCells=getNumberOfCells();
2696 for ( int ielem=0; ielem<nbOfCells;ielem++ )
2698 for (int i=0; i<dim; i++)
2700 elem_bb[i*2]=std::numeric_limits<double>::max();
2701 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2704 for (int inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2706 int node= conn[inode];
2707 if(node>=0)//avoid polyhedron separator
2709 for (int idim=0; idim<dim; idim++)
2711 if ( coords[node*dim+idim] < elem_bb[idim*2] )
2713 elem_bb[idim*2] = coords[node*dim+idim] ;
2715 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2717 elem_bb[idim*2+1] = coords[node*dim+idim] ;
2722 if (intersectsBoundingBox(elem_bb, bbox, dim, eps))
2723 elems->pushBackSilent(ielem);
2725 return elems.retn();
2729 * Given a boundary box 'bbox' returns elements 'elems' contained in this 'bbox' or touching 'bbox' (within 'eps' distance).
2730 * Warning 'elems' is incremented during the call so if elems is not empty before call returned elements will be
2731 * added in 'elems' parameter.
2733 DataArrayInt *MEDCouplingUMesh::getCellsInBoundingBox(const INTERP_KERNEL::DirectedBoundingBox& bbox, double eps)
2735 MCAuto<DataArrayInt> elems=DataArrayInt::New(); elems->alloc(0,1);
2736 if(getMeshDimension()==-1)
2738 elems->pushBackSilent(0);
2739 return elems.retn();
2741 int dim=getSpaceDimension();
2742 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2743 const int* conn = getNodalConnectivity()->getConstPointer();
2744 const int* conn_index= getNodalConnectivityIndex()->getConstPointer();
2745 const double* coords = getCoords()->getConstPointer();
2746 int nbOfCells=getNumberOfCells();
2747 for ( int ielem=0; ielem<nbOfCells;ielem++ )
2749 for (int i=0; i<dim; i++)
2751 elem_bb[i*2]=std::numeric_limits<double>::max();
2752 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2755 for (int inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2757 int node= conn[inode];
2758 if(node>=0)//avoid polyhedron separator
2760 for (int idim=0; idim<dim; idim++)
2762 if ( coords[node*dim+idim] < elem_bb[idim*2] )
2764 elem_bb[idim*2] = coords[node*dim+idim] ;
2766 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2768 elem_bb[idim*2+1] = coords[node*dim+idim] ;
2773 if(intersectsBoundingBox(bbox, elem_bb, dim, eps))
2774 elems->pushBackSilent(ielem);
2776 return elems.retn();
2780 * Returns a type of a cell by its id.
2781 * \param [in] cellId - the id of the cell of interest.
2782 * \return INTERP_KERNEL::NormalizedCellType - enumeration item describing the cell type.
2783 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2785 INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::getTypeOfCell(std::size_t cellId) const
2787 const int *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
2788 if(cellId<_nodal_connec_index->getNbOfElems()-1)
2789 return (INTERP_KERNEL::NormalizedCellType) pt[ptI[cellId]];
2792 std::ostringstream oss; oss << "MEDCouplingUMesh::getTypeOfCell : Requesting type of cell #" << cellId << " but it should be in [0," << _nodal_connec_index->getNbOfElems()-1 << ") !";
2793 throw INTERP_KERNEL::Exception(oss.str());
2798 * This method returns a newly allocated array containing cell ids (ascendingly sorted) whose geometric type are equal to type.
2799 * This method does not throw exception if geometric type \a type is not in \a this.
2800 * This method throws an INTERP_KERNEL::Exception if meshdimension of \b this is not equal to those of \b type.
2801 * The coordinates array is not considered here.
2803 * \param [in] type the geometric type
2804 * \return cell ids in this having geometric type \a type.
2806 DataArrayInt *MEDCouplingUMesh::giveCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2809 MCAuto<DataArrayInt> ret=DataArrayInt::New();
2811 checkConnectivityFullyDefined();
2812 int nbCells=getNumberOfCells();
2813 int mdim=getMeshDimension();
2814 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
2815 if(mdim!=(int)cm.getDimension())
2816 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::giveCellsWithType : Mismatch between mesh dimension and dimension of the cell !");
2817 const int *ptI=_nodal_connec_index->getConstPointer();
2818 const int *pt=_nodal_connec->getConstPointer();
2819 for(int i=0;i<nbCells;i++)
2821 if((INTERP_KERNEL::NormalizedCellType)pt[ptI[i]]==type)
2822 ret->pushBackSilent(i);
2828 * Returns nb of cells having the geometric type \a type. No throw if no cells in \a this has the geometric type \a type.
2830 std::size_t MEDCouplingUMesh::getNumberOfCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2832 const int *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
2833 std::size_t nbOfCells(getNumberOfCells()),ret(0);
2834 for(std::size_t i=0;i<nbOfCells;i++)
2835 if((INTERP_KERNEL::NormalizedCellType) pt[ptI[i]]==type)
2841 * Returns the nodal connectivity of a given cell.
2842 * The separator of faces within polyhedron connectivity (-1) is not returned, thus
2843 * all returned node ids can be used in getCoordinatesOfNode().
2844 * \param [in] cellId - an id of the cell of interest.
2845 * \param [in,out] conn - a vector where the node ids are appended. It is not
2846 * cleared before the appending.
2847 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2849 void MEDCouplingUMesh::getNodeIdsOfCell(std::size_t cellId, std::vector<int>& conn) const
2851 const int *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
2852 for(const int *w=pt+ptI[cellId]+1;w!=pt+ptI[cellId+1];w++)
2857 std::string MEDCouplingUMesh::simpleRepr() const
2859 static const char msg0[]="No coordinates specified !";
2860 std::ostringstream ret;
2861 ret << "Unstructured mesh with name : \"" << getName() << "\"\n";
2862 ret << "Description of mesh : \"" << getDescription() << "\"\n";
2864 double tt=getTime(tmpp1,tmpp2);
2865 ret << "Time attached to the mesh [unit] : " << tt << " [" << getTimeUnit() << "]\n";
2866 ret << "Iteration : " << tmpp1 << " Order : " << tmpp2 << "\n";
2868 { ret << "Mesh dimension : " << _mesh_dim << "\nSpace dimension : "; }
2870 { ret << " Mesh dimension has not been set or is invalid !"; }
2873 const int spaceDim=getSpaceDimension();
2874 ret << spaceDim << "\nInfo attached on space dimension : ";
2875 for(int i=0;i<spaceDim;i++)
2876 ret << "\"" << _coords->getInfoOnComponent(i) << "\" ";
2880 ret << msg0 << "\n";
2881 ret << "Number of nodes : ";
2883 ret << getNumberOfNodes() << "\n";
2885 ret << msg0 << "\n";
2886 ret << "Number of cells : ";
2887 if(_nodal_connec!=0 && _nodal_connec_index!=0)
2888 ret << getNumberOfCells() << "\n";
2890 ret << "No connectivity specified !" << "\n";
2891 ret << "Cell types present : ";
2892 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
2894 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter);
2895 ret << cm.getRepr() << " ";
2901 std::string MEDCouplingUMesh::advancedRepr() const
2903 std::ostringstream ret;
2904 ret << simpleRepr();
2905 ret << "\nCoordinates array : \n___________________\n\n";
2907 _coords->reprWithoutNameStream(ret);
2909 ret << "No array set !\n";
2910 ret << "\n\nConnectivity arrays : \n_____________________\n\n";
2911 reprConnectivityOfThisLL(ret);
2916 * This method returns a C++ code that is a dump of \a this.
2917 * This method will throw if this is not fully defined.
2919 std::string MEDCouplingUMesh::cppRepr() const
2921 static const char coordsName[]="coords";
2922 static const char connName[]="conn";
2923 static const char connIName[]="connI";
2924 checkFullyDefined();
2925 std::ostringstream ret; ret << "// coordinates" << std::endl;
2926 _coords->reprCppStream(coordsName,ret); ret << std::endl << "// connectivity" << std::endl;
2927 _nodal_connec->reprCppStream(connName,ret); ret << std::endl;
2928 _nodal_connec_index->reprCppStream(connIName,ret); ret << std::endl;
2929 ret << "MEDCouplingUMesh *mesh=MEDCouplingUMesh::New(\"" << getName() << "\"," << getMeshDimension() << ");" << std::endl;
2930 ret << "mesh->setCoords(" << coordsName << ");" << std::endl;
2931 ret << "mesh->setConnectivity(" << connName << "," << connIName << ",true);" << std::endl;
2932 ret << coordsName << "->decrRef(); " << connName << "->decrRef(); " << connIName << "->decrRef();" << std::endl;
2936 std::string MEDCouplingUMesh::reprConnectivityOfThis() const
2938 std::ostringstream ret;
2939 reprConnectivityOfThisLL(ret);
2944 * This method builds a newly allocated instance (with the same name than \a this) that the caller has the responsability to deal with.
2945 * This method returns an instance with all arrays allocated (connectivity, connectivity index, coordinates)
2946 * but with length of these arrays set to 0. It allows to define an "empty" mesh (with nor cells nor nodes but compliant with
2949 * This method expects that \a this has a mesh dimension set and higher or equal to 0. If not an exception will be thrown.
2950 * 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
2951 * with number of tuples set to 0, if not the array is taken as this in the returned instance.
2953 MEDCouplingUMesh *MEDCouplingUMesh::buildSetInstanceFromThis(int spaceDim) const
2955 int mdim=getMeshDimension();
2957 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSetInstanceFromThis : invalid mesh dimension ! Should be >= 0 !");
2958 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
2959 MCAuto<DataArrayInt> tmp1,tmp2;
2960 bool needToCpyCT=true;
2963 tmp1=DataArrayInt::New(); tmp1->alloc(0,1);
2971 if(!_nodal_connec_index)
2973 tmp2=DataArrayInt::New(); tmp2->alloc(1,1); tmp2->setIJ(0,0,0);
2978 tmp2=_nodal_connec_index;
2981 ret->setConnectivity(tmp1,tmp2,false);
2986 MCAuto<DataArrayDouble> coords=DataArrayDouble::New(); coords->alloc(0,spaceDim);
2987 ret->setCoords(coords);
2990 ret->setCoords(_coords);
2994 int MEDCouplingUMesh::getNumberOfNodesInCell(int cellId) const
2996 const int *ptI=_nodal_connec_index->getConstPointer();
2997 const int *pt=_nodal_connec->getConstPointer();
2998 if(pt[ptI[cellId]]!=INTERP_KERNEL::NORM_POLYHED)
2999 return ptI[cellId+1]-ptI[cellId]-1;
3001 return (int)std::count_if(pt+ptI[cellId]+1,pt+ptI[cellId+1],std::bind2nd(std::not_equal_to<int>(),-1));
3005 * Returns types of cells of the specified part of \a this mesh.
3006 * This method avoids computing sub-mesh explicitely to get its types.
3007 * \param [in] begin - an array of cell ids of interest.
3008 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3009 * \return std::set<INTERP_KERNEL::NormalizedCellType> - a set of enumeration items
3010 * describing the cell types.
3011 * \throw If the coordinates array is not set.
3012 * \throw If the nodal connectivity of cells is not defined.
3013 * \sa getAllGeoTypes()
3015 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getTypesOfPart(const int *begin, const int *end) const
3017 checkFullyDefined();
3018 std::set<INTERP_KERNEL::NormalizedCellType> ret;
3019 const int *conn=_nodal_connec->getConstPointer();
3020 const int *connIndex=_nodal_connec_index->getConstPointer();
3021 for(const int *w=begin;w!=end;w++)
3022 ret.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]);
3027 * Defines the nodal connectivity using given connectivity arrays in \ref numbering-indirect format.
3028 * Optionally updates
3029 * a set of types of cells constituting \a this mesh.
3030 * This method is for advanced users having prepared their connectivity before. For
3031 * more info on using this method see \ref MEDCouplingUMeshAdvBuild.
3032 * \param [in] conn - the nodal connectivity array.
3033 * \param [in] connIndex - the nodal connectivity index array.
3034 * \param [in] isComputingTypes - if \c true, the set of types constituting \a this
3037 void MEDCouplingUMesh::setConnectivity(DataArrayInt *conn, DataArrayInt *connIndex, bool isComputingTypes)
3039 DataArrayInt::SetArrayIn(conn,_nodal_connec);
3040 DataArrayInt::SetArrayIn(connIndex,_nodal_connec_index);
3041 if(isComputingTypes)
3047 * Copy constructor. If 'deepCopy' is false \a this is a shallow copy of other.
3048 * If 'deeCpy' is true all arrays (coordinates and connectivities) are deeply copied.
3050 MEDCouplingUMesh::MEDCouplingUMesh(const MEDCouplingUMesh& other, bool deepCpy):MEDCouplingPointSet(other,deepCpy),_mesh_dim(other._mesh_dim),
3051 _nodal_connec(0),_nodal_connec_index(0),
3052 _types(other._types)
3054 if(other._nodal_connec)
3055 _nodal_connec=other._nodal_connec->performCopyOrIncrRef(deepCpy);
3056 if(other._nodal_connec_index)
3057 _nodal_connec_index=other._nodal_connec_index->performCopyOrIncrRef(deepCpy);
3060 MEDCouplingUMesh::~MEDCouplingUMesh()
3063 _nodal_connec->decrRef();
3064 if(_nodal_connec_index)
3065 _nodal_connec_index->decrRef();
3069 * Recomputes a set of cell types of \a this mesh. For more info see
3070 * \ref MEDCouplingUMeshNodalConnectivity.
3072 void MEDCouplingUMesh::computeTypes()
3074 ComputeAllTypesInternal(_types,_nodal_connec,_nodal_connec_index);
3079 * Returns a number of cells constituting \a this mesh.
3080 * \return int - the number of cells in \a this mesh.
3081 * \throw If the nodal connectivity of cells is not defined.
3083 std::size_t MEDCouplingUMesh::getNumberOfCells() const
3085 if(_nodal_connec_index)
3086 return _nodal_connec_index->getNumberOfTuples()-1;
3091 throw INTERP_KERNEL::Exception("Unable to get number of cells because no connectivity specified !");
3095 * Returns a dimension of \a this mesh, i.e. a dimension of cells constituting \a this
3096 * mesh. For more info see \ref meshes.
3097 * \return int - the dimension of \a this mesh.
3098 * \throw If the mesh dimension is not defined using setMeshDimension().
3100 int MEDCouplingUMesh::getMeshDimension() const
3103 throw INTERP_KERNEL::Exception("No mesh dimension specified !");
3108 * Returns a length of the nodal connectivity array.
3109 * This method is for test reason. Normally the integer returned is not useable by
3110 * user. For more info see \ref MEDCouplingUMeshNodalConnectivity.
3111 * \return int - the length of the nodal connectivity array.
3113 int MEDCouplingUMesh::getNodalConnectivityArrayLen() const
3115 return _nodal_connec->getNbOfElems();
3119 * First step of serialization process. Used by ParaMEDMEM and MEDCouplingCorba to transfert data between process.
3121 void MEDCouplingUMesh::getTinySerializationInformation(std::vector<double>& tinyInfoD, std::vector<int>& tinyInfo, std::vector<std::string>& littleStrings) const
3123 MEDCouplingPointSet::getTinySerializationInformation(tinyInfoD,tinyInfo,littleStrings);
3124 tinyInfo.push_back(getMeshDimension());
3125 tinyInfo.push_back(getNumberOfCells());
3127 tinyInfo.push_back(getNodalConnectivityArrayLen());
3129 tinyInfo.push_back(-1);
3133 * First step of unserialization process.
3135 bool MEDCouplingUMesh::isEmptyMesh(const std::vector<int>& tinyInfo) const
3137 return tinyInfo[6]<=0;
3141 * Second step of serialization process.
3142 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3145 * \param littleStrings
3147 void MEDCouplingUMesh::resizeForUnserialization(const std::vector<int>& tinyInfo, DataArrayInt *a1, DataArrayDouble *a2, std::vector<std::string>& littleStrings) const
3149 MEDCouplingPointSet::resizeForUnserialization(tinyInfo,a1,a2,littleStrings);
3151 a1->alloc(tinyInfo[7]+tinyInfo[6]+1,1);
3155 * Third and final step of serialization process.
3157 void MEDCouplingUMesh::serialize(DataArrayInt *&a1, DataArrayDouble *&a2) const
3159 MEDCouplingPointSet::serialize(a1,a2);
3160 if(getMeshDimension()>-1)
3162 a1=DataArrayInt::New();
3163 a1->alloc(getNodalConnectivityArrayLen()+getNumberOfCells()+1,1);
3164 int *ptA1=a1->getPointer();
3165 const int *conn=getNodalConnectivity()->getConstPointer();
3166 const int *index=getNodalConnectivityIndex()->getConstPointer();
3167 ptA1=std::copy(index,index+getNumberOfCells()+1,ptA1);
3168 std::copy(conn,conn+getNodalConnectivityArrayLen(),ptA1);
3175 * Second and final unserialization process.
3176 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3178 void MEDCouplingUMesh::unserialization(const std::vector<double>& tinyInfoD, const std::vector<int>& tinyInfo, const DataArrayInt *a1, DataArrayDouble *a2, const std::vector<std::string>& littleStrings)
3180 MEDCouplingPointSet::unserialization(tinyInfoD,tinyInfo,a1,a2,littleStrings);
3181 setMeshDimension(tinyInfo[5]);
3185 const int *recvBuffer=a1->getConstPointer();
3186 MCAuto<DataArrayInt> myConnecIndex=DataArrayInt::New();
3187 myConnecIndex->alloc(tinyInfo[6]+1,1);
3188 std::copy(recvBuffer,recvBuffer+tinyInfo[6]+1,myConnecIndex->getPointer());
3189 MCAuto<DataArrayInt> myConnec=DataArrayInt::New();
3190 myConnec->alloc(tinyInfo[7],1);
3191 std::copy(recvBuffer+tinyInfo[6]+1,recvBuffer+tinyInfo[6]+1+tinyInfo[7],myConnec->getPointer());
3192 setConnectivity(myConnec, myConnecIndex);
3199 * Returns a new MEDCouplingFieldDouble containing volumes of cells constituting \a this
3201 * For 1D cells, the returned field contains lengths.<br>
3202 * For 2D cells, the returned field contains areas.<br>
3203 * For 3D cells, the returned field contains volumes.
3204 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3205 * orientation, i.e. the volume is always positive.
3206 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on cells
3207 * and one time . The caller is to delete this field using decrRef() as it is no
3210 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureField(bool isAbs) const
3212 std::string name="MeasureOfMesh_";
3214 int nbelem=getNumberOfCells();
3215 MCAuto<MEDCouplingFieldDouble> field=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3216 field->setName(name);
3217 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3218 array->alloc(nbelem,1);
3219 double *area_vol=array->getPointer();
3220 field->setArray(array) ; array=0;
3221 field->setMesh(const_cast<MEDCouplingUMesh *>(this));
3222 field->synchronizeTimeWithMesh();
3223 if(getMeshDimension()!=-1)
3226 INTERP_KERNEL::NormalizedCellType type;
3227 int dim_space=getSpaceDimension();
3228 const double *coords=getCoords()->getConstPointer();
3229 const int *connec=getNodalConnectivity()->getConstPointer();
3230 const int *connec_index=getNodalConnectivityIndex()->getConstPointer();
3231 for(int iel=0;iel<nbelem;iel++)
3233 ipt=connec_index[iel];
3234 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3235 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);
3238 std::transform(area_vol,area_vol+nbelem,area_vol,std::ptr_fun<double,double>(fabs));
3242 area_vol[0]=std::numeric_limits<double>::max();
3244 return field.retn();
3248 * Returns a new DataArrayDouble containing volumes of specified cells of \a this
3250 * For 1D cells, the returned array contains lengths.<br>
3251 * For 2D cells, the returned array contains areas.<br>
3252 * For 3D cells, the returned array contains volumes.
3253 * This method avoids building explicitly a part of \a this mesh to perform the work.
3254 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3255 * orientation, i.e. the volume is always positive.
3256 * \param [in] begin - an array of cell ids of interest.
3257 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3258 * \return DataArrayDouble * - a new instance of DataArrayDouble. The caller is to
3259 * delete this array using decrRef() as it is no more needed.
3261 * \if ENABLE_EXAMPLES
3262 * \ref cpp_mcumesh_getPartMeasureField "Here is a C++ example".<br>
3263 * \ref py_mcumesh_getPartMeasureField "Here is a Python example".
3265 * \sa getMeasureField()
3267 DataArrayDouble *MEDCouplingUMesh::getPartMeasureField(bool isAbs, const int *begin, const int *end) const
3269 std::string name="PartMeasureOfMesh_";
3271 int nbelem=(int)std::distance(begin,end);
3272 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3273 array->setName(name);
3274 array->alloc(nbelem,1);
3275 double *area_vol=array->getPointer();
3276 if(getMeshDimension()!=-1)
3279 INTERP_KERNEL::NormalizedCellType type;
3280 int dim_space=getSpaceDimension();
3281 const double *coords=getCoords()->getConstPointer();
3282 const int *connec=getNodalConnectivity()->getConstPointer();
3283 const int *connec_index=getNodalConnectivityIndex()->getConstPointer();
3284 for(const int *iel=begin;iel!=end;iel++)
3286 ipt=connec_index[*iel];
3287 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3288 *area_vol++=INTERP_KERNEL::computeVolSurfOfCell2<int,INTERP_KERNEL::ALL_C_MODE>(type,connec+ipt+1,connec_index[*iel+1]-ipt-1,coords,dim_space);
3291 std::transform(array->getPointer(),area_vol,array->getPointer(),std::ptr_fun<double,double>(fabs));
3295 area_vol[0]=std::numeric_limits<double>::max();
3297 return array.retn();
3301 * Returns a new MEDCouplingFieldDouble containing volumes of cells of a dual mesh of
3302 * \a this one. The returned field contains the dual cell volume for each corresponding
3303 * node in \a this mesh. In other words, the field returns the getMeasureField() of
3304 * the dual mesh in P1 sens of \a this.<br>
3305 * For 1D cells, the returned field contains lengths.<br>
3306 * For 2D cells, the returned field contains areas.<br>
3307 * For 3D cells, the returned field contains volumes.
3308 * This method is useful to check "P1*" conservative interpolators.
3309 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3310 * orientation, i.e. the volume is always positive.
3311 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3312 * nodes and one time. The caller is to delete this array using decrRef() as
3313 * it is no more needed.
3315 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureFieldOnNode(bool isAbs) const
3317 MCAuto<MEDCouplingFieldDouble> tmp=getMeasureField(isAbs);
3318 std::string name="MeasureOnNodeOfMesh_";
3320 int nbNodes=getNumberOfNodes();
3321 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_NODES);
3322 double cst=1./((double)getMeshDimension()+1.);
3323 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3324 array->alloc(nbNodes,1);
3325 double *valsToFill=array->getPointer();
3326 std::fill(valsToFill,valsToFill+nbNodes,0.);
3327 const double *values=tmp->getArray()->getConstPointer();
3328 MCAuto<DataArrayInt> da=DataArrayInt::New();
3329 MCAuto<DataArrayInt> daInd=DataArrayInt::New();
3330 getReverseNodalConnectivity(da,daInd);
3331 const int *daPtr=da->getConstPointer();
3332 const int *daIPtr=daInd->getConstPointer();
3333 for(int i=0;i<nbNodes;i++)
3334 for(const int *cell=daPtr+daIPtr[i];cell!=daPtr+daIPtr[i+1];cell++)
3335 valsToFill[i]+=cst*values[*cell];
3337 ret->setArray(array);
3342 * Returns a new MEDCouplingFieldDouble holding normal vectors to cells of \a this
3343 * mesh. The returned normal vectors to each cell have a norm2 equal to 1.
3344 * The computed vectors have <em> this->getMeshDimension()+1 </em> components
3345 * and are normalized.
3346 * <br> \a this can be either
3347 * - a 2D mesh in 2D or 3D space or
3348 * - an 1D mesh in 2D space.
3350 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3351 * cells and one time. The caller is to delete this field using decrRef() as
3352 * it is no more needed.
3353 * \throw If the nodal connectivity of cells is not defined.
3354 * \throw If the coordinates array is not set.
3355 * \throw If the mesh dimension is not set.
3356 * \throw If the mesh and space dimension is not as specified above.
3358 MEDCouplingFieldDouble *MEDCouplingUMesh::buildOrthogonalField() const
3360 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3361 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3362 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3363 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3364 int nbOfCells=getNumberOfCells();
3365 int nbComp=getMeshDimension()+1;
3366 array->alloc(nbOfCells,nbComp);
3367 double *vals=array->getPointer();
3368 const int *connI=_nodal_connec_index->getConstPointer();
3369 const int *conn=_nodal_connec->getConstPointer();
3370 const double *coords=_coords->getConstPointer();
3371 if(getMeshDimension()==2)
3373 if(getSpaceDimension()==3)
3375 MCAuto<DataArrayDouble> loc=computeCellCenterOfMass();
3376 const double *locPtr=loc->getConstPointer();
3377 for(int i=0;i<nbOfCells;i++,vals+=3)
3379 int offset=connI[i];
3380 INTERP_KERNEL::crossprod<3>(locPtr+3*i,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3381 double n=INTERP_KERNEL::norm<3>(vals);
3382 std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3387 MCAuto<MEDCouplingFieldDouble> isAbs=getMeasureField(false);
3388 const double *isAbsPtr=isAbs->getArray()->begin();
3389 for(int i=0;i<nbOfCells;i++,isAbsPtr++)
3390 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=*isAbsPtr>0.?1.:-1.; }
3393 else//meshdimension==1
3396 for(int i=0;i<nbOfCells;i++)
3398 int offset=connI[i];
3399 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3400 double n=INTERP_KERNEL::norm<2>(tmp);
3401 std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3406 ret->setArray(array);
3408 ret->synchronizeTimeWithSupport();
3413 * Returns a new MEDCouplingFieldDouble holding normal vectors to specified cells of
3414 * \a this mesh. The computed vectors have <em> this->getMeshDimension()+1 </em> components
3415 * and are normalized.
3416 * <br> \a this can be either
3417 * - a 2D mesh in 2D or 3D space or
3418 * - an 1D mesh in 2D space.
3420 * This method avoids building explicitly a part of \a this mesh to perform the work.
3421 * \param [in] begin - an array of cell ids of interest.
3422 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3423 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3424 * cells and one time. The caller is to delete this field using decrRef() as
3425 * it is no more needed.
3426 * \throw If the nodal connectivity of cells is not defined.
3427 * \throw If the coordinates array is not set.
3428 * \throw If the mesh dimension is not set.
3429 * \throw If the mesh and space dimension is not as specified above.
3430 * \sa buildOrthogonalField()
3432 * \if ENABLE_EXAMPLES
3433 * \ref cpp_mcumesh_buildPartOrthogonalField "Here is a C++ example".<br>
3434 * \ref py_mcumesh_buildPartOrthogonalField "Here is a Python example".
3437 MEDCouplingFieldDouble *MEDCouplingUMesh::buildPartOrthogonalField(const int *begin, const int *end) const
3439 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3440 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3441 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3442 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3443 std::size_t nbelems=std::distance(begin,end);
3444 int nbComp=getMeshDimension()+1;
3445 array->alloc((int)nbelems,nbComp);
3446 double *vals=array->getPointer();
3447 const int *connI=_nodal_connec_index->getConstPointer();
3448 const int *conn=_nodal_connec->getConstPointer();
3449 const double *coords=_coords->getConstPointer();
3450 if(getMeshDimension()==2)
3452 if(getSpaceDimension()==3)
3454 MCAuto<DataArrayDouble> loc=getPartBarycenterAndOwner(begin,end);
3455 const double *locPtr=loc->getConstPointer();
3456 for(const int *i=begin;i!=end;i++,vals+=3,locPtr+=3)
3458 int offset=connI[*i];
3459 INTERP_KERNEL::crossprod<3>(locPtr,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3460 double n=INTERP_KERNEL::norm<3>(vals);
3461 std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3466 for(std::size_t i=0;i<nbelems;i++)
3467 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=1.; }
3470 else//meshdimension==1
3473 for(const int *i=begin;i!=end;i++)
3475 int offset=connI[*i];
3476 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3477 double n=INTERP_KERNEL::norm<2>(tmp);
3478 std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3483 ret->setArray(array);
3485 ret->synchronizeTimeWithSupport();
3490 * Returns a new MEDCouplingFieldDouble holding a direction vector for each SEG2 in \a
3491 * this 1D mesh. The computed vectors have <em> this->getSpaceDimension() </em> components
3492 * and are \b not normalized.
3493 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3494 * cells and one time. The caller is to delete this field using decrRef() as
3495 * it is no more needed.
3496 * \throw If the nodal connectivity of cells is not defined.
3497 * \throw If the coordinates array is not set.
3498 * \throw If \a this->getMeshDimension() != 1.
3499 * \throw If \a this mesh includes cells of type other than SEG2.
3501 MEDCouplingFieldDouble *MEDCouplingUMesh::buildDirectionVectorField() const
3503 if(getMeshDimension()!=1)
3504 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for buildDirectionVectorField !");
3505 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3506 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for buildDirectionVectorField !");
3507 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3508 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3509 int nbOfCells=getNumberOfCells();
3510 int spaceDim=getSpaceDimension();
3511 array->alloc(nbOfCells,spaceDim);
3512 double *pt=array->getPointer();
3513 const double *coo=getCoords()->getConstPointer();
3514 std::vector<int> conn;
3516 for(int i=0;i<nbOfCells;i++)
3519 getNodeIdsOfCell(i,conn);
3520 pt=std::transform(coo+conn[1]*spaceDim,coo+(conn[1]+1)*spaceDim,coo+conn[0]*spaceDim,pt,std::minus<double>());
3522 ret->setArray(array);
3524 ret->synchronizeTimeWithSupport();
3529 * Creates a 2D mesh by cutting \a this 3D mesh with a plane. In addition to the mesh,
3530 * returns a new DataArrayInt, of length equal to the number of 2D cells in the result
3531 * mesh, holding, for each cell in the result mesh, an id of a 3D cell it comes
3532 * from. If a result face is shared by two 3D cells, then the face in included twice in
3534 * \param [in] origin - 3 components of a point defining location of the plane.
3535 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3536 * must be greater than 1e-6.
3537 * \param [in] eps - half-thickness of the plane.
3538 * \param [out] cellIds - a new instance of DataArrayInt holding ids of 3D cells
3539 * producing correspondent 2D cells. The caller is to delete this array
3540 * using decrRef() as it is no more needed.
3541 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This mesh does
3542 * not share the node coordinates array with \a this mesh. The caller is to
3543 * delete this mesh using decrRef() as it is no more needed.
3544 * \throw If the coordinates array is not set.
3545 * \throw If the nodal connectivity of cells is not defined.
3546 * \throw If \a this->getMeshDimension() != 3 or \a this->getSpaceDimension() != 3.
3547 * \throw If magnitude of \a vec is less than 1e-6.
3548 * \throw If the plane does not intersect any 3D cell of \a this mesh.
3549 * \throw If \a this includes quadratic cells.
3551 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3D(const double *origin, const double *vec, double eps, DataArrayInt *&cellIds) const
3553 checkFullyDefined();
3554 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3555 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3556 MCAuto<DataArrayInt> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3557 if(candidates->empty())
3558 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane considering bounding boxes !");
3559 std::vector<int> nodes;
3560 DataArrayInt *cellIds1D=0;
3561 MCAuto<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3562 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3563 MCAuto<DataArrayInt> desc1=DataArrayInt::New(),desc2=DataArrayInt::New();
3564 MCAuto<DataArrayInt> descIndx1=DataArrayInt::New(),descIndx2=DataArrayInt::New();
3565 MCAuto<DataArrayInt> revDesc1=DataArrayInt::New(),revDesc2=DataArrayInt::New();
3566 MCAuto<DataArrayInt> revDescIndx1=DataArrayInt::New(),revDescIndx2=DataArrayInt::New();
3567 MCAuto<MEDCouplingUMesh> mDesc2=subMesh->buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2);//meshDim==2 spaceDim==3
3568 revDesc2=0; revDescIndx2=0;
3569 MCAuto<MEDCouplingUMesh> mDesc1=mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3570 revDesc1=0; revDescIndx1=0;
3571 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3572 MCAuto<DataArrayInt> cellIds1DTmp(cellIds1D);
3574 std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3575 for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3577 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3578 std::vector< std::pair<int,int> > cut3DSurf(mDesc2->getNumberOfCells());
3579 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->getConstPointer(),mDesc2->getNodalConnectivityIndex()->getConstPointer(),
3580 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3581 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3582 MCAuto<DataArrayInt> conn(DataArrayInt::New()),connI(DataArrayInt::New()),cellIds2(DataArrayInt::New());
3583 connI->pushBackSilent(0); conn->alloc(0,1); cellIds2->alloc(0,1);
3584 subMesh->assemblyForSplitFrom3DSurf(cut3DSurf,desc2->getConstPointer(),descIndx2->getConstPointer(),conn,connI,cellIds2);
3585 if(cellIds2->empty())
3586 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3587 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3D",2);
3588 ret->setCoords(mDesc1->getCoords());
3589 ret->setConnectivity(conn,connI,true);
3590 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3595 * Creates an 1D mesh by cutting \a this 2D mesh in 3D space with a plane. In
3596 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
3597 from. If a result segment is shared by two 2D cells, then the segment in included twice in
3599 * \param [in] origin - 3 components of a point defining location of the plane.
3600 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3601 * must be greater than 1e-6.
3602 * \param [in] eps - half-thickness of the plane.
3603 * \param [out] cellIds - a new instance of DataArrayInt holding ids of faces
3604 * producing correspondent segments. The caller is to delete this array
3605 * using decrRef() as it is no more needed.
3606 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This is an 1D
3607 * mesh in 3D space. This mesh does not share the node coordinates array with
3608 * \a this mesh. The caller is to delete this mesh using decrRef() as it is
3610 * \throw If the coordinates array is not set.
3611 * \throw If the nodal connectivity of cells is not defined.
3612 * \throw If \a this->getMeshDimension() != 2 or \a this->getSpaceDimension() != 3.
3613 * \throw If magnitude of \a vec is less than 1e-6.
3614 * \throw If the plane does not intersect any 2D cell of \a this mesh.
3615 * \throw If \a this includes quadratic cells.
3617 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3DSurf(const double *origin, const double *vec, double eps, DataArrayInt *&cellIds) const
3619 checkFullyDefined();
3620 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
3621 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf works on umeshes with meshdim equal to 2 and spaceDim equal to 3 !");
3622 MCAuto<DataArrayInt> candidates(getCellIdsCrossingPlane(origin,vec,eps));
3623 if(candidates->empty())
3624 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3D surf cells in this intercepts the specified plane considering bounding boxes !");
3625 std::vector<int> nodes;
3626 DataArrayInt *cellIds1D(0);
3627 MCAuto<MEDCouplingUMesh> subMesh(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3628 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3629 MCAuto<DataArrayInt> desc1(DataArrayInt::New()),descIndx1(DataArrayInt::New()),revDesc1(DataArrayInt::New()),revDescIndx1(DataArrayInt::New());
3630 MCAuto<MEDCouplingUMesh> mDesc1(subMesh->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3631 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3632 MCAuto<DataArrayInt> cellIds1DTmp(cellIds1D);
3634 std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3635 for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3637 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3638 int ncellsSub=subMesh->getNumberOfCells();
3639 std::vector< std::pair<int,int> > cut3DSurf(ncellsSub);
3640 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,subMesh->getNodalConnectivity()->getConstPointer(),subMesh->getNodalConnectivityIndex()->getConstPointer(),
3641 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3642 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3643 MCAuto<DataArrayInt> conn(DataArrayInt::New()),connI(DataArrayInt::New()),cellIds2(DataArrayInt::New()); connI->pushBackSilent(0);
3645 const int *nodal=subMesh->getNodalConnectivity()->getConstPointer();
3646 const int *nodalI=subMesh->getNodalConnectivityIndex()->getConstPointer();
3647 for(int i=0;i<ncellsSub;i++)
3649 if(cut3DSurf[i].first!=-1 && cut3DSurf[i].second!=-1)
3651 if(cut3DSurf[i].first!=-2)
3653 conn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG2); conn->pushBackSilent(cut3DSurf[i].first); conn->pushBackSilent(cut3DSurf[i].second);
3654 connI->pushBackSilent(conn->getNumberOfTuples());
3655 cellIds2->pushBackSilent(i);
3659 int cellId3DSurf=cut3DSurf[i].second;
3660 int offset=nodalI[cellId3DSurf]+1;
3661 int nbOfEdges=nodalI[cellId3DSurf+1]-offset;
3662 for(int j=0;j<nbOfEdges;j++)
3664 conn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG2); conn->pushBackSilent(nodal[offset+j]); conn->pushBackSilent(nodal[offset+(j+1)%nbOfEdges]);
3665 connI->pushBackSilent(conn->getNumberOfTuples());
3666 cellIds2->pushBackSilent(cellId3DSurf);
3671 if(cellIds2->empty())
3672 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3DSurf cells in this intercepts the specified plane !");
3673 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3DSurf",1);
3674 ret->setCoords(mDesc1->getCoords());
3675 ret->setConnectivity(conn,connI,true);
3676 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3680 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::clipSingle3DCellByPlane(const double origin[3], const double vec[3], double eps) const
3682 checkFullyDefined();
3683 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3684 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3685 if(getNumberOfCells()!=1)
3686 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works only on mesh containing exactly one cell !");
3688 std::vector<int> nodes;
3689 findNodesOnPlane(origin,vec,eps,nodes);
3690 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());
3691 MCAuto<MEDCouplingUMesh> mDesc2(buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2));//meshDim==2 spaceDim==3
3692 revDesc2=0; revDescIndx2=0;
3693 MCAuto<MEDCouplingUMesh> mDesc1(mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3694 revDesc1=0; revDescIndx1=0;
3695 DataArrayInt *cellIds1D(0);
3696 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3697 MCAuto<DataArrayInt> cellIds1DTmp(cellIds1D);
3698 std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3699 for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3703 int oldNbNodes(mDesc1->getNumberOfNodes());
3704 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3705 sameNbNodes=(mDesc1->getNumberOfNodes()==oldNbNodes);
3707 std::vector< std::pair<int,int> > cut3DSurf(mDesc2->getNumberOfCells());
3708 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->begin(),mDesc2->getNodalConnectivityIndex()->begin(),
3709 mDesc1->getNodalConnectivity()->begin(),mDesc1->getNodalConnectivityIndex()->begin(),
3710 desc1->begin(),descIndx1->begin(),cut3DSurf);
3711 MCAuto<DataArrayInt> conn(DataArrayInt::New()),connI(DataArrayInt::New());
3712 connI->pushBackSilent(0); conn->alloc(0,1);
3714 MCAuto<DataArrayInt> cellIds2(DataArrayInt::New()); cellIds2->alloc(0,1);
3715 assemblyForSplitFrom3DSurf(cut3DSurf,desc2->begin(),descIndx2->begin(),conn,connI,cellIds2);
3716 if(cellIds2->empty())
3717 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3719 std::vector<std::vector<int> > res;
3720 buildSubCellsFromCut(cut3DSurf,desc2->begin(),descIndx2->begin(),mDesc1->getCoords()->begin(),eps,res);
3721 std::size_t sz(res.size());
3722 if(res.size()==mDesc1->getNumberOfCells() && sameNbNodes)
3723 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane : cell is not clipped !");
3724 for(std::size_t i=0;i<sz;i++)
3726 conn->pushBackSilent((int)INTERP_KERNEL::NORM_POLYGON);
3727 conn->insertAtTheEnd(res[i].begin(),res[i].end());
3728 connI->pushBackSilent(conn->getNumberOfTuples());
3730 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
3731 ret->setCoords(mDesc1->getCoords());
3732 ret->setConnectivity(conn,connI,true);
3733 int nbCellsRet(ret->getNumberOfCells());
3735 MCAuto<DataArrayDouble> vec2(DataArrayDouble::New()); vec2->alloc(1,3); std::copy(vec,vec+3,vec2->getPointer());
3736 MCAuto<MEDCouplingFieldDouble> ortho(ret->buildOrthogonalField());
3737 MCAuto<DataArrayDouble> ortho2(ortho->getArray()->selectByTupleIdSafeSlice(0,1,1));
3738 MCAuto<DataArrayDouble> dott(DataArrayDouble::Dot(ortho2,vec2));
3739 MCAuto<DataArrayDouble> ccm(ret->computeCellCenterOfMass());
3740 MCAuto<DataArrayDouble> occm;
3742 MCAuto<DataArrayDouble> pt(DataArrayDouble::New()); pt->alloc(1,3); std::copy(origin,origin+3,pt->getPointer());
3743 occm=DataArrayDouble::Substract(ccm,pt);
3745 vec2=DataArrayDouble::New(); vec2->alloc(nbCellsRet,3);
3746 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);
3747 MCAuto<DataArrayDouble> dott2(DataArrayDouble::Dot(occm,vec2));
3749 const int *cPtr(ret->getNodalConnectivity()->begin()),*ciPtr(ret->getNodalConnectivityIndex()->begin());
3750 MCAuto<MEDCouplingUMesh> ret2(MEDCouplingUMesh::New("Clip3D",3));
3751 ret2->setCoords(mDesc1->getCoords());
3752 MCAuto<DataArrayInt> conn2(DataArrayInt::New()),conn2I(DataArrayInt::New());
3753 conn2I->pushBackSilent(0); conn2->alloc(0,1);
3754 std::vector<int> cell0(1,(int)INTERP_KERNEL::NORM_POLYHED);
3755 std::vector<int> cell1(1,(int)INTERP_KERNEL::NORM_POLYHED);
3756 if(dott->getIJ(0,0)>0)
3758 cell0.insert(cell0.end(),cPtr+1,cPtr+ciPtr[1]);
3759 std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell1,cell1.end()));
3763 cell1.insert(cell1.end(),cPtr+1,cPtr+ciPtr[1]);
3764 std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell0,cell0.end()));
3766 for(int i=1;i<nbCellsRet;i++)
3768 if(dott2->getIJ(i,0)<0)
3770 if(ciPtr[i+1]-ciPtr[i]>=4)
3772 cell0.push_back(-1);
3773 cell0.insert(cell0.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
3778 if(ciPtr[i+1]-ciPtr[i]>=4)
3780 cell1.push_back(-1);
3781 cell1.insert(cell1.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
3785 conn2->insertAtTheEnd(cell0.begin(),cell0.end());
3786 conn2I->pushBackSilent(conn2->getNumberOfTuples());
3787 conn2->insertAtTheEnd(cell1.begin(),cell1.end());
3788 conn2I->pushBackSilent(conn2->getNumberOfTuples());
3789 ret2->setConnectivity(conn2,conn2I,true);
3790 ret2->checkConsistencyLight();
3791 ret2->orientCorrectlyPolyhedrons();
3796 * Finds cells whose bounding boxes intersect a given plane.
3797 * \param [in] origin - 3 components of a point defining location of the plane.
3798 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3799 * must be greater than 1e-6.
3800 * \param [in] eps - half-thickness of the plane.
3801 * \return DataArrayInt * - a new instance of DataArrayInt holding ids of the found
3802 * cells. The caller is to delete this array using decrRef() as it is no more
3804 * \throw If the coordinates array is not set.
3805 * \throw If the nodal connectivity of cells is not defined.
3806 * \throw If \a this->getSpaceDimension() != 3.
3807 * \throw If magnitude of \a vec is less than 1e-6.
3808 * \sa buildSlice3D()
3810 DataArrayInt *MEDCouplingUMesh::getCellIdsCrossingPlane(const double *origin, const double *vec, double eps) const
3812 checkFullyDefined();
3813 if(getSpaceDimension()!=3)
3814 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with spaceDim equal to 3 !");
3815 double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
3817 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellIdsCrossingPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
3819 vec2[0]=vec[1]; vec2[1]=-vec[0]; vec2[2]=0.;//vec2 is the result of cross product of vec with (0,0,1)
3820 double angle=acos(vec[2]/normm);
3821 MCAuto<DataArrayInt> cellIds;
3825 MCAuto<DataArrayDouble> coo=_coords->deepCopy();
3826 double normm2(sqrt(vec2[0]*vec2[0]+vec2[1]*vec2[1]+vec2[2]*vec2[2]));
3827 if(normm2/normm>1e-6)
3828 DataArrayDouble::Rotate3DAlg(origin,vec2,angle,coo->getNumberOfTuples(),coo->getPointer(),coo->getPointer());
3829 MCAuto<MEDCouplingUMesh> mw=clone(false);//false -> shallow copy
3831 mw->getBoundingBox(bbox);
3832 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3833 cellIds=mw->getCellsInBoundingBox(bbox,eps);
3837 getBoundingBox(bbox);
3838 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3839 cellIds=getCellsInBoundingBox(bbox,eps);
3841 return cellIds.retn();
3845 * This method checks that \a this is a contiguous mesh. The user is expected to call this method on a mesh with meshdim==1.
3846 * If not an exception will thrown. If this is an empty mesh with no cell an exception will be thrown too.
3847 * No consideration of coordinate is done by this method.
3848 * 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)
3849 * If not false is returned. In case that false is returned a call to MEDCoupling::MEDCouplingUMesh::mergeNodes could be usefull.
3851 bool MEDCouplingUMesh::isContiguous1D() const
3853 if(getMeshDimension()!=1)
3854 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense only for 1D mesh !");
3855 int nbCells=getNumberOfCells();
3857 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense for non empty mesh !");
3858 const int *connI(_nodal_connec_index->begin()),*conn(_nodal_connec->begin());
3859 int ref=conn[connI[0]+2];
3860 for(int i=1;i<nbCells;i++)
3862 if(conn[connI[i]+1]!=ref)
3864 ref=conn[connI[i]+2];
3870 * This method is only callable on mesh with meshdim == 1 containing only SEG2 and spaceDim==3.
3871 * This method projects this on the 3D line defined by (pt,v). This methods first checks that all SEG2 are along v vector.
3872 * \param pt reference point of the line
3873 * \param v normalized director vector of the line
3874 * \param eps max precision before throwing an exception
3875 * \param res output of size this->getNumberOfCells
3877 void MEDCouplingUMesh::project1D(const double *pt, const double *v, double eps, double *res) const
3879 if(getMeshDimension()!=1)
3880 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for project1D !");
3881 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3882 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for project1D !");
3883 if(getSpaceDimension()!=3)
3884 throw INTERP_KERNEL::Exception("Expected a umesh with spaceDim==3 for project1D !");
3885 MCAuto<MEDCouplingFieldDouble> f=buildDirectionVectorField();
3886 const double *fPtr=f->getArray()->getConstPointer();
3888 for(std::size_t i=0;i<getNumberOfCells();i++)
3890 const double *tmp1=fPtr+3*i;
3891 tmp[0]=tmp1[1]*v[2]-tmp1[2]*v[1];
3892 tmp[1]=tmp1[2]*v[0]-tmp1[0]*v[2];
3893 tmp[2]=tmp1[0]*v[1]-tmp1[1]*v[0];
3894 double n1=INTERP_KERNEL::norm<3>(tmp);
3895 n1/=INTERP_KERNEL::norm<3>(tmp1);
3897 throw INTERP_KERNEL::Exception("UMesh::Projection 1D failed !");
3899 const double *coo=getCoords()->getConstPointer();
3900 for(int i=0;i<getNumberOfNodes();i++)
3902 std::transform(coo+i*3,coo+i*3+3,pt,tmp,std::minus<double>());
3903 std::transform(tmp,tmp+3,v,tmp,std::multiplies<double>());
3904 res[i]=std::accumulate(tmp,tmp+3,0.);
3909 * 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.
3910 * \a this is expected to be a mesh so that its space dimension is equal to its
3911 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
3912 * 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).
3914 * 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
3915 * 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).
3916 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
3918 * So this method is more accurate (so, more costly) than simply searching for the closest point in \a this.
3919 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
3921 * \param [in] ptBg the start pointer (included) of the coordinates of the point
3922 * \param [in] ptEnd the end pointer (not included) of the coordinates of the point
3923 * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
3924 * \return the positive value of the distance.
3925 * \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
3927 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoints
3929 double MEDCouplingUMesh::distanceToPoint(const double *ptBg, const double *ptEnd, int& cellId) const
3931 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
3932 if(meshDim!=spaceDim-1)
3933 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint works only for spaceDim=meshDim+1 !");
3934 if(meshDim!=2 && meshDim!=1)
3935 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint : only mesh dimension 2 and 1 are implemented !");
3936 checkFullyDefined();
3937 if((int)std::distance(ptBg,ptEnd)!=spaceDim)
3938 { 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()); }
3939 DataArrayInt *ret1=0;
3940 MCAuto<DataArrayDouble> pts=DataArrayDouble::New(); pts->useArray(ptBg,false,C_DEALLOC,1,spaceDim);
3941 MCAuto<DataArrayDouble> ret0=distanceToPoints(pts,ret1);
3942 MCAuto<DataArrayInt> ret1Safe(ret1);
3943 cellId=*ret1Safe->begin();
3944 return *ret0->begin();
3948 * This method computes the distance from each point of points serie \a pts (stored in a DataArrayDouble in which each tuple represents a point)
3949 * to \a this and the first \a cellId in \a this corresponding to the returned distance.
3950 * 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
3951 * 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).
3952 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
3954 * \a this is expected to be a mesh so that its space dimension is equal to its
3955 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
3956 * 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).
3958 * So this method is more accurate (so, more costly) than simply searching for each point in \a pts the closest point in \a this.
3959 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
3961 * \param [in] pts the list of points in which each tuple represents a point
3962 * \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.
3963 * \return a newly allocated object to be dealed by the caller that tells for each point in \a pts the distance to \a this.
3964 * \throw if number of components of \a pts is not equal to the space dimension.
3965 * \throw if mesh dimension of \a this is not equal to space dimension - 1.
3966 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoint
3968 DataArrayDouble *MEDCouplingUMesh::distanceToPoints(const DataArrayDouble *pts, DataArrayInt *& cellIds) const
3971 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : input points pointer is NULL !");
3972 pts->checkAllocated();
3973 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
3974 if(meshDim!=spaceDim-1)
3975 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints works only for spaceDim=meshDim+1 !");
3976 if(meshDim!=2 && meshDim!=1)
3977 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only mesh dimension 2 and 1 are implemented !");
3978 if((int)pts->getNumberOfComponents()!=spaceDim)
3980 std::ostringstream oss; oss << "MEDCouplingUMesh::distanceToPoints : input pts DataArrayDouble has " << pts->getNumberOfComponents() << " components whereas it should be equal to " << spaceDim << " (mesh spaceDimension) !";
3981 throw INTERP_KERNEL::Exception(oss.str());
3983 checkFullyDefined();
3984 int nbCells=getNumberOfCells();
3986 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : no cells in this !");
3987 int nbOfPts=pts->getNumberOfTuples();
3988 MCAuto<DataArrayDouble> ret0=DataArrayDouble::New(); ret0->alloc(nbOfPts,1);
3989 MCAuto<DataArrayInt> ret1=DataArrayInt::New(); ret1->alloc(nbOfPts,1);
3990 const int *nc=_nodal_connec->begin(),*ncI=_nodal_connec_index->begin(); const double *coords=_coords->begin();
3991 double *ret0Ptr=ret0->getPointer(); int *ret1Ptr=ret1->getPointer(); const double *ptsPtr=pts->begin();
3992 MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree());
3993 const double *bbox(bboxArr->begin());
3998 BBTreeDst<3> myTree(bbox,0,0,nbCells);
3999 for(int i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=3)
4001 double x=std::numeric_limits<double>::max();
4002 std::vector<int> elems;
4003 myTree.getMinDistanceOfMax(ptsPtr,x);
4004 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4005 DistanceToPoint3DSurfAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4011 BBTreeDst<2> myTree(bbox,0,0,nbCells);
4012 for(int i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=2)
4014 double x=std::numeric_limits<double>::max();
4015 std::vector<int> elems;
4016 myTree.getMinDistanceOfMax(ptsPtr,x);
4017 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4018 DistanceToPoint2DCurveAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4023 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only spacedim 2 and 3 supported !");
4025 cellIds=ret1.retn();
4034 * Finds cells in contact with a ball (i.e. a point with precision).
4035 * 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.
4036 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4038 * \warning This method is suitable if the caller intends to evaluate only one
4039 * point, for more points getCellsContainingPoints() is recommended as it is
4041 * \param [in] pos - array of coordinates of the ball central point.
4042 * \param [in] eps - ball radius.
4043 * \return int - a smallest id of cells being in contact with the ball, -1 in case
4044 * if there are no such cells.
4045 * \throw If the coordinates array is not set.
4046 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4048 int MEDCouplingUMesh::getCellContainingPoint(const double *pos, double eps) const
4050 std::vector<int> elts;
4051 getCellsContainingPoint(pos,eps,elts);
4054 return elts.front();
4058 * Finds cells in contact with a ball (i.e. a point with precision).
4059 * 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.
4060 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4061 * \warning This method is suitable if the caller intends to evaluate only one
4062 * point, for more points getCellsContainingPoints() is recommended as it is
4064 * \param [in] pos - array of coordinates of the ball central point.
4065 * \param [in] eps - ball radius.
4066 * \param [out] elts - vector returning ids of the found cells. It is cleared
4067 * before inserting ids.
4068 * \throw If the coordinates array is not set.
4069 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4071 * \if ENABLE_EXAMPLES
4072 * \ref cpp_mcumesh_getCellsContainingPoint "Here is a C++ example".<br>
4073 * \ref py_mcumesh_getCellsContainingPoint "Here is a Python example".
4076 void MEDCouplingUMesh::getCellsContainingPoint(const double *pos, double eps, std::vector<int>& elts) const
4078 MCAuto<DataArrayInt> eltsUg,eltsIndexUg;
4079 getCellsContainingPoints(pos,1,eps,eltsUg,eltsIndexUg);
4080 elts.clear(); elts.insert(elts.end(),eltsUg->begin(),eltsUg->end());
4084 * Finds cells in contact with several balls (i.e. points with precision).
4085 * This method is an extension of getCellContainingPoint() and
4086 * getCellsContainingPoint() for the case of multiple points.
4087 * 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.
4088 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4089 * \param [in] pos - an array of coordinates of points in full interlace mode :
4090 * X0,Y0,Z0,X1,Y1,Z1,... Size of the array must be \a
4091 * this->getSpaceDimension() * \a nbOfPoints
4092 * \param [in] nbOfPoints - number of points to locate within \a this mesh.
4093 * \param [in] eps - radius of balls (i.e. the precision).
4094 * \param [out] elts - vector returning ids of found cells.
4095 * \param [out] eltsIndex - an array, of length \a nbOfPoints + 1,
4096 * dividing cell ids in \a elts into groups each referring to one
4097 * point. Its every element (except the last one) is an index pointing to the
4098 * first id of a group of cells. For example cells in contact with the *i*-th
4099 * point are described by following range of indices:
4100 * [ \a eltsIndex[ *i* ], \a eltsIndex[ *i*+1 ] ) and the cell ids are
4101 * \a elts[ \a eltsIndex[ *i* ]], \a elts[ \a eltsIndex[ *i* ] + 1 ], ...
4102 * Number of cells in contact with the *i*-th point is
4103 * \a eltsIndex[ *i*+1 ] - \a eltsIndex[ *i* ].
4104 * \throw If the coordinates array is not set.
4105 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4107 * \if ENABLE_EXAMPLES
4108 * \ref cpp_mcumesh_getCellsContainingPoints "Here is a C++ example".<br>
4109 * \ref py_mcumesh_getCellsContainingPoints "Here is a Python example".
4112 void MEDCouplingUMesh::getCellsContainingPoints(const double *pos, int nbOfPoints, double eps,
4113 MCAuto<DataArrayInt>& elts, MCAuto<DataArrayInt>& eltsIndex) const
4115 int spaceDim=getSpaceDimension();
4116 int mDim=getMeshDimension();
4121 const double *coords=_coords->getConstPointer();
4122 getCellsContainingPointsAlg<3>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4129 throw INTERP_KERNEL::Exception("For spaceDim==3 only meshDim==3 implemented for getelementscontainingpoints !");
4131 else if(spaceDim==2)
4135 const double *coords=_coords->getConstPointer();
4136 getCellsContainingPointsAlg<2>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4139 throw INTERP_KERNEL::Exception("For spaceDim==2 only meshDim==2 implemented for getelementscontainingpoints !");
4141 else if(spaceDim==1)
4145 const double *coords=_coords->getConstPointer();
4146 getCellsContainingPointsAlg<1>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4149 throw INTERP_KERNEL::Exception("For spaceDim==1 only meshDim==1 implemented for getelementscontainingpoints !");
4152 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPoints : not managed for mdim not in [1,2,3] !");
4156 * Finds butterfly cells in \a this mesh. A 2D cell is considered to be butterfly if at
4157 * least two its edges intersect each other anywhere except their extremities. An
4158 * INTERP_KERNEL::NORM_NORI3 cell can \b not be butterfly.
4159 * \param [in,out] cells - a vector returning ids of the found cells. It is not
4160 * cleared before filling in.
4161 * \param [in] eps - precision.
4162 * \throw If \a this->getMeshDimension() != 2.
4163 * \throw If \a this->getSpaceDimension() != 2 && \a this->getSpaceDimension() != 3.
4165 void MEDCouplingUMesh::checkButterflyCells(std::vector<int>& cells, double eps) const
4167 const char msg[]="Butterfly detection work only for 2D cells with spaceDim==2 or 3!";
4168 if(getMeshDimension()!=2)
4169 throw INTERP_KERNEL::Exception(msg);
4170 int spaceDim=getSpaceDimension();
4171 if(spaceDim!=2 && spaceDim!=3)
4172 throw INTERP_KERNEL::Exception(msg);
4173 const int *conn=_nodal_connec->getConstPointer();
4174 const int *connI=_nodal_connec_index->getConstPointer();
4175 int nbOfCells=getNumberOfCells();
4176 std::vector<double> cell2DinS2;
4177 for(int i=0;i<nbOfCells;i++)
4179 int offset=connI[i];
4180 int nbOfNodesForCell=connI[i+1]-offset-1;
4181 if(nbOfNodesForCell<=3)
4183 bool isQuad=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[offset]).isQuadratic();
4184 project2DCellOnXY(conn+offset+1,conn+connI[i+1],cell2DinS2);
4185 if(isButterfly2DCell(cell2DinS2,isQuad,eps))
4192 * This method is typically requested to unbutterfly 2D linear cells in \b this.
4194 * 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.
4195 * 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.
4197 * For each 2D linear cell in \b this, this method builds the convex envelop (or the convex hull) of the current cell.
4198 * This convex envelop is computed using Jarvis march algorithm.
4199 * The coordinates and the number of cells of \b this remain unchanged on invocation of this method.
4200 * 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)
4201 * 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.
4203 * \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.
4204 * \sa MEDCouplingUMesh::colinearize2D
4206 DataArrayInt *MEDCouplingUMesh::convexEnvelop2D()
4208 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
4209 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convexEnvelop2D works only for meshDim=2 and spaceDim=2 !");
4210 checkFullyDefined();
4211 const double *coords=getCoords()->getConstPointer();
4212 int nbOfCells=getNumberOfCells();
4213 MCAuto<DataArrayInt> nodalConnecIndexOut=DataArrayInt::New();
4214 nodalConnecIndexOut->alloc(nbOfCells+1,1);
4215 MCAuto<DataArrayInt> nodalConnecOut(DataArrayInt::New());
4216 int *workIndexOut=nodalConnecIndexOut->getPointer();
4218 const int *nodalConnecIn=_nodal_connec->getConstPointer();
4219 const int *nodalConnecIndexIn=_nodal_connec_index->getConstPointer();
4220 std::set<INTERP_KERNEL::NormalizedCellType> types;
4221 MCAuto<DataArrayInt> isChanged(DataArrayInt::New());
4222 isChanged->alloc(0,1);
4223 for(int i=0;i<nbOfCells;i++,workIndexOut++)
4225 int pos=nodalConnecOut->getNumberOfTuples();
4226 if(BuildConvexEnvelopOf2DCellJarvis(coords,nodalConnecIn+nodalConnecIndexIn[i],nodalConnecIn+nodalConnecIndexIn[i+1],nodalConnecOut))
4227 isChanged->pushBackSilent(i);
4228 types.insert((INTERP_KERNEL::NormalizedCellType)nodalConnecOut->getIJ(pos,0));
4229 workIndexOut[1]=nodalConnecOut->getNumberOfTuples();
4231 if(isChanged->empty())
4233 setConnectivity(nodalConnecOut,nodalConnecIndexOut,false);
4235 return isChanged.retn();
4239 * This method is \b NOT const because it can modify \a this.
4240 * \a this is expected to be an unstructured mesh with meshDim==2 and spaceDim==3. If not an exception will be thrown.
4241 * \param mesh1D is an unstructured mesh with MeshDim==1 and spaceDim==3. If not an exception will be thrown.
4242 * \param policy specifies the type of extrusion chosen:
4243 * - \b 0 for translation only (most simple): the cells of the 1D mesh represent the vectors along which the 2D mesh
4244 * will be repeated to build each level
4245 * - \b 1 for translation and rotation: the translation is done as above. For each level, an arc of circle is fitted on
4246 * 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
4247 * 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
4249 * \return an unstructured mesh with meshDim==3 and spaceDim==3. The returned mesh has the same coords than \a this.
4251 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMesh(const MEDCouplingUMesh *mesh1D, int policy)
4253 checkFullyDefined();
4254 mesh1D->checkFullyDefined();
4255 if(!mesh1D->isContiguous1D())
4256 throw INTERP_KERNEL::Exception("buildExtrudedMesh : 1D mesh passed in parameter is not contiguous !");
4257 if(getSpaceDimension()!=mesh1D->getSpaceDimension())
4258 throw INTERP_KERNEL::Exception("Invalid call to buildExtrudedMesh this and mesh1D must have same space dimension !");
4259 if((getMeshDimension()!=2 || getSpaceDimension()!=3) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
4260 throw INTERP_KERNEL::Exception("Invalid 'this' for buildExtrudedMesh method : must be (meshDim==2 and spaceDim==3) or (meshDim==1 and spaceDim==2) !");
4261 if(mesh1D->getMeshDimension()!=1)
4262 throw INTERP_KERNEL::Exception("Invalid 'mesh1D' for buildExtrudedMesh method : must be meshDim==1 !");
4264 if(isPresenceOfQuadratic())
4266 if(mesh1D->isFullyQuadratic())
4269 throw INTERP_KERNEL::Exception("Invalid 2D mesh and 1D mesh because 2D mesh has quadratic cells and 1D is not fully quadratic !");
4271 int oldNbOfNodes(getNumberOfNodes());
4272 MCAuto<DataArrayDouble> newCoords;
4277 newCoords=fillExtCoordsUsingTranslation(mesh1D,isQuad);
4282 newCoords=fillExtCoordsUsingTranslAndAutoRotation(mesh1D,isQuad);
4286 throw INTERP_KERNEL::Exception("Not implemented extrusion policy : must be in (0) !");
4288 setCoords(newCoords);
4289 MCAuto<MEDCouplingUMesh> ret(buildExtrudedMeshFromThisLowLev(oldNbOfNodes,isQuad));
4296 * Checks if \a this mesh is constituted by only quadratic cells.
4297 * \return bool - \c true if there are only quadratic cells in \a this mesh.
4298 * \throw If the coordinates array is not set.
4299 * \throw If the nodal connectivity of cells is not defined.
4301 bool MEDCouplingUMesh::isFullyQuadratic() const
4303 checkFullyDefined();
4305 int nbOfCells=getNumberOfCells();
4306 for(int i=0;i<nbOfCells && ret;i++)
4308 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4309 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4310 ret=cm.isQuadratic();
4316 * Checks if \a this mesh includes any quadratic cell.
4317 * \return bool - \c true if there is at least one quadratic cells in \a this mesh.
4318 * \throw If the coordinates array is not set.
4319 * \throw If the nodal connectivity of cells is not defined.
4321 bool MEDCouplingUMesh::isPresenceOfQuadratic() const
4323 checkFullyDefined();
4325 int nbOfCells=getNumberOfCells();
4326 for(int i=0;i<nbOfCells && !ret;i++)
4328 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4329 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4330 ret=cm.isQuadratic();
4336 * Converts all quadratic cells to linear ones. If there are no quadratic cells in \a
4337 * this mesh, it remains unchanged.
4338 * \throw If the coordinates array is not set.
4339 * \throw If the nodal connectivity of cells is not defined.
4341 void MEDCouplingUMesh::convertQuadraticCellsToLinear()
4343 checkFullyDefined();
4344 int nbOfCells(getNumberOfCells());
4346 const int *iciptr=_nodal_connec_index->begin();
4347 for(int i=0;i<nbOfCells;i++)
4349 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4350 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4351 if(cm.isQuadratic())
4353 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4354 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4355 if(!cml.isDynamic())
4356 delta+=cm.getNumberOfNodes()-cml.getNumberOfNodes();
4358 delta+=(iciptr[i+1]-iciptr[i]-1)/2;
4363 MCAuto<DataArrayInt> newConn(DataArrayInt::New()),newConnI(DataArrayInt::New());
4364 const int *icptr(_nodal_connec->begin());
4365 newConn->alloc(getNodalConnectivityArrayLen()-delta,1);
4366 newConnI->alloc(nbOfCells+1,1);
4367 int *ocptr(newConn->getPointer()),*ociptr(newConnI->getPointer());
4370 for(int i=0;i<nbOfCells;i++,ociptr++)
4372 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)icptr[iciptr[i]];
4373 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4374 if(!cm.isQuadratic())
4376 _types.insert(type);
4377 ocptr=std::copy(icptr+iciptr[i],icptr+iciptr[i+1],ocptr);
4378 ociptr[1]=ociptr[0]+iciptr[i+1]-iciptr[i];
4382 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4383 _types.insert(typel);
4384 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4385 int newNbOfNodes=cml.getNumberOfNodes();
4387 newNbOfNodes=(iciptr[i+1]-iciptr[i]-1)/2;
4388 *ocptr++=(int)typel;
4389 ocptr=std::copy(icptr+iciptr[i]+1,icptr+iciptr[i]+newNbOfNodes+1,ocptr);
4390 ociptr[1]=ociptr[0]+newNbOfNodes+1;
4393 setConnectivity(newConn,newConnI,false);
4397 * This method converts all linear cell in \a this to quadratic one.
4398 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, here it is needed to specify the target
4399 * 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)
4400 * 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.
4401 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, the coordinates in \a this can be become bigger. All created nodes will be put at the
4402 * end of the existing coordinates.
4404 * \param [in] conversionType specifies the type of conversion expected. Only 0 (default) and 1 are supported presently. 0 those that creates the 'most' simple
4405 * corresponding quadratic cells. 1 is those creating the 'most' complex.
4406 * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
4408 * \throw if \a this is not fully defined. It throws too if \a conversionType is not in [0,1].
4410 * \sa MEDCouplingUMesh::convertQuadraticCellsToLinear
4412 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic(int conversionType)
4414 DataArrayInt *conn=0,*connI=0;
4415 DataArrayDouble *coords=0;
4416 std::set<INTERP_KERNEL::NormalizedCellType> types;
4417 checkFullyDefined();
4418 MCAuto<DataArrayInt> ret,connSafe,connISafe;
4419 MCAuto<DataArrayDouble> coordsSafe;
4420 int meshDim=getMeshDimension();
4421 switch(conversionType)
4427 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);
4428 connSafe=conn; connISafe=connI; coordsSafe=coords;
4431 ret=convertLinearCellsToQuadratic2D0(conn,connI,coords,types);
4432 connSafe=conn; connISafe=connI; coordsSafe=coords;
4435 ret=convertLinearCellsToQuadratic3D0(conn,connI,coords,types);
4436 connSafe=conn; connISafe=connI; coordsSafe=coords;
4439 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 0 mesh dimensions available are [1,2,3] !");
4447 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);//it is not a bug. In 1D policy 0 and 1 are equals
4448 connSafe=conn; connISafe=connI; coordsSafe=coords;
4451 ret=convertLinearCellsToQuadratic2D1(conn,connI,coords,types);
4452 connSafe=conn; connISafe=connI; coordsSafe=coords;
4455 ret=convertLinearCellsToQuadratic3D1(conn,connI,coords,types);
4456 connSafe=conn; connISafe=connI; coordsSafe=coords;
4459 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 1 mesh dimensions available are [1,2,3] !");
4464 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion type available are 0 (default, the simplest) and 1 (the most complex) !");
4466 setConnectivity(connSafe,connISafe,false);
4468 setCoords(coordsSafe);
4473 * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
4474 * so that the number of cells remains the same. Quadratic faces are converted to
4475 * polygons. This method works only for 2D meshes in
4476 * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
4477 * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
4478 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
4479 * \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
4480 * a polylinized edge constituting the input polygon.
4481 * \throw If the coordinates array is not set.
4482 * \throw If the nodal connectivity of cells is not defined.
4483 * \throw If \a this->getMeshDimension() != 2.
4484 * \throw If \a this->getSpaceDimension() != 2.
4486 void MEDCouplingUMesh::tessellate2D(double eps)
4488 int meshDim(getMeshDimension()),spaceDim(getSpaceDimension());
4490 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : works only with space dimension equal to 2 !");
4494 return tessellate2DCurveInternal(eps);
4496 return tessellate2DInternal(eps);
4498 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : mesh dimension must be in [1,2] !");
4502 * Tessellates \a this 1D mesh in 2D space by dividing not straight quadratic edges.
4503 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
4504 * \param [in] eps - specifies the maximal angle (in radian) between 2 sub-edges of
4505 * a sub-divided edge.
4506 * \throw If the coordinates array is not set.
4507 * \throw If the nodal connectivity of cells is not defined.
4508 * \throw If \a this->getMeshDimension() != 1.
4509 * \throw If \a this->getSpaceDimension() != 2.
4514 * This method only works if \a this has spaceDimension equal to 2 and meshDimension also equal to 2.
4515 * This method allows to modify connectivity of cells in \a this that shares some edges in \a edgeIdsToBeSplit.
4516 * The nodes to be added in those 2D cells are defined by the pair of \a nodeIdsToAdd and \a nodeIdsIndexToAdd.
4517 * Length of \a nodeIdsIndexToAdd is expected to equal to length of \a edgeIdsToBeSplit + 1.
4518 * The node ids in \a nodeIdsToAdd should be valid. Those nodes have to be sorted exactly following exactly the direction of the edge.
4519 * This method can be seen as the opposite method of colinearize2D.
4520 * 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
4521 * to avoid to modify the numbering of existing nodes.
4523 * \param [in] nodeIdsToAdd - the list of node ids to be added (\a nodeIdsIndexToAdd array allows to walk on this array)
4524 * \param [in] nodeIdsIndexToAdd - the entry point of \a nodeIdsToAdd to point to the corresponding nodes to be added.
4525 * \param [in] mesh1Desc - 1st output of buildDescendingConnectivity2 on \a this.
4526 * \param [in] desc - 2nd output of buildDescendingConnectivity2 on \a this.
4527 * \param [in] descI - 3rd output of buildDescendingConnectivity2 on \a this.
4528 * \param [in] revDesc - 4th output of buildDescendingConnectivity2 on \a this.
4529 * \param [in] revDescI - 5th output of buildDescendingConnectivity2 on \a this.
4531 * \sa buildDescendingConnectivity2
4533 void MEDCouplingUMesh::splitSomeEdgesOf2DMesh(const DataArrayInt *nodeIdsToAdd, const DataArrayInt *nodeIdsIndexToAdd, const DataArrayInt *edgeIdsToBeSplit,
4534 const MEDCouplingUMesh *mesh1Desc, const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *revDesc, const DataArrayInt *revDescI)
4536 if(!nodeIdsToAdd || !nodeIdsIndexToAdd || !edgeIdsToBeSplit || !mesh1Desc || !desc || !descI || !revDesc || !revDescI)
4537 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : input pointers must be not NULL !");
4538 nodeIdsToAdd->checkAllocated(); nodeIdsIndexToAdd->checkAllocated(); edgeIdsToBeSplit->checkAllocated(); desc->checkAllocated(); descI->checkAllocated(); revDesc->checkAllocated(); revDescI->checkAllocated();
4539 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
4540 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : this must have spacedim=meshdim=2 !");
4541 if(mesh1Desc->getSpaceDimension()!=2 || mesh1Desc->getMeshDimension()!=1)
4542 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : mesh1Desc must be the explosion of this with spaceDim=2 and meshDim = 1 !");
4543 //DataArrayInt *out0(0),*outi0(0);
4544 //MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
4545 //MCAuto<DataArrayInt> out0s(out0),outi0s(outi0);
4546 //out0s=out0s->buildUnique(); out0s->sort(true);
4552 * Divides every cell of \a this mesh into simplices (triangles in 2D and tetrahedra in 3D).
4553 * In addition, returns an array mapping new cells to old ones. <br>
4554 * This method typically increases the number of cells in \a this mesh
4555 * but the number of nodes remains \b unchanged.
4556 * That's why the 3D splitting policies
4557 * INTERP_KERNEL::GENERAL_24 and INTERP_KERNEL::GENERAL_48 are not available here.
4558 * \param [in] policy - specifies a pattern used for splitting.
4559 * The semantic of \a policy is:
4560 * - 0 - to split QUAD4 by cutting it along 0-2 diagonal (for 2D mesh only).
4561 * - 1 - to split QUAD4 by cutting it along 1-3 diagonal (for 2D mesh only).
4562 * - INTERP_KERNEL::PLANAR_FACE_5 - to split HEXA8 into 5 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4563 * - INTERP_KERNEL::PLANAR_FACE_6 - to split HEXA8 into 6 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4566 * \return DataArrayInt * - a new instance of DataArrayInt holding, for each new cell,
4567 * an id of old cell producing it. The caller is to delete this array using
4568 * decrRef() as it is no more needed.
4570 * \throw If \a policy is 0 or 1 and \a this->getMeshDimension() != 2.
4571 * \throw If \a policy is INTERP_KERNEL::PLANAR_FACE_5 or INTERP_KERNEL::PLANAR_FACE_6
4572 * and \a this->getMeshDimension() != 3.
4573 * \throw If \a policy is not one of the four discussed above.
4574 * \throw If the nodal connectivity of cells is not defined.
4575 * \sa MEDCouplingUMesh::tetrahedrize, MEDCoupling1SGTUMesh::sortHexa8EachOther
4577 DataArrayInt *MEDCouplingUMesh::simplexize(int policy)
4582 return simplexizePol0();
4584 return simplexizePol1();
4585 case (int) INTERP_KERNEL::PLANAR_FACE_5:
4586 return simplexizePlanarFace5();
4587 case (int) INTERP_KERNEL::PLANAR_FACE_6:
4588 return simplexizePlanarFace6();
4590 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)");
4595 * Checks if \a this mesh is constituted by simplex cells only. Simplex cells are:
4596 * - 1D: INTERP_KERNEL::NORM_SEG2
4597 * - 2D: INTERP_KERNEL::NORM_TRI3
4598 * - 3D: INTERP_KERNEL::NORM_TETRA4.
4600 * This method is useful for users that need to use P1 field services as
4601 * MEDCouplingFieldDouble::getValueOn(), MEDCouplingField::buildMeasureField() etc.
4602 * All these methods need mesh support containing only simplex cells.
4603 * \return bool - \c true if there are only simplex cells in \a this mesh.
4604 * \throw If the coordinates array is not set.
4605 * \throw If the nodal connectivity of cells is not defined.
4606 * \throw If \a this->getMeshDimension() < 1.
4608 bool MEDCouplingUMesh::areOnlySimplexCells() const
4610 checkFullyDefined();
4611 int mdim=getMeshDimension();
4612 if(mdim<1 || mdim>3)
4613 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::areOnlySimplexCells : only available with meshes having a meshdim 1, 2 or 3 !");
4614 int nbCells=getNumberOfCells();
4615 const int *conn=_nodal_connec->begin();
4616 const int *connI=_nodal_connec_index->begin();
4617 for(int i=0;i<nbCells;i++)
4619 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4629 * Converts degenerated 2D or 3D linear cells of \a this mesh into cells of simpler
4630 * type. For example an INTERP_KERNEL::NORM_QUAD4 cell having only three unique nodes in
4631 * its connectivity is transformed into an INTERP_KERNEL::NORM_TRI3 cell. This method
4632 * does \b not perform geometrical checks and checks only nodal connectivity of cells,
4633 * so it can be useful to call mergeNodes() before calling this method.
4634 * \throw If \a this->getMeshDimension() <= 1.
4635 * \throw If the coordinates array is not set.
4636 * \throw If the nodal connectivity of cells is not defined.
4638 void MEDCouplingUMesh::convertDegeneratedCells()
4640 checkFullyDefined();
4641 if(getMeshDimension()<=1)
4642 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4643 int nbOfCells=getNumberOfCells();
4646 int initMeshLgth=getNodalConnectivityArrayLen();
4647 int *conn=_nodal_connec->getPointer();
4648 int *index=_nodal_connec_index->getPointer();
4652 for(int i=0;i<nbOfCells;i++)
4654 lgthOfCurCell=index[i+1]-posOfCurCell;
4655 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4657 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
4658 conn+newPos+1,newLgth);
4659 conn[newPos]=newType;
4661 posOfCurCell=index[i+1];
4664 if(newPos!=initMeshLgth)
4665 _nodal_connec->reAlloc(newPos);
4670 * Finds incorrectly oriented cells of this 2D mesh in 3D space.
4671 * A cell is considered to be oriented correctly if an angle between its
4672 * normal vector and a given vector is less than \c PI / \c 2.
4673 * \param [in] vec - 3 components of the vector specifying the correct orientation of
4675 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
4677 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
4678 * is not cleared before filling in.
4679 * \throw If \a this->getMeshDimension() != 2.
4680 * \throw If \a this->getSpaceDimension() != 3.
4682 * \if ENABLE_EXAMPLES
4683 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
4684 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
4687 void MEDCouplingUMesh::are2DCellsNotCorrectlyOriented(const double *vec, bool polyOnly, std::vector<int>& cells) const
4689 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
4690 throw INTERP_KERNEL::Exception("Invalid mesh to apply are2DCellsNotCorrectlyOriented on it : must be meshDim==2 and spaceDim==3 !");
4691 int nbOfCells=getNumberOfCells();
4692 const int *conn=_nodal_connec->begin();
4693 const int *connI=_nodal_connec_index->begin();
4694 const double *coordsPtr=_coords->begin();
4695 for(int i=0;i<nbOfCells;i++)
4697 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4698 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
4700 bool isQuadratic=INTERP_KERNEL::CellModel::GetCellModel(type).isQuadratic();
4701 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4708 * Reverse connectivity of 2D cells whose orientation is not correct. A cell is
4709 * considered to be oriented correctly if an angle between its normal vector and a
4710 * given vector is less than \c PI / \c 2.
4711 * \param [in] vec - 3 components of the vector specifying the correct orientation of
4713 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
4715 * \throw If \a this->getMeshDimension() != 2.
4716 * \throw If \a this->getSpaceDimension() != 3.
4718 * \if ENABLE_EXAMPLES
4719 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
4720 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
4723 * \sa changeOrientationOfCells
4725 void MEDCouplingUMesh::orientCorrectly2DCells(const double *vec, bool polyOnly)
4727 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
4728 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectly2DCells on it : must be meshDim==2 and spaceDim==3 !");
4729 int nbOfCells(getNumberOfCells()),*conn(_nodal_connec->getPointer());
4730 const int *connI(_nodal_connec_index->begin());
4731 const double *coordsPtr(_coords->begin());
4732 bool isModified(false);
4733 for(int i=0;i<nbOfCells;i++)
4735 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4736 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
4738 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
4739 bool isQuadratic(cm.isQuadratic());
4740 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4743 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
4748 _nodal_connec->declareAsNew();
4753 * This method change the orientation of cells in \a this without any consideration of coordinates. Only connectivity is impacted.
4755 * \sa orientCorrectly2DCells
4757 void MEDCouplingUMesh::changeOrientationOfCells()
4759 int mdim(getMeshDimension());
4760 if(mdim!=2 && mdim!=1)
4761 throw INTERP_KERNEL::Exception("Invalid mesh to apply changeOrientationOfCells on it : must be meshDim==2 or meshDim==1 !");
4762 int nbOfCells(getNumberOfCells()),*conn(_nodal_connec->getPointer());
4763 const int *connI(_nodal_connec_index->begin());
4766 for(int i=0;i<nbOfCells;i++)
4768 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4769 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
4770 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
4775 for(int i=0;i<nbOfCells;i++)
4777 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4778 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
4779 cm.changeOrientationOf1D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
4785 * Finds incorrectly oriented polyhedral cells, i.e. polyhedrons having correctly
4786 * oriented facets. The normal vector of the facet should point out of the cell.
4787 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
4788 * is not cleared before filling in.
4789 * \throw If \a this->getMeshDimension() != 3.
4790 * \throw If \a this->getSpaceDimension() != 3.
4791 * \throw If the coordinates array is not set.
4792 * \throw If the nodal connectivity of cells is not defined.
4794 * \if ENABLE_EXAMPLES
4795 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
4796 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
4799 void MEDCouplingUMesh::arePolyhedronsNotCorrectlyOriented(std::vector<int>& cells) const
4801 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
4802 throw INTERP_KERNEL::Exception("Invalid mesh to apply arePolyhedronsNotCorrectlyOriented on it : must be meshDim==3 and spaceDim==3 !");
4803 int nbOfCells=getNumberOfCells();
4804 const int *conn=_nodal_connec->begin();
4805 const int *connI=_nodal_connec_index->begin();
4806 const double *coordsPtr=_coords->begin();
4807 for(int i=0;i<nbOfCells;i++)
4809 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4810 if(type==INTERP_KERNEL::NORM_POLYHED)
4812 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4819 * Tries to fix connectivity of polyhedra, so that normal vector of all facets to point
4821 * \throw If \a this->getMeshDimension() != 3.
4822 * \throw If \a this->getSpaceDimension() != 3.
4823 * \throw If the coordinates array is not set.
4824 * \throw If the nodal connectivity of cells is not defined.
4825 * \throw If the reparation fails.
4827 * \if ENABLE_EXAMPLES
4828 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
4829 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
4831 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
4833 void MEDCouplingUMesh::orientCorrectlyPolyhedrons()
4835 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
4836 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectlyPolyhedrons on it : must be meshDim==3 and spaceDim==3 !");
4837 int nbOfCells=getNumberOfCells();
4838 int *conn=_nodal_connec->getPointer();
4839 const int *connI=_nodal_connec_index->begin();
4840 const double *coordsPtr=_coords->begin();
4841 for(int i=0;i<nbOfCells;i++)
4843 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4844 if(type==INTERP_KERNEL::NORM_POLYHED)
4848 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4849 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
4851 catch(INTERP_KERNEL::Exception& e)
4853 std::ostringstream oss; oss << "Something wrong in polyhedron #" << i << " : " << e.what();
4854 throw INTERP_KERNEL::Exception(oss.str());
4862 * This method invert orientation of all cells in \a this.
4863 * After calling this method the absolute value of measure of cells in \a this are the same than before calling.
4864 * This method only operates on the connectivity so coordinates are not touched at all.
4866 void MEDCouplingUMesh::invertOrientationOfAllCells()
4868 checkConnectivityFullyDefined();
4869 std::set<INTERP_KERNEL::NormalizedCellType> gts(getAllGeoTypes());
4870 int *conn(_nodal_connec->getPointer());
4871 const int *conni(_nodal_connec_index->begin());
4872 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator gt=gts.begin();gt!=gts.end();gt++)
4874 INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::OrientationInverter> oi(INTERP_KERNEL::OrientationInverter::BuildInstanceFrom(*gt));
4875 MCAuto<DataArrayInt> cwt(giveCellsWithType(*gt));
4876 for(const int *it=cwt->begin();it!=cwt->end();it++)
4877 oi->operate(conn+conni[*it]+1,conn+conni[*it+1]);
4883 * Finds and fixes incorrectly oriented linear extruded volumes (INTERP_KERNEL::NORM_HEXA8,
4884 * INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXGP12 etc) to respect the MED convention
4885 * according to which the first facet of the cell should be oriented to have the normal vector
4886 * pointing out of cell.
4887 * \return DataArrayInt * - a new instance of DataArrayInt holding ids of fixed
4888 * cells. The caller is to delete this array using decrRef() as it is no more
4890 * \throw If \a this->getMeshDimension() != 3.
4891 * \throw If \a this->getSpaceDimension() != 3.
4892 * \throw If the coordinates array is not set.
4893 * \throw If the nodal connectivity of cells is not defined.
4895 * \if ENABLE_EXAMPLES
4896 * \ref cpp_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a C++ example".<br>
4897 * \ref py_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a Python example".
4899 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
4901 DataArrayInt *MEDCouplingUMesh::findAndCorrectBadOriented3DExtrudedCells()
4903 const char msg[]="check3DCellsWellOriented detection works only for 3D cells !";
4904 if(getMeshDimension()!=3)
4905 throw INTERP_KERNEL::Exception(msg);
4906 int spaceDim=getSpaceDimension();
4908 throw INTERP_KERNEL::Exception(msg);
4910 int nbOfCells=getNumberOfCells();
4911 int *conn=_nodal_connec->getPointer();
4912 const int *connI=_nodal_connec_index->begin();
4913 const double *coo=getCoords()->begin();
4914 MCAuto<DataArrayInt> cells(DataArrayInt::New()); cells->alloc(0,1);
4915 for(int i=0;i<nbOfCells;i++)
4917 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4918 if(cm.isExtruded() && !cm.isDynamic() && !cm.isQuadratic())
4920 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coo))
4922 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
4923 cells->pushBackSilent(i);
4927 return cells.retn();
4931 * This method is a faster method to correct orientation of all 3D cells in \a this.
4932 * 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.
4933 * This method makes the hypothesis that \a this a coherent that is to say MEDCouplingUMesh::checkConsistency should throw no exception.
4935 * \return a newly allocated int array with one components containing cell ids renumbered to fit the convention of MED (MED file and MEDCoupling)
4936 * \sa MEDCouplingUMesh::orientCorrectlyPolyhedrons,
4938 DataArrayInt *MEDCouplingUMesh::findAndCorrectBadOriented3DCells()
4940 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
4941 throw INTERP_KERNEL::Exception("Invalid mesh to apply findAndCorrectBadOriented3DCells on it : must be meshDim==3 and spaceDim==3 !");
4942 int nbOfCells=getNumberOfCells();
4943 int *conn=_nodal_connec->getPointer();
4944 const int *connI=_nodal_connec_index->begin();
4945 const double *coordsPtr=_coords->begin();
4946 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
4947 for(int i=0;i<nbOfCells;i++)
4949 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4952 case INTERP_KERNEL::NORM_TETRA4:
4954 if(!IsTetra4WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4956 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+3));
4957 ret->pushBackSilent(i);
4961 case INTERP_KERNEL::NORM_PYRA5:
4963 if(!IsPyra5WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4965 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+4));
4966 ret->pushBackSilent(i);
4970 case INTERP_KERNEL::NORM_PENTA6:
4971 case INTERP_KERNEL::NORM_HEXA8:
4972 case INTERP_KERNEL::NORM_HEXGP12:
4974 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4976 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
4977 ret->pushBackSilent(i);
4981 case INTERP_KERNEL::NORM_POLYHED:
4983 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4985 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
4986 ret->pushBackSilent(i);
4991 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 !");
4999 * This method has a sense for meshes with spaceDim==3 and meshDim==2.
5000 * If it is not the case an exception will be thrown.
5001 * This method is fast because the first cell of \a this is used to compute the plane.
5002 * \param vec output of size at least 3 used to store the normal vector (with norm equal to Area ) of searched plane.
5003 * \param pos output of size at least 3 used to store a point owned of searched plane.
5005 void MEDCouplingUMesh::getFastAveragePlaneOfThis(double *vec, double *pos) const
5007 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
5008 throw INTERP_KERNEL::Exception("Invalid mesh to apply getFastAveragePlaneOfThis on it : must be meshDim==2 and spaceDim==3 !");
5009 const int *conn=_nodal_connec->begin();
5010 const int *connI=_nodal_connec_index->begin();
5011 const double *coordsPtr=_coords->begin();
5012 INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(conn+1,connI[1]-connI[0]-1,coordsPtr,vec);
5013 std::copy(coordsPtr+3*conn[1],coordsPtr+3*conn[1]+3,pos);
5017 * Creates a new MEDCouplingFieldDouble holding Edge Ratio values of all
5018 * cells. Currently cells of the following types are treated:
5019 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5020 * For a cell of other type an exception is thrown.
5021 * Space dimension of a 2D mesh can be either 2 or 3.
5022 * The Edge Ratio of a cell \f$t\f$ is:
5023 * \f$\frac{|t|_\infty}{|t|_0}\f$,
5024 * where \f$|t|_\infty\f$ and \f$|t|_0\f$ respectively denote the greatest and
5025 * the smallest edge lengths of \f$t\f$.
5026 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5027 * cells and one time, lying on \a this mesh. The caller is to delete this
5028 * field using decrRef() as it is no more needed.
5029 * \throw If the coordinates array is not set.
5030 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5031 * \throw If the connectivity data array has more than one component.
5032 * \throw If the connectivity data array has a named component.
5033 * \throw If the connectivity index data array has more than one component.
5034 * \throw If the connectivity index data array has a named component.
5035 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
5036 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5037 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5039 MEDCouplingFieldDouble *MEDCouplingUMesh::getEdgeRatioField() const
5041 checkConsistencyLight();
5042 int spaceDim=getSpaceDimension();
5043 int meshDim=getMeshDimension();
5044 if(spaceDim!=2 && spaceDim!=3)
5045 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : SpaceDimension must be equal to 2 or 3 !");
5046 if(meshDim!=2 && meshDim!=3)
5047 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : MeshDimension must be equal to 2 or 3 !");
5048 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5050 int nbOfCells=getNumberOfCells();
5051 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5052 arr->alloc(nbOfCells,1);
5053 double *pt=arr->getPointer();
5054 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5055 const int *conn=_nodal_connec->begin();
5056 const int *connI=_nodal_connec_index->begin();
5057 const double *coo=_coords->begin();
5059 for(int i=0;i<nbOfCells;i++,pt++)
5061 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5064 case INTERP_KERNEL::NORM_TRI3:
5066 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5067 *pt=INTERP_KERNEL::triEdgeRatio(tmp);
5070 case INTERP_KERNEL::NORM_QUAD4:
5072 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5073 *pt=INTERP_KERNEL::quadEdgeRatio(tmp);
5076 case INTERP_KERNEL::NORM_TETRA4:
5078 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5079 *pt=INTERP_KERNEL::tetraEdgeRatio(tmp);
5083 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5085 conn+=connI[i+1]-connI[i];
5087 ret->setName("EdgeRatio");
5088 ret->synchronizeTimeWithSupport();
5093 * Creates a new MEDCouplingFieldDouble holding Aspect Ratio values of all
5094 * cells. Currently cells of the following types are treated:
5095 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5096 * For a cell of other type an exception is thrown.
5097 * Space dimension of a 2D mesh can be either 2 or 3.
5098 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5099 * cells and one time, lying on \a this mesh. The caller is to delete this
5100 * field using decrRef() as it is no more needed.
5101 * \throw If the coordinates array is not set.
5102 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5103 * \throw If the connectivity data array has more than one component.
5104 * \throw If the connectivity data array has a named component.
5105 * \throw If the connectivity index data array has more than one component.
5106 * \throw If the connectivity index data array has a named component.
5107 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
5108 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5109 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5111 MEDCouplingFieldDouble *MEDCouplingUMesh::getAspectRatioField() const
5113 checkConsistencyLight();
5114 int spaceDim=getSpaceDimension();
5115 int meshDim=getMeshDimension();
5116 if(spaceDim!=2 && spaceDim!=3)
5117 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : SpaceDimension must be equal to 2 or 3 !");
5118 if(meshDim!=2 && meshDim!=3)
5119 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : MeshDimension must be equal to 2 or 3 !");
5120 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5122 int nbOfCells=getNumberOfCells();
5123 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5124 arr->alloc(nbOfCells,1);
5125 double *pt=arr->getPointer();
5126 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5127 const int *conn=_nodal_connec->begin();
5128 const int *connI=_nodal_connec_index->begin();
5129 const double *coo=_coords->begin();
5131 for(int i=0;i<nbOfCells;i++,pt++)
5133 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5136 case INTERP_KERNEL::NORM_TRI3:
5138 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5139 *pt=INTERP_KERNEL::triAspectRatio(tmp);
5142 case INTERP_KERNEL::NORM_QUAD4:
5144 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5145 *pt=INTERP_KERNEL::quadAspectRatio(tmp);
5148 case INTERP_KERNEL::NORM_TETRA4:
5150 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5151 *pt=INTERP_KERNEL::tetraAspectRatio(tmp);
5155 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5157 conn+=connI[i+1]-connI[i];
5159 ret->setName("AspectRatio");
5160 ret->synchronizeTimeWithSupport();
5165 * Creates a new MEDCouplingFieldDouble holding Warping factor values of all
5166 * cells of \a this 2D mesh in 3D space. It is a measure of the "planarity" of 2D cell
5167 * in 3D space. Currently only cells of the following types are
5168 * treated: INTERP_KERNEL::NORM_QUAD4.
5169 * For a cell of other type an exception is thrown.
5170 * The warp field is computed as follows: let (a,b,c,d) be the points of the quad.
5172 * \f$t=\vec{da}\times\vec{ab}\f$,
5173 * \f$u=\vec{ab}\times\vec{bc}\f$
5174 * \f$v=\vec{bc}\times\vec{cd}\f$
5175 * \f$w=\vec{cd}\times\vec{da}\f$, the warp is defined as \f$W^3\f$ with
5177 * W=min(\frac{t}{|t|}\cdot\frac{v}{|v|}, \frac{u}{|u|}\cdot\frac{w}{|w|})
5179 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5180 * cells and one time, lying on \a this mesh. The caller is to delete this
5181 * field using decrRef() as it is no more needed.
5182 * \throw If the coordinates array is not set.
5183 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5184 * \throw If the connectivity data array has more than one component.
5185 * \throw If the connectivity data array has a named component.
5186 * \throw If the connectivity index data array has more than one component.
5187 * \throw If the connectivity index data array has a named component.
5188 * \throw If \a this->getMeshDimension() != 2.
5189 * \throw If \a this->getSpaceDimension() != 3.
5190 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5192 MEDCouplingFieldDouble *MEDCouplingUMesh::getWarpField() const
5194 checkConsistencyLight();
5195 int spaceDim=getSpaceDimension();
5196 int meshDim=getMeshDimension();
5198 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : SpaceDimension must be equal to 3 !");
5200 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : MeshDimension must be equal to 2 !");
5201 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5203 int nbOfCells=getNumberOfCells();
5204 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5205 arr->alloc(nbOfCells,1);
5206 double *pt=arr->getPointer();
5207 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5208 const int *conn=_nodal_connec->begin();
5209 const int *connI=_nodal_connec_index->begin();
5210 const double *coo=_coords->begin();
5212 for(int i=0;i<nbOfCells;i++,pt++)
5214 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5217 case INTERP_KERNEL::NORM_QUAD4:
5219 FillInCompact3DMode(3,4,conn+1,coo,tmp);
5220 *pt=INTERP_KERNEL::quadWarp(tmp);
5224 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : A cell with not manged type (NORM_QUAD4) has been detected !");
5226 conn+=connI[i+1]-connI[i];
5228 ret->setName("Warp");
5229 ret->synchronizeTimeWithSupport();
5235 * Creates a new MEDCouplingFieldDouble holding Skew factor values of all
5236 * cells of \a this 2D mesh in 3D space. Currently cells of the following types are
5237 * treated: INTERP_KERNEL::NORM_QUAD4.
5238 * The skew is computed as follow for a quad with points (a,b,c,d): let
5239 * \f$u=\vec{ab}+\vec{dc}\f$ and \f$v=\vec{ac}+\vec{bd}\f$
5240 * then the skew is computed as:
5242 * s=\frac{u}{|u|}\cdot\frac{v}{|v|}
5245 * For a cell of other type an exception is thrown.
5246 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5247 * cells and one time, lying on \a this mesh. The caller is to delete this
5248 * field using decrRef() as it is no more needed.
5249 * \throw If the coordinates array is not set.
5250 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5251 * \throw If the connectivity data array has more than one component.
5252 * \throw If the connectivity data array has a named component.
5253 * \throw If the connectivity index data array has more than one component.
5254 * \throw If the connectivity index data array has a named component.
5255 * \throw If \a this->getMeshDimension() != 2.
5256 * \throw If \a this->getSpaceDimension() != 3.
5257 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5259 MEDCouplingFieldDouble *MEDCouplingUMesh::getSkewField() const
5261 checkConsistencyLight();
5262 int spaceDim=getSpaceDimension();
5263 int meshDim=getMeshDimension();
5265 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : SpaceDimension must be equal to 3 !");
5267 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : MeshDimension must be equal to 2 !");
5268 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5270 int nbOfCells=getNumberOfCells();
5271 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5272 arr->alloc(nbOfCells,1);
5273 double *pt=arr->getPointer();
5274 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5275 const int *conn=_nodal_connec->begin();
5276 const int *connI=_nodal_connec_index->begin();
5277 const double *coo=_coords->begin();
5279 for(int i=0;i<nbOfCells;i++,pt++)
5281 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5284 case INTERP_KERNEL::NORM_QUAD4:
5286 FillInCompact3DMode(3,4,conn+1,coo,tmp);
5287 *pt=INTERP_KERNEL::quadSkew(tmp);
5291 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : A cell with not manged type (NORM_QUAD4) has been detected !");
5293 conn+=connI[i+1]-connI[i];
5295 ret->setName("Skew");
5296 ret->synchronizeTimeWithSupport();
5301 * 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.
5303 * \return a new instance of field containing the result. The returned instance has to be deallocated by the caller.
5305 * \sa getSkewField, getWarpField, getAspectRatioField, getEdgeRatioField
5307 MEDCouplingFieldDouble *MEDCouplingUMesh::computeDiameterField() const
5309 checkConsistencyLight();
5310 MCAuto<MEDCouplingFieldDouble> ret(MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME));
5312 std::set<INTERP_KERNEL::NormalizedCellType> types;
5313 ComputeAllTypesInternal(types,_nodal_connec,_nodal_connec_index);
5314 int spaceDim(getSpaceDimension()),nbCells(getNumberOfCells());
5315 MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
5316 arr->alloc(nbCells,1);
5317 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++)
5319 INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::DiameterCalculator> dc(INTERP_KERNEL::CellModel::GetCellModel(*it).buildInstanceOfDiameterCalulator(spaceDim));
5320 MCAuto<DataArrayInt> cellIds(giveCellsWithType(*it));
5321 dc->computeForListOfCellIdsUMeshFrmt(cellIds->begin(),cellIds->end(),_nodal_connec_index->begin(),_nodal_connec->begin(),getCoords()->begin(),arr->getPointer());
5324 ret->setName("Diameter");
5329 * This method aggregate the bbox of each cell and put it into bbox parameter (xmin,xmax,ymin,ymax,zmin,zmax).
5331 * \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)
5332 * For all other cases this input parameter is ignored.
5333 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5335 * \throw If \a this is not fully set (coordinates and connectivity).
5336 * \throw If a cell in \a this has no valid nodeId.
5337 * \sa MEDCouplingUMesh::getBoundingBoxForBBTreeFast, MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5339 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree(double arcDetEps) const
5341 int mDim(getMeshDimension()),sDim(getSpaceDimension());
5342 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.
5343 return getBoundingBoxForBBTreeFast();
5344 if((mDim==2 && sDim==2) || (mDim==1 && sDim==2))
5346 bool presenceOfQuadratic(false);
5347 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=_types.begin();it!=_types.end();it++)
5349 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(*it));
5350 if(cm.isQuadratic())
5351 presenceOfQuadratic=true;
5353 if(!presenceOfQuadratic)
5354 return getBoundingBoxForBBTreeFast();
5355 if(mDim==2 && sDim==2)
5356 return getBoundingBoxForBBTree2DQuadratic(arcDetEps);
5358 return getBoundingBoxForBBTree1DQuadratic(arcDetEps);
5360 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) !");
5364 * This method aggregate the bbox of each cell only considering the nodes constituting each cell and put it into bbox parameter.
5365 * So meshes having quadratic cells the computed bounding boxes can be invalid !
5367 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5369 * \throw If \a this is not fully set (coordinates and connectivity).
5370 * \throw If a cell in \a this has no valid nodeId.
5372 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTreeFast() const
5374 checkFullyDefined();
5375 int spaceDim(getSpaceDimension()),nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
5376 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5377 double *bbox(ret->getPointer());
5378 for(int i=0;i<nbOfCells*spaceDim;i++)
5380 bbox[2*i]=std::numeric_limits<double>::max();
5381 bbox[2*i+1]=-std::numeric_limits<double>::max();
5383 const double *coordsPtr(_coords->begin());
5384 const int *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5385 for(int i=0;i<nbOfCells;i++)
5387 int offset=connI[i]+1;
5388 int nbOfNodesForCell(connI[i+1]-offset),kk(0);
5389 for(int j=0;j<nbOfNodesForCell;j++)
5391 int nodeId=conn[offset+j];
5392 if(nodeId>=0 && nodeId<nbOfNodes)
5394 for(int k=0;k<spaceDim;k++)
5396 bbox[2*spaceDim*i+2*k]=std::min(bbox[2*spaceDim*i+2*k],coordsPtr[spaceDim*nodeId+k]);
5397 bbox[2*spaceDim*i+2*k+1]=std::max(bbox[2*spaceDim*i+2*k+1],coordsPtr[spaceDim*nodeId+k]);
5404 std::ostringstream oss; oss << "MEDCouplingUMesh::getBoundingBoxForBBTree : cell #" << i << " contains no valid nodeId !";
5405 throw INTERP_KERNEL::Exception(oss.str());
5412 * This method aggregates the bbox of each 2D cell in \a this considering the whole shape. This method is particularly
5413 * useful for 2D meshes having quadratic cells
5414 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5415 * the two extremities of the arc of circle).
5417 * \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)
5418 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5419 * \throw If \a this is not fully defined.
5420 * \throw If \a this is not a mesh with meshDimension equal to 2.
5421 * \throw If \a this is not a mesh with spaceDimension equal to 2.
5422 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic
5424 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic(double arcDetEps) const
5426 checkFullyDefined();
5427 INTERP_KERNEL::QuadraticPlanarArcDetectionPrecision arcPrec(arcDetEps);
5429 int spaceDim(getSpaceDimension()),mDim(getMeshDimension()),nbOfCells(getNumberOfCells());
5430 if(spaceDim!=2 || mDim!=2)
5431 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!");
5432 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5433 double *bbox(ret->getPointer());
5434 const double *coords(_coords->begin());
5435 const int *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5436 for(int i=0;i<nbOfCells;i++,bbox+=4,connI++)
5438 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5439 int sz(connI[1]-connI[0]-1);
5440 std::vector<INTERP_KERNEL::Node *> nodes(sz);
5441 INTERP_KERNEL::QuadraticPolygon *pol(0);
5442 for(int j=0;j<sz;j++)
5444 int nodeId(conn[*connI+1+j]);
5445 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5447 if(!cm.isQuadratic())
5448 pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
5450 pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
5451 INTERP_KERNEL::Bounds b; b.prepareForAggregation(); pol->fillBounds(b); delete pol;
5452 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax();
5458 * This method aggregates the bbox of each 1D cell in \a this considering the whole shape. This method is particularly
5459 * useful for 2D meshes having quadratic cells
5460 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5461 * the two extremities of the arc of circle).
5463 * \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)
5464 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5465 * \throw If \a this is not fully defined.
5466 * \throw If \a this is not a mesh with meshDimension equal to 1.
5467 * \throw If \a this is not a mesh with spaceDimension equal to 2.
5468 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5470 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic(double arcDetEps) const
5472 checkFullyDefined();
5473 int spaceDim(getSpaceDimension()),mDim(getMeshDimension()),nbOfCells(getNumberOfCells());
5474 if(spaceDim!=2 || mDim!=1)
5475 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!");
5476 INTERP_KERNEL::QuadraticPlanarArcDetectionPrecision arcPrec(arcDetEps);
5477 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5478 double *bbox(ret->getPointer());
5479 const double *coords(_coords->begin());
5480 const int *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5481 for(int i=0;i<nbOfCells;i++,bbox+=4,connI++)
5483 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5484 int sz(connI[1]-connI[0]-1);
5485 std::vector<INTERP_KERNEL::Node *> nodes(sz);
5486 INTERP_KERNEL::Edge *edge(0);
5487 for(int j=0;j<sz;j++)
5489 int nodeId(conn[*connI+1+j]);
5490 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5492 if(!cm.isQuadratic())
5493 edge=INTERP_KERNEL::QuadraticPolygon::BuildLinearEdge(nodes);
5495 edge=INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(nodes);
5496 const INTERP_KERNEL::Bounds& b(edge->getBounds());
5497 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax(); edge->decrRef();
5504 namespace MEDCouplingImpl
5509 ConnReader(const int *c, int val):_conn(c),_val(val) { }
5510 bool operator() (const int& pos) { return _conn[pos]!=_val; }
5519 ConnReader2(const int *c, int val):_conn(c),_val(val) { }
5520 bool operator() (const int& pos) { return _conn[pos]==_val; }
5530 * This method expects that \a this is sorted by types. If not an exception will be thrown.
5531 * This method returns in the same format as code (see MEDCouplingUMesh::checkTypeConsistencyAndContig or MEDCouplingUMesh::splitProfilePerType) how
5532 * \a this is composed in cell types.
5533 * The returned array is of size 3*n where n is the number of different types present in \a this.
5534 * For every k in [0,n] ret[3*k+2]==-1 because it has no sense here.
5535 * This parameter is kept only for compatibility with other methode listed above.
5537 std::vector<int> MEDCouplingUMesh::getDistributionOfTypes() const
5539 checkConnectivityFullyDefined();
5540 const int *conn=_nodal_connec->begin();
5541 const int *connI=_nodal_connec_index->begin();
5542 const int *work=connI;
5543 int nbOfCells=getNumberOfCells();
5544 std::size_t n=getAllGeoTypes().size();
5545 std::vector<int> ret(3*n,-1); //ret[3*k+2]==-1 because it has no sense here
5546 std::set<INTERP_KERNEL::NormalizedCellType> types;
5547 for(std::size_t i=0;work!=connI+nbOfCells;i++)
5549 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn[*work];
5550 if(types.find(typ)!=types.end())
5552 std::ostringstream oss; oss << "MEDCouplingUMesh::getDistributionOfTypes : Type " << INTERP_KERNEL::CellModel::GetCellModel(typ).getRepr();
5553 oss << " is not contiguous !";
5554 throw INTERP_KERNEL::Exception(oss.str());
5558 const int *work2=std::find_if(work+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,typ));
5559 ret[3*i+1]=(int)std::distance(work,work2);
5566 * This method is used to check that this has contiguous cell type in same order than described in \a code.
5567 * only for types cell, type node is not managed.
5568 * Format of \a code is the following. \a code should be of size 3*n and non empty. If not an exception is thrown.
5569 * foreach k in [0,n) on 3*k pos represent the geometric type and 3*k+1 number of elements of type 3*k.
5570 * 3*k+2 refers if different from -1 the pos in 'idsPerType' to get the corresponding array.
5571 * If 2 or more same geometric type is in \a code and exception is thrown too.
5573 * This method firstly checks
5574 * If it exists k so that 3*k geometric type is not in geometric types of this an exception will be thrown.
5575 * If it exists k so that 3*k geometric type exists but the number of consecutive cell types does not match,
5576 * an exception is thrown too.
5578 * If all geometric types in \a code are exactly those in \a this null pointer is returned.
5579 * If it exists a geometric type in \a this \b not in \a code \b no exception is thrown
5580 * and a DataArrayInt instance is returned that the user has the responsability to deallocate.
5582 DataArrayInt *MEDCouplingUMesh::checkTypeConsistencyAndContig(const std::vector<int>& code, const std::vector<const DataArrayInt *>& idsPerType) const
5585 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code is empty, should not !");
5586 std::size_t sz=code.size();
5589 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code size is NOT %3 !");
5590 std::vector<INTERP_KERNEL::NormalizedCellType> types;
5592 bool isNoPflUsed=true;
5593 for(std::size_t i=0;i<n;i++)
5594 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)code[3*i])==types.end())
5596 types.push_back((INTERP_KERNEL::NormalizedCellType)code[3*i]);
5598 if(_types.find((INTERP_KERNEL::NormalizedCellType)code[3*i])==_types.end())
5599 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : expected geo types not in this !");
5600 isNoPflUsed=isNoPflUsed && (code[3*i+2]==-1);
5603 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code contains duplication of types in unstructured mesh !");
5606 if(!checkConsecutiveCellTypesAndOrder(&types[0],&types[0]+types.size()))
5607 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : non contiguous type !");
5608 if(types.size()==_types.size())
5611 MCAuto<DataArrayInt> ret=DataArrayInt::New();
5613 int *retPtr=ret->getPointer();
5614 const int *connI=_nodal_connec_index->begin();
5615 const int *conn=_nodal_connec->begin();
5616 int nbOfCells=getNumberOfCells();
5619 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++,kk++)
5621 i=std::find_if(i,connI+nbOfCells,MEDCouplingImpl::ConnReader2(conn,(int)(*it)));
5622 int offset=(int)std::distance(connI,i);
5623 const int *j=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)(*it)));
5624 int nbOfCellsOfCurType=(int)std::distance(i,j);
5625 if(code[3*kk+2]==-1)
5626 for(int k=0;k<nbOfCellsOfCurType;k++)
5630 int idInIdsPerType=code[3*kk+2];
5631 if(idInIdsPerType>=0 && idInIdsPerType<(int)idsPerType.size())
5633 const DataArrayInt *zePfl=idsPerType[idInIdsPerType];
5636 zePfl->checkAllocated();
5637 if(zePfl->getNumberOfComponents()==1)
5639 for(const int *k=zePfl->begin();k!=zePfl->end();k++,retPtr++)
5641 if(*k>=0 && *k<nbOfCellsOfCurType)
5642 *retPtr=(*k)+offset;
5645 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : the section " << kk << " points to the profile #" << idInIdsPerType;
5646 oss << ", and this profile contains a value " << *k << " should be in [0," << nbOfCellsOfCurType << ") !";
5647 throw INTERP_KERNEL::Exception(oss.str());
5652 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of a profile with nb of compo != 1 !");
5655 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of null profile !");
5659 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : at section " << kk << " of code it points to the array #" << idInIdsPerType;
5660 oss << " should be in [0," << idsPerType.size() << ") !";
5661 throw INTERP_KERNEL::Exception(oss.str());
5670 * This method makes the hypothesis that \a this is sorted by type. If not an exception will be thrown.
5671 * 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.
5672 * 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.
5673 * This method has 1 input \a profile and 3 outputs \a code \a idsInPflPerType and \a idsPerType.
5675 * \param [in] profile
5676 * \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.
5677 * \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,
5678 * \a idsInPflPerType[i] stores the tuple ids in \a profile that correspond to the geometric type code[3*i+0]
5679 * \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.
5680 * This vector can be empty in case of all geometric type cells are fully covered in ascending in the given input \a profile.
5681 * \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
5683 void MEDCouplingUMesh::splitProfilePerType(const DataArrayInt *profile, std::vector<int>& code, std::vector<DataArrayInt *>& idsInPflPerType, std::vector<DataArrayInt *>& idsPerType) const
5686 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile is NULL !");
5687 if(profile->getNumberOfComponents()!=1)
5688 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile should have exactly one component !");
5689 checkConnectivityFullyDefined();
5690 const int *conn=_nodal_connec->begin();
5691 const int *connI=_nodal_connec_index->begin();
5692 int nbOfCells=getNumberOfCells();
5693 std::vector<INTERP_KERNEL::NormalizedCellType> types;
5694 std::vector<int> typeRangeVals(1);
5695 for(const int *i=connI;i!=connI+nbOfCells;)
5697 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5698 if(std::find(types.begin(),types.end(),curType)!=types.end())
5700 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : current mesh is not sorted by type !");
5702 types.push_back(curType);
5703 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
5704 typeRangeVals.push_back((int)std::distance(connI,i));
5707 DataArrayInt *castArr=0,*rankInsideCast=0,*castsPresent=0;
5708 profile->splitByValueRange(&typeRangeVals[0],&typeRangeVals[0]+typeRangeVals.size(),castArr,rankInsideCast,castsPresent);
5709 MCAuto<DataArrayInt> tmp0=castArr;
5710 MCAuto<DataArrayInt> tmp1=rankInsideCast;
5711 MCAuto<DataArrayInt> tmp2=castsPresent;
5713 int nbOfCastsFinal=castsPresent->getNumberOfTuples();
5714 code.resize(3*nbOfCastsFinal);
5715 std::vector< MCAuto<DataArrayInt> > idsInPflPerType2;
5716 std::vector< MCAuto<DataArrayInt> > idsPerType2;
5717 for(int i=0;i<nbOfCastsFinal;i++)
5719 int castId=castsPresent->getIJ(i,0);
5720 MCAuto<DataArrayInt> tmp3=castArr->findIdsEqual(castId);
5721 idsInPflPerType2.push_back(tmp3);
5722 code[3*i]=(int)types[castId];
5723 code[3*i+1]=tmp3->getNumberOfTuples();
5724 MCAuto<DataArrayInt> tmp4=rankInsideCast->selectByTupleId(tmp3->begin(),tmp3->begin()+tmp3->getNumberOfTuples());
5725 if(!tmp4->isIota(typeRangeVals[castId+1]-typeRangeVals[castId]))
5727 tmp4->copyStringInfoFrom(*profile);
5728 idsPerType2.push_back(tmp4);
5729 code[3*i+2]=(int)idsPerType2.size()-1;
5736 std::size_t sz2=idsInPflPerType2.size();
5737 idsInPflPerType.resize(sz2);
5738 for(std::size_t i=0;i<sz2;i++)
5740 DataArrayInt *locDa=idsInPflPerType2[i];
5742 idsInPflPerType[i]=locDa;
5744 std::size_t sz=idsPerType2.size();
5745 idsPerType.resize(sz);
5746 for(std::size_t i=0;i<sz;i++)
5748 DataArrayInt *locDa=idsPerType2[i];
5750 idsPerType[i]=locDa;
5755 * This method is here too emulate the MEDMEM behaviour on BDC (buildDescendingConnectivity). Hoping this method becomes deprecated very soon.
5756 * This method make the assumption that \a this and 'nM1LevMesh' mesh lyies on same coords (same pointer) as MED and MEDMEM does.
5757 * The following equality should be verified 'nM1LevMesh->getMeshDimension()==this->getMeshDimension()-1'
5758 * 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.
5760 MEDCouplingUMesh *MEDCouplingUMesh::emulateMEDMEMBDC(const MEDCouplingUMesh *nM1LevMesh, DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *&revDesc, DataArrayInt *&revDescIndx, DataArrayInt *& nM1LevMeshIds, DataArrayInt *&meshnM1Old2New) const
5762 checkFullyDefined();
5763 nM1LevMesh->checkFullyDefined();
5764 if(getMeshDimension()-1!=nM1LevMesh->getMeshDimension())
5765 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : The mesh passed as first argument should have a meshDim equal to this->getMeshDimension()-1 !" );
5766 if(_coords!=nM1LevMesh->getCoords())
5767 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : 'this' and mesh in first argument should share the same coords : Use tryToShareSameCoords method !");
5768 MCAuto<DataArrayInt> tmp0=DataArrayInt::New();
5769 MCAuto<DataArrayInt> tmp1=DataArrayInt::New();
5770 MCAuto<MEDCouplingUMesh> ret1=buildDescendingConnectivity(desc,descIndx,tmp0,tmp1);
5771 MCAuto<DataArrayInt> ret0=ret1->sortCellsInMEDFileFrmt();
5772 desc->transformWithIndArr(ret0->begin(),ret0->begin()+ret0->getNbOfElems());
5773 MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
5774 tmp->setConnectivity(tmp0,tmp1);
5775 tmp->renumberCells(ret0->begin(),false);
5776 revDesc=tmp->getNodalConnectivity();
5777 revDescIndx=tmp->getNodalConnectivityIndex();
5778 DataArrayInt *ret=0;
5779 if(!ret1->areCellsIncludedIn(nM1LevMesh,2,ret))
5782 ret->getMaxValue(tmp2);
5784 std::ostringstream oss; oss << "MEDCouplingUMesh::emulateMEDMEMBDC : input N-1 mesh present a cell not in descending mesh ... Id of cell is " << tmp2 << " !";
5785 throw INTERP_KERNEL::Exception(oss.str());
5790 revDescIndx->incrRef();
5793 meshnM1Old2New=ret0;
5798 * Permutes the nodal connectivity arrays so that the cells are sorted by type, which is
5799 * necessary for writing the mesh to MED file. Additionally returns a permutation array
5800 * in "Old to New" mode.
5801 * \return DataArrayInt * - a new instance of DataArrayInt. The caller is to delete
5802 * this array using decrRef() as it is no more needed.
5803 * \throw If the nodal connectivity of cells is not defined.
5805 DataArrayInt *MEDCouplingUMesh::sortCellsInMEDFileFrmt()
5807 checkConnectivityFullyDefined();
5808 MCAuto<DataArrayInt> ret=getRenumArrForMEDFileFrmt();
5809 renumberCells(ret->begin(),false);
5814 * This methods checks that cells are sorted by their types.
5815 * This method makes asumption (no check) that connectivity is correctly set before calling.
5817 bool MEDCouplingUMesh::checkConsecutiveCellTypes() const
5819 checkFullyDefined();
5820 const int *conn=_nodal_connec->begin();
5821 const int *connI=_nodal_connec_index->begin();
5822 int nbOfCells=getNumberOfCells();
5823 std::set<INTERP_KERNEL::NormalizedCellType> types;
5824 for(const int *i=connI;i!=connI+nbOfCells;)
5826 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5827 if(types.find(curType)!=types.end())
5829 types.insert(curType);
5830 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
5836 * This method is a specialization of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method that is called here.
5837 * The geometric type order is specified by MED file.
5839 * \sa MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder
5841 bool MEDCouplingUMesh::checkConsecutiveCellTypesForMEDFileFrmt() const
5843 return checkConsecutiveCellTypesAndOrder(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
5847 * This method performs the same job as checkConsecutiveCellTypes except that the order of types sequence is analyzed to check
5848 * that the order is specified in array defined by [ \a orderBg , \a orderEnd ).
5849 * If there is some geo types in \a this \b NOT in [ \a orderBg, \a orderEnd ) it is OK (return true) if contiguous.
5850 * If there is some geo types in [ \a orderBg, \a orderEnd ) \b NOT in \a this it is OK too (return true) if contiguous.
5852 bool MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
5854 checkFullyDefined();
5855 const int *conn=_nodal_connec->begin();
5856 const int *connI=_nodal_connec_index->begin();
5857 int nbOfCells=getNumberOfCells();
5861 std::set<INTERP_KERNEL::NormalizedCellType> sg;
5862 for(const int *i=connI;i!=connI+nbOfCells;)
5864 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5865 const INTERP_KERNEL::NormalizedCellType *isTypeExists=std::find(orderBg,orderEnd,curType);
5866 if(isTypeExists!=orderEnd)
5868 int pos=(int)std::distance(orderBg,isTypeExists);
5872 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
5876 if(sg.find(curType)==sg.end())
5878 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
5889 * This method returns 2 newly allocated DataArrayInt instances. The first is an array of size 'this->getNumberOfCells()' with one component,
5890 * 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
5891 * 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'.
5893 DataArrayInt *MEDCouplingUMesh::getLevArrPerCellTypes(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd, DataArrayInt *&nbPerType) const
5895 checkConnectivityFullyDefined();
5896 int nbOfCells=getNumberOfCells();
5897 const int *conn=_nodal_connec->begin();
5898 const int *connI=_nodal_connec_index->begin();
5899 MCAuto<DataArrayInt> tmpa=DataArrayInt::New();
5900 MCAuto<DataArrayInt> tmpb=DataArrayInt::New();
5901 tmpa->alloc(nbOfCells,1);
5902 tmpb->alloc((int)std::distance(orderBg,orderEnd),1);
5903 tmpb->fillWithZero();
5904 int *tmp=tmpa->getPointer();
5905 int *tmp2=tmpb->getPointer();
5906 for(const int *i=connI;i!=connI+nbOfCells;i++)
5908 const INTERP_KERNEL::NormalizedCellType *where=std::find(orderBg,orderEnd,(INTERP_KERNEL::NormalizedCellType)conn[*i]);
5911 int pos=(int)std::distance(orderBg,where);
5913 tmp[std::distance(connI,i)]=pos;
5917 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*i]);
5918 std::ostringstream oss; oss << "MEDCouplingUMesh::getLevArrPerCellTypes : Cell #" << std::distance(connI,i);
5919 oss << " has a type " << cm.getRepr() << " not in input array of type !";
5920 throw INTERP_KERNEL::Exception(oss.str());
5923 nbPerType=tmpb.retn();
5928 * This method behaves exactly as MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec but the order is those defined in MED file spec.
5930 * \return a new object containing the old to new correspondance.
5932 * \sa MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec, MEDCouplingUMesh::sortCellsInMEDFileFrmt.
5934 DataArrayInt *MEDCouplingUMesh::getRenumArrForMEDFileFrmt() const
5936 return getRenumArrForConsecutiveCellTypesSpec(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
5940 * 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.
5941 * This method returns an array of size getNumberOfCells() that gives a renumber array old2New that can be used as input of MEDCouplingMesh::renumberCells.
5942 * The mesh after this call to MEDCouplingMesh::renumberCells will pass the test of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder with the same inputs.
5943 * The returned array minimizes the permutations that is to say the order of cells inside same geometric type remains the same.
5945 DataArrayInt *MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
5947 DataArrayInt *nbPerType=0;
5948 MCAuto<DataArrayInt> tmpa=getLevArrPerCellTypes(orderBg,orderEnd,nbPerType);
5949 nbPerType->decrRef();
5950 return tmpa->buildPermArrPerLevel();
5954 * This method reorganize the cells of \a this so that the cells with same geometric types are put together.
5955 * The number of cells remains unchanged after the call of this method.
5956 * This method tries to minimizes the number of needed permutations. So, this method behaves not exactly as
5957 * MEDCouplingUMesh::sortCellsInMEDFileFrmt.
5959 * \return the array giving the correspondance old to new.
5961 DataArrayInt *MEDCouplingUMesh::rearrange2ConsecutiveCellTypes()
5963 checkFullyDefined();
5965 const int *conn=_nodal_connec->begin();
5966 const int *connI=_nodal_connec_index->begin();
5967 int nbOfCells=getNumberOfCells();
5968 std::vector<INTERP_KERNEL::NormalizedCellType> types;
5969 for(const int *i=connI;i!=connI+nbOfCells && (types.size()!=_types.size());)
5970 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)conn[*i])==types.end())
5972 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5973 types.push_back(curType);
5974 for(i++;i!=connI+nbOfCells && (INTERP_KERNEL::NormalizedCellType)conn[*i]==curType;i++);
5976 DataArrayInt *ret=DataArrayInt::New();
5977 ret->alloc(nbOfCells,1);
5978 int *retPtr=ret->getPointer();
5979 std::fill(retPtr,retPtr+nbOfCells,-1);
5981 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
5983 for(const int *i=connI;i!=connI+nbOfCells;i++)
5984 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
5985 retPtr[std::distance(connI,i)]=newCellId++;
5987 renumberCells(retPtr,false);
5992 * This method splits \a this into as mush as untructured meshes that consecutive set of same type cells.
5993 * So this method has typically a sense if MEDCouplingUMesh::checkConsecutiveCellTypes has a sense.
5994 * This method makes asumption that connectivity is correctly set before calling.
5996 std::vector<MEDCouplingUMesh *> MEDCouplingUMesh::splitByType() const
5998 checkConnectivityFullyDefined();
5999 const int *conn=_nodal_connec->begin();
6000 const int *connI=_nodal_connec_index->begin();
6001 int nbOfCells=getNumberOfCells();
6002 std::vector<MEDCouplingUMesh *> ret;
6003 for(const int *i=connI;i!=connI+nbOfCells;)
6005 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6006 int beginCellId=(int)std::distance(connI,i);
6007 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
6008 int endCellId=(int)std::distance(connI,i);
6009 int sz=endCellId-beginCellId;
6010 int *cells=new int[sz];
6011 for(int j=0;j<sz;j++)
6012 cells[j]=beginCellId+j;
6013 MEDCouplingUMesh *m=(MEDCouplingUMesh *)buildPartOfMySelf(cells,cells+sz,true);
6021 * This method performs the opposite operation than those in MEDCoupling1SGTUMesh::buildUnstructured.
6022 * If \a this is a single geometric type unstructured mesh, it will be converted into a more compact data structure,
6023 * MEDCoupling1GTUMesh instance. The returned instance will aggregate the same DataArrayDouble instance of coordinates than \a this.
6025 * \return a newly allocated instance, that the caller must manage.
6026 * \throw If \a this contains more than one geometric type.
6027 * \throw If the nodal connectivity of \a this is not fully defined.
6028 * \throw If the internal data is not coherent.
6030 MEDCoupling1GTUMesh *MEDCouplingUMesh::convertIntoSingleGeoTypeMesh() const
6032 checkConnectivityFullyDefined();
6033 if(_types.size()!=1)
6034 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6035 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6036 MCAuto<MEDCoupling1GTUMesh> ret=MEDCoupling1GTUMesh::New(getName(),typ);
6037 ret->setCoords(getCoords());
6038 MEDCoupling1SGTUMesh *retC=dynamic_cast<MEDCoupling1SGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6041 MCAuto<DataArrayInt> c=convertNodalConnectivityToStaticGeoTypeMesh();
6042 retC->setNodalConnectivity(c);
6046 MEDCoupling1DGTUMesh *retD=dynamic_cast<MEDCoupling1DGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6048 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : Internal error !");
6049 DataArrayInt *c=0,*ci=0;
6050 convertNodalConnectivityToDynamicGeoTypeMesh(c,ci);
6051 MCAuto<DataArrayInt> cs(c),cis(ci);
6052 retD->setNodalConnectivity(cs,cis);
6057 DataArrayInt *MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh() const
6059 checkConnectivityFullyDefined();
6060 if(_types.size()!=1)
6061 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6062 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6063 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6066 std::ostringstream oss; oss << "MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : this contains a single geo type (" << cm.getRepr() << ") but ";
6067 oss << "this type is dynamic ! Only static geometric type is possible for that type ! call convertNodalConnectivityToDynamicGeoTypeMesh instead !";
6068 throw INTERP_KERNEL::Exception(oss.str());
6070 int nbCells=getNumberOfCells();
6072 int nbNodesPerCell=(int)cm.getNumberOfNodes();
6073 MCAuto<DataArrayInt> connOut=DataArrayInt::New(); connOut->alloc(nbCells*nbNodesPerCell,1);
6074 int *outPtr=connOut->getPointer();
6075 const int *conn=_nodal_connec->begin();
6076 const int *connI=_nodal_connec_index->begin();
6078 for(int i=0;i<nbCells;i++,connI++)
6080 if(conn[connI[0]]==typi && connI[1]-connI[0]==nbNodesPerCell)
6081 outPtr=std::copy(conn+connI[0]+1,conn+connI[1],outPtr);
6084 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 << ") !";
6085 throw INTERP_KERNEL::Exception(oss.str());
6088 return connOut.retn();
6092 * Convert the nodal connectivity of the mesh so that all the cells are of dynamic types (polygon or quadratic
6093 * polygon). This returns the corresponding new nodal connectivity in \ref numbering-indirect format.
6097 void MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh(DataArrayInt *&nodalConn, DataArrayInt *&nodalConnIndex) const
6099 static const char msg0[]="MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : nodal connectivity in this are invalid ! Call checkConsistency !";
6100 checkConnectivityFullyDefined();
6101 if(_types.size()!=1)
6102 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6103 int nbCells=getNumberOfCells(),lgth=_nodal_connec->getNumberOfTuples();
6105 throw INTERP_KERNEL::Exception(msg0);
6106 MCAuto<DataArrayInt> c(DataArrayInt::New()),ci(DataArrayInt::New());
6107 c->alloc(lgth-nbCells,1); ci->alloc(nbCells+1,1);
6108 int *cp(c->getPointer()),*cip(ci->getPointer());
6109 const int *incp(_nodal_connec->begin()),*incip(_nodal_connec_index->begin());
6111 for(int i=0;i<nbCells;i++,cip++,incip++)
6113 int strt(incip[0]+1),stop(incip[1]);//+1 to skip geo type
6114 int delta(stop-strt);
6117 if((strt>=0 && strt<lgth) && (stop>=0 && stop<=lgth))
6118 cp=std::copy(incp+strt,incp+stop,cp);
6120 throw INTERP_KERNEL::Exception(msg0);
6123 throw INTERP_KERNEL::Exception(msg0);
6124 cip[1]=cip[0]+delta;
6126 nodalConn=c.retn(); nodalConnIndex=ci.retn();
6130 * This method takes in input a vector of MEDCouplingUMesh instances lying on the same coordinates with same mesh dimensions.
6131 * Each mesh in \b ms must be sorted by type with the same order (typically using MEDCouplingUMesh::sortCellsInMEDFileFrmt).
6132 * This method is particulary useful for MED file interaction. It allows to aggregate several meshes and keeping the type sorting
6133 * and the track of the permutation by chunk of same geotype cells to retrieve it. The traditional formats old2new and new2old
6134 * are not used here to avoid the build of big permutation array.
6136 * \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
6137 * those specified in MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6138 * \param [out] szOfCellGrpOfSameType is a newly allocated DataArrayInt instance whose number of tuples is equal to the number of chunks of same geotype
6139 * in all meshes in \b ms. The accumulation of all values of this array is equal to the number of cells of returned mesh.
6140 * \param [out] idInMsOfCellGrpOfSameType is a newly allocated DataArrayInt instance having the same size than \b szOfCellGrpOfSameType. This
6141 * output array gives for each chunck of same type the corresponding mesh id in \b ms.
6142 * \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
6143 * is sorted by type following the geo cell types order of MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6145 MEDCouplingUMesh *MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& ms,
6146 DataArrayInt *&szOfCellGrpOfSameType,
6147 DataArrayInt *&idInMsOfCellGrpOfSameType)
6149 std::vector<const MEDCouplingUMesh *> ms2;
6150 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms.begin();it!=ms.end();it++)
6153 (*it)->checkConnectivityFullyDefined();
6157 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : input vector is empty !");
6158 const DataArrayDouble *refCoo=ms2[0]->getCoords();
6159 int meshDim=ms2[0]->getMeshDimension();
6160 std::vector<const MEDCouplingUMesh *> m1ssm;
6161 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmAuto;
6163 std::vector<const MEDCouplingUMesh *> m1ssmSingle;
6164 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmSingleAuto;
6166 MCAuto<DataArrayInt> ret1(DataArrayInt::New()),ret2(DataArrayInt::New());
6167 ret1->alloc(0,1); ret2->alloc(0,1);
6168 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms2.begin();it!=ms2.end();it++,rk++)
6170 if(meshDim!=(*it)->getMeshDimension())
6171 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshdims mismatch !");
6172 if(refCoo!=(*it)->getCoords())
6173 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshes are not shared by a single coordinates coords !");
6174 std::vector<MEDCouplingUMesh *> sp=(*it)->splitByType();
6175 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<const MEDCouplingUMesh *> >(m1ssm));
6176 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<MCAuto<MEDCouplingUMesh> > >(m1ssmAuto));
6177 for(std::vector<MEDCouplingUMesh *>::const_iterator it2=sp.begin();it2!=sp.end();it2++)
6179 MEDCouplingUMesh *singleCell=static_cast<MEDCouplingUMesh *>((*it2)->buildPartOfMySelf(&fake,&fake+1,true));
6180 m1ssmSingleAuto.push_back(singleCell);
6181 m1ssmSingle.push_back(singleCell);
6182 ret1->pushBackSilent((*it2)->getNumberOfCells()); ret2->pushBackSilent(rk);
6185 MCAuto<MEDCouplingUMesh> m1ssmSingle2=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmSingle);
6186 MCAuto<DataArrayInt> renum=m1ssmSingle2->sortCellsInMEDFileFrmt();
6187 std::vector<const MEDCouplingUMesh *> m1ssmfinal(m1ssm.size());
6188 for(std::size_t i=0;i<m1ssm.size();i++)
6189 m1ssmfinal[renum->getIJ(i,0)]=m1ssm[i];
6190 MCAuto<MEDCouplingUMesh> ret0=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmfinal);
6191 szOfCellGrpOfSameType=ret1->renumber(renum->begin());
6192 idInMsOfCellGrpOfSameType=ret2->renumber(renum->begin());
6197 * This method returns a newly created DataArrayInt instance.
6198 * This method retrieves cell ids in [ \a begin, \a end ) that have the type \a type.
6200 DataArrayInt *MEDCouplingUMesh::keepCellIdsByType(INTERP_KERNEL::NormalizedCellType type, const int *begin, const int *end) const
6202 checkFullyDefined();
6203 const int *conn=_nodal_connec->begin();
6204 const int *connIndex=_nodal_connec_index->begin();
6205 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(0,1);
6206 for(const int *w=begin;w!=end;w++)
6207 if((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]==type)
6208 ret->pushBackSilent(*w);
6213 * This method makes the assumption that da->getNumberOfTuples()<this->getNumberOfCells(). This method makes the assumption that ids contained in 'da'
6214 * are in [0:getNumberOfCells())
6216 DataArrayInt *MEDCouplingUMesh::convertCellArrayPerGeoType(const DataArrayInt *da) const
6218 checkFullyDefined();
6219 const int *conn=_nodal_connec->begin();
6220 const int *connI=_nodal_connec_index->begin();
6221 int nbOfCells=getNumberOfCells();
6222 std::set<INTERP_KERNEL::NormalizedCellType> types(getAllGeoTypes());
6223 int *tmp=new int[nbOfCells];
6224 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
6227 for(const int *i=connI;i!=connI+nbOfCells;i++)
6228 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
6229 tmp[std::distance(connI,i)]=j++;
6231 DataArrayInt *ret=DataArrayInt::New();
6232 ret->alloc(da->getNumberOfTuples(),da->getNumberOfComponents());
6233 ret->copyStringInfoFrom(*da);
6234 int *retPtr=ret->getPointer();
6235 const int *daPtr=da->begin();
6236 int nbOfElems=da->getNbOfElems();
6237 for(int k=0;k<nbOfElems;k++)
6238 retPtr[k]=tmp[daPtr[k]];
6244 * This method reduced number of cells of this by keeping cells whose type is different from 'type' and if type=='type'
6245 * This method \b works \b for mesh sorted by type.
6246 * cells whose ids is in 'idsPerGeoType' array.
6247 * This method conserves coords and name of mesh.
6249 MEDCouplingUMesh *MEDCouplingUMesh::keepSpecifiedCells(INTERP_KERNEL::NormalizedCellType type, const int *idsPerGeoTypeBg, const int *idsPerGeoTypeEnd) const
6251 std::vector<int> code=getDistributionOfTypes();
6252 std::size_t nOfTypesInThis=code.size()/3;
6253 int sz=0,szOfType=0;
6254 for(std::size_t i=0;i<nOfTypesInThis;i++)
6259 szOfType=code[3*i+1];
6261 for(const int *work=idsPerGeoTypeBg;work!=idsPerGeoTypeEnd;work++)
6262 if(*work<0 || *work>=szOfType)
6264 std::ostringstream oss; oss << "MEDCouplingUMesh::keepSpecifiedCells : Request on type " << type << " at place #" << std::distance(idsPerGeoTypeBg,work) << " value " << *work;
6265 oss << ". It should be in [0," << szOfType << ") !";
6266 throw INTERP_KERNEL::Exception(oss.str());
6268 MCAuto<DataArrayInt> idsTokeep=DataArrayInt::New(); idsTokeep->alloc(sz+(int)std::distance(idsPerGeoTypeBg,idsPerGeoTypeEnd),1);
6269 int *idsPtr=idsTokeep->getPointer();
6271 for(std::size_t i=0;i<nOfTypesInThis;i++)
6274 for(int j=0;j<code[3*i+1];j++)
6277 idsPtr=std::transform(idsPerGeoTypeBg,idsPerGeoTypeEnd,idsPtr,std::bind2nd(std::plus<int>(),offset));
6278 offset+=code[3*i+1];
6280 MCAuto<MEDCouplingUMesh> ret=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(idsTokeep->begin(),idsTokeep->end(),true));
6281 ret->copyTinyInfoFrom(this);
6286 * This method returns a vector of size 'this->getNumberOfCells()'.
6287 * This method retrieves for each cell in \a this if it is linear (false) or quadratic(true).
6289 std::vector<bool> MEDCouplingUMesh::getQuadraticStatus() const
6291 int ncell=getNumberOfCells();
6292 std::vector<bool> ret(ncell);
6293 const int *cI=getNodalConnectivityIndex()->begin();
6294 const int *c=getNodalConnectivity()->begin();
6295 for(int i=0;i<ncell;i++)
6297 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[i]];
6298 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6299 ret[i]=cm.isQuadratic();
6305 * Returns a newly created mesh (with ref count ==1) that contains merge of \a this and \a other.
6307 MEDCouplingMesh *MEDCouplingUMesh::mergeMyselfWith(const MEDCouplingMesh *other) const
6309 if(other->getType()!=UNSTRUCTURED)
6310 throw INTERP_KERNEL::Exception("Merge of umesh only available with umesh each other !");
6311 const MEDCouplingUMesh *otherC=static_cast<const MEDCouplingUMesh *>(other);
6312 return MergeUMeshes(this,otherC);
6316 * Returns a new DataArrayDouble holding barycenters of all cells. The barycenter is
6317 * computed by averaging coordinates of cell nodes, so this method is not a right
6318 * choice for degnerated meshes (not well oriented, cells with measure close to zero).
6319 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
6320 * this->getNumberOfCells() tuples per \a this->getSpaceDimension()
6321 * components. The caller is to delete this array using decrRef() as it is
6323 * \throw If the coordinates array is not set.
6324 * \throw If the nodal connectivity of cells is not defined.
6325 * \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
6327 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMass() const
6329 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6330 int spaceDim=getSpaceDimension();
6331 int nbOfCells=getNumberOfCells();
6332 ret->alloc(nbOfCells,spaceDim);
6333 ret->copyStringInfoFrom(*getCoords());
6334 double *ptToFill=ret->getPointer();
6335 const int *nodal=_nodal_connec->begin();
6336 const int *nodalI=_nodal_connec_index->begin();
6337 const double *coor=_coords->begin();
6338 for(int i=0;i<nbOfCells;i++)
6340 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6341 INTERP_KERNEL::computeBarycenter2<int,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[i]+1,nodalI[i+1]-nodalI[i]-1,coor,spaceDim,ptToFill);
6348 * This method computes for each cell in \a this, the location of the iso barycenter of nodes constituting
6349 * the cell. Contrary to badly named MEDCouplingUMesh::computeCellCenterOfMass method that returns the center of inertia of the
6351 * \return a newly allocated DataArrayDouble instance that the caller has to deal with. The returned
6352 * DataArrayDouble instance will have \c this->getNumberOfCells() tuples and \c this->getSpaceDimension() components.
6354 * \sa MEDCouplingUMesh::computeCellCenterOfMass
6355 * \throw If \a this is not fully defined (coordinates and connectivity)
6356 * \throw If there is presence in nodal connectivity in \a this of node ids not in [0, \c this->getNumberOfNodes() )
6358 DataArrayDouble *MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell() const
6360 checkFullyDefined();
6361 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6362 int spaceDim=getSpaceDimension();
6363 int nbOfCells=getNumberOfCells();
6364 int nbOfNodes=getNumberOfNodes();
6365 ret->alloc(nbOfCells,spaceDim);
6366 double *ptToFill=ret->getPointer();
6367 const int *nodal=_nodal_connec->begin();
6368 const int *nodalI=_nodal_connec_index->begin();
6369 const double *coor=_coords->begin();
6370 for(int i=0;i<nbOfCells;i++,ptToFill+=spaceDim)
6372 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6373 std::fill(ptToFill,ptToFill+spaceDim,0.);
6374 if(type!=INTERP_KERNEL::NORM_POLYHED)
6376 for(const int *conn=nodal+nodalI[i]+1;conn!=nodal+nodalI[i+1];conn++)
6378 if(*conn>=0 && *conn<nbOfNodes)
6379 std::transform(coor+spaceDim*conn[0],coor+spaceDim*(conn[0]+1),ptToFill,ptToFill,std::plus<double>());
6382 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of nodeId #" << *conn << " should be in [0," << nbOfNodes << ") !";
6383 throw INTERP_KERNEL::Exception(oss.str());
6386 int nbOfNodesInCell=nodalI[i+1]-nodalI[i]-1;
6387 if(nbOfNodesInCell>0)
6388 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies<double>(),1./(double)nbOfNodesInCell));
6391 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of cell with no nodes !";
6392 throw INTERP_KERNEL::Exception(oss.str());
6397 std::set<int> s(nodal+nodalI[i]+1,nodal+nodalI[i+1]);
6399 for(std::set<int>::const_iterator it=s.begin();it!=s.end();it++)
6401 if(*it>=0 && *it<nbOfNodes)
6402 std::transform(coor+spaceDim*(*it),coor+spaceDim*((*it)+1),ptToFill,ptToFill,std::plus<double>());
6405 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell polyhedron cell #" << i << " presence of nodeId #" << *it << " should be in [0," << nbOfNodes << ") !";
6406 throw INTERP_KERNEL::Exception(oss.str());
6410 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies<double>(),1./(double)s.size()));
6413 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on polyhedron cell #" << i << " there are no nodes !";
6414 throw INTERP_KERNEL::Exception(oss.str());
6422 * Returns a new DataArrayDouble holding barycenters of specified cells. The
6423 * barycenter is computed by averaging coordinates of cell nodes. The cells to treat
6424 * are specified via an array of cell ids.
6425 * \warning Validity of the specified cell ids is not checked!
6426 * Valid range is [ 0, \a this->getNumberOfCells() ).
6427 * \param [in] begin - an array of cell ids of interest.
6428 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
6429 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size ( \a
6430 * end - \a begin ) tuples per \a this->getSpaceDimension() components. The
6431 * caller is to delete this array using decrRef() as it is no more needed.
6432 * \throw If the coordinates array is not set.
6433 * \throw If the nodal connectivity of cells is not defined.
6435 * \if ENABLE_EXAMPLES
6436 * \ref cpp_mcumesh_getPartBarycenterAndOwner "Here is a C++ example".<br>
6437 * \ref py_mcumesh_getPartBarycenterAndOwner "Here is a Python example".
6440 DataArrayDouble *MEDCouplingUMesh::getPartBarycenterAndOwner(const int *begin, const int *end) const
6442 DataArrayDouble *ret=DataArrayDouble::New();
6443 int spaceDim=getSpaceDimension();
6444 int nbOfTuple=(int)std::distance(begin,end);
6445 ret->alloc(nbOfTuple,spaceDim);
6446 double *ptToFill=ret->getPointer();
6447 double *tmp=new double[spaceDim];
6448 const int *nodal=_nodal_connec->begin();
6449 const int *nodalI=_nodal_connec_index->begin();
6450 const double *coor=_coords->begin();
6451 for(const int *w=begin;w!=end;w++)
6453 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[*w]];
6454 INTERP_KERNEL::computeBarycenter2<int,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[*w]+1,nodalI[*w+1]-nodalI[*w]-1,coor,spaceDim,ptToFill);
6462 * 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".
6463 * So the returned instance will have 4 components and \c this->getNumberOfCells() tuples.
6464 * So this method expects that \a this has a spaceDimension equal to 3 and meshDimension equal to 2.
6465 * The computation of the plane equation is done using each time the 3 first nodes of 2D cells.
6466 * This method is useful to detect 2D cells in 3D space that are not coplanar.
6468 * \return DataArrayDouble * - a new instance of DataArrayDouble having 4 components and a number of tuples equal to number of cells in \a this.
6469 * \throw If spaceDim!=3 or meshDim!=2.
6470 * \throw If connectivity of \a this is invalid.
6471 * \throw If connectivity of a cell in \a this points to an invalid node.
6473 DataArrayDouble *MEDCouplingUMesh::computePlaneEquationOf3DFaces() const
6475 MCAuto<DataArrayDouble> ret(DataArrayDouble::New());
6476 int nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
6477 if(getSpaceDimension()!=3 || getMeshDimension()!=2)
6478 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computePlaneEquationOf3DFaces : This method must be applied on a mesh having meshDimension equal 2 and a spaceDimension equal to 3 !");
6479 ret->alloc(nbOfCells,4);
6480 double *retPtr(ret->getPointer());
6481 const int *nodal(_nodal_connec->begin()),*nodalI(_nodal_connec_index->begin());
6482 const double *coor(_coords->begin());
6483 for(int i=0;i<nbOfCells;i++,nodalI++,retPtr+=4)
6485 double matrix[16]={0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,0},matrix2[16];
6486 if(nodalI[1]-nodalI[0]>=4)
6488 double aa[3]={coor[nodal[nodalI[0]+1+1]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6489 coor[nodal[nodalI[0]+1+1]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6490 coor[nodal[nodalI[0]+1+1]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]}
6491 ,bb[3]={coor[nodal[nodalI[0]+1+2]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6492 coor[nodal[nodalI[0]+1+2]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6493 coor[nodal[nodalI[0]+1+2]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]};
6494 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]};
6495 for(int j=0;j<3;j++)
6497 int nodeId(nodal[nodalI[0]+1+j]);
6498 if(nodeId>=0 && nodeId<nbOfNodes)
6499 std::copy(coor+nodeId*3,coor+(nodeId+1)*3,matrix+4*j);
6502 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! This cell points to an invalid nodeId : " << nodeId << " !";
6503 throw INTERP_KERNEL::Exception(oss.str());
6506 if(sqrt(cc[0]*cc[0]+cc[1]*cc[1]+cc[2]*cc[2])>1e-7)
6508 INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6509 retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6513 if(nodalI[1]-nodalI[0]==4)
6515 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : cell" << i << " : Presence of The 3 colinear points !";
6516 throw INTERP_KERNEL::Exception(oss.str());
6519 double dd[3]={0.,0.,0.};
6520 for(int offset=nodalI[0]+1;offset<nodalI[1];offset++)
6521 std::transform(coor+3*nodal[offset],coor+3*(nodal[offset]+1),dd,dd,std::plus<double>());
6522 int nbOfNodesInCell(nodalI[1]-nodalI[0]-1);
6523 std::transform(dd,dd+3,dd,std::bind2nd(std::multiplies<double>(),1./(double)nbOfNodesInCell));
6524 std::copy(dd,dd+3,matrix+4*2);
6525 INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6526 retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6531 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! Must be constitued by more than 3 nodes !";
6532 throw INTERP_KERNEL::Exception(oss.str());
6539 * This method expects as input a DataArrayDouble non nul instance 'da' that should be allocated. If not an exception is thrown.
6542 MEDCouplingUMesh *MEDCouplingUMesh::Build0DMeshFromCoords(DataArrayDouble *da)
6545 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build0DMeshFromCoords : instance of DataArrayDouble must be not null !");
6546 da->checkAllocated();
6547 std::string name(da->getName());
6548 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New(name,0));
6550 ret->setName("Mesh");
6552 int nbOfTuples(da->getNumberOfTuples());
6553 MCAuto<DataArrayInt> c(DataArrayInt::New()),cI(DataArrayInt::New());
6554 c->alloc(2*nbOfTuples,1);
6555 cI->alloc(nbOfTuples+1,1);
6556 int *cp(c->getPointer()),*cip(cI->getPointer());
6558 for(int i=0;i<nbOfTuples;i++)
6560 *cp++=INTERP_KERNEL::NORM_POINT1;
6564 ret->setConnectivity(c,cI,true);
6568 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::Build1DMeshFromCoords(DataArrayDouble *da)
6571 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build01MeshFromCoords : instance of DataArrayDouble must be not null !");
6572 da->checkAllocated();
6573 std::string name(da->getName());
6574 MCAuto<MEDCouplingUMesh> ret;
6576 MCAuto<MEDCouplingCMesh> tmp(MEDCouplingCMesh::New());
6577 MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
6578 arr->alloc(da->getNumberOfTuples());
6579 tmp->setCoordsAt(0,arr);
6580 ret=tmp->buildUnstructured();
6584 ret->setName("Mesh");
6591 * Creates a new MEDCouplingUMesh by concatenating two given meshes of the same dimension.
6592 * Cells and nodes of
6593 * the first mesh precede cells and nodes of the second mesh within the result mesh.
6594 * \param [in] mesh1 - the first mesh.
6595 * \param [in] mesh2 - the second mesh.
6596 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6597 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6598 * is no more needed.
6599 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
6600 * \throw If the coordinates array is not set in none of the meshes.
6601 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
6602 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
6604 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
6606 std::vector<const MEDCouplingUMesh *> tmp(2);
6607 tmp[0]=const_cast<MEDCouplingUMesh *>(mesh1); tmp[1]=const_cast<MEDCouplingUMesh *>(mesh2);
6608 return MergeUMeshes(tmp);
6612 * Creates a new MEDCouplingUMesh by concatenating all given meshes of the same dimension.
6613 * Cells and nodes of
6614 * the *i*-th mesh precede cells and nodes of the (*i*+1)-th mesh within the result mesh.
6615 * \param [in] a - a vector of meshes (MEDCouplingUMesh) to concatenate.
6616 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6617 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6618 * is no more needed.
6619 * \throw If \a a.size() == 0.
6620 * \throw If \a a[ *i* ] == NULL.
6621 * \throw If the coordinates array is not set in none of the meshes.
6622 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
6623 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
6625 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const std::vector<const MEDCouplingUMesh *>& a)
6627 std::size_t sz=a.size();
6629 return MergeUMeshesLL(a);
6630 for(std::size_t ii=0;ii<sz;ii++)
6633 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshes : item #" << ii << " in input array of size "<< sz << " is empty !";
6634 throw INTERP_KERNEL::Exception(oss.str());
6636 std::vector< MCAuto<MEDCouplingUMesh> > bb(sz);
6637 std::vector< const MEDCouplingUMesh * > aa(sz);
6639 for(std::size_t i=0;i<sz && spaceDim==-3;i++)
6641 const MEDCouplingUMesh *cur=a[i];
6642 const DataArrayDouble *coo=cur->getCoords();
6644 spaceDim=coo->getNumberOfComponents();
6647 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : no spaceDim specified ! unable to perform merge !");
6648 for(std::size_t i=0;i<sz;i++)
6650 bb[i]=a[i]->buildSetInstanceFromThis(spaceDim);
6653 return MergeUMeshesLL(aa);
6657 * Creates a new MEDCouplingUMesh by concatenating cells of two given meshes of same
6658 * dimension and sharing the node coordinates array.
6659 * All cells of the first mesh precede all cells of the second mesh
6660 * within the result mesh.
6661 * \param [in] mesh1 - the first mesh.
6662 * \param [in] mesh2 - the second mesh.
6663 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6664 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6665 * is no more needed.
6666 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
6667 * \throw If the meshes do not share the node coordinates array.
6668 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
6669 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
6671 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
6673 std::vector<const MEDCouplingUMesh *> tmp(2);
6674 tmp[0]=mesh1; tmp[1]=mesh2;
6675 return MergeUMeshesOnSameCoords(tmp);
6679 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
6680 * dimension and sharing the node coordinates array.
6681 * All cells of the *i*-th mesh precede all cells of the
6682 * (*i*+1)-th mesh within the result mesh.
6683 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
6684 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6685 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6686 * is no more needed.
6687 * \throw If \a a.size() == 0.
6688 * \throw If \a a[ *i* ] == NULL.
6689 * \throw If the meshes do not share the node coordinates array.
6690 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
6691 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
6693 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes)
6696 throw INTERP_KERNEL::Exception("meshes input parameter is expected to be non empty.");
6697 for(std::size_t ii=0;ii<meshes.size();ii++)
6700 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshesOnSameCoords : item #" << ii << " in input array of size "<< meshes.size() << " is empty !";
6701 throw INTERP_KERNEL::Exception(oss.str());
6703 const DataArrayDouble *coords=meshes.front()->getCoords();
6704 int meshDim=meshes.front()->getMeshDimension();
6705 std::vector<const MEDCouplingUMesh *>::const_iterator iter=meshes.begin();
6707 int meshIndexLgth=0;
6708 for(;iter!=meshes.end();iter++)
6710 if(coords!=(*iter)->getCoords())
6711 throw INTERP_KERNEL::Exception("meshes does not share the same coords ! Try using tryToShareSameCoords method !");
6712 if(meshDim!=(*iter)->getMeshDimension())
6713 throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, FuseUMeshesOnSameCoords impossible !");
6714 meshLgth+=(*iter)->getNodalConnectivityArrayLen();
6715 meshIndexLgth+=(*iter)->getNumberOfCells();
6717 MCAuto<DataArrayInt> nodal=DataArrayInt::New();
6718 nodal->alloc(meshLgth,1);
6719 int *nodalPtr=nodal->getPointer();
6720 MCAuto<DataArrayInt> nodalIndex=DataArrayInt::New();
6721 nodalIndex->alloc(meshIndexLgth+1,1);
6722 int *nodalIndexPtr=nodalIndex->getPointer();
6724 for(iter=meshes.begin();iter!=meshes.end();iter++)
6726 const int *nod=(*iter)->getNodalConnectivity()->begin();
6727 const int *index=(*iter)->getNodalConnectivityIndex()->begin();
6728 int nbOfCells=(*iter)->getNumberOfCells();
6729 int meshLgth2=(*iter)->getNodalConnectivityArrayLen();
6730 nodalPtr=std::copy(nod,nod+meshLgth2,nodalPtr);
6731 if(iter!=meshes.begin())
6732 nodalIndexPtr=std::transform(index+1,index+nbOfCells+1,nodalIndexPtr,std::bind2nd(std::plus<int>(),offset));
6734 nodalIndexPtr=std::copy(index,index+nbOfCells+1,nodalIndexPtr);
6737 MEDCouplingUMesh *ret=MEDCouplingUMesh::New();
6738 ret->setName("merge");
6739 ret->setMeshDimension(meshDim);
6740 ret->setConnectivity(nodal,nodalIndex,true);
6741 ret->setCoords(coords);
6746 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
6747 * dimension and sharing the node coordinates array. Cells of the *i*-th mesh precede
6748 * cells of the (*i*+1)-th mesh within the result mesh. Duplicates of cells are
6749 * removed from \a this mesh and arrays mapping between new and old cell ids in "Old to
6750 * New" mode are returned for each input mesh.
6751 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
6752 * \param [in] compType - specifies a cell comparison technique. For meaning of its
6753 * valid values [0,1,2], see zipConnectivityTraducer().
6754 * \param [in,out] corr - an array of DataArrayInt, of the same size as \a
6755 * meshes. The *i*-th array describes cell ids mapping for \a meshes[ *i* ]
6756 * mesh. The caller is to delete each of the arrays using decrRef() as it is
6758 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6759 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6760 * is no more needed.
6761 * \throw If \a meshes.size() == 0.
6762 * \throw If \a meshes[ *i* ] == NULL.
6763 * \throw If the meshes do not share the node coordinates array.
6764 * \throw If \a meshes[ *i* ]->getMeshDimension() < 0.
6765 * \throw If the \a meshes are of different dimension (getMeshDimension()).
6766 * \throw If the nodal connectivity of cells of any of \a meshes is not defined.
6767 * \throw If the nodal connectivity any of \a meshes includes an invalid id.
6769 MEDCouplingUMesh *MEDCouplingUMesh::FuseUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes, int compType, std::vector<DataArrayInt *>& corr)
6771 //All checks are delegated to MergeUMeshesOnSameCoords
6772 MCAuto<MEDCouplingUMesh> ret=MergeUMeshesOnSameCoords(meshes);
6773 MCAuto<DataArrayInt> o2n=ret->zipConnectivityTraducer(compType);
6774 corr.resize(meshes.size());
6775 std::size_t nbOfMeshes=meshes.size();
6777 const int *o2nPtr=o2n->begin();
6778 for(std::size_t i=0;i<nbOfMeshes;i++)
6780 DataArrayInt *tmp=DataArrayInt::New();
6781 int curNbOfCells=meshes[i]->getNumberOfCells();
6782 tmp->alloc(curNbOfCells,1);
6783 std::copy(o2nPtr+offset,o2nPtr+offset+curNbOfCells,tmp->getPointer());
6784 offset+=curNbOfCells;
6785 tmp->setName(meshes[i]->getName());
6792 * Makes all given meshes share the nodal connectivity array. The common connectivity
6793 * array is created by concatenating the connectivity arrays of all given meshes. All
6794 * the given meshes must be of the same space dimension but dimension of cells **can
6795 * differ**. This method is particulary useful in MEDLoader context to build a \ref
6796 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
6797 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
6798 * \param [in,out] meshes - a vector of meshes to update.
6799 * \throw If any of \a meshes is NULL.
6800 * \throw If the coordinates array is not set in any of \a meshes.
6801 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
6802 * \throw If \a meshes are of different space dimension.
6804 void MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords(const std::vector<MEDCouplingUMesh *>& meshes)
6806 std::size_t sz=meshes.size();
6809 std::vector< const DataArrayDouble * > coords(meshes.size());
6810 std::vector< const DataArrayDouble * >::iterator it2=coords.begin();
6811 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++,it2++)
6815 (*it)->checkConnectivityFullyDefined();
6816 const DataArrayDouble *coo=(*it)->getCoords();
6821 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
6822 oss << " has no coordinate array defined !";
6823 throw INTERP_KERNEL::Exception(oss.str());
6828 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
6829 oss << " is null !";
6830 throw INTERP_KERNEL::Exception(oss.str());
6833 MCAuto<DataArrayDouble> res=DataArrayDouble::Aggregate(coords);
6834 std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();
6835 int offset=(*it)->getNumberOfNodes();
6836 (*it++)->setCoords(res);
6837 for(;it!=meshes.end();it++)
6839 int oldNumberOfNodes=(*it)->getNumberOfNodes();
6840 (*it)->setCoords(res);
6841 (*it)->shiftNodeNumbersInConn(offset);
6842 offset+=oldNumberOfNodes;
6847 * Merges nodes coincident with a given precision within all given meshes that share
6848 * the nodal connectivity array. The given meshes **can be of different** mesh
6849 * dimension. This method is particulary useful in MEDLoader context to build a \ref
6850 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
6851 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
6852 * \param [in,out] meshes - a vector of meshes to update.
6853 * \param [in] eps - the precision used to detect coincident nodes (infinite norm).
6854 * \throw If any of \a meshes is NULL.
6855 * \throw If the \a meshes do not share the same node coordinates array.
6856 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
6858 void MEDCouplingUMesh::MergeNodesOnUMeshesSharingSameCoords(const std::vector<MEDCouplingUMesh *>& meshes, double eps)
6862 std::set<const DataArrayDouble *> s;
6863 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
6866 s.insert((*it)->getCoords());
6869 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 !";
6870 throw INTERP_KERNEL::Exception(oss.str());
6875 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 !";
6876 throw INTERP_KERNEL::Exception(oss.str());
6878 const DataArrayDouble *coo=*(s.begin());
6882 DataArrayInt *comm,*commI;
6883 coo->findCommonTuples(eps,-1,comm,commI);
6884 MCAuto<DataArrayInt> tmp1(comm),tmp2(commI);
6885 int oldNbOfNodes=coo->getNumberOfTuples();
6887 MCAuto<DataArrayInt> o2n=DataArrayInt::ConvertIndexArrayToO2N(oldNbOfNodes,comm->begin(),commI->begin(),commI->end(),newNbOfNodes);
6888 if(oldNbOfNodes==newNbOfNodes)
6890 MCAuto<DataArrayDouble> newCoords=coo->renumberAndReduce(o2n->begin(),newNbOfNodes);
6891 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
6893 (*it)->renumberNodesInConn(o2n->begin());
6894 (*it)->setCoords(newCoords);
6900 * This static operates only for coords in 3D. The polygon is specfied by its connectivity nodes in [ \a begin , \a end ).
6902 bool MEDCouplingUMesh::IsPolygonWellOriented(bool isQuadratic, const double *vec, const int *begin, const int *end, const double *coords)
6905 double v[3]={0.,0.,0.};
6906 std::size_t sz=std::distance(begin,end);
6911 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];
6912 v[1]+=coords[3*begin[i]+2]*coords[3*begin[(i+1)%sz]]-coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+2];
6913 v[2]+=coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+1]-coords[3*begin[i]+1]*coords[3*begin[(i+1)%sz]];
6915 double ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
6917 // Try using quadratic points if standard points are degenerated (for example a QPOLYG with two
6918 // SEG3 forming a circle):
6919 if (fabs(ret) < INTERP_KERNEL::DEFAULT_ABS_TOL && isQuadratic)
6921 v[0] = 0.0; v[1] = 0.0; v[2] = 0.0;
6922 for(std::size_t j=0;j<sz;j++)
6924 if (j%2) // current point i is quadratic, next point i+1 is standard
6927 ip1 = (j+1)%sz; // ip1 = "i+1"
6929 else // current point i is standard, next point i+1 is quadratic
6934 v[0]+=coords[3*begin[i]+1]*coords[3*begin[ip1]+2]-coords[3*begin[i]+2]*coords[3*begin[ip1]+1];
6935 v[1]+=coords[3*begin[i]+2]*coords[3*begin[ip1]]-coords[3*begin[i]]*coords[3*begin[ip1]+2];
6936 v[2]+=coords[3*begin[i]]*coords[3*begin[ip1]+1]-coords[3*begin[i]+1]*coords[3*begin[ip1]];
6938 ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
6944 * The polyhedron is specfied by its connectivity nodes in [ \a begin , \a end ).
6946 bool MEDCouplingUMesh::IsPolyhedronWellOriented(const int *begin, const int *end, const double *coords)
6948 std::vector<std::pair<int,int> > edges;
6949 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
6950 const int *bgFace=begin;
6951 for(std::size_t i=0;i<nbOfFaces;i++)
6953 const int *endFace=std::find(bgFace+1,end,-1);
6954 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
6955 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
6957 std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
6958 if(std::find(edges.begin(),edges.end(),p1)!=edges.end())
6960 edges.push_back(p1);
6964 return INTERP_KERNEL::calculateVolumeForPolyh2<int,INTERP_KERNEL::ALL_C_MODE>(begin,(int)std::distance(begin,end),coords)>-EPS_FOR_POLYH_ORIENTATION;
6968 * The 3D extruded static cell (PENTA6,HEXA8,HEXAGP12...) its connectivity nodes in [ \a begin , \a end ).
6970 bool MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented(const int *begin, const int *end, const double *coords)
6972 double vec0[3],vec1[3];
6973 std::size_t sz=std::distance(begin,end);
6975 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented : the length of nodal connectivity of extruded cell is not even !");
6976 int nbOfNodes=(int)sz/2;
6977 INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(begin,nbOfNodes,coords,vec0);
6978 const double *pt0=coords+3*begin[0];
6979 const double *pt1=coords+3*begin[nbOfNodes];
6980 vec1[0]=pt1[0]-pt0[0]; vec1[1]=pt1[1]-pt0[1]; vec1[2]=pt1[2]-pt0[2];
6981 return (vec0[0]*vec1[0]+vec0[1]*vec1[1]+vec0[2]*vec1[2])<0.;
6984 void MEDCouplingUMesh::CorrectExtrudedStaticCell(int *begin, int *end)
6986 std::size_t sz=std::distance(begin,end);
6987 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz];
6988 std::size_t nbOfNodes(sz/2);
6989 std::copy(begin,end,(int *)tmp);
6990 for(std::size_t j=1;j<nbOfNodes;j++)
6992 begin[j]=tmp[nbOfNodes-j];
6993 begin[j+nbOfNodes]=tmp[nbOfNodes+nbOfNodes-j];
6997 bool MEDCouplingUMesh::IsTetra4WellOriented(const int *begin, const int *end, const double *coords)
6999 std::size_t sz=std::distance(begin,end);
7001 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsTetra4WellOriented : Tetra4 cell with not 4 nodes ! Call checkConsistency !");
7002 double vec0[3],vec1[3];
7003 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[1],*pt2=coords+3*begin[2],*pt3=coords+3*begin[3];
7004 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];
7005 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;
7008 bool MEDCouplingUMesh::IsPyra5WellOriented(const int *begin, const int *end, const double *coords)
7010 std::size_t sz=std::distance(begin,end);
7012 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsPyra5WellOriented : Pyra5 cell with not 5 nodes ! Call checkConsistency !");
7014 INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(begin,4,coords,vec0);
7015 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[4];
7016 return (vec0[0]*(pt1[0]-pt0[0])+vec0[1]*(pt1[1]-pt0[1])+vec0[2]*(pt1[2]-pt0[2]))<0.;
7020 * 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 )
7021 * 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
7024 * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not.
7025 * \param [in] coords the coordinates with nb of components exactly equal to 3
7026 * \param [in] begin begin of the nodal connectivity (geometric type included) of a single polyhedron cell
7027 * \param [in] end end of nodal connectivity of a single polyhedron cell (excluded)
7028 * \param [out] res the result is put at the end of the vector without any alteration of the data.
7030 void MEDCouplingUMesh::SimplifyPolyhedronCell(double eps, const DataArrayDouble *coords, int index, DataArrayInt *res, MEDCouplingUMesh *faces,
7031 DataArrayInt *E_Fi, DataArrayInt *E_F, DataArrayInt *F_Ei, DataArrayInt *F_E)
7033 int nbFaces = E_Fi->getIJ(index + 1, 0) - E_Fi->getIJ(index, 0);
7034 MCAuto<DataArrayDouble> v=DataArrayDouble::New(); v->alloc(nbFaces,3);
7035 double *vPtr=v->getPointer();
7036 MCAuto<DataArrayDouble> p=DataArrayDouble::New(); p->alloc(nbFaces,2);
7037 double *pPtr=p->getPointer();
7038 int *e_fi = E_Fi->getPointer(), *e_f = E_F->getPointer(), *f_ei = F_Ei->getPointer(), *f_e = F_E->getPointer();
7039 const int *f_idx = faces->getNodalConnectivityIndex()->getPointer(), *f_cnn = faces->getNodalConnectivity()->getPointer();
7040 for(int i=0;i<nbFaces;i++,vPtr+=3,pPtr++)
7042 int face = e_f[e_fi[index] + i];
7043 ComputeVecAndPtOfFace(eps, coords->begin(), f_cnn + f_idx[face] + 1, f_cnn + f_idx[face + 1], vPtr, pPtr);
7044 // to differentiate faces going to different cells:
7046 for (int j = f_ei[face]; j < f_ei[face + 1]; j++)
7049 pPtr=p->getPointer(); vPtr=v->getPointer();
7050 DataArrayInt *comm1=0,*commI1=0;
7051 v->findCommonTuples(eps,-1,comm1,commI1);
7052 for (int i = 0; i < nbFaces; i++)
7053 if (comm1->findIdFirstEqual(i) < 0)
7055 comm1->pushBackSilent(i);
7056 commI1->pushBackSilent(comm1->getNumberOfTuples());
7058 MCAuto<DataArrayInt> comm1Auto(comm1),commI1Auto(commI1);
7059 const int *comm1Ptr=comm1->begin();
7060 const int *commI1Ptr=commI1->begin();
7061 int nbOfGrps1=commI1Auto->getNumberOfTuples()-1;
7062 res->pushBackSilent((int)INTERP_KERNEL::NORM_POLYHED);
7064 for(int i=0;i<nbOfGrps1;i++)
7066 int vecId=comm1Ptr[commI1Ptr[i]];
7067 MCAuto<DataArrayDouble> tmpgrp2=p->selectByTupleId(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7068 DataArrayInt *comm2=0,*commI2=0;
7069 tmpgrp2->findCommonTuples(eps,-1,comm2,commI2);
7070 for (int j = 0; j < commI1Ptr[i+1] - commI1Ptr[i]; j++)
7071 if (comm2->findIdFirstEqual(j) < 0)
7073 comm2->pushBackSilent(j);
7074 commI2->pushBackSilent(comm2->getNumberOfTuples());
7076 MCAuto<DataArrayInt> comm2Auto(comm2),commI2Auto(commI2);
7077 const int *comm2Ptr=comm2->begin();
7078 const int *commI2Ptr=commI2->begin();
7079 int nbOfGrps2=commI2Auto->getNumberOfTuples()-1;
7080 for(int j=0;j<nbOfGrps2;j++)
7082 if(commI2Ptr[j+1] == commI2Ptr[j] + 1)
7084 int face = e_f[e_fi[index] + comm1Ptr[commI1Ptr[i] + comm2Ptr[commI2Ptr[j]]]]; //hmmm
7085 res->insertAtTheEnd(f_cnn + f_idx[face] + 1, f_cnn + f_idx[face + 1]);
7086 res->pushBackSilent(-1);
7090 int pointId=comm1Ptr[commI1Ptr[i]+comm2Ptr[commI2Ptr[j]]];
7091 MCAuto<DataArrayInt> ids2=comm2->selectByTupleIdSafeSlice(commI2Ptr[j],commI2Ptr[j+1],1);
7092 ids2->transformWithIndArr(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7093 ids2->transformWithIndArr(e_f + e_fi[index], e_f + e_fi[index + 1]);
7094 MCAuto<MEDCouplingUMesh> mm3=static_cast<MEDCouplingUMesh *>(faces->buildPartOfMySelf(ids2->begin(),ids2->end(),true));
7095 MCAuto<DataArrayInt> idsNodeTmp=mm3->zipCoordsTraducer();
7096 MCAuto<DataArrayInt> idsNode=idsNodeTmp->invertArrayO2N2N2O(mm3->getNumberOfNodes());
7097 const int *idsNodePtr=idsNode->begin();
7098 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];
7099 double vec[3]; vec[0]=vPtr[3*vecId+1]; vec[1]=-vPtr[3*vecId]; vec[2]=0.;
7100 double norm=vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2];
7101 if(std::abs(norm)>eps)
7103 double angle=INTERP_KERNEL::EdgeArcCircle::SafeAsin(norm);
7104 mm3->rotate(center,vec,angle);
7106 mm3->changeSpaceDimension(2);
7107 MCAuto<MEDCouplingUMesh> mm4=mm3->buildSpreadZonesWithPoly();
7108 const int *conn4=mm4->getNodalConnectivity()->begin();
7109 const int *connI4=mm4->getNodalConnectivityIndex()->begin();
7110 int nbOfCells=mm4->getNumberOfCells();
7111 for(int k=0;k<nbOfCells;k++)
7114 for(const int *work=conn4+connI4[k]+1;work!=conn4+connI4[k+1];work++,l++)
7115 res->pushBackSilent(idsNodePtr[*work]);
7116 res->pushBackSilent(-1);
7121 res->popBackSilent();
7125 * 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
7126 * through origin. The plane is defined by its nodal connectivity [ \b begin, \b end ).
7128 * \param [in] eps below that value the dot product of 2 vectors is considered as colinears
7129 * \param [in] coords coordinates expected to have 3 components.
7130 * \param [in] begin start of the nodal connectivity of the face.
7131 * \param [in] end end of the nodal connectivity (excluded) of the face.
7132 * \param [out] v the normalized vector of size 3
7133 * \param [out] p the pos of plane
7135 void MEDCouplingUMesh::ComputeVecAndPtOfFace(double eps, const double *coords, const int *begin, const int *end, double *v, double *p)
7137 std::size_t nbPoints=std::distance(begin,end);
7139 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeVecAndPtOfFace : < of 3 points in face ! not able to find a plane on that face !");
7140 double vec[3]={0.,0.,0.};
7142 bool refFound=false;
7143 for(;j<nbPoints-1 && !refFound;j++)
7145 vec[0]=coords[3*begin[j+1]]-coords[3*begin[j]];
7146 vec[1]=coords[3*begin[j+1]+1]-coords[3*begin[j]+1];
7147 vec[2]=coords[3*begin[j+1]+2]-coords[3*begin[j]+2];
7148 double norm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
7152 vec[0]/=norm; vec[1]/=norm; vec[2]/=norm;
7155 for(std::size_t i=j;i<nbPoints-1;i++)
7158 curVec[0]=coords[3*begin[i+1]]-coords[3*begin[i]];
7159 curVec[1]=coords[3*begin[i+1]+1]-coords[3*begin[i]+1];
7160 curVec[2]=coords[3*begin[i+1]+2]-coords[3*begin[i]+2];
7161 double norm=sqrt(curVec[0]*curVec[0]+curVec[1]*curVec[1]+curVec[2]*curVec[2]);
7164 curVec[0]/=norm; curVec[1]/=norm; curVec[2]/=norm;
7165 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];
7166 norm=sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
7169 v[0]/=norm; v[1]/=norm; v[2]/=norm;
7170 *p=v[0]*coords[3*begin[i]]+v[1]*coords[3*begin[i]+1]+v[2]*coords[3*begin[i]+2];
7174 throw INTERP_KERNEL::Exception("Not able to find a normal vector of that 3D face !");
7178 * This method tries to obtain a well oriented polyhedron.
7179 * If the algorithm fails, an exception will be thrown.
7181 void MEDCouplingUMesh::TryToCorrectPolyhedronOrientation(int *begin, int *end, const double *coords)
7183 std::list< std::pair<int,int> > edgesOK,edgesFinished;
7184 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
7185 std::vector<bool> isPerm(nbOfFaces,false);//field on faces False: I don't know, True : oriented
7187 int *bgFace=begin,*endFace=std::find(begin+1,end,-1);
7188 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
7189 for(std::size_t l=0;l<nbOfEdgesInFace;l++) { std::pair<int,int> p1(bgFace[l],bgFace[(l+1)%nbOfEdgesInFace]); edgesOK.push_back(p1); }
7191 while(std::find(isPerm.begin(),isPerm.end(),false)!=isPerm.end())
7194 std::size_t smthChanged=0;
7195 for(std::size_t i=0;i<nbOfFaces;i++)
7197 endFace=std::find(bgFace+1,end,-1);
7198 nbOfEdgesInFace=std::distance(bgFace,endFace);
7202 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7204 std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7205 std::pair<int,int> p2(p1.second,p1.first);
7206 bool b1=std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end();
7207 bool b2=std::find(edgesOK.begin(),edgesOK.end(),p2)!=edgesOK.end();
7208 if(b1 || b2) { b=b2; isPerm[i]=true; smthChanged++; break; }
7213 std::reverse(bgFace+1,endFace);
7214 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7216 std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7217 std::pair<int,int> p2(p1.second,p1.first);
7218 if(std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end())
7219 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7220 if(std::find(edgesFinished.begin(),edgesFinished.end(),p1)!=edgesFinished.end() || std::find(edgesFinished.begin(),edgesFinished.end(),p2)!=edgesFinished.end())
7221 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7222 std::list< std::pair<int,int> >::iterator it=std::find(edgesOK.begin(),edgesOK.end(),p2);
7223 if(it!=edgesOK.end())
7226 edgesFinished.push_back(p1);
7229 edgesOK.push_back(p1);
7236 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired !"); }
7238 if(!edgesOK.empty())
7239 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired : Some edges are shared only once !"); }
7240 if(INTERP_KERNEL::calculateVolumeForPolyh2<int,INTERP_KERNEL::ALL_C_MODE>(begin,(int)std::distance(begin,end),coords)<-EPS_FOR_POLYH_ORIENTATION)
7241 {//not lucky ! The first face was not correctly oriented : reorient all faces...
7243 for(std::size_t i=0;i<nbOfFaces;i++)
7245 endFace=std::find(bgFace+1,end,-1);
7246 std::reverse(bgFace+1,endFace);
7254 * This method makes the assumption spacedimension == meshdimension == 2.
7255 * This method works only for linear cells.
7257 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYGON in pos#0)
7259 DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMesh() const
7261 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
7262 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : meshdimension, spacedimension must be equal to 2 !");
7263 MCAuto<MEDCouplingUMesh> skin(computeSkin());
7264 int oldNbOfNodes(skin->getNumberOfNodes());
7265 MCAuto<DataArrayInt> o2n(skin->zipCoordsTraducer());
7266 int nbOfNodesExpected(skin->getNumberOfNodes());
7267 MCAuto<DataArrayInt> n2o(o2n->invertArrayO2N2N2O(oldNbOfNodes));
7268 int nbCells(skin->getNumberOfCells());
7269 if(nbCells==nbOfNodesExpected)
7270 return buildUnionOf2DMeshLinear(skin,n2o);
7271 else if(2*nbCells==nbOfNodesExpected)
7272 return buildUnionOf2DMeshQuadratic(skin,n2o);
7274 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : the mesh 2D in input appears to be not in a single part of a 2D mesh !");
7278 * This method makes the assumption spacedimension == meshdimension == 3.
7279 * This method works only for linear cells.
7281 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYHED in pos#0)
7283 DataArrayInt *MEDCouplingUMesh::buildUnionOf3DMesh() const
7285 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
7286 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf3DMesh : meshdimension, spacedimension must be equal to 2 !");
7287 MCAuto<MEDCouplingUMesh> m=computeSkin();
7288 const int *conn=m->getNodalConnectivity()->begin();
7289 const int *connI=m->getNodalConnectivityIndex()->begin();
7290 int nbOfCells=m->getNumberOfCells();
7291 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(m->getNodalConnectivity()->getNumberOfTuples(),1);
7292 int *work=ret->getPointer(); *work++=INTERP_KERNEL::NORM_POLYHED;
7295 work=std::copy(conn+connI[0]+1,conn+connI[1],work);
7296 for(int i=1;i<nbOfCells;i++)
7299 work=std::copy(conn+connI[i]+1,conn+connI[i+1],work);
7305 * \brief Creates a graph of cell neighbors
7306 * \return MEDCouplingSkyLineArray * - an sky line array the user should delete.
7307 * In the sky line array, graph arcs are stored in terms of (index,value) notation.
7309 * - index: 0 3 5 6 6
7310 * - value: 1 2 3 2 3 3
7311 * means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7312 * Arcs are not doubled but reflexive (1,1) arcs are present for each cell
7314 MEDCouplingSkyLineArray* MEDCouplingUMesh::generateGraph() const
7316 checkConnectivityFullyDefined();
7318 int meshDim = this->getMeshDimension();
7319 MEDCoupling::DataArrayInt* indexr=MEDCoupling::DataArrayInt::New();
7320 MEDCoupling::DataArrayInt* revConn=MEDCoupling::DataArrayInt::New();
7321 this->getReverseNodalConnectivity(revConn,indexr);
7322 const int* indexr_ptr=indexr->begin();
7323 const int* revConn_ptr=revConn->begin();
7325 const MEDCoupling::DataArrayInt* index;
7326 const MEDCoupling::DataArrayInt* conn;
7327 conn=this->getNodalConnectivity(); // it includes a type as the 1st element!!!
7328 index=this->getNodalConnectivityIndex();
7329 int nbCells=this->getNumberOfCells();
7330 const int* index_ptr=index->begin();
7331 const int* conn_ptr=conn->begin();
7333 //creating graph arcs (cell to cell relations)
7334 //arcs are stored in terms of (index,value) notation
7337 // means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7338 // in present version arcs are not doubled but reflexive (1,1) arcs are present for each cell
7340 //warning here one node have less than or equal effective number of cell with it
7341 //but cell could have more than effective nodes
7342 //because other equals nodes in other domain (with other global inode)
7343 std::vector <int> cell2cell_index(nbCells+1,0);
7344 std::vector <int> cell2cell;
7345 cell2cell.reserve(3*nbCells);
7347 for (int icell=0; icell<nbCells;icell++)
7349 std::map<int,int > counter;
7350 for (int iconn=index_ptr[icell]+1; iconn<index_ptr[icell+1];iconn++)
7352 int inode=conn_ptr[iconn];
7353 for (int iconnr=indexr_ptr[inode]; iconnr<indexr_ptr[inode+1];iconnr++)
7355 int icell2=revConn_ptr[iconnr];
7356 std::map<int,int>::iterator iter=counter.find(icell2);
7357 if (iter!=counter.end()) (iter->second)++;
7358 else counter.insert(std::make_pair(icell2,1));
7361 for (std::map<int,int>::const_iterator iter=counter.begin();
7362 iter!=counter.end(); iter++)
7363 if (iter->second >= meshDim)
7365 cell2cell_index[icell+1]++;
7366 cell2cell.push_back(iter->first);
7371 cell2cell_index[0]=0;
7372 for (int icell=0; icell<nbCells;icell++)
7373 cell2cell_index[icell+1]=cell2cell_index[icell]+cell2cell_index[icell+1];
7375 //filling up index and value to create skylinearray structure
7376 MEDCouplingSkyLineArray * array(MEDCouplingSkyLineArray::New(cell2cell_index,cell2cell));
7381 void MEDCouplingUMesh::writeVTKLL(std::ostream& ofs, const std::string& cellData, const std::string& pointData, DataArrayByte *byteData) const
7383 int nbOfCells=getNumberOfCells();
7385 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::writeVTK : the unstructured mesh has no cells !");
7386 ofs << " <" << getVTKDataSetType() << ">\n";
7387 ofs << " <Piece NumberOfPoints=\"" << getNumberOfNodes() << "\" NumberOfCells=\"" << nbOfCells << "\">\n";
7388 ofs << " <PointData>\n" << pointData << std::endl;
7389 ofs << " </PointData>\n";
7390 ofs << " <CellData>\n" << cellData << std::endl;
7391 ofs << " </CellData>\n";
7392 ofs << " <Points>\n";
7393 if(getSpaceDimension()==3)
7394 _coords->writeVTK(ofs,8,"Points",byteData);
7397 MCAuto<DataArrayDouble> coo=_coords->changeNbOfComponents(3,0.);
7398 coo->writeVTK(ofs,8,"Points",byteData);
7400 ofs << " </Points>\n";
7401 ofs << " <Cells>\n";
7402 const int *cPtr=_nodal_connec->begin();
7403 const int *cIPtr=_nodal_connec_index->begin();
7404 MCAuto<DataArrayInt> faceoffsets=DataArrayInt::New(); faceoffsets->alloc(nbOfCells,1);
7405 MCAuto<DataArrayInt> types=DataArrayInt::New(); types->alloc(nbOfCells,1);
7406 MCAuto<DataArrayInt> offsets=DataArrayInt::New(); offsets->alloc(nbOfCells,1);
7407 MCAuto<DataArrayInt> connectivity=DataArrayInt::New(); connectivity->alloc(_nodal_connec->getNumberOfTuples()-nbOfCells,1);
7408 int *w1=faceoffsets->getPointer(),*w2=types->getPointer(),*w3=offsets->getPointer(),*w4=connectivity->getPointer();
7409 int szFaceOffsets=0,szConn=0;
7410 for(int i=0;i<nbOfCells;i++,w1++,w2++,w3++)
7413 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]!=INTERP_KERNEL::NORM_POLYHED)
7416 *w3=szConn+cIPtr[i+1]-cIPtr[i]-1; szConn+=cIPtr[i+1]-cIPtr[i]-1;
7417 w4=std::copy(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],w4);
7421 int deltaFaceOffset=cIPtr[i+1]-cIPtr[i]+1;
7422 *w1=szFaceOffsets+deltaFaceOffset; szFaceOffsets+=deltaFaceOffset;
7423 std::set<int> c(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1]); c.erase(-1);
7424 *w3=szConn+(int)c.size(); szConn+=(int)c.size();
7425 w4=std::copy(c.begin(),c.end(),w4);
7428 types->transformWithIndArr(MEDCOUPLING2VTKTYPETRADUCER,MEDCOUPLING2VTKTYPETRADUCER+INTERP_KERNEL::NORM_MAXTYPE+1);
7429 types->writeVTK(ofs,8,"UInt8","types",byteData);
7430 offsets->writeVTK(ofs,8,"Int32","offsets",byteData);
7431 if(szFaceOffsets!=0)
7432 {//presence of Polyhedra
7433 connectivity->reAlloc(szConn);
7434 faceoffsets->writeVTK(ofs,8,"Int32","faceoffsets",byteData);
7435 MCAuto<DataArrayInt> faces=DataArrayInt::New(); faces->alloc(szFaceOffsets,1);
7436 w1=faces->getPointer();
7437 for(int i=0;i<nbOfCells;i++)
7438 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]==INTERP_KERNEL::NORM_POLYHED)
7440 int nbFaces=std::count(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],-1)+1;
7442 const int *w6=cPtr+cIPtr[i]+1,*w5=0;
7443 for(int j=0;j<nbFaces;j++)
7445 w5=std::find(w6,cPtr+cIPtr[i+1],-1);
7446 *w1++=(int)std::distance(w6,w5);
7447 w1=std::copy(w6,w5,w1);
7451 faces->writeVTK(ofs,8,"Int32","faces",byteData);
7453 connectivity->writeVTK(ofs,8,"Int32","connectivity",byteData);
7454 ofs << " </Cells>\n";
7455 ofs << " </Piece>\n";
7456 ofs << " </" << getVTKDataSetType() << ">\n";
7459 void MEDCouplingUMesh::reprQuickOverview(std::ostream& stream) const
7461 stream << "MEDCouplingUMesh C++ instance at " << this << ". Name : \"" << getName() << "\".";
7463 { stream << " Not set !"; return ; }
7464 stream << " Mesh dimension : " << _mesh_dim << ".";
7468 { stream << " No coordinates set !"; return ; }
7469 if(!_coords->isAllocated())
7470 { stream << " Coordinates set but not allocated !"; return ; }
7471 stream << " Space dimension : " << _coords->getNumberOfComponents() << "." << std::endl;
7472 stream << "Number of nodes : " << _coords->getNumberOfTuples() << ".";
7473 if(!_nodal_connec_index)
7474 { stream << std::endl << "Nodal connectivity NOT set !"; return ; }
7475 if(!_nodal_connec_index->isAllocated())
7476 { stream << std::endl << "Nodal connectivity set but not allocated !"; return ; }
7477 int lgth=_nodal_connec_index->getNumberOfTuples();
7478 int cpt=_nodal_connec_index->getNumberOfComponents();
7479 if(cpt!=1 || lgth<1)
7481 stream << std::endl << "Number of cells : " << lgth-1 << ".";
7484 std::string MEDCouplingUMesh::getVTKDataSetType() const
7486 return std::string("UnstructuredGrid");
7489 std::string MEDCouplingUMesh::getVTKFileExtension() const
7491 return std::string("vtu");
7497 * Provides a renumbering of the cells of this (which has to be a piecewise connected 1D line), so that
7498 * the segments of the line are indexed in consecutive order (i.e. cells \a i and \a i+1 are neighbors).
7499 * This doesn't modify the mesh. This method only works using nodal connectivity consideration. Coordinates of nodes are ignored here.
7500 * The caller is to deal with the resulting DataArrayInt.
7501 * \throw If the coordinate array is not set.
7502 * \throw If the nodal connectivity of the cells is not defined.
7503 * \throw If m1 is not a mesh of dimension 2, or m1 is not a mesh of dimension 1
7504 * \throw If m2 is not a (piecewise) line (i.e. if a point has more than 2 adjacent segments)
7506 * \sa DataArrayInt::sortEachPairToMakeALinkedList
7508 DataArrayInt *MEDCouplingUMesh::orderConsecutiveCells1D() const
7510 checkFullyDefined();
7511 if(getMeshDimension()!=1)
7512 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D works on unstructured mesh with meshdim = 1 !");
7514 // Check that this is a line (and not a more complex 1D mesh) - each point is used at most by 2 segments:
7515 MCAuto<DataArrayInt> _d(DataArrayInt::New()),_dI(DataArrayInt::New());
7516 MCAuto<DataArrayInt> _rD(DataArrayInt::New()),_rDI(DataArrayInt::New());
7517 MCAuto<MEDCouplingUMesh> m_points(buildDescendingConnectivity(_d, _dI, _rD, _rDI));
7518 const int *d(_d->begin()), *dI(_dI->begin());
7519 const int *rD(_rD->begin()), *rDI(_rDI->begin());
7520 MCAuto<DataArrayInt> _dsi(_rDI->deltaShiftIndex());
7521 const int * dsi(_dsi->begin());
7522 MCAuto<DataArrayInt> dsii = _dsi->findIdsNotInRange(0,3);
7524 if (dsii->getNumberOfTuples())
7525 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D only work with a mesh being a (piecewise) connected line!");
7527 int nc(getNumberOfCells());
7528 MCAuto<DataArrayInt> result(DataArrayInt::New());
7529 result->alloc(nc,1);
7531 // set of edges not used so far
7532 std::set<int> edgeSet;
7533 for (int i=0; i<nc; edgeSet.insert(i), i++);
7537 // while we have points with only one neighbor segments
7540 std::list<int> linePiece;
7541 // fills a list of consecutive segment linked to startSeg. This can go forward or backward.
7542 for (int direction=0;direction<2;direction++) // direction=0 --> forward, direction=1 --> backward
7544 // Fill the list forward (resp. backward) from the start segment:
7545 int activeSeg = startSeg;
7546 int prevPointId = -20;
7548 while (!edgeSet.empty())
7550 if (!(direction == 1 && prevPointId==-20)) // prevent adding twice startSeg
7553 linePiece.push_back(activeSeg);
7555 linePiece.push_front(activeSeg);
7556 edgeSet.erase(activeSeg);
7559 int ptId1 = d[dI[activeSeg]], ptId2 = d[dI[activeSeg]+1];
7560 ptId = direction ? (ptId1 == prevPointId ? ptId2 : ptId1) : (ptId2 == prevPointId ? ptId1 : ptId2);
7561 if (dsi[ptId] == 1) // hitting the end of the line
7564 int seg1 = rD[rDI[ptId]], seg2 = rD[rDI[ptId]+1];
7565 activeSeg = (seg1 == activeSeg) ? seg2 : seg1;
7568 // Done, save final piece into DA:
7569 std::copy(linePiece.begin(), linePiece.end(), result->getPointer()+newIdx);
7570 newIdx += linePiece.size();
7572 // identify next valid start segment (one which is not consumed)
7573 if(!edgeSet.empty())
7574 startSeg = *(edgeSet.begin());
7576 while (!edgeSet.empty());
7577 return result.retn();
7581 * This method split some of edges of 2D cells in \a this. The edges to be split are specified in \a subNodesInSeg
7582 * and in \a subNodesInSegI using \ref numbering-indirect storage mode.
7583 * To do the work this method can optionally needs information about middle of subedges for quadratic cases if
7584 * a minimal creation of new nodes is wanted.
7585 * So this method try to reduce at most the number of new nodes. The only case that can lead this method to add
7586 * nodes if a SEG3 is split without information of middle.
7587 * \b WARNING : is returned value is different from 0 a call to MEDCouplingUMesh::mergeNodes is necessary to
7588 * avoid to have a non conform mesh.
7590 * \return int - the number of new nodes created (in most of cases 0).
7592 * \throw If \a this is not coherent.
7593 * \throw If \a this has not spaceDim equal to 2.
7594 * \throw If \a this has not meshDim equal to 2.
7595 * \throw If some subcells needed to be split are orphan.
7596 * \sa MEDCouplingUMesh::conformize2D
7598 int MEDCouplingUMesh::split2DCells(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI, const DataArrayInt *midOpt, const DataArrayInt *midOptI)
7600 if(!desc || !descI || !subNodesInSeg || !subNodesInSegI)
7601 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : the 4 first arrays must be not null !");
7602 desc->checkAllocated(); descI->checkAllocated(); subNodesInSeg->checkAllocated(); subNodesInSegI->checkAllocated();
7603 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
7604 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : This method only works for meshes with spaceDim=2 and meshDim=2 !");
7605 if(midOpt==0 && midOptI==0)
7607 split2DCellsLinear(desc,descI,subNodesInSeg,subNodesInSegI);
7610 else if(midOpt!=0 && midOptI!=0)
7611 return split2DCellsQuadratic(desc,descI,subNodesInSeg,subNodesInSegI,midOpt,midOptI);
7613 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : middle parameters must be set to null for all or not null for all.");
7617 * 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
7618 * 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
7619 * the geometric cell type set to INTERP_KERNEL::NORM_POLYGON.
7620 * 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
7621 * 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.
7623 * \return false if the input connectivity represents already the convex hull, true if the input cell needs to be reordered.
7625 bool MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis(const double *coords, const int *nodalConnBg, const int *nodalConnEnd, DataArrayInt *nodalConnecOut)
7627 std::size_t sz=std::distance(nodalConnBg,nodalConnEnd);
7630 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)*nodalConnBg);
7631 if(cm.getDimension()==2)
7633 const int *node=nodalConnBg+1;
7634 int startNode=*node++;
7635 double refX=coords[2*startNode];
7636 for(;node!=nodalConnEnd;node++)
7638 if(coords[2*(*node)]<refX)
7641 refX=coords[2*startNode];
7644 std::vector<int> tmpOut; tmpOut.reserve(sz); tmpOut.push_back(startNode);
7648 double angle0=-M_PI/2;
7653 double angleNext=0.;
7654 while(nextNode!=startNode)
7658 for(node=nodalConnBg+1;node!=nodalConnEnd;node++)
7660 if(*node!=tmpOut.back() && *node!=prevNode)
7662 tmp2[0]=coords[2*(*node)]-coords[2*tmpOut.back()]; tmp2[1]=coords[2*(*node)+1]-coords[2*tmpOut.back()+1];
7663 double angleM=INTERP_KERNEL::EdgeArcCircle::GetAbsoluteAngle(tmp2,tmp1);
7668 res=angle0-angleM+2.*M_PI;
7677 if(nextNode!=startNode)
7679 angle0=angleNext-M_PI;
7682 prevNode=tmpOut.back();
7683 tmpOut.push_back(nextNode);
7686 std::vector<int> tmp3(2*(sz-1));
7687 std::vector<int>::iterator it=std::copy(nodalConnBg+1,nodalConnEnd,tmp3.begin());
7688 std::copy(nodalConnBg+1,nodalConnEnd,it);
7689 if(std::search(tmp3.begin(),tmp3.end(),tmpOut.begin(),tmpOut.end())!=tmp3.end())
7691 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
7694 if(std::search(tmp3.rbegin(),tmp3.rend(),tmpOut.begin(),tmpOut.end())!=tmp3.rend())
7696 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
7701 nodalConnecOut->pushBackSilent((int)INTERP_KERNEL::NORM_POLYGON);
7702 nodalConnecOut->insertAtTheEnd(tmpOut.begin(),tmpOut.end());
7707 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
7710 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
7714 * This method works on an input pair (\b arr, \b arrIndx) where \b arr indexes is in \b arrIndx.
7715 * 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.
7717 * \param [in] idsToRemoveBg begin of set of ids to remove in \b arr (included)
7718 * \param [in] idsToRemoveEnd end of set of ids to remove in \b arr (excluded)
7719 * \param [in,out] arr array in which the remove operation will be done.
7720 * \param [in,out] arrIndx array in the remove operation will modify
7721 * \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])
7722 * \return true if \b arr and \b arrIndx have been modified, false if not.
7724 bool MEDCouplingUMesh::RemoveIdsFromIndexedArrays(const int *idsToRemoveBg, const int *idsToRemoveEnd, DataArrayInt *arr, DataArrayInt *arrIndx, int offsetForRemoval)
7726 if(!arrIndx || !arr)
7727 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::RemoveIdsFromIndexedArrays : some input arrays are empty !");
7728 if(offsetForRemoval<0)
7729 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::RemoveIdsFromIndexedArrays : offsetForRemoval should be >=0 !");
7730 std::set<int> s(idsToRemoveBg,idsToRemoveEnd);
7731 int nbOfGrps=arrIndx->getNumberOfTuples()-1;
7732 int *arrIPtr=arrIndx->getPointer();
7735 const int *arrPtr=arr->begin();
7736 std::vector<int> arrOut;//no utility to switch to DataArrayInt because copy always needed
7737 for(int i=0;i<nbOfGrps;i++,arrIPtr++)
7739 if(*arrIPtr-previousArrI>offsetForRemoval)
7741 for(const int *work=arrPtr+previousArrI+offsetForRemoval;work!=arrPtr+*arrIPtr;work++)
7743 if(s.find(*work)==s.end())
7744 arrOut.push_back(*work);
7747 previousArrI=*arrIPtr;
7748 *arrIPtr=(int)arrOut.size();
7750 if(arr->getNumberOfTuples()==arrOut.size())
7752 arr->alloc((int)arrOut.size(),1);
7753 std::copy(arrOut.begin(),arrOut.end(),arr->getPointer());
7758 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn
7759 * (\ref numbering-indirect).
7760 * This method returns the result of the extraction ( specified by a set of ids in [\b idsOfSelectBg , \b idsOfSelectEnd ) ).
7761 * The selection of extraction is done standardly in new2old format.
7762 * This method returns indexed arrays (\ref numbering-indirect) using 2 arrays (arrOut,arrIndexOut).
7764 * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
7765 * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
7766 * \param [in] arrIn arr origin array from which the extraction will be done.
7767 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7768 * \param [out] arrOut the resulting array
7769 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
7770 * \sa MEDCouplingUMesh::ExtractFromIndexedArraysSlice
7772 void MEDCouplingUMesh::ExtractFromIndexedArrays(const int *idsOfSelectBg, const int *idsOfSelectEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
7773 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
7775 if(!arrIn || !arrIndxIn)
7776 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : input pointer is NULL !");
7777 arrIn->checkAllocated(); arrIndxIn->checkAllocated();
7778 if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1)
7779 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : input arrays must have exactly one component !");
7780 std::size_t sz=std::distance(idsOfSelectBg,idsOfSelectEnd);
7781 const int *arrInPtr=arrIn->begin();
7782 const int *arrIndxPtr=arrIndxIn->begin();
7783 int nbOfGrps=arrIndxIn->getNumberOfTuples()-1;
7785 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : The format of \"arrIndxIn\" is invalid ! Its nb of tuples should be >=1 !");
7786 int maxSizeOfArr=arrIn->getNumberOfTuples();
7787 MCAuto<DataArrayInt> arro=DataArrayInt::New();
7788 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
7789 arrIo->alloc((int)(sz+1),1);
7790 const int *idsIt=idsOfSelectBg;
7791 int *work=arrIo->getPointer();
7794 for(std::size_t i=0;i<sz;i++,work++,idsIt++)
7796 if(*idsIt>=0 && *idsIt<nbOfGrps)
7797 lgth+=arrIndxPtr[*idsIt+1]-arrIndxPtr[*idsIt];
7800 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " ! Must be in [0," << nbOfGrps << ") !";
7801 throw INTERP_KERNEL::Exception(oss.str());
7807 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " and at this pos arrIndxIn[" << *idsIt;
7808 oss << "+1]-arrIndxIn[" << *idsIt << "] < 0 ! The input index array is bugged !";
7809 throw INTERP_KERNEL::Exception(oss.str());
7812 arro->alloc(lgth,1);
7813 work=arro->getPointer();
7814 idsIt=idsOfSelectBg;
7815 for(std::size_t i=0;i<sz;i++,idsIt++)
7817 if(arrIndxPtr[*idsIt]>=0 && arrIndxPtr[*idsIt+1]<=maxSizeOfArr)
7818 work=std::copy(arrInPtr+arrIndxPtr[*idsIt],arrInPtr+arrIndxPtr[*idsIt+1],work);
7821 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " arrIndx[" << *idsIt << "] must be >= 0 and arrIndx[";
7822 oss << *idsIt << "+1] <= " << maxSizeOfArr << " (the size of arrIn)!";
7823 throw INTERP_KERNEL::Exception(oss.str());
7827 arrIndexOut=arrIo.retn();
7831 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn
7832 * (\ref numbering-indirect).
7833 * 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 ).
7834 * The selection of extraction is done standardly in new2old format.
7835 * This method returns indexed arrays (\ref numbering-indirect) using 2 arrays (arrOut,arrIndexOut).
7837 * \param [in] idsOfSelectStart begin of set of ids of the input extraction (included)
7838 * \param [in] idsOfSelectStop end of set of ids of the input extraction (excluded)
7839 * \param [in] idsOfSelectStep
7840 * \param [in] arrIn arr origin array from which the extraction will be done.
7841 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7842 * \param [out] arrOut the resulting array
7843 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
7844 * \sa MEDCouplingUMesh::ExtractFromIndexedArrays
7846 void MEDCouplingUMesh::ExtractFromIndexedArraysSlice(int idsOfSelectStart, int idsOfSelectStop, int idsOfSelectStep, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
7847 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
7849 if(!arrIn || !arrIndxIn)
7850 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : input pointer is NULL !");
7851 arrIn->checkAllocated(); arrIndxIn->checkAllocated();
7852 if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1)
7853 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : input arrays must have exactly one component !");
7854 int sz=DataArrayInt::GetNumberOfItemGivenBESRelative(idsOfSelectStart,idsOfSelectStop,idsOfSelectStep,"MEDCouplingUMesh::ExtractFromIndexedArraysSlice : Input slice ");
7855 const int *arrInPtr=arrIn->begin();
7856 const int *arrIndxPtr=arrIndxIn->begin();
7857 int nbOfGrps=arrIndxIn->getNumberOfTuples()-1;
7859 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : The format of \"arrIndxIn\" is invalid ! Its nb of tuples should be >=1 !");
7860 int maxSizeOfArr=arrIn->getNumberOfTuples();
7861 MCAuto<DataArrayInt> arro=DataArrayInt::New();
7862 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
7863 arrIo->alloc((int)(sz+1),1);
7864 int idsIt=idsOfSelectStart;
7865 int *work=arrIo->getPointer();
7868 for(int i=0;i<sz;i++,work++,idsIt+=idsOfSelectStep)
7870 if(idsIt>=0 && idsIt<nbOfGrps)
7871 lgth+=arrIndxPtr[idsIt+1]-arrIndxPtr[idsIt];
7874 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " ! Must be in [0," << nbOfGrps << ") !";
7875 throw INTERP_KERNEL::Exception(oss.str());
7881 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " and at this pos arrIndxIn[" << idsIt;
7882 oss << "+1]-arrIndxIn[" << idsIt << "] < 0 ! The input index array is bugged !";
7883 throw INTERP_KERNEL::Exception(oss.str());
7886 arro->alloc(lgth,1);
7887 work=arro->getPointer();
7888 idsIt=idsOfSelectStart;
7889 for(int i=0;i<sz;i++,idsIt+=idsOfSelectStep)
7891 if(arrIndxPtr[idsIt]>=0 && arrIndxPtr[idsIt+1]<=maxSizeOfArr)
7892 work=std::copy(arrInPtr+arrIndxPtr[idsIt],arrInPtr+arrIndxPtr[idsIt+1],work);
7895 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " arrIndx[" << idsIt << "] must be >= 0 and arrIndx[";
7896 oss << idsIt << "+1] <= " << maxSizeOfArr << " (the size of arrIn)!";
7897 throw INTERP_KERNEL::Exception(oss.str());
7901 arrIndexOut=arrIo.retn();
7905 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
7906 * 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
7907 * cellIds \b in [ \b idsOfSelectBg , \b idsOfSelectEnd ) a copy coming from the corresponding values in input pair (\b srcArr, \b srcArrIndex).
7908 * This method is an generalization of MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx that performs the same thing but by without building explicitely a result output arrays.
7910 * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
7911 * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
7912 * \param [in] arrIn arr origin array from which the extraction will be done.
7913 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7914 * \param [in] srcArr input array that will be used as source of copy for ids in [ \b idsOfSelectBg, \b idsOfSelectEnd )
7915 * \param [in] srcArrIndex index array of \b srcArr
7916 * \param [out] arrOut the resulting array
7917 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
7919 * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx
7921 void MEDCouplingUMesh::SetPartOfIndexedArrays(const int *idsOfSelectBg, const int *idsOfSelectEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
7922 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex,
7923 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
7925 if(arrIn==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
7926 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArrays : presence of null pointer in input parameter !");
7927 MCAuto<DataArrayInt> arro=DataArrayInt::New();
7928 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
7929 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
7930 std::vector<bool> v(nbOfTuples,true);
7932 const int *arrIndxInPtr=arrIndxIn->begin();
7933 const int *srcArrIndexPtr=srcArrIndex->begin();
7934 for(const int *it=idsOfSelectBg;it!=idsOfSelectEnd;it++,srcArrIndexPtr++)
7936 if(*it>=0 && *it<nbOfTuples)
7939 offset+=(srcArrIndexPtr[1]-srcArrIndexPtr[0])-(arrIndxInPtr[*it+1]-arrIndxInPtr[*it]);
7943 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArrays : On pos #" << std::distance(idsOfSelectBg,it) << " value is " << *it << " not in [0," << nbOfTuples << ") !";
7944 throw INTERP_KERNEL::Exception(oss.str());
7947 srcArrIndexPtr=srcArrIndex->begin();
7948 arrIo->alloc(nbOfTuples+1,1);
7949 arro->alloc(arrIn->getNumberOfTuples()+offset,1);
7950 const int *arrInPtr=arrIn->begin();
7951 const int *srcArrPtr=srcArr->begin();
7952 int *arrIoPtr=arrIo->getPointer(); *arrIoPtr++=0;
7953 int *arroPtr=arro->getPointer();
7954 for(int ii=0;ii<nbOfTuples;ii++,arrIoPtr++)
7958 arroPtr=std::copy(arrInPtr+arrIndxInPtr[ii],arrInPtr+arrIndxInPtr[ii+1],arroPtr);
7959 *arrIoPtr=arrIoPtr[-1]+(arrIndxInPtr[ii+1]-arrIndxInPtr[ii]);
7963 std::size_t pos=std::distance(idsOfSelectBg,std::find(idsOfSelectBg,idsOfSelectEnd,ii));
7964 arroPtr=std::copy(srcArrPtr+srcArrIndexPtr[pos],srcArrPtr+srcArrIndexPtr[pos+1],arroPtr);
7965 *arrIoPtr=arrIoPtr[-1]+(srcArrIndexPtr[pos+1]-srcArrIndexPtr[pos]);
7969 arrIndexOut=arrIo.retn();
7973 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
7974 * This method is an specialization of MEDCouplingUMesh::SetPartOfIndexedArrays in the case of assignement do not modify the index in \b arrIndxIn.
7976 * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
7977 * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
7978 * \param [in,out] arrInOut arr origin array from which the extraction will be done.
7979 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7980 * \param [in] srcArr input array that will be used as source of copy for ids in [ \b idsOfSelectBg , \b idsOfSelectEnd )
7981 * \param [in] srcArrIndex index array of \b srcArr
7983 * \sa MEDCouplingUMesh::SetPartOfIndexedArrays
7985 void MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx(const int *idsOfSelectBg, const int *idsOfSelectEnd, DataArrayInt *arrInOut, const DataArrayInt *arrIndxIn,
7986 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex)
7988 if(arrInOut==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
7989 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx : presence of null pointer in input parameter !");
7990 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
7991 const int *arrIndxInPtr=arrIndxIn->begin();
7992 const int *srcArrIndexPtr=srcArrIndex->begin();
7993 int *arrInOutPtr=arrInOut->getPointer();
7994 const int *srcArrPtr=srcArr->begin();
7995 for(const int *it=idsOfSelectBg;it!=idsOfSelectEnd;it++,srcArrIndexPtr++)
7997 if(*it>=0 && *it<nbOfTuples)
7999 if(srcArrIndexPtr[1]-srcArrIndexPtr[0]==arrIndxInPtr[*it+1]-arrIndxInPtr[*it])
8000 std::copy(srcArrPtr+srcArrIndexPtr[0],srcArrPtr+srcArrIndexPtr[1],arrInOutPtr+arrIndxInPtr[*it]);
8003 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] !";
8004 throw INTERP_KERNEL::Exception(oss.str());
8009 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx : On pos #" << std::distance(idsOfSelectBg,it) << " value is " << *it << " not in [0," << nbOfTuples << ") !";
8010 throw INTERP_KERNEL::Exception(oss.str());
8016 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
8017 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
8018 * 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]].
8019 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
8020 * A negative value in \b arrIn means that it is ignored.
8021 * 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.
8023 * \param [in] arrIn arr origin array from which the extraction will be done.
8024 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
8025 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
8026 * \sa MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed, MEDCouplingUMesh::partitionBySpreadZone
8028 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGradually(const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn)
8030 int seed=0,nbOfDepthPeelingPerformed=0;
8031 return ComputeSpreadZoneGraduallyFromSeed(&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfDepthPeelingPerformed);
8035 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
8036 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
8037 * 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]].
8038 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
8039 * A negative value in \b arrIn means that it is ignored.
8040 * 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.
8041 * \param [in] seedBg the begin pointer (included) of an array containing the seed of the search zone
8042 * \param [in] seedEnd the end pointer (not included) of an array containing the seed of the search zone
8043 * \param [in] arrIn arr origin array from which the extraction will be done.
8044 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
8045 * \param [in] nbOfDepthPeeling the max number of peels requested in search. By default -1, that is to say, no limit.
8046 * \param [out] nbOfDepthPeelingPerformed the number of peels effectively performed. May be different from \a nbOfDepthPeeling
8047 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
8048 * \sa MEDCouplingUMesh::partitionBySpreadZone
8050 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(const int *seedBg, const int *seedEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn, int nbOfDepthPeeling, int& nbOfDepthPeelingPerformed)
8052 nbOfDepthPeelingPerformed=0;
8054 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed : arrIndxIn input pointer is NULL !");
8055 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
8058 DataArrayInt *ret=DataArrayInt::New(); ret->alloc(0,1);
8062 std::vector<bool> fetched(nbOfTuples,false);
8063 return ComputeSpreadZoneGraduallyFromSeedAlg(fetched,seedBg,seedEnd,arrIn,arrIndxIn,nbOfDepthPeeling,nbOfDepthPeelingPerformed);
8068 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
8069 * 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
8070 * cellIds \b in [\b idsOfSelectBg, \b idsOfSelectEnd) a copy coming from the corresponding values in input pair (\b srcArr, \b srcArrIndex).
8071 * This method is an generalization of MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx that performs the same thing but by without building explicitely a result output arrays.
8073 * \param [in] start begin of set of ids of the input extraction (included)
8074 * \param [in] end end of set of ids of the input extraction (excluded)
8075 * \param [in] step step of the set of ids in range mode.
8076 * \param [in] arrIn arr origin array from which the extraction will be done.
8077 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
8078 * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd)
8079 * \param [in] srcArrIndex index array of \b srcArr
8080 * \param [out] arrOut the resulting array
8081 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
8083 * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx MEDCouplingUMesh::SetPartOfIndexedArrays
8085 void MEDCouplingUMesh::SetPartOfIndexedArraysSlice(int start, int end, int step, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
8086 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex,
8087 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
8089 if(arrIn==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
8090 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSlice : presence of null pointer in input parameter !");
8091 MCAuto<DataArrayInt> arro=DataArrayInt::New();
8092 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
8093 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
8095 const int *arrIndxInPtr=arrIndxIn->begin();
8096 const int *srcArrIndexPtr=srcArrIndex->begin();
8097 int nbOfElemsToSet=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::SetPartOfIndexedArraysSlice : ");
8099 for(int i=0;i<nbOfElemsToSet;i++,srcArrIndexPtr++,it+=step)
8101 if(it>=0 && it<nbOfTuples)
8102 offset+=(srcArrIndexPtr[1]-srcArrIndexPtr[0])-(arrIndxInPtr[it+1]-arrIndxInPtr[it]);
8105 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSlice : On pos #" << i << " value is " << it << " not in [0," << nbOfTuples << ") !";
8106 throw INTERP_KERNEL::Exception(oss.str());
8109 srcArrIndexPtr=srcArrIndex->begin();
8110 arrIo->alloc(nbOfTuples+1,1);
8111 arro->alloc(arrIn->getNumberOfTuples()+offset,1);
8112 const int *arrInPtr=arrIn->begin();
8113 const int *srcArrPtr=srcArr->begin();
8114 int *arrIoPtr=arrIo->getPointer(); *arrIoPtr++=0;
8115 int *arroPtr=arro->getPointer();
8116 for(int ii=0;ii<nbOfTuples;ii++,arrIoPtr++)
8118 int pos=DataArray::GetPosOfItemGivenBESRelativeNoThrow(ii,start,end,step);
8121 arroPtr=std::copy(arrInPtr+arrIndxInPtr[ii],arrInPtr+arrIndxInPtr[ii+1],arroPtr);
8122 *arrIoPtr=arrIoPtr[-1]+(arrIndxInPtr[ii+1]-arrIndxInPtr[ii]);
8126 arroPtr=std::copy(srcArrPtr+srcArrIndexPtr[pos],srcArrPtr+srcArrIndexPtr[pos+1],arroPtr);
8127 *arrIoPtr=arrIoPtr[-1]+(srcArrIndexPtr[pos+1]-srcArrIndexPtr[pos]);
8131 arrIndexOut=arrIo.retn();
8135 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
8136 * This method is an specialization of MEDCouplingUMesh::SetPartOfIndexedArrays in the case of assignement do not modify the index in \b arrIndxIn.
8138 * \param [in] start begin of set of ids of the input extraction (included)
8139 * \param [in] end end of set of ids of the input extraction (excluded)
8140 * \param [in] step step of the set of ids in range mode.
8141 * \param [in,out] arrInOut arr origin array from which the extraction will be done.
8142 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
8143 * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd)
8144 * \param [in] srcArrIndex index array of \b srcArr
8146 * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSlice MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx
8148 void MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice(int start, int end, int step, DataArrayInt *arrInOut, const DataArrayInt *arrIndxIn,
8149 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex)
8151 if(arrInOut==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
8152 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : presence of null pointer in input parameter !");
8153 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
8154 const int *arrIndxInPtr=arrIndxIn->begin();
8155 const int *srcArrIndexPtr=srcArrIndex->begin();
8156 int *arrInOutPtr=arrInOut->getPointer();
8157 const int *srcArrPtr=srcArr->begin();
8158 int nbOfElemsToSet=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : ");
8160 for(int i=0;i<nbOfElemsToSet;i++,srcArrIndexPtr++,it+=step)
8162 if(it>=0 && it<nbOfTuples)
8164 if(srcArrIndexPtr[1]-srcArrIndexPtr[0]==arrIndxInPtr[it+1]-arrIndxInPtr[it])
8165 std::copy(srcArrPtr+srcArrIndexPtr[0],srcArrPtr+srcArrIndexPtr[1],arrInOutPtr+arrIndxInPtr[it]);
8168 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : On pos #" << i << " id (idsOfSelectBg[" << i << "]) is " << it << " arrIndxIn[id+1]-arrIndxIn[id]!=srcArrIndex[pos+1]-srcArrIndex[pos] !";
8169 throw INTERP_KERNEL::Exception(oss.str());
8174 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : On pos #" << i << " value is " << it << " not in [0," << nbOfTuples << ") !";
8175 throw INTERP_KERNEL::Exception(oss.str());
8181 * \b this is expected to be a mesh fully defined whose spaceDim==meshDim.
8182 * It returns a new allocated mesh having the same mesh dimension and lying on same coordinates.
8183 * The returned mesh contains as poly cells as number of contiguous zone (regarding connectivity).
8184 * A spread contiguous zone is built using poly cells (polyhedra in 3D, polygons in 2D and polyline in 1D).
8185 * The sum of measure field of returned mesh is equal to the sum of measure field of this.
8187 * \return a newly allocated mesh lying on the same coords than \b this with same meshdimension than \b this.
8189 MEDCouplingUMesh *MEDCouplingUMesh::buildSpreadZonesWithPoly() const
8191 checkFullyDefined();
8192 int mdim=getMeshDimension();
8193 int spaceDim=getSpaceDimension();
8195 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension and spacedimension do not match !");
8196 std::vector<DataArrayInt *> partition=partitionBySpreadZone();
8197 std::vector< MCAuto<DataArrayInt> > partitionAuto; partitionAuto.reserve(partition.size());
8198 std::copy(partition.begin(),partition.end(),std::back_insert_iterator<std::vector< MCAuto<DataArrayInt> > >(partitionAuto));
8199 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
8200 ret->setCoords(getCoords());
8201 ret->allocateCells((int)partition.size());
8203 for(std::vector<DataArrayInt *>::const_iterator it=partition.begin();it!=partition.end();it++)
8205 MCAuto<MEDCouplingUMesh> tmp=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf((*it)->begin(),(*it)->end(),true));
8206 MCAuto<DataArrayInt> cell;
8210 cell=tmp->buildUnionOf2DMesh();
8213 cell=tmp->buildUnionOf3DMesh();
8216 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension supported are [2,3] ! Not implemented yet for others !");
8219 ret->insertNextCell((INTERP_KERNEL::NormalizedCellType)cell->getIJSafe(0,0),cell->getNumberOfTuples()-1,cell->begin()+1);
8222 ret->finishInsertingCells();
8227 * This method partitions \b this into contiguous zone.
8228 * This method only needs a well defined connectivity. Coordinates are not considered here.
8229 * This method returns a vector of \b newly allocated arrays that the caller has to deal with.
8231 std::vector<DataArrayInt *> MEDCouplingUMesh::partitionBySpreadZone() const
8233 DataArrayInt *neigh=0,*neighI=0;
8234 computeNeighborsOfCells(neigh,neighI);
8235 MCAuto<DataArrayInt> neighAuto(neigh),neighIAuto(neighI);
8236 return PartitionBySpreadZone(neighAuto,neighIAuto);
8239 std::vector<DataArrayInt *> MEDCouplingUMesh::PartitionBySpreadZone(const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn)
8241 if(!arrIn || !arrIndxIn)
8242 throw INTERP_KERNEL::Exception("PartitionBySpreadZone : null input pointers !");
8243 arrIn->checkAllocated(); arrIndxIn->checkAllocated();
8244 int nbOfTuples(arrIndxIn->getNumberOfTuples());
8245 if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1 || nbOfTuples<1)
8246 throw INTERP_KERNEL::Exception("PartitionBySpreadZone : invalid arrays in input !");
8247 int nbOfCellsCur(nbOfTuples-1);
8248 std::vector<DataArrayInt *> ret;
8251 std::vector<bool> fetchedCells(nbOfCellsCur,false);
8252 std::vector< MCAuto<DataArrayInt> > ret2;
8254 while(seed<nbOfCellsCur)
8256 int nbOfPeelPerformed=0;
8257 ret2.push_back(ComputeSpreadZoneGraduallyFromSeedAlg(fetchedCells,&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfPeelPerformed));
8258 seed=(int)std::distance(fetchedCells.begin(),std::find(fetchedCells.begin()+seed,fetchedCells.end(),false));
8260 for(std::vector< MCAuto<DataArrayInt> >::iterator it=ret2.begin();it!=ret2.end();it++)
8261 ret.push_back((*it).retn());
8266 * This method returns given a distribution of cell type (returned for example by MEDCouplingUMesh::getDistributionOfTypes method and customized after) a
8267 * newly allocated DataArrayInt instance with 2 components ready to be interpreted as input of DataArrayInt::findRangeIdForEachTuple method.
8269 * \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.
8270 * \return a newly allocated DataArrayInt to be managed by the caller.
8271 * \throw In case of \a code has not the right format (typically of size 3*n)
8273 DataArrayInt *MEDCouplingUMesh::ComputeRangesFromTypeDistribution(const std::vector<int>& code)
8275 MCAuto<DataArrayInt> ret=DataArrayInt::New();
8276 std::size_t nb=code.size()/3;
8277 if(code.size()%3!=0)
8278 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeRangesFromTypeDistribution : invalid input code !");
8279 ret->alloc((int)nb,2);
8280 int *retPtr=ret->getPointer();
8281 for(std::size_t i=0;i<nb;i++,retPtr+=2)
8283 retPtr[0]=code[3*i+2];
8284 retPtr[1]=code[3*i+2]+code[3*i+1];
8290 * This method expects that \a this a 3D mesh (spaceDim=3 and meshDim=3) with all coordinates and connectivities set.
8291 * All cells in \a this are expected to be linear 3D cells.
8292 * This method will split **all** 3D cells in \a this into INTERP_KERNEL::NORM_TETRA4 cells and put them in the returned mesh.
8293 * It leads to an increase to number of cells.
8294 * This method contrary to MEDCouplingUMesh::simplexize can append coordinates in \a this to perform its work.
8295 * The \a nbOfAdditionalPoints returned value informs about it. If > 0, the coordinates array in returned mesh will have \a nbOfAdditionalPoints
8296 * more tuples (nodes) than in \a this. Anyway, all the nodes in \a this (with the same order) will be in the returned mesh.
8298 * \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.
8299 * For all other cells, the splitting policy will be ignored. See INTERP_KERNEL::SplittingPolicy for the images.
8300 * \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.
8301 * \param [out] n2oCells - A new instance of DataArrayInt holding, for each new cell,
8302 * an id of old cell producing it. The caller is to delete this array using
8303 * decrRef() as it is no more needed.
8304 * \return MEDCoupling1SGTUMesh * - the mesh containing only INTERP_KERNEL::NORM_TETRA4 cells.
8306 * \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
8307 * the policy PLANAR_FACE_6 should be used on a mesh sorted with MEDCoupling1SGTUMesh::sortHexa8EachOther.
8309 * \throw If \a this is not a 3D mesh (spaceDim==3 and meshDim==3).
8310 * \throw If \a this is not fully constituted with linear 3D cells.
8311 * \sa MEDCouplingUMesh::simplexize, MEDCoupling1SGTUMesh::sortHexa8EachOther
8313 MEDCoupling1SGTUMesh *MEDCouplingUMesh::tetrahedrize(int policy, DataArrayInt *& n2oCells, int& nbOfAdditionalPoints) const
8315 INTERP_KERNEL::SplittingPolicy pol((INTERP_KERNEL::SplittingPolicy)policy);
8316 checkConnectivityFullyDefined();
8317 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
8318 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tetrahedrize : only available for mesh with meshdim == 3 and spacedim == 3 !");
8319 int nbOfCells(getNumberOfCells()),nbNodes(getNumberOfNodes());
8320 MCAuto<MEDCoupling1SGTUMesh> ret0(MEDCoupling1SGTUMesh::New(getName(),INTERP_KERNEL::NORM_TETRA4));
8321 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(nbOfCells,1);
8322 int *retPt(ret->getPointer());
8323 MCAuto<DataArrayInt> newConn(DataArrayInt::New()); newConn->alloc(0,1);
8324 MCAuto<DataArrayDouble> addPts(DataArrayDouble::New()); addPts->alloc(0,1);
8325 const int *oldc(_nodal_connec->begin());
8326 const int *oldci(_nodal_connec_index->begin());
8327 const double *coords(_coords->begin());
8328 for(int i=0;i<nbOfCells;i++,oldci++,retPt++)
8330 std::vector<int> a; std::vector<double> b;
8331 INTERP_KERNEL::SplitIntoTetras(pol,(INTERP_KERNEL::NormalizedCellType)oldc[oldci[0]],oldc+oldci[0]+1,oldc+oldci[1],coords,a,b);
8332 std::size_t nbOfTet(a.size()/4); *retPt=(int)nbOfTet;
8333 const int *aa(&a[0]);
8336 for(std::vector<int>::iterator it=a.begin();it!=a.end();it++)
8338 *it=(-(*(it))-1+nbNodes);
8339 addPts->insertAtTheEnd(b.begin(),b.end());
8340 nbNodes+=(int)b.size()/3;
8342 for(std::size_t j=0;j<nbOfTet;j++,aa+=4)
8343 newConn->insertAtTheEnd(aa,aa+4);
8345 if(!addPts->empty())
8347 addPts->rearrange(3);
8348 nbOfAdditionalPoints=addPts->getNumberOfTuples();
8349 addPts=DataArrayDouble::Aggregate(getCoords(),addPts);
8350 ret0->setCoords(addPts);
8354 nbOfAdditionalPoints=0;
8355 ret0->setCoords(getCoords());
8357 ret0->setNodalConnectivity(newConn);
8359 ret->computeOffsetsFull();
8360 n2oCells=ret->buildExplicitArrOfSliceOnScaledArr(0,nbOfCells,1);
8364 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),
8365 _own_cell(true),_cell_id(-1),_nb_cell(0)
8370 _nb_cell=mesh->getNumberOfCells();
8374 MEDCouplingUMeshCellIterator::~MEDCouplingUMeshCellIterator()
8382 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh, MEDCouplingUMeshCell *itc, int bg, int end):_mesh(mesh),_cell(itc),
8383 _own_cell(false),_cell_id(bg-1),
8390 MEDCouplingUMeshCell *MEDCouplingUMeshCellIterator::nextt()
8393 if(_cell_id<_nb_cell)
8402 MEDCouplingUMeshCellByTypeEntry::MEDCouplingUMeshCellByTypeEntry(MEDCouplingUMesh *mesh):_mesh(mesh)
8408 MEDCouplingUMeshCellByTypeIterator *MEDCouplingUMeshCellByTypeEntry::iterator()
8410 return new MEDCouplingUMeshCellByTypeIterator(_mesh);
8413 MEDCouplingUMeshCellByTypeEntry::~MEDCouplingUMeshCellByTypeEntry()
8419 MEDCouplingUMeshCellEntry::MEDCouplingUMeshCellEntry(MEDCouplingUMesh *mesh, INTERP_KERNEL::NormalizedCellType type, MEDCouplingUMeshCell *itc, int bg, int end):_mesh(mesh),_type(type),
8427 MEDCouplingUMeshCellEntry::~MEDCouplingUMeshCellEntry()
8433 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCellEntry::getType() const
8438 int MEDCouplingUMeshCellEntry::getNumberOfElems() const
8443 MEDCouplingUMeshCellIterator *MEDCouplingUMeshCellEntry::iterator()
8445 return new MEDCouplingUMeshCellIterator(_mesh,_itc,_bg,_end);
8448 MEDCouplingUMeshCellByTypeIterator::MEDCouplingUMeshCellByTypeIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),_cell_id(0),_nb_cell(0)
8453 _nb_cell=mesh->getNumberOfCells();
8457 MEDCouplingUMeshCellByTypeIterator::~MEDCouplingUMeshCellByTypeIterator()
8464 MEDCouplingUMeshCellEntry *MEDCouplingUMeshCellByTypeIterator::nextt()
8466 const int *c=_mesh->getNodalConnectivity()->begin();
8467 const int *ci=_mesh->getNodalConnectivityIndex()->begin();
8468 if(_cell_id<_nb_cell)
8470 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[_cell_id]];
8471 int nbOfElems=(int)std::distance(ci+_cell_id,std::find_if(ci+_cell_id,ci+_nb_cell,MEDCouplingImpl::ConnReader(c,type)));
8472 int startId=_cell_id;
8473 _cell_id+=nbOfElems;
8474 return new MEDCouplingUMeshCellEntry(_mesh,type,_cell,startId,_cell_id);
8480 MEDCouplingUMeshCell::MEDCouplingUMeshCell(MEDCouplingUMesh *mesh):_conn(0),_conn_indx(0),_conn_lgth(NOTICABLE_FIRST_VAL)
8484 _conn=mesh->getNodalConnectivity()->getPointer();
8485 _conn_indx=mesh->getNodalConnectivityIndex()->getPointer();
8489 void MEDCouplingUMeshCell::next()
8491 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8496 _conn_lgth=_conn_indx[1]-_conn_indx[0];
8499 std::string MEDCouplingUMeshCell::repr() const
8501 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8503 std::ostringstream oss; oss << "Cell Type " << INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)_conn[0]).getRepr();
8505 std::copy(_conn+1,_conn+_conn_lgth,std::ostream_iterator<int>(oss," "));
8509 return std::string("MEDCouplingUMeshCell::repr : Invalid pos");
8512 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCell::getType() const
8514 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8515 return (INTERP_KERNEL::NormalizedCellType)_conn[0];
8517 return INTERP_KERNEL::NORM_ERROR;
8520 const int *MEDCouplingUMeshCell::getAllConn(int& lgth) const
8523 if(_conn_lgth!=NOTICABLE_FIRST_VAL)