1 // Copyright (C) 2007-2016 CEA/DEN, EDF R&D
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 // Author : Anthony Geay (CEA/DEN)
21 #include "MEDCouplingUMesh.hxx"
22 #include "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_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,-1,-1,25,42,36,4};
63 MEDCouplingUMesh *MEDCouplingUMesh::New()
65 return new MEDCouplingUMesh;
68 MEDCouplingUMesh *MEDCouplingUMesh::New(const std::string& meshName, int meshDim)
70 MEDCouplingUMesh *ret=new MEDCouplingUMesh;
71 ret->setName(meshName);
72 ret->setMeshDimension(meshDim);
77 * Returns a new MEDCouplingUMesh which is a full copy of \a this one. No data is shared
78 * between \a this and the new mesh.
79 * \return MEDCouplingUMesh * - a new instance of MEDCouplingMesh. The caller is to
80 * delete this mesh using decrRef() as it is no more needed.
82 MEDCouplingUMesh *MEDCouplingUMesh::deepCopy() const
89 * Returns a new MEDCouplingUMesh which is a copy of \a this one.
90 * \param [in] recDeepCpy - if \a true, the copy is deep, else all data arrays of \a
91 * this mesh are shared by the new mesh.
92 * \return MEDCouplingUMesh * - a new instance of MEDCouplingMesh. The caller is to
93 * delete this mesh using decrRef() as it is no more needed.
95 MEDCouplingUMesh *MEDCouplingUMesh::clone(bool recDeepCpy) const
97 return new MEDCouplingUMesh(*this,recDeepCpy);
101 * This method behaves mostly like MEDCouplingUMesh::deepCopy method, except that only nodal connectivity arrays are deeply copied.
102 * The coordinates are shared between \a this and the returned instance.
104 * \return MEDCouplingUMesh * - A new object instance holding the copy of \a this (deep for connectivity, shallow for coordiantes)
105 * \sa MEDCouplingUMesh::deepCopy
107 MEDCouplingUMesh *MEDCouplingUMesh::deepCopyConnectivityOnly() const
109 checkConnectivityFullyDefined();
110 MCAuto<MEDCouplingUMesh> ret=clone(false);
111 MCAuto<DataArrayInt> c(getNodalConnectivity()->deepCopy()),ci(getNodalConnectivityIndex()->deepCopy());
112 ret->setConnectivity(c,ci);
116 void MEDCouplingUMesh::shallowCopyConnectivityFrom(const MEDCouplingPointSet *other)
119 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is null !");
120 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
122 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is not an MEDCouplingUMesh instance !");
123 MEDCouplingUMesh *otherC2=const_cast<MEDCouplingUMesh *>(otherC);//sorry :(
124 setConnectivity(otherC2->getNodalConnectivity(),otherC2->getNodalConnectivityIndex(),true);
127 std::size_t MEDCouplingUMesh::getHeapMemorySizeWithoutChildren() const
129 std::size_t ret(MEDCouplingPointSet::getHeapMemorySizeWithoutChildren());
133 std::vector<const BigMemoryObject *> MEDCouplingUMesh::getDirectChildrenWithNull() const
135 std::vector<const BigMemoryObject *> ret(MEDCouplingPointSet::getDirectChildrenWithNull());
136 ret.push_back(_nodal_connec);
137 ret.push_back(_nodal_connec_index);
141 void MEDCouplingUMesh::updateTime() const
143 MEDCouplingPointSet::updateTime();
146 updateTimeWith(*_nodal_connec);
148 if(_nodal_connec_index)
150 updateTimeWith(*_nodal_connec_index);
154 MEDCouplingUMesh::MEDCouplingUMesh():_mesh_dim(-2),_nodal_connec(0),_nodal_connec_index(0)
159 * Checks if \a this mesh is well defined. If no exception is thrown by this method,
160 * then \a this mesh is most probably is writable, exchangeable and available for most
161 * of algorithms. When a mesh is constructed from scratch, it is a good habit to call
162 * this method to check that all is in order with \a this mesh.
163 * \throw If the mesh dimension is not set.
164 * \throw If the coordinates array is not set (if mesh dimension != -1 ).
165 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
166 * \throw If the connectivity data array has more than one component.
167 * \throw If the connectivity data array has a named component.
168 * \throw If the connectivity index data array has more than one component.
169 * \throw If the connectivity index data array has a named component.
171 void MEDCouplingUMesh::checkConsistencyLight() const
174 throw INTERP_KERNEL::Exception("No mesh dimension specified !");
176 MEDCouplingPointSet::checkConsistencyLight();
177 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
179 if((int)INTERP_KERNEL::CellModel::GetCellModel(*iter).getDimension()!=_mesh_dim)
181 std::ostringstream message;
182 message << "Mesh invalid because dimension is " << _mesh_dim << " and there is presence of cell(s) with type " << (*iter);
183 throw INTERP_KERNEL::Exception(message.str().c_str());
188 if(_nodal_connec->getNumberOfComponents()!=1)
189 throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to be with number of components set to one !");
190 if(_nodal_connec->getInfoOnComponent(0)!="")
191 throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to have no info on its single component !");
195 throw INTERP_KERNEL::Exception("Nodal connectivity array is not defined !");
196 if(_nodal_connec_index)
198 if(_nodal_connec_index->getNumberOfComponents()!=1)
199 throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to be with number of components set to one !");
200 if(_nodal_connec_index->getInfoOnComponent(0)!="")
201 throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to have no info on its single component !");
205 throw INTERP_KERNEL::Exception("Nodal connectivity index array is not defined !");
209 * Checks if \a this mesh is well defined. If no exception is thrown by this method,
210 * then \a this mesh is most probably is writable, exchangeable and available for all
211 * algorithms. <br> In addition to the checks performed by checkConsistencyLight(), this
212 * method thoroughly checks the nodal connectivity.
213 * \param [in] eps - a not used parameter.
214 * \throw If the mesh dimension is not set.
215 * \throw If the coordinates array is not set (if mesh dimension != -1 ).
216 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
217 * \throw If the connectivity data array has more than one component.
218 * \throw If the connectivity data array has a named component.
219 * \throw If the connectivity index data array has more than one component.
220 * \throw If the connectivity index data array has a named component.
221 * \throw If number of nodes defining an element does not correspond to the type of element.
222 * \throw If the nodal connectivity includes an invalid node id.
224 void MEDCouplingUMesh::checkConsistency(double eps) const
226 checkConsistencyLight();
229 int meshDim=getMeshDimension();
230 int nbOfNodes=getNumberOfNodes();
231 int nbOfCells=getNumberOfCells();
232 const int *ptr=_nodal_connec->getConstPointer();
233 const int *ptrI=_nodal_connec_index->getConstPointer();
234 for(int i=0;i<nbOfCells;i++)
236 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)ptr[ptrI[i]]);
237 if((int)cm.getDimension()!=meshDim)
239 std::ostringstream oss;
240 oss << "MEDCouplingUMesh::checkConsistency : cell << #" << i<< " with type Type " << cm.getRepr() << " in 'this' whereas meshdim == " << meshDim << " !";
241 throw INTERP_KERNEL::Exception(oss.str());
243 int nbOfNodesInCell=ptrI[i+1]-ptrI[i]-1;
245 if(nbOfNodesInCell!=(int)cm.getNumberOfNodes())
247 std::ostringstream oss;
248 oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with static Type '" << cm.getRepr() << "' has " << cm.getNumberOfNodes();
249 oss << " nodes whereas in connectivity there is " << nbOfNodesInCell << " nodes ! Looks very bad !";
250 throw INTERP_KERNEL::Exception(oss.str());
252 if(cm.isQuadratic() && cm.isDynamic() && meshDim == 2)
253 if (nbOfNodesInCell % 2 || nbOfNodesInCell < 4)
255 std::ostringstream oss;
256 oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with quadratic type '" << cm.getRepr() << "' has " << nbOfNodesInCell;
257 oss << " nodes. This should be even, and greater or equal than 4!! Looks very bad!";
258 throw INTERP_KERNEL::Exception(oss.str());
260 for(const int *w=ptr+ptrI[i]+1;w!=ptr+ptrI[i+1];w++)
265 if(nodeId>=nbOfNodes)
267 std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " whereas there are only " << nbOfNodes << " nodes in the mesh !";
268 throw INTERP_KERNEL::Exception(oss.str());
273 std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " in connectivity ! sounds bad !";
274 throw INTERP_KERNEL::Exception(oss.str());
278 if((INTERP_KERNEL::NormalizedCellType)(ptr[ptrI[i]])!=INTERP_KERNEL::NORM_POLYHED)
280 std::ostringstream oss; oss << "Cell #" << i << " is built with node #-1 in connectivity ! sounds bad !";
281 throw INTERP_KERNEL::Exception(oss.str());
289 * Sets dimension of \a this mesh. The mesh dimension in general depends on types of
290 * elements contained in the mesh. For more info on the mesh dimension see
291 * \ref MEDCouplingUMeshPage.
292 * \param [in] meshDim - a new mesh dimension.
293 * \throw If \a meshDim is invalid. A valid range is <em> -1 <= meshDim <= 3</em>.
295 void MEDCouplingUMesh::setMeshDimension(int meshDim)
297 if(meshDim<-1 || meshDim>3)
298 throw INTERP_KERNEL::Exception("Invalid meshDim specified ! Must be greater or equal to -1 and lower or equal to 3 !");
304 * Allocates memory to store an estimation of the given number of cells. The closer is the estimation to the number of cells effectively inserted,
305 * the less will the library need to reallocate memory. If the number of cells to be inserted is not known simply put 0 to this parameter.
306 * If a nodal connectivity previouly existed before the call of this method, it will be reset.
308 * \param [in] nbOfCells - estimation of the number of cell \a this mesh will contain.
310 * \if ENABLE_EXAMPLES
311 * \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
312 * \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
315 void MEDCouplingUMesh::allocateCells(int nbOfCells)
318 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::allocateCells : the input number of cells should be >= 0 !");
319 if(_nodal_connec_index)
321 _nodal_connec_index->decrRef();
325 _nodal_connec->decrRef();
327 _nodal_connec_index=DataArrayInt::New();
328 _nodal_connec_index->reserve(nbOfCells+1);
329 _nodal_connec_index->pushBackSilent(0);
330 _nodal_connec=DataArrayInt::New();
331 _nodal_connec->reserve(2*nbOfCells);
337 * Appends a cell to the connectivity array. For deeper understanding what is
338 * happening see \ref MEDCouplingUMeshNodalConnectivity.
339 * \param [in] type - type of cell to add.
340 * \param [in] size - number of nodes constituting this cell.
341 * \param [in] nodalConnOfCell - the connectivity of the cell to add.
343 * \if ENABLE_EXAMPLES
344 * \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
345 * \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
348 void MEDCouplingUMesh::insertNextCell(INTERP_KERNEL::NormalizedCellType type, int size, const int *nodalConnOfCell)
350 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
351 if(_nodal_connec_index==0)
352 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::insertNextCell : nodal connectivity not set ! invoke allocateCells before calling insertNextCell !");
353 if((int)cm.getDimension()==_mesh_dim)
356 if(size!=(int)cm.getNumberOfNodes())
358 std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : Trying to push a " << cm.getRepr() << " cell with a size of " << size;
359 oss << " ! Expecting " << cm.getNumberOfNodes() << " !";
360 throw INTERP_KERNEL::Exception(oss.str());
362 int idx=_nodal_connec_index->back();
364 _nodal_connec_index->pushBackSilent(val);
365 _nodal_connec->writeOnPlace(idx,type,nodalConnOfCell,size);
370 std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : cell type " << cm.getRepr() << " has a dimension " << cm.getDimension();
371 oss << " whereas Mesh Dimension of current UMesh instance is set to " << _mesh_dim << " ! Please invoke \"setMeshDimension\" method before or invoke ";
372 oss << "\"MEDCouplingUMesh::New\" static method with 2 parameters name and meshDimension !";
373 throw INTERP_KERNEL::Exception(oss.str());
378 * Compacts data arrays to release unused memory. This method is to be called after
379 * finishing cell insertion using \a this->insertNextCell().
381 * \if ENABLE_EXAMPLES
382 * \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
383 * \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
386 void MEDCouplingUMesh::finishInsertingCells()
388 _nodal_connec->pack();
389 _nodal_connec_index->pack();
390 _nodal_connec->declareAsNew();
391 _nodal_connec_index->declareAsNew();
396 * Entry point for iteration over cells of this. Warning the returned cell iterator should be deallocated.
397 * Useful for python users.
399 MEDCouplingUMeshCellIterator *MEDCouplingUMesh::cellIterator()
401 return new MEDCouplingUMeshCellIterator(this);
405 * Entry point for iteration over cells groups geo types per geotypes. Warning the returned cell iterator should be deallocated.
406 * If \a this is not so that that cells are grouped by geo types this method will throw an exception.
407 * In this case MEDCouplingUMesh::sortCellsInMEDFileFrmt or MEDCouplingUMesh::rearrange2ConsecutiveCellTypes methods for example can be called before invoking this method.
408 * Useful for python users.
410 MEDCouplingUMeshCellByTypeEntry *MEDCouplingUMesh::cellsByType()
412 if(!checkConsecutiveCellTypes())
413 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::cellsByType : this mesh is not sorted by type !");
414 return new MEDCouplingUMeshCellByTypeEntry(this);
418 * Returns a set of all cell types available in \a this mesh.
419 * \return std::set<INTERP_KERNEL::NormalizedCellType> - the set of cell types.
420 * \warning this method does not throw any exception even if \a this is not defined.
421 * \sa MEDCouplingUMesh::getAllGeoTypesSorted
423 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypes() const
429 * This method returns the sorted list of geometric types in \a this.
430 * Sorted means in the same order than the cells in \a this. A single entry in return vector means the maximal chunk of consecutive cells in \a this
431 * having the same geometric type. So a same geometric type can appear more than once if the cells are not sorted per geometric type.
433 * \throw if connectivity in \a this is not correctly defined.
435 * \sa MEDCouplingMesh::getAllGeoTypes
437 std::vector<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypesSorted() const
439 std::vector<INTERP_KERNEL::NormalizedCellType> ret;
440 checkConnectivityFullyDefined();
441 int nbOfCells(getNumberOfCells());
444 if(getNodalConnectivityArrayLen()<1)
445 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAllGeoTypesSorted : the connectivity in this seems invalid !");
446 const int *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin());
447 ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci++]);
448 for(int i=1;i<nbOfCells;i++,ci++)
449 if(ret.back()!=((INTERP_KERNEL::NormalizedCellType)c[*ci]))
450 ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci]);
455 * This method is a method that compares \a this and \a other.
456 * This method compares \b all attributes, even names and component names.
458 bool MEDCouplingUMesh::isEqualIfNotWhy(const MEDCouplingMesh *other, double prec, std::string& reason) const
461 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isEqualIfNotWhy : input other pointer is null !");
462 std::ostringstream oss; oss.precision(15);
463 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
466 reason="mesh given in input is not castable in MEDCouplingUMesh !";
469 if(!MEDCouplingPointSet::isEqualIfNotWhy(other,prec,reason))
471 if(_mesh_dim!=otherC->_mesh_dim)
473 oss << "umesh dimension mismatch : this mesh dimension=" << _mesh_dim << " other mesh dimension=" << otherC->_mesh_dim;
477 if(_types!=otherC->_types)
479 oss << "umesh geometric type mismatch :\nThis geometric types are :";
480 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
481 { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
482 oss << "\nOther geometric types are :";
483 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=otherC->_types.begin();iter!=otherC->_types.end();iter++)
484 { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
488 if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
489 if(_nodal_connec==0 || otherC->_nodal_connec==0)
491 reason="Only one UMesh between the two this and other has its nodal connectivity DataArrayInt defined !";
494 if(_nodal_connec!=otherC->_nodal_connec)
495 if(!_nodal_connec->isEqualIfNotWhy(*otherC->_nodal_connec,reason))
497 reason.insert(0,"Nodal connectivity DataArrayInt differ : ");
500 if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
501 if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
503 reason="Only one UMesh between the two this and other has its nodal connectivity index DataArrayInt defined !";
506 if(_nodal_connec_index!=otherC->_nodal_connec_index)
507 if(!_nodal_connec_index->isEqualIfNotWhy(*otherC->_nodal_connec_index,reason))
509 reason.insert(0,"Nodal connectivity index DataArrayInt differ : ");
516 * Checks if data arrays of this mesh (node coordinates, nodal
517 * connectivity of cells, etc) of two meshes are same. Textual data like name etc. are
519 * \param [in] other - the mesh to compare with.
520 * \param [in] prec - precision value used to compare node coordinates.
521 * \return bool - \a true if the two meshes are same.
523 bool MEDCouplingUMesh::isEqualWithoutConsideringStr(const MEDCouplingMesh *other, double prec) const
525 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
528 if(!MEDCouplingPointSet::isEqualWithoutConsideringStr(other,prec))
530 if(_mesh_dim!=otherC->_mesh_dim)
532 if(_types!=otherC->_types)
534 if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
535 if(_nodal_connec==0 || otherC->_nodal_connec==0)
537 if(_nodal_connec!=otherC->_nodal_connec)
538 if(!_nodal_connec->isEqualWithoutConsideringStr(*otherC->_nodal_connec))
540 if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
541 if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
543 if(_nodal_connec_index!=otherC->_nodal_connec_index)
544 if(!_nodal_connec_index->isEqualWithoutConsideringStr(*otherC->_nodal_connec_index))
550 * Checks if \a this and \a other meshes are geometrically equivalent with high
551 * probability, else an exception is thrown. The meshes are considered equivalent if
552 * (1) meshes contain the same number of nodes and the same number of elements of the
553 * same types (2) three cells of the two meshes (first, last and middle) are based
554 * on coincident nodes (with a specified precision).
555 * \param [in] other - the mesh to compare with.
556 * \param [in] prec - the precision used to compare nodes of the two meshes.
557 * \throw If the two meshes do not match.
559 void MEDCouplingUMesh::checkFastEquivalWith(const MEDCouplingMesh *other, double prec) const
561 MEDCouplingPointSet::checkFastEquivalWith(other,prec);
562 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
564 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkFastEquivalWith : Two meshes are not not unstructured !");
568 * Returns the reverse nodal connectivity. The reverse nodal connectivity enumerates
569 * cells each node belongs to.
570 * \warning For speed reasons, this method does not check if node ids in the nodal
571 * connectivity correspond to the size of node coordinates array.
572 * \param [in,out] revNodal - an array holding ids of cells sharing each node.
573 * \param [in,out] revNodalIndx - an array, of length \a this->getNumberOfNodes() + 1,
574 * dividing cell ids in \a revNodal into groups each referring to one
575 * node. Its every element (except the last one) is an index pointing to the
576 * first id of a group of cells. For example cells sharing the node #1 are
577 * described by following range of indices:
578 * [ \a revNodalIndx[1], \a revNodalIndx[2] ) and the cell ids are
579 * \a revNodal[ \a revNodalIndx[1] ], \a revNodal[ \a revNodalIndx[1] + 1], ...
580 * Number of cells sharing the *i*-th node is
581 * \a revNodalIndx[ *i*+1 ] - \a revNodalIndx[ *i* ].
582 * \throw If the coordinates array is not set.
583 * \throw If the nodal connectivity of cells is not defined.
585 * \if ENABLE_EXAMPLES
586 * \ref cpp_mcumesh_getReverseNodalConnectivity "Here is a C++ example".<br>
587 * \ref py_mcumesh_getReverseNodalConnectivity "Here is a Python example".
590 void MEDCouplingUMesh::getReverseNodalConnectivity(DataArrayInt *revNodal, DataArrayInt *revNodalIndx) const
593 int nbOfNodes(getNumberOfNodes());
594 int *revNodalIndxPtr=(int *)malloc((nbOfNodes+1)*sizeof(int));
595 revNodalIndx->useArray(revNodalIndxPtr,true,C_DEALLOC,nbOfNodes+1,1);
596 std::fill(revNodalIndxPtr,revNodalIndxPtr+nbOfNodes+1,0);
597 const int *conn(_nodal_connec->begin()),*connIndex(_nodal_connec_index->begin());
598 int nbOfCells(getNumberOfCells()),nbOfEltsInRevNodal(0);
599 for(int eltId=0;eltId<nbOfCells;eltId++)
601 const int *strtNdlConnOfCurCell(conn+connIndex[eltId]+1),*endNdlConnOfCurCell(conn+connIndex[eltId+1]);
602 for(const int *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
603 if(*iter>=0)//for polyhedrons
605 nbOfEltsInRevNodal++;
606 revNodalIndxPtr[(*iter)+1]++;
609 std::transform(revNodalIndxPtr+1,revNodalIndxPtr+nbOfNodes+1,revNodalIndxPtr,revNodalIndxPtr+1,std::plus<int>());
610 int *revNodalPtr=(int *)malloc((nbOfEltsInRevNodal)*sizeof(int));
611 revNodal->useArray(revNodalPtr,true,C_DEALLOC,nbOfEltsInRevNodal,1);
612 std::fill(revNodalPtr,revNodalPtr+nbOfEltsInRevNodal,-1);
613 for(int eltId=0;eltId<nbOfCells;eltId++)
615 const int *strtNdlConnOfCurCell=conn+connIndex[eltId]+1;
616 const int *endNdlConnOfCurCell=conn+connIndex[eltId+1];
617 for(const int *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
618 if(*iter>=0)//for polyhedrons
619 *std::find_if(revNodalPtr+revNodalIndxPtr[*iter],revNodalPtr+revNodalIndxPtr[*iter+1],std::bind2nd(std::equal_to<int>(),-1))=eltId;
624 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
625 * this->getMeshDimension(), that bound cells of \a this mesh. In addition arrays
626 * describing correspondence between cells of \a this and the result meshes are
627 * returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending connectivity,
628 * i.e. enumerate cells of the result mesh bounding each cell of \a this mesh. The
629 * arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
630 * i.e. enumerate cells of \a this mesh bounded by each cell of the result mesh.
631 * \warning For speed reasons, this method does not check if node ids in the nodal
632 * connectivity correspond to the size of node coordinates array.
633 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
634 * to write this mesh to the MED file, its cells must be sorted using
635 * sortCellsInMEDFileFrmt().
636 * \param [in,out] desc - the array containing cell ids of the result mesh bounding
637 * each cell of \a this mesh.
638 * \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
639 * dividing cell ids in \a desc into groups each referring to one
640 * cell of \a this mesh. Its every element (except the last one) is an index
641 * pointing to the first id of a group of cells. For example cells of the
642 * result mesh bounding the cell #1 of \a this mesh are described by following
644 * [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
645 * \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
646 * Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
647 * \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
648 * \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
649 * by each cell of the result mesh.
650 * \param [in,out] revDescIndx - the array, of length one more than number of cells
651 * in the result mesh,
652 * dividing cell ids in \a revDesc into groups each referring to one
653 * cell of the result mesh the same way as \a descIndx divides \a desc.
654 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is to
655 * delete this mesh using decrRef() as it is no more needed.
656 * \throw If the coordinates array is not set.
657 * \throw If the nodal connectivity of cells is node defined.
658 * \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
659 * revDescIndx == NULL.
661 * \if ENABLE_EXAMPLES
662 * \ref cpp_mcumesh_buildDescendingConnectivity "Here is a C++ example".<br>
663 * \ref py_mcumesh_buildDescendingConnectivity "Here is a Python example".
665 * \sa buildDescendingConnectivity2()
667 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
669 return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
673 * \a this has to have a mesh dimension equal to 3. If it is not the case an INTERP_KERNEL::Exception will be thrown.
674 * This behaves exactly as MEDCouplingUMesh::buildDescendingConnectivity does except that this method compute directly the transition from mesh dimension 3 to sub edges (dimension 1)
675 * in one shot. That is to say that this method is equivalent to 2 successive calls to MEDCouplingUMesh::buildDescendingConnectivity.
676 * This method returns 4 arrays and a mesh as MEDCouplingUMesh::buildDescendingConnectivity does.
677 * \sa MEDCouplingUMesh::buildDescendingConnectivity
679 MEDCouplingUMesh *MEDCouplingUMesh::explode3DMeshTo1D(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
682 if(getMeshDimension()!=3)
683 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explode3DMeshTo1D : This has to have a mesh dimension to 3 !");
684 return buildDescendingConnectivityGen<MinusTwoSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
688 * This method computes the micro edges constituting each cell in \a this. Micro edge is an edge for non quadratic cells. Micro edge is an half edge for quadratic cells.
689 * This method works for both meshes with mesh dimenstion equal to 2 or 3. Dynamical cells are not supported (polygons, polyhedrons...)
691 * \sa explode3DMeshTo1D, buildDescendingConnectiviy
693 MEDCouplingUMesh *MEDCouplingUMesh::explodeMeshIntoMicroEdges(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
696 switch(getMeshDimension())
699 return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
701 return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
703 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explodeMeshIntoMicroEdges : Only 2D and 3D supported !");
708 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
709 * this->getMeshDimension(), that bound cells of \a this mesh. In
710 * addition arrays describing correspondence between cells of \a this and the result
711 * meshes are returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending
712 * connectivity, i.e. enumerate cells of the result mesh bounding each cell of \a this
713 * mesh. This method differs from buildDescendingConnectivity() in that apart
714 * from cell ids, \a desc returns mutual orientation of cells in \a this and the
715 * result meshes. So a positive id means that order of nodes in corresponding cells
716 * of two meshes is same, and a negative id means a reverse order of nodes. Since a
717 * cell with id #0 can't be negative, the array \a desc returns ids in FORTRAN mode,
718 * i.e. cell ids are one-based.
719 * Arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
720 * i.e. enumerate cells of \a this mesh bounded by each cell of the result mesh.
721 * \warning For speed reasons, this method does not check if node ids in the nodal
722 * connectivity correspond to the size of node coordinates array.
723 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
724 * to write this mesh to the MED file, its cells must be sorted using
725 * sortCellsInMEDFileFrmt().
726 * \param [in,out] desc - the array containing cell ids of the result mesh bounding
727 * each cell of \a this mesh.
728 * \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
729 * dividing cell ids in \a desc into groups each referring to one
730 * cell of \a this mesh. Its every element (except the last one) is an index
731 * pointing to the first id of a group of cells. For example cells of the
732 * result mesh bounding the cell #1 of \a this mesh are described by following
734 * [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
735 * \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
736 * Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
737 * \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
738 * \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
739 * by each cell of the result mesh.
740 * \param [in,out] revDescIndx - the array, of length one more than number of cells
741 * in the result mesh,
742 * dividing cell ids in \a revDesc into groups each referring to one
743 * cell of the result mesh the same way as \a descIndx divides \a desc.
744 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This result mesh
745 * shares the node coordinates array with \a this mesh. The caller is to
746 * delete this mesh using decrRef() as it is no more needed.
747 * \throw If the coordinates array is not set.
748 * \throw If the nodal connectivity of cells is node defined.
749 * \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
750 * revDescIndx == NULL.
752 * \if ENABLE_EXAMPLES
753 * \ref cpp_mcumesh_buildDescendingConnectivity2 "Here is a C++ example".<br>
754 * \ref py_mcumesh_buildDescendingConnectivity2 "Here is a Python example".
756 * \sa buildDescendingConnectivity()
758 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity2(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
760 return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingOrientationSensitiveNbrer);
764 * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
765 * For speed reasons no check of this will be done. This method calls
766 * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
767 * This method lists cell by cell in \b this which are its neighbors. To compute the result
768 * only connectivities are considered.
769 * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
770 * The format of return is hence \ref numbering-indirect.
772 * \param [out] neighbors is an array storing all the neighbors of all cells in \b this. This array is newly
773 * allocated and should be dealt by the caller. \b neighborsIndx 2nd output
774 * parameter allows to select the right part in this array (\ref numbering-indirect). The number of tuples
775 * is equal to the last values in \b neighborsIndx.
776 * \param [out] neighborsIndx is an array of size this->getNumberOfCells()+1 newly allocated and should be
777 * dealt by the caller. This arrays allow to use the first output parameter \b neighbors (\ref numbering-indirect).
779 void MEDCouplingUMesh::computeNeighborsOfCells(DataArrayInt *&neighbors, DataArrayInt *&neighborsIndx) const
781 MCAuto<DataArrayInt> desc=DataArrayInt::New();
782 MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
783 MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
784 MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
785 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
787 ComputeNeighborsOfCellsAdv(desc,descIndx,revDesc,revDescIndx,neighbors,neighborsIndx);
790 void MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne(const DataArrayInt *nodeNeigh, const DataArrayInt *nodeNeighI, MCAuto<DataArrayInt>& cellNeigh, MCAuto<DataArrayInt>& cellNeighIndex) const
792 if(!nodeNeigh || !nodeNeighI)
793 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : null pointer !");
794 checkConsistencyLight();
795 nodeNeigh->checkAllocated(); nodeNeighI->checkAllocated();
796 nodeNeigh->checkNbOfComps(1,"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : node neigh");
797 nodeNeighI->checkNbOfComps(1,"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : node neigh index");
798 nodeNeighI->checkNbOfTuples(1+getNumberOfNodes(),"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : invalid length");
799 int nbCells(getNumberOfCells());
800 const int *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin()),*ne(nodeNeigh->begin()),*nei(nodeNeighI->begin());
801 cellNeigh=DataArrayInt::New(); cellNeigh->alloc(0,1); cellNeighIndex=DataArrayInt::New(); cellNeighIndex->alloc(1,1); cellNeighIndex->setIJ(0,0,0);
802 for(int i=0;i<nbCells;i++)
805 for(const int *it=c+ci[i]+1;it!=c+ci[i+1];it++)
807 s.insert(ne+nei[*it],ne+nei[*it+1]);
809 cellNeigh->insertAtTheEnd(s.begin(),s.end());
810 cellNeighIndex->pushBackSilent(cellNeigh->getNumberOfTuples());
815 * This method is called by MEDCouplingUMesh::computeNeighborsOfCells. This methods performs the algorithm
816 * of MEDCouplingUMesh::computeNeighborsOfCells.
817 * This method is useful for users that want to reduce along a criterion the set of neighbours cell. This is
818 * typically the case to extract a set a neighbours,
819 * excluding a set of meshdim-1 cells in input descending connectivity.
820 * Typically \b desc, \b descIndx, \b revDesc and \b revDescIndx (\ref numbering-indirect) input params are
821 * the result of MEDCouplingUMesh::buildDescendingConnectivity.
822 * This method lists cell by cell in \b this which are its neighbors. To compute the result only connectivities
824 * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
826 * \param [in] desc descending connectivity array.
827 * \param [in] descIndx descending connectivity index array used to walk through \b desc (\ref numbering-indirect).
828 * \param [in] revDesc reverse descending connectivity array.
829 * \param [in] revDescIndx reverse descending connectivity index array used to walk through \b revDesc (\ref numbering-indirect).
830 * \param [out] neighbors is an array storing all the neighbors of all cells in \b this. This array is newly allocated and should be dealt by the caller. \b neighborsIndx 2nd output
831 * parameter allows to select the right part in this array. The number of tuples is equal to the last values in \b neighborsIndx.
832 * \param [out] neighborsIndx is an array of size this->getNumberOfCells()+1 newly allocated and should be dealt by the caller. This arrays allow to use the first output parameter \b neighbors.
834 void MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(const DataArrayInt *desc, const DataArrayInt *descIndx, const DataArrayInt *revDesc, const DataArrayInt *revDescIndx,
835 DataArrayInt *&neighbors, DataArrayInt *&neighborsIndx)
837 if(!desc || !descIndx || !revDesc || !revDescIndx)
838 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeNeighborsOfCellsAdv some input array is empty !");
839 const int *descPtr=desc->begin();
840 const int *descIPtr=descIndx->begin();
841 const int *revDescPtr=revDesc->begin();
842 const int *revDescIPtr=revDescIndx->begin();
844 int nbCells=descIndx->getNumberOfTuples()-1;
845 MCAuto<DataArrayInt> out0=DataArrayInt::New();
846 MCAuto<DataArrayInt> out1=DataArrayInt::New(); out1->alloc(nbCells+1,1);
847 int *out1Ptr=out1->getPointer();
849 out0->reserve(desc->getNumberOfTuples());
850 for(int i=0;i<nbCells;i++,descIPtr++,out1Ptr++)
852 for(const int *w1=descPtr+descIPtr[0];w1!=descPtr+descIPtr[1];w1++)
854 std::set<int> s(revDescPtr+revDescIPtr[*w1],revDescPtr+revDescIPtr[(*w1)+1]);
856 out0->insertAtTheEnd(s.begin(),s.end());
858 *out1Ptr=out0->getNumberOfTuples();
860 neighbors=out0.retn();
861 neighborsIndx=out1.retn();
865 * Explodes \a this into edges whatever its dimension.
867 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::explodeIntoEdges(MCAuto<DataArrayInt>& desc, MCAuto<DataArrayInt>& descIndex, MCAuto<DataArrayInt>& revDesc, MCAuto<DataArrayInt>& revDescIndx) const
870 int mdim(getMeshDimension());
871 desc=DataArrayInt::New(); descIndex=DataArrayInt::New(); revDesc=DataArrayInt::New(); revDescIndx=DataArrayInt::New();
872 MCAuto<MEDCouplingUMesh> mesh1D;
877 mesh1D=explode3DMeshTo1D(desc,descIndex,revDesc,revDescIndx);
882 mesh1D=buildDescendingConnectivity(desc,descIndex,revDesc,revDescIndx);
887 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2] !");
894 * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
895 * For speed reasons no check of this will be done. This method calls
896 * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
897 * This method lists node by node in \b this which are its neighbors. To compute the result
898 * only connectivities are considered.
899 * The neighbor nodes of node having id 'nodeId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
901 * \param [out] neighbors is an array storing all the neighbors of all nodes in \b this. This array
902 * is newly allocated and should be dealt by the caller. \b neighborsIndx 2nd output
903 * parameter allows to select the right part in this array (\ref numbering-indirect).
904 * The number of tuples is equal to the last values in \b neighborsIndx.
905 * \param [out] neighborsIdx is an array of size this->getNumberOfCells()+1 newly allocated and should
906 * be dealt by the caller. This arrays allow to use the first output parameter \b neighbors.
908 * \sa MEDCouplingUMesh::computeEnlargedNeighborsOfNodes
910 void MEDCouplingUMesh::computeNeighborsOfNodes(DataArrayInt *&neighbors, DataArrayInt *&neighborsIdx) const
913 int mdim(getMeshDimension()),nbNodes(getNumberOfNodes());
914 MCAuto<DataArrayInt> desc(DataArrayInt::New()),descIndx(DataArrayInt::New()),revDesc(DataArrayInt::New()),revDescIndx(DataArrayInt::New());
915 MCConstAuto<MEDCouplingUMesh> mesh1D;
920 mesh1D=explode3DMeshTo1D(desc,descIndx,revDesc,revDescIndx);
925 mesh1D=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
930 mesh1D.takeRef(this);
935 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2,1] !");
938 desc=DataArrayInt::New(); descIndx=DataArrayInt::New(); revDesc=0; revDescIndx=0;
939 mesh1D->getReverseNodalConnectivity(desc,descIndx);
940 MCAuto<DataArrayInt> ret0(DataArrayInt::New());
941 ret0->alloc(desc->getNumberOfTuples(),1);
942 int *r0Pt(ret0->getPointer());
943 const int *c1DPtr(mesh1D->getNodalConnectivity()->begin()),*rn(desc->begin()),*rni(descIndx->begin());
944 for(int i=0;i<nbNodes;i++,rni++)
946 for(const int *oneDCellIt=rn+rni[0];oneDCellIt!=rn+rni[1];oneDCellIt++)
947 *r0Pt++=c1DPtr[3*(*oneDCellIt)+1]==i?c1DPtr[3*(*oneDCellIt)+2]:c1DPtr[3*(*oneDCellIt)+1];
949 neighbors=ret0.retn();
950 neighborsIdx=descIndx.retn();
954 * Computes enlarged neighbors for each nodes in \a this. The behavior of this method is close to MEDCouplingUMesh::computeNeighborsOfNodes except that the neighborhood of each node is wider here.
955 * A node j is considered to be in the neighborhood of i if and only if there is a cell in \a this containing in its nodal connectivity both i and j.
956 * This method is useful to find ghost cells of a part of a mesh with a code based on fields on nodes.
958 * \sa MEDCouplingUMesh::computeNeighborsOfNodes
960 void MEDCouplingUMesh::computeEnlargedNeighborsOfNodes(MCAuto<DataArrayInt> &neighbors, MCAuto<DataArrayInt>& neighborsIdx) const
963 int nbOfNodes(getNumberOfNodes());
964 const int *conn(_nodal_connec->begin()),*connIndex(_nodal_connec_index->begin());
965 int nbOfCells(getNumberOfCells());
966 std::vector< std::set<int> > st0(nbOfNodes);
967 for(int eltId=0;eltId<nbOfCells;eltId++)
969 const int *strtNdlConnOfCurCell(conn+connIndex[eltId]+1),*endNdlConnOfCurCell(conn+connIndex[eltId+1]);
970 std::set<int> s(strtNdlConnOfCurCell,endNdlConnOfCurCell); s.erase(-1); //for polyhedrons
971 for(std::set<int>::const_iterator iter2=s.begin();iter2!=s.end();iter2++)
972 st0[*iter2].insert(s.begin(),s.end());
974 neighborsIdx=DataArrayInt::New(); neighborsIdx->alloc(nbOfNodes+1,1); neighborsIdx->setIJ(0,0,0);
976 int *neighIdx(neighborsIdx->getPointer());
977 for(std::vector< std::set<int> >::const_iterator it=st0.begin();it!=st0.end();it++,neighIdx++)
978 neighIdx[1]=neighIdx[0]+(*it).size()-1;
980 neighbors=DataArrayInt::New(); neighbors->alloc(neighborsIdx->back(),1);
982 const int *neighIdx(neighborsIdx->begin());
983 int *neigh(neighbors->getPointer()),nodeId(0);
984 for(std::vector< std::set<int> >::const_iterator it=st0.begin();it!=st0.end();it++,neighIdx++,nodeId++)
986 std::set<int> s(*it); s.erase(nodeId);
987 std::copy(s.begin(),s.end(),neigh+*neighIdx);
993 * Converts specified cells to either polygons (if \a this is a 2D mesh) or
994 * polyhedrons (if \a this is a 3D mesh). The cells to convert are specified by an
995 * array of cell ids. Pay attention that after conversion all algorithms work slower
996 * with \a this mesh than before conversion. <br> If an exception is thrown during the
997 * conversion due presence of invalid ids in the array of cells to convert, as a
998 * result \a this mesh contains some already converted elements. In this case the 2D
999 * mesh remains valid but 3D mesh becomes \b inconsistent!
1000 * \warning This method can significantly modify the order of geometric types in \a this,
1001 * hence, to write this mesh to the MED file, its cells must be sorted using
1002 * sortCellsInMEDFileFrmt().
1003 * \param [in] cellIdsToConvertBg - the array holding ids of cells to convert.
1004 * \param [in] cellIdsToConvertEnd - a pointer to the last-plus-one-th element of \a
1005 * cellIdsToConvertBg.
1006 * \throw If the coordinates array is not set.
1007 * \throw If the nodal connectivity of cells is node defined.
1008 * \throw If dimension of \a this mesh is not either 2 or 3.
1010 * \if ENABLE_EXAMPLES
1011 * \ref cpp_mcumesh_convertToPolyTypes "Here is a C++ example".<br>
1012 * \ref py_mcumesh_convertToPolyTypes "Here is a Python example".
1015 void MEDCouplingUMesh::convertToPolyTypes(const int *cellIdsToConvertBg, const int *cellIdsToConvertEnd)
1017 checkFullyDefined();
1018 int dim=getMeshDimension();
1020 throw INTERP_KERNEL::Exception("Invalid mesh dimension : must be 2 or 3 !");
1021 int nbOfCells(getNumberOfCells());
1024 const int *connIndex=_nodal_connec_index->begin();
1025 int *conn=_nodal_connec->getPointer();
1026 for(const int *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1028 if(*iter>=0 && *iter<nbOfCells)
1030 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*iter]]);
1031 if(!cm.isQuadratic())
1032 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_POLYGON;
1034 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_QPOLYG;
1038 std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1039 oss << " in range [0," << nbOfCells << ") !";
1040 throw INTERP_KERNEL::Exception(oss.str());
1046 int *connIndex(_nodal_connec_index->getPointer());
1047 const int *connOld(_nodal_connec->getConstPointer());
1048 MCAuto<DataArrayInt> connNew(DataArrayInt::New()),connNewI(DataArrayInt::New()); connNew->alloc(0,1); connNewI->alloc(1,1); connNewI->setIJ(0,0,0);
1049 std::vector<bool> toBeDone(nbOfCells,false);
1050 for(const int *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1052 if(*iter>=0 && *iter<nbOfCells)
1053 toBeDone[*iter]=true;
1056 std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1057 oss << " in range [0," << nbOfCells << ") !";
1058 throw INTERP_KERNEL::Exception(oss.str());
1061 for(int cellId=0;cellId<nbOfCells;cellId++)
1063 int pos(connIndex[cellId]),posP1(connIndex[cellId+1]);
1064 int lgthOld(posP1-pos-1);
1065 if(toBeDone[cellId])
1067 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connOld[pos]);
1068 unsigned nbOfFaces(cm.getNumberOfSons2(connOld+pos+1,lgthOld));
1069 int *tmp(new int[nbOfFaces*lgthOld+1]);
1070 int *work=tmp; *work++=INTERP_KERNEL::NORM_POLYHED;
1071 for(unsigned j=0;j<nbOfFaces;j++)
1073 INTERP_KERNEL::NormalizedCellType type;
1074 unsigned offset=cm.fillSonCellNodalConnectivity2(j,connOld+pos+1,lgthOld,work,type);
1078 std::size_t newLgth(std::distance(tmp,work)-1);//-1 for last -1
1079 connNew->pushBackValsSilent(tmp,tmp+newLgth);
1080 connNewI->pushBackSilent(connNewI->back()+(int)newLgth);
1085 connNew->pushBackValsSilent(connOld+pos,connOld+posP1);
1086 connNewI->pushBackSilent(connNewI->back()+posP1-pos);
1089 setConnectivity(connNew,connNewI,false);//false because computeTypes called just behind.
1095 * Converts all cells to either polygons (if \a this is a 2D mesh) or
1096 * polyhedrons (if \a this is a 3D mesh).
1097 * \warning As this method is purely for user-friendliness and no optimization is
1098 * done to avoid construction of a useless vector, this method can be costly
1100 * \throw If the coordinates array is not set.
1101 * \throw If the nodal connectivity of cells is node defined.
1102 * \throw If dimension of \a this mesh is not either 2 or 3.
1104 void MEDCouplingUMesh::convertAllToPoly()
1106 int nbOfCells=getNumberOfCells();
1107 std::vector<int> cellIds(nbOfCells);
1108 for(int i=0;i<nbOfCells;i++)
1110 convertToPolyTypes(&cellIds[0],&cellIds[0]+cellIds.size());
1114 * Fixes nodal connectivity of invalid cells of type NORM_POLYHED. This method
1115 * expects that all NORM_POLYHED cells have connectivity similar to that of prismatic
1116 * volumes like NORM_HEXA8, NORM_PENTA6 etc., i.e. the first half of nodes describes a
1117 * base facet of the volume and the second half of nodes describes an opposite facet
1118 * having the same number of nodes as the base one. This method converts such
1119 * connectivity to a valid polyhedral format where connectivity of each facet is
1120 * explicitly described and connectivity of facets are separated by -1. If \a this mesh
1121 * contains a NORM_POLYHED cell with a valid connectivity, or an invalid connectivity is
1122 * not as expected, an exception is thrown and the mesh remains unchanged. Care of
1123 * a correct orientation of the first facet of a polyhedron, else orientation of a
1124 * corrected cell is reverse.<br>
1125 * This method is useful to build an extruded unstructured mesh with polyhedrons as
1126 * it releases the user from boring description of polyhedra connectivity in the valid
1128 * \throw If \a this->getMeshDimension() != 3.
1129 * \throw If \a this->getSpaceDimension() != 3.
1130 * \throw If the nodal connectivity of cells is not defined.
1131 * \throw If the coordinates array is not set.
1132 * \throw If \a this mesh contains polyhedrons with the valid connectivity.
1133 * \throw If \a this mesh contains polyhedrons with odd number of nodes.
1135 * \if ENABLE_EXAMPLES
1136 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
1137 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
1140 void MEDCouplingUMesh::convertExtrudedPolyhedra()
1142 checkFullyDefined();
1143 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1144 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertExtrudedPolyhedra works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
1145 int nbOfCells=getNumberOfCells();
1146 MCAuto<DataArrayInt> newCi=DataArrayInt::New();
1147 newCi->alloc(nbOfCells+1,1);
1148 int *newci=newCi->getPointer();
1149 const int *ci=_nodal_connec_index->getConstPointer();
1150 const int *c=_nodal_connec->getConstPointer();
1152 for(int i=0;i<nbOfCells;i++)
1154 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1155 if(type==INTERP_KERNEL::NORM_POLYHED)
1157 if(std::count(c+ci[i]+1,c+ci[i+1],-1)!=0)
1159 std::ostringstream oss; oss << "MEDCouplingUMesh::convertExtrudedPolyhedra : cell # " << i << " is a polhedron BUT it has NOT exactly 1 face !";
1160 throw INTERP_KERNEL::Exception(oss.str());
1162 std::size_t n2=std::distance(c+ci[i]+1,c+ci[i+1]);
1165 std::ostringstream oss; oss << "MEDCouplingUMesh::convertExtrudedPolyhedra : cell # " << i << " is a polhedron with 1 face but there is a mismatch of number of nodes in face should be even !";
1166 throw INTERP_KERNEL::Exception(oss.str());
1169 newci[i+1]=7*n1+2+newci[i];//6*n1 (nodal length) + n1+2 (number of faces) - 1 (number of '-1' separator is equal to number of faces -1) + 1 (for cell type)
1172 newci[i+1]=(ci[i+1]-ci[i])+newci[i];
1174 MCAuto<DataArrayInt> newC=DataArrayInt::New();
1175 newC->alloc(newci[nbOfCells],1);
1176 int *newc=newC->getPointer();
1177 for(int i=0;i<nbOfCells;i++)
1179 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1180 if(type==INTERP_KERNEL::NORM_POLYHED)
1182 std::size_t n1=std::distance(c+ci[i]+1,c+ci[i+1])/2;
1183 newc=std::copy(c+ci[i],c+ci[i]+n1+1,newc);
1185 for(std::size_t j=0;j<n1;j++)
1187 newc[j]=c[ci[i]+1+n1+(n1-j)%n1];
1189 newc[n1+5*j+1]=c[ci[i]+1+j];
1190 newc[n1+5*j+2]=c[ci[i]+1+j+n1];
1191 newc[n1+5*j+3]=c[ci[i]+1+(j+1)%n1+n1];
1192 newc[n1+5*j+4]=c[ci[i]+1+(j+1)%n1];
1197 newc=std::copy(c+ci[i],c+ci[i+1],newc);
1199 _nodal_connec_index->decrRef(); _nodal_connec_index=newCi.retn();
1200 _nodal_connec->decrRef(); _nodal_connec=newC.retn();
1205 * Converts all polygons (if \a this is a 2D mesh) or polyhedrons (if \a this is a 3D
1206 * mesh) to cells of classical types. This method is opposite to convertToPolyTypes().
1207 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
1208 * to write this mesh to the MED file, its cells must be sorted using
1209 * sortCellsInMEDFileFrmt().
1210 * \warning Cells (and most notably polyhedrons) must be correctly oriented for this to work
1211 * properly. See orientCorrectlyPolyhedrons() and arePolyhedronsNotCorrectlyOriented().
1212 * \return \c true if at least one cell has been converted, \c false else. In the
1213 * last case the nodal connectivity remains unchanged.
1214 * \throw If the coordinates array is not set.
1215 * \throw If the nodal connectivity of cells is not defined.
1216 * \throw If \a this->getMeshDimension() < 0.
1218 bool MEDCouplingUMesh::unPolyze()
1220 checkFullyDefined();
1221 int mdim=getMeshDimension();
1223 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::unPolyze works on umeshes with meshdim equals to 0, 1 2 or 3 !");
1226 int nbOfCells=getNumberOfCells();
1229 int initMeshLgth=getNodalConnectivityArrayLen();
1230 int *conn=_nodal_connec->getPointer();
1231 int *index=_nodal_connec_index->getPointer();
1236 for(int i=0;i<nbOfCells;i++)
1238 lgthOfCurCell=index[i+1]-posOfCurCell;
1239 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
1240 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
1241 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::NORM_ERROR;
1245 switch(cm.getDimension())
1249 INTERP_KERNEL::AutoPtr<int> tmp=new int[lgthOfCurCell-1];
1250 std::copy(conn+posOfCurCell+1,conn+posOfCurCell+lgthOfCurCell,(int *)tmp);
1251 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly2D(cm.isQuadratic(),tmp,lgthOfCurCell-1,conn+newPos+1,newLgth);
1256 int nbOfFaces,lgthOfPolyhConn;
1257 INTERP_KERNEL::AutoPtr<int> zipFullReprOfPolyh=INTERP_KERNEL::CellSimplify::getFullPolyh3DCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,nbOfFaces,lgthOfPolyhConn);
1258 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly3D(zipFullReprOfPolyh,nbOfFaces,lgthOfPolyhConn,conn+newPos+1,newLgth);
1263 newType=(lgthOfCurCell==3)?INTERP_KERNEL::NORM_SEG2:INTERP_KERNEL::NORM_POLYL;
1267 ret=ret || (newType!=type);
1268 conn[newPos]=newType;
1270 posOfCurCell=index[i+1];
1275 std::copy(conn+posOfCurCell,conn+posOfCurCell+lgthOfCurCell,conn+newPos);
1276 newPos+=lgthOfCurCell;
1277 posOfCurCell+=lgthOfCurCell;
1281 if(newPos!=initMeshLgth)
1282 _nodal_connec->reAlloc(newPos);
1289 * This method expects that spaceDimension is equal to 3 and meshDimension equal to 3.
1290 * This method performs operation only on polyhedrons in \b this. If no polyhedrons exists in \b this, \b this remains unchanged.
1291 * This method allows to merge if any coplanar 3DSurf cells that may appear in some polyhedrons cells.
1293 * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not. This epsilon is used to recenter around origin to have maximal
1296 void MEDCouplingUMesh::simplifyPolyhedra(double eps)
1298 checkFullyDefined();
1299 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1300 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplifyPolyhedra : works on meshdimension 3 and spaceDimension 3 !");
1301 MCAuto<DataArrayDouble> coords=getCoords()->deepCopy();
1302 coords->recenterForMaxPrecision(eps);
1304 int nbOfCells=getNumberOfCells();
1305 const int *conn=_nodal_connec->getConstPointer();
1306 const int *index=_nodal_connec_index->getConstPointer();
1307 MCAuto<DataArrayInt> connINew=DataArrayInt::New();
1308 connINew->alloc(nbOfCells+1,1);
1309 int *connINewPtr=connINew->getPointer(); *connINewPtr++=0;
1310 MCAuto<DataArrayInt> connNew=DataArrayInt::New(); connNew->alloc(0,1);
1312 for(int i=0;i<nbOfCells;i++,connINewPtr++)
1314 if(conn[index[i]]==(int)INTERP_KERNEL::NORM_POLYHED)
1316 SimplifyPolyhedronCell(eps,coords,conn+index[i],conn+index[i+1],connNew);
1320 connNew->insertAtTheEnd(conn+index[i],conn+index[i+1]);
1321 *connINewPtr=connNew->getNumberOfTuples();
1324 setConnectivity(connNew,connINew,false);
1328 * This method returns all node ids used in the connectivity of \b this. The data array returned has to be dealt by the caller.
1329 * The returned node ids are sorted ascendingly. This method is close to MEDCouplingUMesh::getNodeIdsInUse except
1330 * the format of the returned DataArrayInt instance.
1332 * \return a newly allocated DataArrayInt sorted ascendingly of fetched node ids.
1333 * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1335 DataArrayInt *MEDCouplingUMesh::computeFetchedNodeIds() const
1337 checkConnectivityFullyDefined();
1338 const int *maxEltPt(std::max_element(_nodal_connec->begin(),_nodal_connec->end()));
1339 int maxElt(maxEltPt==_nodal_connec->end()?0:std::abs(*maxEltPt)+1);
1340 std::vector<bool> retS(maxElt,false);
1341 computeNodeIdsAlg(retS);
1342 return DataArrayInt::BuildListOfSwitchedOn(retS);
1346 * \param [in,out] nodeIdsInUse an array of size typically equal to nbOfNodes.
1347 * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1349 void MEDCouplingUMesh::computeNodeIdsAlg(std::vector<bool>& nodeIdsInUse) const
1351 int nbOfNodes((int)nodeIdsInUse.size()),nbOfCells(getNumberOfCells());
1352 const int *connIndex(_nodal_connec_index->getConstPointer()),*conn(_nodal_connec->getConstPointer());
1353 for(int i=0;i<nbOfCells;i++)
1354 for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1357 if(conn[j]<nbOfNodes)
1358 nodeIdsInUse[conn[j]]=true;
1361 std::ostringstream oss; oss << "MEDCouplingUMesh::computeNodeIdsAlg : In cell #" << i << " presence of node id " << conn[j] << " not in [0," << nbOfNodes << ") !";
1362 throw INTERP_KERNEL::Exception(oss.str());
1369 struct MEDCouplingAccVisit
1371 MEDCouplingAccVisit():_new_nb_of_nodes(0) { }
1372 int operator()(int val) { if(val!=-1) return _new_nb_of_nodes++; else return -1; }
1373 int _new_nb_of_nodes;
1379 * Finds nodes not used in any cell and returns an array giving a new id to every node
1380 * by excluding the unused nodes, for which the array holds -1. The result array is
1381 * a mapping in "Old to New" mode.
1382 * \param [out] nbrOfNodesInUse - number of node ids present in the nodal connectivity.
1383 * \return DataArrayInt * - a new instance of DataArrayInt. Its length is \a
1384 * this->getNumberOfNodes(). It holds for each node of \a this mesh either -1
1385 * if the node is unused or a new id else. The caller is to delete this
1386 * array using decrRef() as it is no more needed.
1387 * \throw If the coordinates array is not set.
1388 * \throw If the nodal connectivity of cells is not defined.
1389 * \throw If the nodal connectivity includes an invalid id.
1391 * \if ENABLE_EXAMPLES
1392 * \ref cpp_mcumesh_getNodeIdsInUse "Here is a C++ example".<br>
1393 * \ref py_mcumesh_getNodeIdsInUse "Here is a Python example".
1395 * \sa computeFetchedNodeIds, computeNodeIdsAlg()
1397 DataArrayInt *MEDCouplingUMesh::getNodeIdsInUse(int& nbrOfNodesInUse) const
1400 int nbOfNodes(getNumberOfNodes());
1401 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1402 ret->alloc(nbOfNodes,1);
1403 int *traducer=ret->getPointer();
1404 std::fill(traducer,traducer+nbOfNodes,-1);
1405 int nbOfCells=getNumberOfCells();
1406 const int *connIndex=_nodal_connec_index->getConstPointer();
1407 const int *conn=_nodal_connec->getConstPointer();
1408 for(int i=0;i<nbOfCells;i++)
1409 for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1412 if(conn[j]<nbOfNodes)
1413 traducer[conn[j]]=1;
1416 std::ostringstream oss; oss << "MEDCouplingUMesh::getNodeIdsInUse : In cell #" << i << " presence of node id " << conn[j] << " not in [0," << nbOfNodes << ") !";
1417 throw INTERP_KERNEL::Exception(oss.str());
1420 nbrOfNodesInUse=(int)std::count(traducer,traducer+nbOfNodes,1);
1421 std::transform(traducer,traducer+nbOfNodes,traducer,MEDCouplingAccVisit());
1426 * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1427 * For each cell in \b this the number of nodes constituting cell is computed.
1428 * For each polyhedron cell, the sum of the number of nodes of each face constituting polyhedron cell is returned.
1429 * So for pohyhedrons some nodes can be counted several times in the returned result.
1431 * \return a newly allocated array
1432 * \sa MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell
1434 DataArrayInt *MEDCouplingUMesh::computeNbOfNodesPerCell() const
1436 checkConnectivityFullyDefined();
1437 int nbOfCells=getNumberOfCells();
1438 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1439 ret->alloc(nbOfCells,1);
1440 int *retPtr=ret->getPointer();
1441 const int *conn=getNodalConnectivity()->getConstPointer();
1442 const int *connI=getNodalConnectivityIndex()->getConstPointer();
1443 for(int i=0;i<nbOfCells;i++,retPtr++)
1445 if(conn[connI[i]]!=(int)INTERP_KERNEL::NORM_POLYHED)
1446 *retPtr=connI[i+1]-connI[i]-1;
1448 *retPtr=connI[i+1]-connI[i]-1-std::count(conn+connI[i]+1,conn+connI[i+1],-1);
1454 * This method computes effective number of nodes per cell. That is to say nodes appearing several times in nodal connectivity of a cell,
1455 * will be counted only once here whereas it will be counted several times in MEDCouplingUMesh::computeNbOfNodesPerCell method.
1457 * \return DataArrayInt * - new object to be deallocated by the caller.
1458 * \sa MEDCouplingUMesh::computeNbOfNodesPerCell
1460 DataArrayInt *MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell() const
1462 checkConnectivityFullyDefined();
1463 int nbOfCells=getNumberOfCells();
1464 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1465 ret->alloc(nbOfCells,1);
1466 int *retPtr=ret->getPointer();
1467 const int *conn=getNodalConnectivity()->getConstPointer();
1468 const int *connI=getNodalConnectivityIndex()->getConstPointer();
1469 for(int i=0;i<nbOfCells;i++,retPtr++)
1471 std::set<int> s(conn+connI[i]+1,conn+connI[i+1]);
1472 if(conn[connI[i]]!=(int)INTERP_KERNEL::NORM_POLYHED)
1473 *retPtr=(int)s.size();
1477 *retPtr=(int)s.size();
1484 * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1485 * For each cell in \b this the number of faces constituting (entity of dimension this->getMeshDimension()-1) cell is computed.
1487 * \return a newly allocated array
1489 DataArrayInt *MEDCouplingUMesh::computeNbOfFacesPerCell() const
1491 checkConnectivityFullyDefined();
1492 int nbOfCells=getNumberOfCells();
1493 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1494 ret->alloc(nbOfCells,1);
1495 int *retPtr=ret->getPointer();
1496 const int *conn=getNodalConnectivity()->getConstPointer();
1497 const int *connI=getNodalConnectivityIndex()->getConstPointer();
1498 for(int i=0;i<nbOfCells;i++,retPtr++,connI++)
1500 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]);
1501 *retPtr=cm.getNumberOfSons2(conn+connI[0]+1,connI[1]-connI[0]-1);
1507 * Removes unused nodes (the node coordinates array is shorten) and returns an array
1508 * mapping between new and old node ids in "Old to New" mode. -1 values in the returned
1509 * array mean that the corresponding old node is no more used.
1510 * \return DataArrayInt * - a new instance of DataArrayInt of length \a
1511 * this->getNumberOfNodes() before call of this method. The caller is to
1512 * delete this array using decrRef() as it is no more needed.
1513 * \throw If the coordinates array is not set.
1514 * \throw If the nodal connectivity of cells is not defined.
1515 * \throw If the nodal connectivity includes an invalid id.
1516 * \sa areAllNodesFetched
1518 * \if ENABLE_EXAMPLES
1519 * \ref cpp_mcumesh_zipCoordsTraducer "Here is a C++ example".<br>
1520 * \ref py_mcumesh_zipCoordsTraducer "Here is a Python example".
1523 DataArrayInt *MEDCouplingUMesh::zipCoordsTraducer()
1525 return MEDCouplingPointSet::zipCoordsTraducer();
1529 * This method stands if 'cell1' and 'cell2' are equals regarding 'compType' policy.
1530 * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1532 int MEDCouplingUMesh::AreCellsEqual(const int *conn, const int *connI, int cell1, int cell2, int compType)
1537 return AreCellsEqualPolicy0(conn,connI,cell1,cell2);
1539 return AreCellsEqualPolicy1(conn,connI,cell1,cell2);
1541 return AreCellsEqualPolicy2(conn,connI,cell1,cell2);
1543 return AreCellsEqualPolicy2NoType(conn,connI,cell1,cell2);
1545 return AreCellsEqualPolicy7(conn,connI,cell1,cell2);
1547 throw INTERP_KERNEL::Exception("Unknown comparison asked ! Must be in 0,1,2,3 or 7.");
1551 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 0.
1553 int MEDCouplingUMesh::AreCellsEqualPolicy0(const int *conn, const int *connI, int cell1, int cell2)
1555 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1556 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;
1561 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 1.
1563 int MEDCouplingUMesh::AreCellsEqualPolicy1(const int *conn, const int *connI, int cell1, int cell2)
1565 int sz=connI[cell1+1]-connI[cell1];
1566 if(sz==connI[cell2+1]-connI[cell2])
1568 if(conn[connI[cell1]]==conn[connI[cell2]])
1570 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1571 unsigned dim=cm.getDimension();
1577 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz1];
1578 int *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(int *)tmp);
1579 std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1580 work=std::search((int *)tmp,(int *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1581 return work!=tmp+sz1?1:0;
1584 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;//case of SEG2 and SEG3
1587 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy1 : not implemented yet for meshdim == 3 !");
1594 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 2.
1596 int MEDCouplingUMesh::AreCellsEqualPolicy2(const int *conn, const int *connI, int cell1, int cell2)
1598 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1600 if(conn[connI[cell1]]==conn[connI[cell2]])
1602 std::set<int> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1603 std::set<int> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1611 * This method is less restrictive than AreCellsEqualPolicy2. Here the geometric type is absolutely not taken into account !
1613 int MEDCouplingUMesh::AreCellsEqualPolicy2NoType(const int *conn, const int *connI, int cell1, int cell2)
1615 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1617 std::set<int> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1618 std::set<int> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1625 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 7.
1627 int MEDCouplingUMesh::AreCellsEqualPolicy7(const int *conn, const int *connI, int cell1, int cell2)
1629 int sz=connI[cell1+1]-connI[cell1];
1630 if(sz==connI[cell2+1]-connI[cell2])
1632 if(conn[connI[cell1]]==conn[connI[cell2]])
1634 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1635 unsigned dim=cm.getDimension();
1641 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz1];
1642 int *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(int *)tmp);
1643 std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1644 work=std::search((int *)tmp,(int *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1649 std::reverse_iterator<int *> it1((int *)tmp+sz1);
1650 std::reverse_iterator<int *> it2((int *)tmp);
1651 if(std::search(it1,it2,conn+connI[cell2]+1,conn+connI[cell2+1])!=it2)
1657 return work!=tmp+sz1?1:0;
1660 {//case of SEG2 and SEG3
1661 if(std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1))
1663 if(!cm.isQuadratic())
1665 std::reverse_iterator<const int *> it1(conn+connI[cell1+1]);
1666 std::reverse_iterator<const int *> it2(conn+connI[cell1]+1);
1667 if(std::equal(it1,it2,conn+connI[cell2]+1))
1673 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])
1680 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy7 : not implemented yet for meshdim == 3 !");
1688 * This method find cells that are equal (regarding \a compType) in \a this. The comparison is specified
1690 * This method keeps the coordiantes of \a this. This method is time consuming.
1692 * \param [in] compType input specifying the technique used to compare cells each other.
1693 * - 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.
1694 * - 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)
1695 * and their type equal. For 1D mesh the policy 1 is equivalent to 0.
1696 * - 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
1697 * can be used for users not sensitive to orientation of cell
1698 * \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.
1699 * \param [out] commonCellsArr common cells ids (\ref numbering-indirect)
1700 * \param [out] commonCellsIArr common cells ids (\ref numbering-indirect)
1701 * \return the correspondance array old to new in a newly allocated array.
1704 void MEDCouplingUMesh::findCommonCells(int compType, int startCellId, DataArrayInt *& commonCellsArr, DataArrayInt *& commonCellsIArr) const
1706 MCAuto<DataArrayInt> revNodal=DataArrayInt::New(),revNodalI=DataArrayInt::New();
1707 getReverseNodalConnectivity(revNodal,revNodalI);
1708 FindCommonCellsAlg(compType,startCellId,_nodal_connec,_nodal_connec_index,revNodal,revNodalI,commonCellsArr,commonCellsIArr);
1711 void MEDCouplingUMesh::FindCommonCellsAlg(int compType, int startCellId, const DataArrayInt *nodal, const DataArrayInt *nodalI, const DataArrayInt *revNodal, const DataArrayInt *revNodalI,
1712 DataArrayInt *& commonCellsArr, DataArrayInt *& commonCellsIArr)
1714 MCAuto<DataArrayInt> commonCells=DataArrayInt::New(),commonCellsI=DataArrayInt::New(); commonCells->alloc(0,1);
1715 int nbOfCells=nodalI->getNumberOfTuples()-1;
1716 commonCellsI->reserve(1); commonCellsI->pushBackSilent(0);
1717 const int *revNodalPtr=revNodal->getConstPointer(),*revNodalIPtr=revNodalI->getConstPointer();
1718 const int *connPtr=nodal->getConstPointer(),*connIPtr=nodalI->getConstPointer();
1719 std::vector<bool> isFetched(nbOfCells,false);
1722 for(int i=0;i<nbOfCells;i++)
1726 const int *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind2nd(std::not_equal_to<int>(),-1));
1727 std::vector<int> v,v2;
1728 if(connOfNode!=connPtr+connIPtr[i+1])
1730 const int *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1731 v2.insert(v2.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1]);
1734 for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1738 const int *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1739 std::vector<int>::iterator it=std::set_intersection(v.begin(),v.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1740 v2.resize(std::distance(v2.begin(),it));
1744 if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1746 int pos=commonCellsI->back();
1747 commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1748 for(const int *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1749 isFetched[*it]=true;
1757 for(int i=startCellId;i<nbOfCells;i++)
1761 const int *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind2nd(std::not_equal_to<int>(),-1));
1762 std::vector<int> v,v2;
1763 if(connOfNode!=connPtr+connIPtr[i+1])
1765 v2.insert(v2.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1]);
1768 for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1772 std::vector<int>::iterator it=std::set_intersection(v.begin(),v.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1773 v2.resize(std::distance(v2.begin(),it));
1777 if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1779 int pos=commonCellsI->back();
1780 commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1781 for(const int *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1782 isFetched[*it]=true;
1788 commonCellsArr=commonCells.retn();
1789 commonCellsIArr=commonCellsI.retn();
1793 * Checks if \a this mesh includes all cells of an \a other mesh, and returns an array
1794 * giving for each cell of the \a other an id of a cell in \a this mesh. A value larger
1795 * than \a this->getNumberOfCells() in the returned array means that there is no
1796 * corresponding cell in \a this mesh.
1797 * It is expected that \a this and \a other meshes share the same node coordinates
1798 * array, if it is not so an exception is thrown.
1799 * \param [in] other - the mesh to compare with.
1800 * \param [in] compType - specifies a cell comparison technique. For meaning of its
1801 * valid values [0,1,2], see zipConnectivityTraducer().
1802 * \param [out] arr - a new instance of DataArrayInt returning correspondence
1803 * between cells of the two meshes. It contains \a other->getNumberOfCells()
1804 * values. The caller is to delete this array using
1805 * decrRef() as it is no more needed.
1806 * \return bool - \c true if all cells of \a other mesh are present in the \a this
1809 * \if ENABLE_EXAMPLES
1810 * \ref cpp_mcumesh_areCellsIncludedIn "Here is a C++ example".<br>
1811 * \ref py_mcumesh_areCellsIncludedIn "Here is a Python example".
1813 * \sa checkDeepEquivalOnSameNodesWith()
1814 * \sa checkGeoEquivalWith()
1816 bool MEDCouplingUMesh::areCellsIncludedIn(const MEDCouplingUMesh *other, int compType, DataArrayInt *& arr) const
1818 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1819 int nbOfCells=getNumberOfCells();
1820 static const int possibleCompType[]={0,1,2};
1821 if(std::find(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),compType)==possibleCompType+sizeof(possibleCompType)/sizeof(int))
1823 std::ostringstream oss; oss << "MEDCouplingUMesh::areCellsIncludedIn : only following policies are possible : ";
1824 std::copy(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),std::ostream_iterator<int>(oss," "));
1826 throw INTERP_KERNEL::Exception(oss.str());
1828 MCAuto<DataArrayInt> o2n=mesh->zipConnectivityTraducer(compType,nbOfCells);
1829 arr=o2n->subArray(nbOfCells);
1830 arr->setName(other->getName());
1832 if(other->getNumberOfCells()==0)
1834 return arr->getMaxValue(tmp)<nbOfCells;
1838 * This method makes the assumption that \a this and \a other share the same coords. If not an exception will be thrown !
1839 * This method tries to determine if \b other is fully included in \b this.
1840 * The main difference is that this method is not expected to throw exception.
1841 * This method has two outputs :
1843 * \param other other mesh
1844 * \param arr is an output parameter that returns a \b newly created instance. This array is of size 'other->getNumberOfCells()'.
1845 * \return If \a other is fully included in 'this 'true is returned. If not false is returned.
1847 bool MEDCouplingUMesh::areCellsIncludedInPolicy7(const MEDCouplingUMesh *other, DataArrayInt *& arr) const
1849 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1850 DataArrayInt *commonCells=0,*commonCellsI=0;
1851 int thisNbCells=getNumberOfCells();
1852 mesh->findCommonCells(7,thisNbCells,commonCells,commonCellsI);
1853 MCAuto<DataArrayInt> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1854 const int *commonCellsPtr=commonCells->getConstPointer(),*commonCellsIPtr=commonCellsI->getConstPointer();
1855 int otherNbCells=other->getNumberOfCells();
1856 MCAuto<DataArrayInt> arr2=DataArrayInt::New();
1857 arr2->alloc(otherNbCells,1);
1858 arr2->fillWithZero();
1859 int *arr2Ptr=arr2->getPointer();
1860 int nbOfCommon=commonCellsI->getNumberOfTuples()-1;
1861 for(int i=0;i<nbOfCommon;i++)
1863 int start=commonCellsPtr[commonCellsIPtr[i]];
1864 if(start<thisNbCells)
1866 for(int j=commonCellsIPtr[i]+1;j!=commonCellsIPtr[i+1];j++)
1868 int sig=commonCellsPtr[j]>0?1:-1;
1869 int val=std::abs(commonCellsPtr[j])-1;
1870 if(val>=thisNbCells)
1871 arr2Ptr[val-thisNbCells]=sig*(start+1);
1875 arr2->setName(other->getName());
1876 if(arr2->presenceOfValue(0))
1882 MEDCouplingUMesh *MEDCouplingUMesh::mergeMyselfWithOnSameCoords(const MEDCouplingPointSet *other) const
1885 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : input other is null !");
1886 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
1888 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : the input other mesh is not of type unstructured !");
1889 std::vector<const MEDCouplingUMesh *> ms(2);
1892 return MergeUMeshesOnSameCoords(ms);
1896 * Build a sub part of \b this lying or not on the same coordinates than \b this (regarding value of \b keepCoords).
1897 * By default coordinates are kept. This method is close to MEDCouplingUMesh::buildPartOfMySelf except that here input
1898 * cellIds is not given explicitely but by a range python like.
1903 * \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.
1904 * \return a newly allocated
1906 * \warning This method modifies can generate an unstructured mesh whose cells are not sorted by geometric type order.
1907 * In view of the MED file writing, a renumbering of cells of returned unstructured mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
1909 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfSlice(int start, int end, int step, bool keepCoords) const
1911 if(getMeshDimension()!=-1)
1912 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelfSlice(start,end,step,keepCoords));
1915 int newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfSlice for -1 dimension mesh ");
1917 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
1919 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
1921 return const_cast<MEDCouplingUMesh *>(this);
1926 * Creates a new MEDCouplingUMesh containing specified cells of \a this mesh.
1927 * The result mesh shares or not the node coordinates array with \a this mesh depending
1928 * on \a keepCoords parameter.
1929 * \warning Cells of the result mesh can be \b not sorted by geometric type, hence,
1930 * to write this mesh to the MED file, its cells must be sorted using
1931 * sortCellsInMEDFileFrmt().
1932 * \param [in] begin - an array of cell ids to include to the new mesh.
1933 * \param [in] end - a pointer to last-plus-one-th element of \a begin.
1934 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
1935 * array of \a this mesh, else "free" nodes are removed from the result mesh
1936 * by calling zipCoords().
1937 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
1938 * to delete this mesh using decrRef() as it is no more needed.
1939 * \throw If the coordinates array is not set.
1940 * \throw If the nodal connectivity of cells is not defined.
1941 * \throw If any cell id in the array \a begin is not valid.
1943 * \if ENABLE_EXAMPLES
1944 * \ref cpp_mcumesh_buildPartOfMySelf "Here is a C++ example".<br>
1945 * \ref py_mcumesh_buildPartOfMySelf "Here is a Python example".
1948 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelf(const int *begin, const int *end, bool keepCoords) const
1950 if(getMeshDimension()!=-1)
1951 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelf(begin,end,keepCoords));
1955 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
1957 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
1959 return const_cast<MEDCouplingUMesh *>(this);
1964 * This method operates only on nodal connectivity on \b this. Coordinates of \b this is completely ignored here.
1966 * 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.
1967 * Size of [ \b cellIdsBg, \b cellIdsEnd ) ) must be equal to the number of cells of otherOnSameCoordsThanThis.
1968 * The number of cells of \b this will remain the same with this method.
1970 * \param [in] cellIdsBg begin of cell ids (included) of cells in this to assign
1971 * \param [in] cellIdsEnd end of cell ids (excluded) of cells in this to assign
1972 * \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 ).
1973 * Coordinate pointer of \b this and those of \b otherOnSameCoordsThanThis must be the same
1975 void MEDCouplingUMesh::setPartOfMySelf(const int *cellIdsBg, const int *cellIdsEnd, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
1977 checkConnectivityFullyDefined();
1978 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
1979 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
1980 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelf : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
1981 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
1983 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
1984 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
1985 throw INTERP_KERNEL::Exception(oss.str());
1987 int nbOfCellsToModify=(int)std::distance(cellIdsBg,cellIdsEnd);
1988 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
1990 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
1991 throw INTERP_KERNEL::Exception(oss.str());
1993 int nbOfCells=getNumberOfCells();
1994 bool easyAssign=true;
1995 const int *connI=_nodal_connec_index->getConstPointer();
1996 const int *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
1997 for(const int *it=cellIdsBg;it!=cellIdsEnd && easyAssign;it++,connIOther++)
1999 if(*it>=0 && *it<nbOfCells)
2001 easyAssign=(connIOther[1]-connIOther[0])==(connI[*it+1]-connI[*it]);
2005 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : On pos #" << std::distance(cellIdsBg,it) << " id is equal to " << *it << " which is not in [0," << nbOfCells << ") !";
2006 throw INTERP_KERNEL::Exception(oss.str());
2011 MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2016 DataArrayInt *arrOut=0,*arrIOut=0;
2017 MEDCouplingUMesh::SetPartOfIndexedArrays(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2019 MCAuto<DataArrayInt> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2020 setConnectivity(arrOut,arrIOut,true);
2024 void MEDCouplingUMesh::setPartOfMySelfSlice(int start, int end, int step, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2026 checkConnectivityFullyDefined();
2027 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2028 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2029 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelfSlice : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2030 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2032 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2033 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2034 throw INTERP_KERNEL::Exception(oss.str());
2036 int nbOfCellsToModify=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::setPartOfMySelfSlice : ");
2037 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2039 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2040 throw INTERP_KERNEL::Exception(oss.str());
2042 int nbOfCells=getNumberOfCells();
2043 bool easyAssign=true;
2044 const int *connI=_nodal_connec_index->getConstPointer();
2045 const int *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2047 for(int i=0;i<nbOfCellsToModify && easyAssign;i++,it+=step,connIOther++)
2049 if(it>=0 && it<nbOfCells)
2051 easyAssign=(connIOther[1]-connIOther[0])==(connI[it+1]-connI[it]);
2055 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : On pos #" << i << " id is equal to " << it << " which is not in [0," << nbOfCells << ") !";
2056 throw INTERP_KERNEL::Exception(oss.str());
2061 MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2066 DataArrayInt *arrOut=0,*arrIOut=0;
2067 MEDCouplingUMesh::SetPartOfIndexedArraysSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2069 MCAuto<DataArrayInt> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2070 setConnectivity(arrOut,arrIOut,true);
2076 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2077 * this->getMeshDimension(), that bound some cells of \a this mesh.
2078 * The cells of lower dimension to include to the result mesh are selected basing on
2079 * specified node ids and the value of \a fullyIn parameter. If \a fullyIn ==\c true, a
2080 * cell is copied if its all nodes are in the array \a begin of node ids. If \a fullyIn
2081 * ==\c false, a cell is copied if any its node is in the array of node ids. The
2082 * created mesh shares the node coordinates array with \a this mesh.
2083 * \param [in] begin - the array of node ids.
2084 * \param [in] end - a pointer to the (last+1)-th element of \a begin.
2085 * \param [in] fullyIn - if \c true, then cells whose all nodes are in the
2086 * array \a begin are added, else cells whose any node is in the
2087 * array \a begin are added.
2088 * \return MEDCouplingUMesh * - new instance of MEDCouplingUMesh. The caller is
2089 * to delete this mesh using decrRef() as it is no more needed.
2090 * \throw If the coordinates array is not set.
2091 * \throw If the nodal connectivity of cells is not defined.
2092 * \throw If any node id in \a begin is not valid.
2094 * \if ENABLE_EXAMPLES
2095 * \ref cpp_mcumesh_buildFacePartOfMySelfNode "Here is a C++ example".<br>
2096 * \ref py_mcumesh_buildFacePartOfMySelfNode "Here is a Python example".
2099 MEDCouplingUMesh *MEDCouplingUMesh::buildFacePartOfMySelfNode(const int *begin, const int *end, bool fullyIn) const
2101 MCAuto<DataArrayInt> desc,descIndx,revDesc,revDescIndx;
2102 desc=DataArrayInt::New(); descIndx=DataArrayInt::New(); revDesc=DataArrayInt::New(); revDescIndx=DataArrayInt::New();
2103 MCAuto<MEDCouplingUMesh> subMesh=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2104 desc=0; descIndx=0; revDesc=0; revDescIndx=0;
2105 return static_cast<MEDCouplingUMesh*>(subMesh->buildPartOfMySelfNode(begin,end,fullyIn));
2109 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2110 * this->getMeshDimension(), which bound only one cell of \a this mesh.
2111 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2112 * array of \a this mesh, else "free" nodes are removed from the result mesh
2113 * by calling zipCoords().
2114 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2115 * to delete this mesh using decrRef() as it is no more needed.
2116 * \throw If the coordinates array is not set.
2117 * \throw If the nodal connectivity of cells is not defined.
2119 * \if ENABLE_EXAMPLES
2120 * \ref cpp_mcumesh_buildBoundaryMesh "Here is a C++ example".<br>
2121 * \ref py_mcumesh_buildBoundaryMesh "Here is a Python example".
2124 MEDCouplingUMesh *MEDCouplingUMesh::buildBoundaryMesh(bool keepCoords) const
2126 DataArrayInt *desc=DataArrayInt::New();
2127 DataArrayInt *descIndx=DataArrayInt::New();
2128 DataArrayInt *revDesc=DataArrayInt::New();
2129 DataArrayInt *revDescIndx=DataArrayInt::New();
2131 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2134 descIndx->decrRef();
2135 int nbOfCells=meshDM1->getNumberOfCells();
2136 const int *revDescIndxC=revDescIndx->getConstPointer();
2137 std::vector<int> boundaryCells;
2138 for(int i=0;i<nbOfCells;i++)
2139 if(revDescIndxC[i+1]-revDescIndxC[i]==1)
2140 boundaryCells.push_back(i);
2141 revDescIndx->decrRef();
2142 MEDCouplingUMesh *ret=meshDM1->buildPartOfMySelf(&boundaryCells[0],&boundaryCells[0]+boundaryCells.size(),keepCoords);
2147 * This method returns a newly created DataArrayInt instance containing ids of cells located in boundary.
2148 * A cell is detected to be on boundary if it contains one or more than one face having only one father.
2149 * This method makes the assumption that \a this is fully defined (coords,connectivity). If not an exception will be thrown.
2151 DataArrayInt *MEDCouplingUMesh::findCellIdsOnBoundary() const
2153 checkFullyDefined();
2154 MCAuto<DataArrayInt> desc=DataArrayInt::New();
2155 MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
2156 MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
2157 MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
2159 buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx)->decrRef();
2160 desc=(DataArrayInt*)0; descIndx=(DataArrayInt*)0;
2162 MCAuto<DataArrayInt> tmp=revDescIndx->deltaShiftIndex();
2163 MCAuto<DataArrayInt> faceIds=tmp->findIdsEqual(1); tmp=(DataArrayInt*)0;
2164 const int *revDescPtr=revDesc->getConstPointer();
2165 const int *revDescIndxPtr=revDescIndx->getConstPointer();
2166 int nbOfCells=getNumberOfCells();
2167 std::vector<bool> ret1(nbOfCells,false);
2169 for(const int *pt=faceIds->begin();pt!=faceIds->end();pt++)
2170 if(!ret1[revDescPtr[revDescIndxPtr[*pt]]])
2171 { ret1[revDescPtr[revDescIndxPtr[*pt]]]=true; sz++; }
2173 DataArrayInt *ret2=DataArrayInt::New();
2175 int *ret2Ptr=ret2->getPointer();
2177 for(std::vector<bool>::const_iterator it=ret1.begin();it!=ret1.end();it++,sz++)
2180 ret2->setName("BoundaryCells");
2185 * This method finds in \b this the cell ids that lie on mesh \b otherDimM1OnSameCoords.
2186 * \b this and \b otherDimM1OnSameCoords have to lie on the same coordinate array pointer. The coherency of that coords array with connectivity
2187 * of \b this and \b otherDimM1OnSameCoords is not important here because this method works only on connectivity.
2188 * this->getMeshDimension() - 1 must be equal to otherDimM1OnSameCoords.getMeshDimension()
2190 * s0 is the cell ids set in \b this lying on at least one node in the fetched nodes in \b otherDimM1OnSameCoords.
2191 * 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
2192 * equals a cell in \b otherDimM1OnSameCoords.
2194 * \throw if \b otherDimM1OnSameCoords is not part of constituent of \b this, or if coordinate pointer of \b this and \b otherDimM1OnSameCoords
2195 * are not same, or if this->getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension()
2197 * \param [in] otherDimM1OnSameCoords
2198 * \param [out] cellIdsRk0 a newly allocated array containing the cell ids of s0 (which are cell ids of \b this) in the above algorithm.
2199 * \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
2200 * cellIdsRk1->transformWithIndArr(cellIdsRk0->begin(),cellIdsRk0->end());
2202 void MEDCouplingUMesh::findCellIdsLyingOn(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayInt *&cellIdsRk0, DataArrayInt *&cellIdsRk1) const
2204 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2205 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : coordinates pointer are not the same ! Use tryToShareSameCoords method !");
2206 checkConnectivityFullyDefined();
2207 otherDimM1OnSameCoords.checkConnectivityFullyDefined();
2208 if(getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension())
2209 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : invalid mesh dimension of input mesh regarding meshdimesion of this !");
2210 MCAuto<DataArrayInt> fetchedNodeIds1=otherDimM1OnSameCoords.computeFetchedNodeIds();
2211 MCAuto<DataArrayInt> s0arr=getCellIdsLyingOnNodes(fetchedNodeIds1->begin(),fetchedNodeIds1->end(),false);
2212 MCAuto<MEDCouplingUMesh> thisPart=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(s0arr->begin(),s0arr->end(),true));
2213 MCAuto<DataArrayInt> descThisPart=DataArrayInt::New(),descIThisPart=DataArrayInt::New(),revDescThisPart=DataArrayInt::New(),revDescIThisPart=DataArrayInt::New();
2214 MCAuto<MEDCouplingUMesh> thisPartConsti=thisPart->buildDescendingConnectivity(descThisPart,descIThisPart,revDescThisPart,revDescIThisPart);
2215 const int *revDescThisPartPtr=revDescThisPart->getConstPointer(),*revDescIThisPartPtr=revDescIThisPart->getConstPointer();
2216 DataArrayInt *idsOtherInConsti=0;
2217 bool b=thisPartConsti->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsOtherInConsti);
2218 MCAuto<DataArrayInt> idsOtherInConstiAuto(idsOtherInConsti);
2220 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : the given mdim-1 mesh in other is not a constituent of this !");
2222 for(const int *idOther=idsOtherInConsti->begin();idOther!=idsOtherInConsti->end();idOther++)
2223 s1.insert(revDescThisPartPtr+revDescIThisPartPtr[*idOther],revDescThisPartPtr+revDescIThisPartPtr[*idOther+1]);
2224 MCAuto<DataArrayInt> s1arr_renum1=DataArrayInt::New(); s1arr_renum1->alloc((int)s1.size(),1); std::copy(s1.begin(),s1.end(),s1arr_renum1->getPointer());
2225 s1arr_renum1->sort();
2226 cellIdsRk0=s0arr.retn();
2227 //cellIdsRk1=s_renum1.retn();
2228 cellIdsRk1=s1arr_renum1.retn();
2232 * 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
2233 * returned. This subpart of meshdim-1 mesh is built using meshdim-1 cells in it shared only one cell in \b this.
2235 * \return a newly allocated mesh lying on the same coordinates than \b this. The caller has to deal with returned mesh.
2237 MEDCouplingUMesh *MEDCouplingUMesh::computeSkin() const
2239 MCAuto<DataArrayInt> desc=DataArrayInt::New();
2240 MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
2241 MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
2242 MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
2244 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2245 revDesc=0; desc=0; descIndx=0;
2246 MCAuto<DataArrayInt> revDescIndx2=revDescIndx->deltaShiftIndex();
2247 MCAuto<DataArrayInt> part=revDescIndx2->findIdsEqual(1);
2248 return static_cast<MEDCouplingUMesh *>(meshDM1->buildPartOfMySelf(part->begin(),part->end(),true));
2252 * Finds nodes lying on the boundary of \a this mesh.
2253 * \return DataArrayInt * - a new instance of DataArrayInt holding ids of found
2254 * nodes. The caller is to delete this array using decrRef() as it is no
2256 * \throw If the coordinates array is not set.
2257 * \throw If the nodal connectivity of cells is node defined.
2259 * \if ENABLE_EXAMPLES
2260 * \ref cpp_mcumesh_findBoundaryNodes "Here is a C++ example".<br>
2261 * \ref py_mcumesh_findBoundaryNodes "Here is a Python example".
2264 DataArrayInt *MEDCouplingUMesh::findBoundaryNodes() const
2266 MCAuto<MEDCouplingUMesh> skin=computeSkin();
2267 return skin->computeFetchedNodeIds();
2270 MEDCouplingUMesh *MEDCouplingUMesh::buildUnstructured() const
2273 return const_cast<MEDCouplingUMesh *>(this);
2277 * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2278 * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2279 * 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.
2280 * 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.
2281 * 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.
2283 * \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
2284 * parameter is altered during the call.
2285 * \param [out] nodeIdsToDuplicate node ids needed to be duplicated following the algorithm explain above.
2286 * \param [out] cellIdsNeededToBeRenum cell ids in \b this in which the renumber of nodes should be performed.
2287 * \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.
2289 * \warning This method modifies param \b otherDimM1OnSameCoords (for speed reasons).
2291 void MEDCouplingUMesh::findNodesToDuplicate(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayInt *& nodeIdsToDuplicate,
2292 DataArrayInt *& cellIdsNeededToBeRenum, DataArrayInt *& cellIdsNotModified) const
2294 typedef MCAuto<DataArrayInt> DAInt;
2295 typedef MCAuto<MEDCouplingUMesh> MCUMesh;
2297 checkFullyDefined();
2298 otherDimM1OnSameCoords.checkFullyDefined();
2299 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2300 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : meshes do not share the same coords array !");
2301 if(otherDimM1OnSameCoords.getMeshDimension()!=getMeshDimension()-1)
2302 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the mesh given in other parameter must have this->getMeshDimension()-1 !");
2304 // Checking star-shaped M1 group:
2305 DAInt dt0=DataArrayInt::New(),dit0=DataArrayInt::New(),rdt0=DataArrayInt::New(),rdit0=DataArrayInt::New();
2306 MCUMesh meshM2 = otherDimM1OnSameCoords.buildDescendingConnectivity(dt0, dit0, rdt0, rdit0);
2307 DAInt dsi = rdit0->deltaShiftIndex();
2308 DAInt idsTmp0 = dsi->findIdsNotInRange(-1, 3);
2309 if(idsTmp0->getNumberOfTuples())
2310 throw INTERP_KERNEL::Exception("MEDFileUMesh::buildInnerBoundaryAlongM1Group: group is too complex: some points (or edges) have more than two connected segments (or faces)!");
2311 dt0=0; dit0=0; rdt0=0; rdit0=0; idsTmp0=0;
2313 // Get extreme nodes from the group (they won't be duplicated), ie nodes belonging to boundary cells of M1
2314 DAInt xtremIdsM2 = dsi->findIdsEqual(1); dsi = 0;
2315 MCUMesh meshM2Part = static_cast<MEDCouplingUMesh *>(meshM2->buildPartOfMySelf(xtremIdsM2->begin(), xtremIdsM2->end(),true));
2316 DAInt xtrem = meshM2Part->computeFetchedNodeIds();
2317 // Remove from the list points on the boundary of the M0 mesh (those need duplication!)
2318 dt0=DataArrayInt::New(),dit0=DataArrayInt::New(),rdt0=DataArrayInt::New(),rdit0=DataArrayInt::New();
2319 MCUMesh m0desc = buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); dt0=0; dit0=0; rdt0=0;
2320 dsi = rdit0->deltaShiftIndex();
2321 DAInt boundSegs = dsi->findIdsEqual(1); // boundary segs/faces of the M0 mesh
2322 MCUMesh m0descSkin = static_cast<MEDCouplingUMesh *>(m0desc->buildPartOfMySelf(boundSegs->begin(),boundSegs->end(), true));
2323 DAInt fNodes = m0descSkin->computeFetchedNodeIds();
2324 // In 3D, some points on the boundary of M0 still need duplication:
2326 if (getMeshDimension() == 3)
2328 DAInt dnu1=DataArrayInt::New(), dnu2=DataArrayInt::New(), dnu3=DataArrayInt::New(), dnu4=DataArrayInt::New();
2329 MCUMesh m0descSkinDesc = m0descSkin->buildDescendingConnectivity(dnu1, dnu2, dnu3, dnu4);
2330 dnu1=0;dnu2=0;dnu3=0;dnu4=0;
2331 DataArrayInt * corresp=0;
2332 meshM2->areCellsIncludedIn(m0descSkinDesc,2,corresp);
2333 DAInt validIds = corresp->findIdsInRange(0, meshM2->getNumberOfCells());
2335 if (validIds->getNumberOfTuples())
2337 MCUMesh m1IntersecSkin = static_cast<MEDCouplingUMesh *>(m0descSkinDesc->buildPartOfMySelf(validIds->begin(), validIds->end(), true));
2338 DAInt notDuplSkin = m1IntersecSkin->findBoundaryNodes();
2339 DAInt fNodes1 = fNodes->buildSubstraction(notDuplSkin);
2340 notDup = xtrem->buildSubstraction(fNodes1);
2343 notDup = xtrem->buildSubstraction(fNodes);
2346 notDup = xtrem->buildSubstraction(fNodes);
2348 // Now compute cells around group (i.e. cells where we will do the propagation to identify the two sub-sets delimited by the group)
2349 DAInt m1Nodes = otherDimM1OnSameCoords.computeFetchedNodeIds();
2350 DAInt dupl = m1Nodes->buildSubstraction(notDup);
2351 DAInt cellsAroundGroup = getCellIdsLyingOnNodes(dupl->begin(), dupl->end(), false); // false= take cell in, even if not all nodes are in notDup
2354 MCUMesh m0Part2=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(cellsAroundGroup->begin(),cellsAroundGroup->end(),true));
2355 int nCells2 = m0Part2->getNumberOfCells();
2356 DAInt desc00=DataArrayInt::New(),descI00=DataArrayInt::New(),revDesc00=DataArrayInt::New(),revDescI00=DataArrayInt::New();
2357 MCUMesh m01=m0Part2->buildDescendingConnectivity(desc00,descI00,revDesc00,revDescI00);
2359 // Neighbor information of the mesh without considering the crack (serves to count how many connex pieces it is made of)
2360 DataArrayInt *tmp00=0,*tmp11=0;
2361 MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00, tmp00, tmp11);
2362 DAInt neighInit00(tmp00);
2363 DAInt neighIInit00(tmp11);
2364 // Neighbor information of the mesh WITH the crack (some neighbors are removed):
2365 DataArrayInt *idsTmp=0;
2366 m01->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsTmp);
2368 // In the neighbor information remove the connection between high dimension cells and its low level constituents which are part
2369 // of the frontier given in parameter (i.e. the cells of low dimension from the group delimiting the crack):
2370 MEDCouplingUMesh::RemoveIdsFromIndexedArrays(ids->begin(),ids->end(),desc00,descI00);
2371 DataArrayInt *tmp0=0,*tmp1=0;
2372 // Compute the neighbor of each cell in m0Part2, taking into account the broken link above. Two
2373 // cells on either side of the crack (defined by the mesh of low dimension) are not neighbor anymore.
2374 ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00,tmp0,tmp1);
2375 DAInt neigh00(tmp0);
2376 DAInt neighI00(tmp1);
2378 // For each initial connex part of the sub-mesh (or said differently for each independent crack):
2379 int seed = 0, nIter = 0;
2380 int nIterMax = nCells2+1; // Safety net for the loop
2381 DAInt hitCells = DataArrayInt::New(); hitCells->alloc(nCells2);
2382 hitCells->fillWithValue(-1);
2383 DAInt cellsToModifyConn0_torenum = DataArrayInt::New();
2384 cellsToModifyConn0_torenum->alloc(0,1);
2385 while (nIter < nIterMax)
2387 DAInt t = hitCells->findIdsEqual(-1);
2388 if (!t->getNumberOfTuples())
2390 // Connex zone without the crack (to compute the next seed really)
2392 DAInt connexCheck = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neighInit00,neighIInit00, -1, dnu);
2394 for (int * ptr = connexCheck->getPointer(); cnt < connexCheck->getNumberOfTuples(); ptr++, cnt++)
2395 hitCells->setIJ(*ptr,0,1);
2396 // Connex zone WITH the crack (to identify cells lying on either part of the crack)
2397 DAInt spreadZone = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neigh00,neighI00, -1, dnu);
2398 cellsToModifyConn0_torenum = DataArrayInt::Aggregate(cellsToModifyConn0_torenum, spreadZone, 0);
2399 // Compute next seed, i.e. a cell in another connex part, which was not covered by the previous iterations
2400 DAInt comple = cellsToModifyConn0_torenum->buildComplement(nCells2);
2401 DAInt nonHitCells = hitCells->findIdsEqual(-1);
2402 DAInt intersec = nonHitCells->buildIntersection(comple);
2403 if (intersec->getNumberOfTuples())
2404 { seed = intersec->getIJ(0,0); }
2409 if (nIter >= nIterMax)
2410 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate(): internal error - too many iterations.");
2412 DAInt cellsToModifyConn1_torenum=cellsToModifyConn0_torenum->buildComplement(neighI00->getNumberOfTuples()-1);
2413 cellsToModifyConn0_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2414 cellsToModifyConn1_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2416 cellIdsNeededToBeRenum=cellsToModifyConn0_torenum.retn();
2417 cellIdsNotModified=cellsToModifyConn1_torenum.retn();
2418 nodeIdsToDuplicate=dupl.retn();
2422 * This method operates a modification of the connectivity and coords in \b this.
2423 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2424 * its ids will be modified to id this->getNumberOfNodes()+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2425 * 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
2426 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id this->getNumberOfNodes()+0, node id nodeIdsToDuplicateBg[1] will have id this->getNumberOfNodes()+1,
2427 * node id nodeIdsToDuplicateBg[2] will have id this->getNumberOfNodes()+2...
2429 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2431 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2432 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2434 void MEDCouplingUMesh::duplicateNodes(const int *nodeIdsToDuplicateBg, const int *nodeIdsToDuplicateEnd)
2436 int nbOfNodes=getNumberOfNodes();
2437 duplicateNodesInCoords(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd);
2438 duplicateNodesInConn(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,nbOfNodes);
2442 * This method renumbers only nodal connectivity in \a this. The renumbering is only an offset applied. So this method is a specialization of
2443 * \a renumberNodesInConn. \b WARNING, this method does not check that the resulting node ids in the nodal connectivity is in a valid range !
2445 * \param [in] offset - specifies the offset to be applied on each element of connectivity.
2447 * \sa renumberNodesInConn
2449 void MEDCouplingUMesh::renumberNodesWithOffsetInConn(int offset)
2451 checkConnectivityFullyDefined();
2452 int *conn(getNodalConnectivity()->getPointer());
2453 const int *connIndex(getNodalConnectivityIndex()->getConstPointer());
2454 int nbOfCells(getNumberOfCells());
2455 for(int i=0;i<nbOfCells;i++)
2456 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2458 int& node=conn[iconn];
2459 if(node>=0)//avoid polyhedron separator
2464 _nodal_connec->declareAsNew();
2469 * Same than renumberNodesInConn(const int *) except that here the format of old-to-new traducer is using map instead
2470 * 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
2473 void MEDCouplingUMesh::renumberNodesInConn(const INTERP_KERNEL::HashMap<int,int>& newNodeNumbersO2N)
2475 checkConnectivityFullyDefined();
2476 int *conn(getNodalConnectivity()->getPointer());
2477 const int *connIndex(getNodalConnectivityIndex()->getConstPointer());
2478 int nbOfCells(getNumberOfCells());
2479 for(int i=0;i<nbOfCells;i++)
2480 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2482 int& node=conn[iconn];
2483 if(node>=0)//avoid polyhedron separator
2485 INTERP_KERNEL::HashMap<int,int>::const_iterator it(newNodeNumbersO2N.find(node));
2486 if(it!=newNodeNumbersO2N.end())
2492 std::ostringstream oss; oss << "MEDCouplingUMesh::renumberNodesInConn(map) : presence in connectivity for cell #" << i << " of node #" << node << " : Not in map !";
2493 throw INTERP_KERNEL::Exception(oss.str());
2497 _nodal_connec->declareAsNew();
2502 * Changes ids of nodes within the nodal connectivity arrays according to a permutation
2503 * array in "Old to New" mode. The node coordinates array is \b not changed by this method.
2504 * This method is a generalization of shiftNodeNumbersInConn().
2505 * \warning This method performs no check of validity of new ids. **Use it with care !**
2506 * \param [in] newNodeNumbersO2N - a permutation array, of length \a
2507 * this->getNumberOfNodes(), in "Old to New" mode.
2508 * See \ref numbering for more info on renumbering modes.
2509 * \throw If the nodal connectivity of cells is not defined.
2511 * \if ENABLE_EXAMPLES
2512 * \ref cpp_mcumesh_renumberNodesInConn "Here is a C++ example".<br>
2513 * \ref py_mcumesh_renumberNodesInConn "Here is a Python example".
2516 void MEDCouplingUMesh::renumberNodesInConn(const int *newNodeNumbersO2N)
2518 checkConnectivityFullyDefined();
2519 int *conn=getNodalConnectivity()->getPointer();
2520 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2521 int nbOfCells(getNumberOfCells());
2522 for(int i=0;i<nbOfCells;i++)
2523 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2525 int& node=conn[iconn];
2526 if(node>=0)//avoid polyhedron separator
2528 node=newNodeNumbersO2N[node];
2531 _nodal_connec->declareAsNew();
2536 * This method renumbers nodes \b in \b connectivity \b only \b without \b any \b reference \b to \b coords.
2537 * This method performs no check on the fact that new coordinate ids are valid. \b Use \b it \b with \b care !
2538 * This method is an specialization of \ref MEDCoupling::MEDCouplingUMesh::renumberNodesInConn "renumberNodesInConn method".
2540 * \param [in] delta specifies the shift size applied to nodeId in nodal connectivity in \b this.
2542 void MEDCouplingUMesh::shiftNodeNumbersInConn(int delta)
2544 checkConnectivityFullyDefined();
2545 int *conn=getNodalConnectivity()->getPointer();
2546 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2547 int nbOfCells=getNumberOfCells();
2548 for(int i=0;i<nbOfCells;i++)
2549 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2551 int& node=conn[iconn];
2552 if(node>=0)//avoid polyhedron separator
2557 _nodal_connec->declareAsNew();
2562 * This method operates a modification of the connectivity in \b this.
2563 * 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.
2564 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2565 * its ids will be modified to id offset+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2566 * 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
2567 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id offset+0, node id nodeIdsToDuplicateBg[1] will have id offset+1,
2568 * node id nodeIdsToDuplicateBg[2] will have id offset+2...
2570 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2571 * As an another consequense after the call of this method \b this can be transiently non cohrent.
2573 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2574 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2575 * \param [in] offset the offset applied to all node ids in connectivity that are in [ \a nodeIdsToDuplicateBg, \a nodeIdsToDuplicateEnd ).
2577 void MEDCouplingUMesh::duplicateNodesInConn(const int *nodeIdsToDuplicateBg, const int *nodeIdsToDuplicateEnd, int offset)
2579 checkConnectivityFullyDefined();
2580 std::map<int,int> m;
2582 for(const int *work=nodeIdsToDuplicateBg;work!=nodeIdsToDuplicateEnd;work++,val++)
2584 int *conn=getNodalConnectivity()->getPointer();
2585 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2586 int nbOfCells=getNumberOfCells();
2587 for(int i=0;i<nbOfCells;i++)
2588 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2590 int& node=conn[iconn];
2591 if(node>=0)//avoid polyhedron separator
2593 std::map<int,int>::iterator it=m.find(node);
2602 * This method renumbers cells of \a this using the array specified by [old2NewBg;old2NewBg+getNumberOfCells())
2604 * Contrary to MEDCouplingPointSet::renumberNodes, this method makes a permutation without any fuse of cell.
2605 * After the call of this method the number of cells remains the same as before.
2607 * If 'check' equals true the method will check that any elements in [ \a old2NewBg; \a old2NewEnd ) is unique ; if not
2608 * an INTERP_KERNEL::Exception will be thrown. When 'check' equals true [ \a old2NewBg ; \a old2NewEnd ) is not expected to
2609 * be strictly in [0;this->getNumberOfCells()).
2611 * If 'check' equals false the method will not check the content of [ \a old2NewBg ; \a old2NewEnd ).
2612 * To avoid any throw of SIGSEGV when 'check' equals false, the elements in [ \a old2NewBg ; \a old2NewEnd ) should be unique and
2613 * should be contained in[0;this->getNumberOfCells()).
2615 * \param [in] old2NewBg is expected to be a dynamically allocated pointer of size at least equal to this->getNumberOfCells()
2618 void MEDCouplingUMesh::renumberCells(const int *old2NewBg, bool check)
2620 checkConnectivityFullyDefined();
2621 int nbCells=getNumberOfCells();
2622 const int *array=old2NewBg;
2624 array=DataArrayInt::CheckAndPreparePermutation(old2NewBg,old2NewBg+nbCells);
2626 const int *conn=_nodal_connec->getConstPointer();
2627 const int *connI=_nodal_connec_index->getConstPointer();
2628 MCAuto<DataArrayInt> o2n=DataArrayInt::New(); o2n->useArray(array,false,C_DEALLOC,nbCells,1);
2629 MCAuto<DataArrayInt> n2o=o2n->invertArrayO2N2N2O(nbCells);
2630 const int *n2oPtr=n2o->begin();
2631 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
2632 newConn->alloc(_nodal_connec->getNumberOfTuples(),_nodal_connec->getNumberOfComponents());
2633 newConn->copyStringInfoFrom(*_nodal_connec);
2634 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
2635 newConnI->alloc(_nodal_connec_index->getNumberOfTuples(),_nodal_connec_index->getNumberOfComponents());
2636 newConnI->copyStringInfoFrom(*_nodal_connec_index);
2638 int *newC=newConn->getPointer();
2639 int *newCI=newConnI->getPointer();
2642 for(int i=0;i<nbCells;i++)
2645 int nbOfElts=connI[pos+1]-connI[pos];
2646 newC=std::copy(conn+connI[pos],conn+connI[pos+1],newC);
2651 setConnectivity(newConn,newConnI);
2653 free(const_cast<int *>(array));
2657 * Finds cells whose bounding boxes intersect a given bounding box.
2658 * \param [in] bbox - an array defining the bounding box via coordinates of its
2659 * extremum points in "no interlace" mode, i.e. xMin, xMax, yMin, yMax, zMin,
2661 * \param [in] eps - a factor used to increase size of the bounding box of cell
2662 * before comparing it with \a bbox. This factor is multiplied by the maximal
2663 * extent of the bounding box of cell to produce an addition to this bounding box.
2664 * \return DataArrayInt * - a new instance of DataArrayInt holding ids for found
2665 * cells. The caller is to delete this array using decrRef() as it is no more
2667 * \throw If the coordinates array is not set.
2668 * \throw If the nodal connectivity of cells is not defined.
2670 * \if ENABLE_EXAMPLES
2671 * \ref cpp_mcumesh_getCellsInBoundingBox "Here is a C++ example".<br>
2672 * \ref py_mcumesh_getCellsInBoundingBox "Here is a Python example".
2675 DataArrayInt *MEDCouplingUMesh::getCellsInBoundingBox(const double *bbox, double eps) const
2677 MCAuto<DataArrayInt> elems=DataArrayInt::New(); elems->alloc(0,1);
2678 if(getMeshDimension()==-1)
2680 elems->pushBackSilent(0);
2681 return elems.retn();
2683 int dim=getSpaceDimension();
2684 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2685 const int* conn = getNodalConnectivity()->getConstPointer();
2686 const int* conn_index= getNodalConnectivityIndex()->getConstPointer();
2687 const double* coords = getCoords()->getConstPointer();
2688 int nbOfCells=getNumberOfCells();
2689 for ( int ielem=0; ielem<nbOfCells;ielem++ )
2691 for (int i=0; i<dim; i++)
2693 elem_bb[i*2]=std::numeric_limits<double>::max();
2694 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2697 for (int inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2699 int node= conn[inode];
2700 if(node>=0)//avoid polyhedron separator
2702 for (int idim=0; idim<dim; idim++)
2704 if ( coords[node*dim+idim] < elem_bb[idim*2] )
2706 elem_bb[idim*2] = coords[node*dim+idim] ;
2708 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2710 elem_bb[idim*2+1] = coords[node*dim+idim] ;
2715 if (intersectsBoundingBox(elem_bb, bbox, dim, eps))
2716 elems->pushBackSilent(ielem);
2718 return elems.retn();
2722 * Given a boundary box 'bbox' returns elements 'elems' contained in this 'bbox' or touching 'bbox' (within 'eps' distance).
2723 * Warning 'elems' is incremented during the call so if elems is not empty before call returned elements will be
2724 * added in 'elems' parameter.
2726 DataArrayInt *MEDCouplingUMesh::getCellsInBoundingBox(const INTERP_KERNEL::DirectedBoundingBox& bbox, double eps)
2728 MCAuto<DataArrayInt> elems=DataArrayInt::New(); elems->alloc(0,1);
2729 if(getMeshDimension()==-1)
2731 elems->pushBackSilent(0);
2732 return elems.retn();
2734 int dim=getSpaceDimension();
2735 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2736 const int* conn = getNodalConnectivity()->getConstPointer();
2737 const int* conn_index= getNodalConnectivityIndex()->getConstPointer();
2738 const double* coords = getCoords()->getConstPointer();
2739 int nbOfCells=getNumberOfCells();
2740 for ( int ielem=0; ielem<nbOfCells;ielem++ )
2742 for (int i=0; i<dim; i++)
2744 elem_bb[i*2]=std::numeric_limits<double>::max();
2745 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2748 for (int inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2750 int node= conn[inode];
2751 if(node>=0)//avoid polyhedron separator
2753 for (int idim=0; idim<dim; idim++)
2755 if ( coords[node*dim+idim] < elem_bb[idim*2] )
2757 elem_bb[idim*2] = coords[node*dim+idim] ;
2759 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2761 elem_bb[idim*2+1] = coords[node*dim+idim] ;
2766 if(intersectsBoundingBox(bbox, elem_bb, dim, eps))
2767 elems->pushBackSilent(ielem);
2769 return elems.retn();
2773 * Returns a type of a cell by its id.
2774 * \param [in] cellId - the id of the cell of interest.
2775 * \return INTERP_KERNEL::NormalizedCellType - enumeration item describing the cell type.
2776 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2778 INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::getTypeOfCell(int cellId) const
2780 const int *ptI=_nodal_connec_index->getConstPointer();
2781 const int *pt=_nodal_connec->getConstPointer();
2782 if(cellId>=0 && cellId<(int)_nodal_connec_index->getNbOfElems()-1)
2783 return (INTERP_KERNEL::NormalizedCellType) pt[ptI[cellId]];
2786 std::ostringstream oss; oss << "MEDCouplingUMesh::getTypeOfCell : Requesting type of cell #" << cellId << " but it should be in [0," << _nodal_connec_index->getNbOfElems()-1 << ") !";
2787 throw INTERP_KERNEL::Exception(oss.str());
2792 * This method returns a newly allocated array containing cell ids (ascendingly sorted) whose geometric type are equal to type.
2793 * This method does not throw exception if geometric type \a type is not in \a this.
2794 * This method throws an INTERP_KERNEL::Exception if meshdimension of \b this is not equal to those of \b type.
2795 * The coordinates array is not considered here.
2797 * \param [in] type the geometric type
2798 * \return cell ids in this having geometric type \a type.
2800 DataArrayInt *MEDCouplingUMesh::giveCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2803 MCAuto<DataArrayInt> ret=DataArrayInt::New();
2805 checkConnectivityFullyDefined();
2806 int nbCells=getNumberOfCells();
2807 int mdim=getMeshDimension();
2808 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
2809 if(mdim!=(int)cm.getDimension())
2810 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::giveCellsWithType : Mismatch between mesh dimension and dimension of the cell !");
2811 const int *ptI=_nodal_connec_index->getConstPointer();
2812 const int *pt=_nodal_connec->getConstPointer();
2813 for(int i=0;i<nbCells;i++)
2815 if((INTERP_KERNEL::NormalizedCellType)pt[ptI[i]]==type)
2816 ret->pushBackSilent(i);
2822 * Returns nb of cells having the geometric type \a type. No throw if no cells in \a this has the geometric type \a type.
2824 int MEDCouplingUMesh::getNumberOfCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2826 const int *ptI=_nodal_connec_index->getConstPointer();
2827 const int *pt=_nodal_connec->getConstPointer();
2828 int nbOfCells=getNumberOfCells();
2830 for(int i=0;i<nbOfCells;i++)
2831 if((INTERP_KERNEL::NormalizedCellType) pt[ptI[i]]==type)
2837 * Returns the nodal connectivity of a given cell.
2838 * The separator of faces within polyhedron connectivity (-1) is not returned, thus
2839 * all returned node ids can be used in getCoordinatesOfNode().
2840 * \param [in] cellId - an id of the cell of interest.
2841 * \param [in,out] conn - a vector where the node ids are appended. It is not
2842 * cleared before the appending.
2843 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2845 void MEDCouplingUMesh::getNodeIdsOfCell(int cellId, std::vector<int>& conn) const
2847 const int *ptI=_nodal_connec_index->getConstPointer();
2848 const int *pt=_nodal_connec->getConstPointer();
2849 for(const int *w=pt+ptI[cellId]+1;w!=pt+ptI[cellId+1];w++)
2854 std::string MEDCouplingUMesh::simpleRepr() const
2856 static const char msg0[]="No coordinates specified !";
2857 std::ostringstream ret;
2858 ret << "Unstructured mesh with name : \"" << getName() << "\"\n";
2859 ret << "Description of mesh : \"" << getDescription() << "\"\n";
2861 double tt=getTime(tmpp1,tmpp2);
2862 ret << "Time attached to the mesh [unit] : " << tt << " [" << getTimeUnit() << "]\n";
2863 ret << "Iteration : " << tmpp1 << " Order : " << tmpp2 << "\n";
2865 { ret << "Mesh dimension : " << _mesh_dim << "\nSpace dimension : "; }
2867 { ret << " Mesh dimension has not been set or is invalid !"; }
2870 const int spaceDim=getSpaceDimension();
2871 ret << spaceDim << "\nInfo attached on space dimension : ";
2872 for(int i=0;i<spaceDim;i++)
2873 ret << "\"" << _coords->getInfoOnComponent(i) << "\" ";
2877 ret << msg0 << "\n";
2878 ret << "Number of nodes : ";
2880 ret << getNumberOfNodes() << "\n";
2882 ret << msg0 << "\n";
2883 ret << "Number of cells : ";
2884 if(_nodal_connec!=0 && _nodal_connec_index!=0)
2885 ret << getNumberOfCells() << "\n";
2887 ret << "No connectivity specified !" << "\n";
2888 ret << "Cell types present : ";
2889 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
2891 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter);
2892 ret << cm.getRepr() << " ";
2898 std::string MEDCouplingUMesh::advancedRepr() const
2900 std::ostringstream ret;
2901 ret << simpleRepr();
2902 ret << "\nCoordinates array : \n___________________\n\n";
2904 _coords->reprWithoutNameStream(ret);
2906 ret << "No array set !\n";
2907 ret << "\n\nConnectivity arrays : \n_____________________\n\n";
2908 reprConnectivityOfThisLL(ret);
2913 * This method returns a C++ code that is a dump of \a this.
2914 * This method will throw if this is not fully defined.
2916 std::string MEDCouplingUMesh::cppRepr() const
2918 static const char coordsName[]="coords";
2919 static const char connName[]="conn";
2920 static const char connIName[]="connI";
2921 checkFullyDefined();
2922 std::ostringstream ret; ret << "// coordinates" << std::endl;
2923 _coords->reprCppStream(coordsName,ret); ret << std::endl << "// connectivity" << std::endl;
2924 _nodal_connec->reprCppStream(connName,ret); ret << std::endl;
2925 _nodal_connec_index->reprCppStream(connIName,ret); ret << std::endl;
2926 ret << "MEDCouplingUMesh *mesh=MEDCouplingUMesh::New(\"" << getName() << "\"," << getMeshDimension() << ");" << std::endl;
2927 ret << "mesh->setCoords(" << coordsName << ");" << std::endl;
2928 ret << "mesh->setConnectivity(" << connName << "," << connIName << ",true);" << std::endl;
2929 ret << coordsName << "->decrRef(); " << connName << "->decrRef(); " << connIName << "->decrRef();" << std::endl;
2933 std::string MEDCouplingUMesh::reprConnectivityOfThis() const
2935 std::ostringstream ret;
2936 reprConnectivityOfThisLL(ret);
2941 * This method builds a newly allocated instance (with the same name than \a this) that the caller has the responsability to deal with.
2942 * This method returns an instance with all arrays allocated (connectivity, connectivity index, coordinates)
2943 * but with length of these arrays set to 0. It allows to define an "empty" mesh (with nor cells nor nodes but compliant with
2946 * This method expects that \a this has a mesh dimension set and higher or equal to 0. If not an exception will be thrown.
2947 * 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
2948 * with number of tuples set to 0, if not the array is taken as this in the returned instance.
2950 MEDCouplingUMesh *MEDCouplingUMesh::buildSetInstanceFromThis(int spaceDim) const
2952 int mdim=getMeshDimension();
2954 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSetInstanceFromThis : invalid mesh dimension ! Should be >= 0 !");
2955 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
2956 MCAuto<DataArrayInt> tmp1,tmp2;
2957 bool needToCpyCT=true;
2960 tmp1=DataArrayInt::New(); tmp1->alloc(0,1);
2968 if(!_nodal_connec_index)
2970 tmp2=DataArrayInt::New(); tmp2->alloc(1,1); tmp2->setIJ(0,0,0);
2975 tmp2=_nodal_connec_index;
2978 ret->setConnectivity(tmp1,tmp2,false);
2983 MCAuto<DataArrayDouble> coords=DataArrayDouble::New(); coords->alloc(0,spaceDim);
2984 ret->setCoords(coords);
2987 ret->setCoords(_coords);
2991 int MEDCouplingUMesh::getNumberOfNodesInCell(int cellId) const
2993 const int *ptI=_nodal_connec_index->getConstPointer();
2994 const int *pt=_nodal_connec->getConstPointer();
2995 if(pt[ptI[cellId]]!=INTERP_KERNEL::NORM_POLYHED)
2996 return ptI[cellId+1]-ptI[cellId]-1;
2998 return (int)std::count_if(pt+ptI[cellId]+1,pt+ptI[cellId+1],std::bind2nd(std::not_equal_to<int>(),-1));
3002 * Returns types of cells of the specified part of \a this mesh.
3003 * This method avoids computing sub-mesh explicitely to get its types.
3004 * \param [in] begin - an array of cell ids of interest.
3005 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3006 * \return std::set<INTERP_KERNEL::NormalizedCellType> - a set of enumeration items
3007 * describing the cell types.
3008 * \throw If the coordinates array is not set.
3009 * \throw If the nodal connectivity of cells is not defined.
3010 * \sa getAllGeoTypes()
3012 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getTypesOfPart(const int *begin, const int *end) const
3014 checkFullyDefined();
3015 std::set<INTERP_KERNEL::NormalizedCellType> ret;
3016 const int *conn=_nodal_connec->getConstPointer();
3017 const int *connIndex=_nodal_connec_index->getConstPointer();
3018 for(const int *w=begin;w!=end;w++)
3019 ret.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]);
3024 * Defines the nodal connectivity using given connectivity arrays in \ref numbering-indirect format.
3025 * Optionally updates
3026 * a set of types of cells constituting \a this mesh.
3027 * This method is for advanced users having prepared their connectivity before. For
3028 * more info on using this method see \ref MEDCouplingUMeshAdvBuild.
3029 * \param [in] conn - the nodal connectivity array.
3030 * \param [in] connIndex - the nodal connectivity index array.
3031 * \param [in] isComputingTypes - if \c true, the set of types constituting \a this
3034 void MEDCouplingUMesh::setConnectivity(DataArrayInt *conn, DataArrayInt *connIndex, bool isComputingTypes)
3036 DataArrayInt::SetArrayIn(conn,_nodal_connec);
3037 DataArrayInt::SetArrayIn(connIndex,_nodal_connec_index);
3038 if(isComputingTypes)
3044 * Copy constructor. If 'deepCopy' is false \a this is a shallow copy of other.
3045 * If 'deeCpy' is true all arrays (coordinates and connectivities) are deeply copied.
3047 MEDCouplingUMesh::MEDCouplingUMesh(const MEDCouplingUMesh& other, bool deepCpy):MEDCouplingPointSet(other,deepCpy),_mesh_dim(other._mesh_dim),
3048 _nodal_connec(0),_nodal_connec_index(0),
3049 _types(other._types)
3051 if(other._nodal_connec)
3052 _nodal_connec=other._nodal_connec->performCopyOrIncrRef(deepCpy);
3053 if(other._nodal_connec_index)
3054 _nodal_connec_index=other._nodal_connec_index->performCopyOrIncrRef(deepCpy);
3057 MEDCouplingUMesh::~MEDCouplingUMesh()
3060 _nodal_connec->decrRef();
3061 if(_nodal_connec_index)
3062 _nodal_connec_index->decrRef();
3066 * Recomputes a set of cell types of \a this mesh. For more info see
3067 * \ref MEDCouplingUMeshNodalConnectivity.
3069 void MEDCouplingUMesh::computeTypes()
3071 ComputeAllTypesInternal(_types,_nodal_connec,_nodal_connec_index);
3076 * Returns a number of cells constituting \a this mesh.
3077 * \return int - the number of cells in \a this mesh.
3078 * \throw If the nodal connectivity of cells is not defined.
3080 int MEDCouplingUMesh::getNumberOfCells() const
3082 if(_nodal_connec_index)
3083 return _nodal_connec_index->getNumberOfTuples()-1;
3088 throw INTERP_KERNEL::Exception("Unable to get number of cells because no connectivity specified !");
3092 * Returns a dimension of \a this mesh, i.e. a dimension of cells constituting \a this
3093 * mesh. For more info see \ref meshes.
3094 * \return int - the dimension of \a this mesh.
3095 * \throw If the mesh dimension is not defined using setMeshDimension().
3097 int MEDCouplingUMesh::getMeshDimension() const
3100 throw INTERP_KERNEL::Exception("No mesh dimension specified !");
3105 * Returns a length of the nodal connectivity array.
3106 * This method is for test reason. Normally the integer returned is not useable by
3107 * user. For more info see \ref MEDCouplingUMeshNodalConnectivity.
3108 * \return int - the length of the nodal connectivity array.
3110 int MEDCouplingUMesh::getNodalConnectivityArrayLen() const
3112 return _nodal_connec->getNbOfElems();
3116 * First step of serialization process. Used by ParaMEDMEM and MEDCouplingCorba to transfert data between process.
3118 void MEDCouplingUMesh::getTinySerializationInformation(std::vector<double>& tinyInfoD, std::vector<int>& tinyInfo, std::vector<std::string>& littleStrings) const
3120 MEDCouplingPointSet::getTinySerializationInformation(tinyInfoD,tinyInfo,littleStrings);
3121 tinyInfo.push_back(getMeshDimension());
3122 tinyInfo.push_back(getNumberOfCells());
3124 tinyInfo.push_back(getNodalConnectivityArrayLen());
3126 tinyInfo.push_back(-1);
3130 * First step of unserialization process.
3132 bool MEDCouplingUMesh::isEmptyMesh(const std::vector<int>& tinyInfo) const
3134 return tinyInfo[6]<=0;
3138 * Second step of serialization process.
3139 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3142 * \param littleStrings
3144 void MEDCouplingUMesh::resizeForUnserialization(const std::vector<int>& tinyInfo, DataArrayInt *a1, DataArrayDouble *a2, std::vector<std::string>& littleStrings) const
3146 MEDCouplingPointSet::resizeForUnserialization(tinyInfo,a1,a2,littleStrings);
3148 a1->alloc(tinyInfo[7]+tinyInfo[6]+1,1);
3152 * Third and final step of serialization process.
3154 void MEDCouplingUMesh::serialize(DataArrayInt *&a1, DataArrayDouble *&a2) const
3156 MEDCouplingPointSet::serialize(a1,a2);
3157 if(getMeshDimension()>-1)
3159 a1=DataArrayInt::New();
3160 a1->alloc(getNodalConnectivityArrayLen()+getNumberOfCells()+1,1);
3161 int *ptA1=a1->getPointer();
3162 const int *conn=getNodalConnectivity()->getConstPointer();
3163 const int *index=getNodalConnectivityIndex()->getConstPointer();
3164 ptA1=std::copy(index,index+getNumberOfCells()+1,ptA1);
3165 std::copy(conn,conn+getNodalConnectivityArrayLen(),ptA1);
3172 * Second and final unserialization process.
3173 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3175 void MEDCouplingUMesh::unserialization(const std::vector<double>& tinyInfoD, const std::vector<int>& tinyInfo, const DataArrayInt *a1, DataArrayDouble *a2, const std::vector<std::string>& littleStrings)
3177 MEDCouplingPointSet::unserialization(tinyInfoD,tinyInfo,a1,a2,littleStrings);
3178 setMeshDimension(tinyInfo[5]);
3182 const int *recvBuffer=a1->getConstPointer();
3183 MCAuto<DataArrayInt> myConnecIndex=DataArrayInt::New();
3184 myConnecIndex->alloc(tinyInfo[6]+1,1);
3185 std::copy(recvBuffer,recvBuffer+tinyInfo[6]+1,myConnecIndex->getPointer());
3186 MCAuto<DataArrayInt> myConnec=DataArrayInt::New();
3187 myConnec->alloc(tinyInfo[7],1);
3188 std::copy(recvBuffer+tinyInfo[6]+1,recvBuffer+tinyInfo[6]+1+tinyInfo[7],myConnec->getPointer());
3189 setConnectivity(myConnec, myConnecIndex);
3196 * Returns a new MEDCouplingFieldDouble containing volumes of cells constituting \a this
3198 * For 1D cells, the returned field contains lengths.<br>
3199 * For 2D cells, the returned field contains areas.<br>
3200 * For 3D cells, the returned field contains volumes.
3201 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3202 * orientation, i.e. the volume is always positive.
3203 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on cells
3204 * and one time . The caller is to delete this field using decrRef() as it is no
3207 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureField(bool isAbs) const
3209 std::string name="MeasureOfMesh_";
3211 int nbelem=getNumberOfCells();
3212 MCAuto<MEDCouplingFieldDouble> field=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3213 field->setName(name);
3214 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3215 array->alloc(nbelem,1);
3216 double *area_vol=array->getPointer();
3217 field->setArray(array) ; array=0;
3218 field->setMesh(const_cast<MEDCouplingUMesh *>(this));
3219 field->synchronizeTimeWithMesh();
3220 if(getMeshDimension()!=-1)
3223 INTERP_KERNEL::NormalizedCellType type;
3224 int dim_space=getSpaceDimension();
3225 const double *coords=getCoords()->getConstPointer();
3226 const int *connec=getNodalConnectivity()->getConstPointer();
3227 const int *connec_index=getNodalConnectivityIndex()->getConstPointer();
3228 for(int iel=0;iel<nbelem;iel++)
3230 ipt=connec_index[iel];
3231 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3232 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);
3235 std::transform(area_vol,area_vol+nbelem,area_vol,std::ptr_fun<double,double>(fabs));
3239 area_vol[0]=std::numeric_limits<double>::max();
3241 return field.retn();
3245 * Returns a new DataArrayDouble containing volumes of specified cells of \a this
3247 * For 1D cells, the returned array contains lengths.<br>
3248 * For 2D cells, the returned array contains areas.<br>
3249 * For 3D cells, the returned array contains volumes.
3250 * This method avoids building explicitly a part of \a this mesh to perform the work.
3251 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3252 * orientation, i.e. the volume is always positive.
3253 * \param [in] begin - an array of cell ids of interest.
3254 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3255 * \return DataArrayDouble * - a new instance of DataArrayDouble. The caller is to
3256 * delete this array using decrRef() as it is no more needed.
3258 * \if ENABLE_EXAMPLES
3259 * \ref cpp_mcumesh_getPartMeasureField "Here is a C++ example".<br>
3260 * \ref py_mcumesh_getPartMeasureField "Here is a Python example".
3262 * \sa getMeasureField()
3264 DataArrayDouble *MEDCouplingUMesh::getPartMeasureField(bool isAbs, const int *begin, const int *end) const
3266 std::string name="PartMeasureOfMesh_";
3268 int nbelem=(int)std::distance(begin,end);
3269 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3270 array->setName(name);
3271 array->alloc(nbelem,1);
3272 double *area_vol=array->getPointer();
3273 if(getMeshDimension()!=-1)
3276 INTERP_KERNEL::NormalizedCellType type;
3277 int dim_space=getSpaceDimension();
3278 const double *coords=getCoords()->getConstPointer();
3279 const int *connec=getNodalConnectivity()->getConstPointer();
3280 const int *connec_index=getNodalConnectivityIndex()->getConstPointer();
3281 for(const int *iel=begin;iel!=end;iel++)
3283 ipt=connec_index[*iel];
3284 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3285 *area_vol++=INTERP_KERNEL::computeVolSurfOfCell2<int,INTERP_KERNEL::ALL_C_MODE>(type,connec+ipt+1,connec_index[*iel+1]-ipt-1,coords,dim_space);
3288 std::transform(array->getPointer(),area_vol,array->getPointer(),std::ptr_fun<double,double>(fabs));
3292 area_vol[0]=std::numeric_limits<double>::max();
3294 return array.retn();
3298 * Returns a new MEDCouplingFieldDouble containing volumes of cells of a dual mesh of
3299 * \a this one. The returned field contains the dual cell volume for each corresponding
3300 * node in \a this mesh. In other words, the field returns the getMeasureField() of
3301 * the dual mesh in P1 sens of \a this.<br>
3302 * For 1D cells, the returned field contains lengths.<br>
3303 * For 2D cells, the returned field contains areas.<br>
3304 * For 3D cells, the returned field contains volumes.
3305 * This method is useful to check "P1*" conservative interpolators.
3306 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3307 * orientation, i.e. the volume is always positive.
3308 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3309 * nodes and one time. The caller is to delete this array using decrRef() as
3310 * it is no more needed.
3312 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureFieldOnNode(bool isAbs) const
3314 MCAuto<MEDCouplingFieldDouble> tmp=getMeasureField(isAbs);
3315 std::string name="MeasureOnNodeOfMesh_";
3317 int nbNodes=getNumberOfNodes();
3318 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_NODES);
3319 double cst=1./((double)getMeshDimension()+1.);
3320 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3321 array->alloc(nbNodes,1);
3322 double *valsToFill=array->getPointer();
3323 std::fill(valsToFill,valsToFill+nbNodes,0.);
3324 const double *values=tmp->getArray()->getConstPointer();
3325 MCAuto<DataArrayInt> da=DataArrayInt::New();
3326 MCAuto<DataArrayInt> daInd=DataArrayInt::New();
3327 getReverseNodalConnectivity(da,daInd);
3328 const int *daPtr=da->getConstPointer();
3329 const int *daIPtr=daInd->getConstPointer();
3330 for(int i=0;i<nbNodes;i++)
3331 for(const int *cell=daPtr+daIPtr[i];cell!=daPtr+daIPtr[i+1];cell++)
3332 valsToFill[i]+=cst*values[*cell];
3334 ret->setArray(array);
3339 * Returns a new MEDCouplingFieldDouble holding normal vectors to cells of \a this
3340 * mesh. The returned normal vectors to each cell have a norm2 equal to 1.
3341 * The computed vectors have <em> this->getMeshDimension()+1 </em> components
3342 * and are normalized.
3343 * <br> \a this can be either
3344 * - a 2D mesh in 2D or 3D space or
3345 * - an 1D mesh in 2D space.
3347 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3348 * cells and one time. The caller is to delete this field using decrRef() as
3349 * it is no more needed.
3350 * \throw If the nodal connectivity of cells is not defined.
3351 * \throw If the coordinates array is not set.
3352 * \throw If the mesh dimension is not set.
3353 * \throw If the mesh and space dimension is not as specified above.
3355 MEDCouplingFieldDouble *MEDCouplingUMesh::buildOrthogonalField() const
3357 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3358 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3359 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3360 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3361 int nbOfCells=getNumberOfCells();
3362 int nbComp=getMeshDimension()+1;
3363 array->alloc(nbOfCells,nbComp);
3364 double *vals=array->getPointer();
3365 const int *connI=_nodal_connec_index->getConstPointer();
3366 const int *conn=_nodal_connec->getConstPointer();
3367 const double *coords=_coords->getConstPointer();
3368 if(getMeshDimension()==2)
3370 if(getSpaceDimension()==3)
3372 MCAuto<DataArrayDouble> loc=computeCellCenterOfMass();
3373 const double *locPtr=loc->getConstPointer();
3374 for(int i=0;i<nbOfCells;i++,vals+=3)
3376 int offset=connI[i];
3377 INTERP_KERNEL::crossprod<3>(locPtr+3*i,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3378 double n=INTERP_KERNEL::norm<3>(vals);
3379 std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3384 MCAuto<MEDCouplingFieldDouble> isAbs=getMeasureField(false);
3385 const double *isAbsPtr=isAbs->getArray()->begin();
3386 for(int i=0;i<nbOfCells;i++,isAbsPtr++)
3387 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=*isAbsPtr>0.?1.:-1.; }
3390 else//meshdimension==1
3393 for(int i=0;i<nbOfCells;i++)
3395 int offset=connI[i];
3396 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3397 double n=INTERP_KERNEL::norm<2>(tmp);
3398 std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3403 ret->setArray(array);
3405 ret->synchronizeTimeWithSupport();
3410 * Returns a new MEDCouplingFieldDouble holding normal vectors to specified cells of
3411 * \a this mesh. The computed vectors have <em> this->getMeshDimension()+1 </em> components
3412 * and are normalized.
3413 * <br> \a this can be either
3414 * - a 2D mesh in 2D or 3D space or
3415 * - an 1D mesh in 2D space.
3417 * This method avoids building explicitly a part of \a this mesh to perform the work.
3418 * \param [in] begin - an array of cell ids of interest.
3419 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3420 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3421 * cells and one time. The caller is to delete this field using decrRef() as
3422 * it is no more needed.
3423 * \throw If the nodal connectivity of cells is not defined.
3424 * \throw If the coordinates array is not set.
3425 * \throw If the mesh dimension is not set.
3426 * \throw If the mesh and space dimension is not as specified above.
3427 * \sa buildOrthogonalField()
3429 * \if ENABLE_EXAMPLES
3430 * \ref cpp_mcumesh_buildPartOrthogonalField "Here is a C++ example".<br>
3431 * \ref py_mcumesh_buildPartOrthogonalField "Here is a Python example".
3434 MEDCouplingFieldDouble *MEDCouplingUMesh::buildPartOrthogonalField(const int *begin, const int *end) const
3436 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3437 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3438 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3439 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3440 std::size_t nbelems=std::distance(begin,end);
3441 int nbComp=getMeshDimension()+1;
3442 array->alloc((int)nbelems,nbComp);
3443 double *vals=array->getPointer();
3444 const int *connI=_nodal_connec_index->getConstPointer();
3445 const int *conn=_nodal_connec->getConstPointer();
3446 const double *coords=_coords->getConstPointer();
3447 if(getMeshDimension()==2)
3449 if(getSpaceDimension()==3)
3451 MCAuto<DataArrayDouble> loc=getPartBarycenterAndOwner(begin,end);
3452 const double *locPtr=loc->getConstPointer();
3453 for(const int *i=begin;i!=end;i++,vals+=3,locPtr+=3)
3455 int offset=connI[*i];
3456 INTERP_KERNEL::crossprod<3>(locPtr,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3457 double n=INTERP_KERNEL::norm<3>(vals);
3458 std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3463 for(std::size_t i=0;i<nbelems;i++)
3464 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=1.; }
3467 else//meshdimension==1
3470 for(const int *i=begin;i!=end;i++)
3472 int offset=connI[*i];
3473 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3474 double n=INTERP_KERNEL::norm<2>(tmp);
3475 std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3480 ret->setArray(array);
3482 ret->synchronizeTimeWithSupport();
3487 * Returns a new MEDCouplingFieldDouble holding a direction vector for each SEG2 in \a
3488 * this 1D mesh. The computed vectors have <em> this->getSpaceDimension() </em> components
3489 * and are \b not normalized.
3490 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3491 * cells and one time. The caller is to delete this field using decrRef() as
3492 * it is no more needed.
3493 * \throw If the nodal connectivity of cells is not defined.
3494 * \throw If the coordinates array is not set.
3495 * \throw If \a this->getMeshDimension() != 1.
3496 * \throw If \a this mesh includes cells of type other than SEG2.
3498 MEDCouplingFieldDouble *MEDCouplingUMesh::buildDirectionVectorField() const
3500 if(getMeshDimension()!=1)
3501 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for buildDirectionVectorField !");
3502 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3503 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for buildDirectionVectorField !");
3504 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3505 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3506 int nbOfCells=getNumberOfCells();
3507 int spaceDim=getSpaceDimension();
3508 array->alloc(nbOfCells,spaceDim);
3509 double *pt=array->getPointer();
3510 const double *coo=getCoords()->getConstPointer();
3511 std::vector<int> conn;
3513 for(int i=0;i<nbOfCells;i++)
3516 getNodeIdsOfCell(i,conn);
3517 pt=std::transform(coo+conn[1]*spaceDim,coo+(conn[1]+1)*spaceDim,coo+conn[0]*spaceDim,pt,std::minus<double>());
3519 ret->setArray(array);
3521 ret->synchronizeTimeWithSupport();
3526 * Creates a 2D mesh by cutting \a this 3D mesh with a plane. In addition to the mesh,
3527 * returns a new DataArrayInt, of length equal to the number of 2D cells in the result
3528 * mesh, holding, for each cell in the result mesh, an id of a 3D cell it comes
3529 * from. If a result face is shared by two 3D cells, then the face in included twice in
3531 * \param [in] origin - 3 components of a point defining location of the plane.
3532 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3533 * must be greater than 1e-6.
3534 * \param [in] eps - half-thickness of the plane.
3535 * \param [out] cellIds - a new instance of DataArrayInt holding ids of 3D cells
3536 * producing correspondent 2D cells. The caller is to delete this array
3537 * using decrRef() as it is no more needed.
3538 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This mesh does
3539 * not share the node coordinates array with \a this mesh. The caller is to
3540 * delete this mesh using decrRef() as it is no more needed.
3541 * \throw If the coordinates array is not set.
3542 * \throw If the nodal connectivity of cells is not defined.
3543 * \throw If \a this->getMeshDimension() != 3 or \a this->getSpaceDimension() != 3.
3544 * \throw If magnitude of \a vec is less than 1e-6.
3545 * \throw If the plane does not intersect any 3D cell of \a this mesh.
3546 * \throw If \a this includes quadratic cells.
3548 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3D(const double *origin, const double *vec, double eps, DataArrayInt *&cellIds) const
3550 checkFullyDefined();
3551 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3552 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3553 MCAuto<DataArrayInt> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3554 if(candidates->empty())
3555 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane considering bounding boxes !");
3556 std::vector<int> nodes;
3557 DataArrayInt *cellIds1D=0;
3558 MCAuto<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3559 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3560 MCAuto<DataArrayInt> desc1=DataArrayInt::New(),desc2=DataArrayInt::New();
3561 MCAuto<DataArrayInt> descIndx1=DataArrayInt::New(),descIndx2=DataArrayInt::New();
3562 MCAuto<DataArrayInt> revDesc1=DataArrayInt::New(),revDesc2=DataArrayInt::New();
3563 MCAuto<DataArrayInt> revDescIndx1=DataArrayInt::New(),revDescIndx2=DataArrayInt::New();
3564 MCAuto<MEDCouplingUMesh> mDesc2=subMesh->buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2);//meshDim==2 spaceDim==3
3565 revDesc2=0; revDescIndx2=0;
3566 MCAuto<MEDCouplingUMesh> mDesc1=mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3567 revDesc1=0; revDescIndx1=0;
3568 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3569 MCAuto<DataArrayInt> cellIds1DTmp(cellIds1D);
3571 std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3572 for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3574 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3575 std::vector< std::pair<int,int> > cut3DSurf(mDesc2->getNumberOfCells());
3576 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->getConstPointer(),mDesc2->getNodalConnectivityIndex()->getConstPointer(),
3577 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3578 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3579 MCAuto<DataArrayInt> conn(DataArrayInt::New()),connI(DataArrayInt::New()),cellIds2(DataArrayInt::New());
3580 connI->pushBackSilent(0); conn->alloc(0,1); cellIds2->alloc(0,1);
3581 subMesh->assemblyForSplitFrom3DSurf(cut3DSurf,desc2->getConstPointer(),descIndx2->getConstPointer(),conn,connI,cellIds2);
3582 if(cellIds2->empty())
3583 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3584 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3D",2);
3585 ret->setCoords(mDesc1->getCoords());
3586 ret->setConnectivity(conn,connI,true);
3587 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3592 * Creates an 1D mesh by cutting \a this 2D mesh in 3D space with a plane. In
3593 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
3594 from. If a result segment is shared by two 2D cells, then the segment in included twice in
3596 * \param [in] origin - 3 components of a point defining location of the plane.
3597 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3598 * must be greater than 1e-6.
3599 * \param [in] eps - half-thickness of the plane.
3600 * \param [out] cellIds - a new instance of DataArrayInt holding ids of faces
3601 * producing correspondent segments. The caller is to delete this array
3602 * using decrRef() as it is no more needed.
3603 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This is an 1D
3604 * mesh in 3D space. This mesh does not share the node coordinates array with
3605 * \a this mesh. The caller is to delete this mesh using decrRef() as it is
3607 * \throw If the coordinates array is not set.
3608 * \throw If the nodal connectivity of cells is not defined.
3609 * \throw If \a this->getMeshDimension() != 2 or \a this->getSpaceDimension() != 3.
3610 * \throw If magnitude of \a vec is less than 1e-6.
3611 * \throw If the plane does not intersect any 2D cell of \a this mesh.
3612 * \throw If \a this includes quadratic cells.
3614 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3DSurf(const double *origin, const double *vec, double eps, DataArrayInt *&cellIds) const
3616 checkFullyDefined();
3617 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
3618 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf works on umeshes with meshdim equal to 2 and spaceDim equal to 3 !");
3619 MCAuto<DataArrayInt> candidates(getCellIdsCrossingPlane(origin,vec,eps));
3620 if(candidates->empty())
3621 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3D surf cells in this intercepts the specified plane considering bounding boxes !");
3622 std::vector<int> nodes;
3623 DataArrayInt *cellIds1D(0);
3624 MCAuto<MEDCouplingUMesh> subMesh(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3625 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3626 MCAuto<DataArrayInt> desc1(DataArrayInt::New()),descIndx1(DataArrayInt::New()),revDesc1(DataArrayInt::New()),revDescIndx1(DataArrayInt::New());
3627 MCAuto<MEDCouplingUMesh> mDesc1(subMesh->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3628 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3629 MCAuto<DataArrayInt> cellIds1DTmp(cellIds1D);
3631 std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3632 for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3634 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3635 int ncellsSub=subMesh->getNumberOfCells();
3636 std::vector< std::pair<int,int> > cut3DSurf(ncellsSub);
3637 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,subMesh->getNodalConnectivity()->getConstPointer(),subMesh->getNodalConnectivityIndex()->getConstPointer(),
3638 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3639 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3640 MCAuto<DataArrayInt> conn(DataArrayInt::New()),connI(DataArrayInt::New()),cellIds2(DataArrayInt::New()); connI->pushBackSilent(0);
3642 const int *nodal=subMesh->getNodalConnectivity()->getConstPointer();
3643 const int *nodalI=subMesh->getNodalConnectivityIndex()->getConstPointer();
3644 for(int i=0;i<ncellsSub;i++)
3646 if(cut3DSurf[i].first!=-1 && cut3DSurf[i].second!=-1)
3648 if(cut3DSurf[i].first!=-2)
3650 conn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG2); conn->pushBackSilent(cut3DSurf[i].first); conn->pushBackSilent(cut3DSurf[i].second);
3651 connI->pushBackSilent(conn->getNumberOfTuples());
3652 cellIds2->pushBackSilent(i);
3656 int cellId3DSurf=cut3DSurf[i].second;
3657 int offset=nodalI[cellId3DSurf]+1;
3658 int nbOfEdges=nodalI[cellId3DSurf+1]-offset;
3659 for(int j=0;j<nbOfEdges;j++)
3661 conn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG2); conn->pushBackSilent(nodal[offset+j]); conn->pushBackSilent(nodal[offset+(j+1)%nbOfEdges]);
3662 connI->pushBackSilent(conn->getNumberOfTuples());
3663 cellIds2->pushBackSilent(cellId3DSurf);
3668 if(cellIds2->empty())
3669 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3DSurf cells in this intercepts the specified plane !");
3670 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3DSurf",1);
3671 ret->setCoords(mDesc1->getCoords());
3672 ret->setConnectivity(conn,connI,true);
3673 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3677 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::clipSingle3DCellByPlane(const double origin[3], const double vec[3], double eps) const
3679 checkFullyDefined();
3680 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3681 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3682 if(getNumberOfCells()!=1)
3683 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works only on mesh containing exactly one cell !");
3685 std::vector<int> nodes;
3686 findNodesOnPlane(origin,vec,eps,nodes);
3687 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());
3688 MCAuto<MEDCouplingUMesh> mDesc2(buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2));//meshDim==2 spaceDim==3
3689 revDesc2=0; revDescIndx2=0;
3690 MCAuto<MEDCouplingUMesh> mDesc1(mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3691 revDesc1=0; revDescIndx1=0;
3692 DataArrayInt *cellIds1D(0);
3693 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3694 MCAuto<DataArrayInt> cellIds1DTmp(cellIds1D);
3695 std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3696 for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3700 int oldNbNodes(mDesc1->getNumberOfNodes());
3701 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3702 sameNbNodes=(mDesc1->getNumberOfNodes()==oldNbNodes);
3704 std::vector< std::pair<int,int> > cut3DSurf(mDesc2->getNumberOfCells());
3705 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->begin(),mDesc2->getNodalConnectivityIndex()->begin(),
3706 mDesc1->getNodalConnectivity()->begin(),mDesc1->getNodalConnectivityIndex()->begin(),
3707 desc1->begin(),descIndx1->begin(),cut3DSurf);
3708 MCAuto<DataArrayInt> conn(DataArrayInt::New()),connI(DataArrayInt::New());
3709 connI->pushBackSilent(0); conn->alloc(0,1);
3711 MCAuto<DataArrayInt> cellIds2(DataArrayInt::New()); cellIds2->alloc(0,1);
3712 assemblyForSplitFrom3DSurf(cut3DSurf,desc2->begin(),descIndx2->begin(),conn,connI,cellIds2);
3713 if(cellIds2->empty())
3714 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3716 std::vector<std::vector<int> > res;
3717 buildSubCellsFromCut(cut3DSurf,desc2->begin(),descIndx2->begin(),mDesc1->getCoords()->begin(),eps,res);
3718 std::size_t sz(res.size());
3719 if((int)res.size()==mDesc1->getNumberOfCells() && sameNbNodes)
3720 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane : cell is not clipped !");
3721 for(std::size_t i=0;i<sz;i++)
3723 conn->pushBackSilent((int)INTERP_KERNEL::NORM_POLYGON);
3724 conn->insertAtTheEnd(res[i].begin(),res[i].end());
3725 connI->pushBackSilent(conn->getNumberOfTuples());
3727 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
3728 ret->setCoords(mDesc1->getCoords());
3729 ret->setConnectivity(conn,connI,true);
3730 int nbCellsRet(ret->getNumberOfCells());
3732 MCAuto<DataArrayDouble> vec2(DataArrayDouble::New()); vec2->alloc(1,3); std::copy(vec,vec+3,vec2->getPointer());
3733 MCAuto<MEDCouplingFieldDouble> ortho(ret->buildOrthogonalField());
3734 MCAuto<DataArrayDouble> ortho2(ortho->getArray()->selectByTupleIdSafeSlice(0,1,1));
3735 MCAuto<DataArrayDouble> dott(DataArrayDouble::Dot(ortho2,vec2));
3736 MCAuto<DataArrayDouble> ccm(ret->computeCellCenterOfMass());
3737 MCAuto<DataArrayDouble> occm;
3739 MCAuto<DataArrayDouble> pt(DataArrayDouble::New()); pt->alloc(1,3); std::copy(origin,origin+3,pt->getPointer());
3740 occm=DataArrayDouble::Substract(ccm,pt);
3742 vec2=DataArrayDouble::New(); vec2->alloc(nbCellsRet,3);
3743 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);
3744 MCAuto<DataArrayDouble> dott2(DataArrayDouble::Dot(occm,vec2));
3746 const int *cPtr(ret->getNodalConnectivity()->begin()),*ciPtr(ret->getNodalConnectivityIndex()->begin());
3747 MCAuto<MEDCouplingUMesh> ret2(MEDCouplingUMesh::New("Clip3D",3));
3748 ret2->setCoords(mDesc1->getCoords());
3749 MCAuto<DataArrayInt> conn2(DataArrayInt::New()),conn2I(DataArrayInt::New());
3750 conn2I->pushBackSilent(0); conn2->alloc(0,1);
3751 std::vector<int> cell0(1,(int)INTERP_KERNEL::NORM_POLYHED);
3752 std::vector<int> cell1(1,(int)INTERP_KERNEL::NORM_POLYHED);
3753 if(dott->getIJ(0,0)>0)
3755 cell0.insert(cell0.end(),cPtr+1,cPtr+ciPtr[1]);
3756 std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell1,cell1.end()));
3760 cell1.insert(cell1.end(),cPtr+1,cPtr+ciPtr[1]);
3761 std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell0,cell0.end()));
3763 for(int i=1;i<nbCellsRet;i++)
3765 if(dott2->getIJ(i,0)<0)
3767 if(ciPtr[i+1]-ciPtr[i]>=4)
3769 cell0.push_back(-1);
3770 cell0.insert(cell0.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
3775 if(ciPtr[i+1]-ciPtr[i]>=4)
3777 cell1.push_back(-1);
3778 cell1.insert(cell1.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
3782 conn2->insertAtTheEnd(cell0.begin(),cell0.end());
3783 conn2I->pushBackSilent(conn2->getNumberOfTuples());
3784 conn2->insertAtTheEnd(cell1.begin(),cell1.end());
3785 conn2I->pushBackSilent(conn2->getNumberOfTuples());
3786 ret2->setConnectivity(conn2,conn2I,true);
3787 ret2->checkConsistencyLight();
3788 ret2->orientCorrectlyPolyhedrons();
3793 * Finds cells whose bounding boxes intersect a given plane.
3794 * \param [in] origin - 3 components of a point defining location of the plane.
3795 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3796 * must be greater than 1e-6.
3797 * \param [in] eps - half-thickness of the plane.
3798 * \return DataArrayInt * - a new instance of DataArrayInt holding ids of the found
3799 * cells. The caller is to delete this array using decrRef() as it is no more
3801 * \throw If the coordinates array is not set.
3802 * \throw If the nodal connectivity of cells is not defined.
3803 * \throw If \a this->getSpaceDimension() != 3.
3804 * \throw If magnitude of \a vec is less than 1e-6.
3805 * \sa buildSlice3D()
3807 DataArrayInt *MEDCouplingUMesh::getCellIdsCrossingPlane(const double *origin, const double *vec, double eps) const
3809 checkFullyDefined();
3810 if(getSpaceDimension()!=3)
3811 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with spaceDim equal to 3 !");
3812 double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
3814 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellIdsCrossingPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
3816 vec2[0]=vec[1]; vec2[1]=-vec[0]; vec2[2]=0.;//vec2 is the result of cross product of vec with (0,0,1)
3817 double angle=acos(vec[2]/normm);
3818 MCAuto<DataArrayInt> cellIds;
3822 MCAuto<DataArrayDouble> coo=_coords->deepCopy();
3823 double normm2(sqrt(vec2[0]*vec2[0]+vec2[1]*vec2[1]+vec2[2]*vec2[2]));
3824 if(normm2/normm>1e-6)
3825 DataArrayDouble::Rotate3DAlg(origin,vec2,angle,coo->getNumberOfTuples(),coo->getPointer(),coo->getPointer());
3826 MCAuto<MEDCouplingUMesh> mw=clone(false);//false -> shallow copy
3828 mw->getBoundingBox(bbox);
3829 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3830 cellIds=mw->getCellsInBoundingBox(bbox,eps);
3834 getBoundingBox(bbox);
3835 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3836 cellIds=getCellsInBoundingBox(bbox,eps);
3838 return cellIds.retn();
3842 * This method checks that \a this is a contiguous mesh. The user is expected to call this method on a mesh with meshdim==1.
3843 * If not an exception will thrown. If this is an empty mesh with no cell an exception will be thrown too.
3844 * No consideration of coordinate is done by this method.
3845 * 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)
3846 * If not false is returned. In case that false is returned a call to MEDCoupling::MEDCouplingUMesh::mergeNodes could be usefull.
3848 bool MEDCouplingUMesh::isContiguous1D() const
3850 if(getMeshDimension()!=1)
3851 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense only for 1D mesh !");
3852 int nbCells=getNumberOfCells();
3854 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense for non empty mesh !");
3855 const int *connI(_nodal_connec_index->begin()),*conn(_nodal_connec->begin());
3856 int ref=conn[connI[0]+2];
3857 for(int i=1;i<nbCells;i++)
3859 if(conn[connI[i]+1]!=ref)
3861 ref=conn[connI[i]+2];
3867 * This method is only callable on mesh with meshdim == 1 containing only SEG2 and spaceDim==3.
3868 * This method projects this on the 3D line defined by (pt,v). This methods first checks that all SEG2 are along v vector.
3869 * \param pt reference point of the line
3870 * \param v normalized director vector of the line
3871 * \param eps max precision before throwing an exception
3872 * \param res output of size this->getNumberOfCells
3874 void MEDCouplingUMesh::project1D(const double *pt, const double *v, double eps, double *res) const
3876 if(getMeshDimension()!=1)
3877 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for project1D !");
3878 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3879 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for project1D !");
3880 if(getSpaceDimension()!=3)
3881 throw INTERP_KERNEL::Exception("Expected a umesh with spaceDim==3 for project1D !");
3882 MCAuto<MEDCouplingFieldDouble> f=buildDirectionVectorField();
3883 const double *fPtr=f->getArray()->getConstPointer();
3885 for(int i=0;i<getNumberOfCells();i++)
3887 const double *tmp1=fPtr+3*i;
3888 tmp[0]=tmp1[1]*v[2]-tmp1[2]*v[1];
3889 tmp[1]=tmp1[2]*v[0]-tmp1[0]*v[2];
3890 tmp[2]=tmp1[0]*v[1]-tmp1[1]*v[0];
3891 double n1=INTERP_KERNEL::norm<3>(tmp);
3892 n1/=INTERP_KERNEL::norm<3>(tmp1);
3894 throw INTERP_KERNEL::Exception("UMesh::Projection 1D failed !");
3896 const double *coo=getCoords()->getConstPointer();
3897 for(int i=0;i<getNumberOfNodes();i++)
3899 std::transform(coo+i*3,coo+i*3+3,pt,tmp,std::minus<double>());
3900 std::transform(tmp,tmp+3,v,tmp,std::multiplies<double>());
3901 res[i]=std::accumulate(tmp,tmp+3,0.);
3906 * 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.
3907 * \a this is expected to be a mesh so that its space dimension is equal to its
3908 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
3909 * 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).
3911 * 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
3912 * 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).
3913 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
3915 * So this method is more accurate (so, more costly) than simply searching for the closest point in \a this.
3916 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
3918 * \param [in] ptBg the start pointer (included) of the coordinates of the point
3919 * \param [in] ptEnd the end pointer (not included) of the coordinates of the point
3920 * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
3921 * \return the positive value of the distance.
3922 * \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
3924 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoints
3926 double MEDCouplingUMesh::distanceToPoint(const double *ptBg, const double *ptEnd, int& cellId) const
3928 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
3929 if(meshDim!=spaceDim-1)
3930 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint works only for spaceDim=meshDim+1 !");
3931 if(meshDim!=2 && meshDim!=1)
3932 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint : only mesh dimension 2 and 1 are implemented !");
3933 checkFullyDefined();
3934 if((int)std::distance(ptBg,ptEnd)!=spaceDim)
3935 { 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()); }
3936 DataArrayInt *ret1=0;
3937 MCAuto<DataArrayDouble> pts=DataArrayDouble::New(); pts->useArray(ptBg,false,C_DEALLOC,1,spaceDim);
3938 MCAuto<DataArrayDouble> ret0=distanceToPoints(pts,ret1);
3939 MCAuto<DataArrayInt> ret1Safe(ret1);
3940 cellId=*ret1Safe->begin();
3941 return *ret0->begin();
3945 * This method computes the distance from each point of points serie \a pts (stored in a DataArrayDouble in which each tuple represents a point)
3946 * to \a this and the first \a cellId in \a this corresponding to the returned distance.
3947 * 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
3948 * 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).
3949 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
3951 * \a this is expected to be a mesh so that its space dimension is equal to its
3952 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
3953 * 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).
3955 * So this method is more accurate (so, more costly) than simply searching for each point in \a pts the closest point in \a this.
3956 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
3958 * \param [in] pts the list of points in which each tuple represents a point
3959 * \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.
3960 * \return a newly allocated object to be dealed by the caller that tells for each point in \a pts the distance to \a this.
3961 * \throw if number of components of \a pts is not equal to the space dimension.
3962 * \throw if mesh dimension of \a this is not equal to space dimension - 1.
3963 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoint
3965 DataArrayDouble *MEDCouplingUMesh::distanceToPoints(const DataArrayDouble *pts, DataArrayInt *& cellIds) const
3968 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : input points pointer is NULL !");
3969 pts->checkAllocated();
3970 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
3971 if(meshDim!=spaceDim-1)
3972 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints works only for spaceDim=meshDim+1 !");
3973 if(meshDim!=2 && meshDim!=1)
3974 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only mesh dimension 2 and 1 are implemented !");
3975 if((int)pts->getNumberOfComponents()!=spaceDim)
3977 std::ostringstream oss; oss << "MEDCouplingUMesh::distanceToPoints : input pts DataArrayDouble has " << pts->getNumberOfComponents() << " components whereas it should be equal to " << spaceDim << " (mesh spaceDimension) !";
3978 throw INTERP_KERNEL::Exception(oss.str());
3980 checkFullyDefined();
3981 int nbCells=getNumberOfCells();
3983 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : no cells in this !");
3984 int nbOfPts=pts->getNumberOfTuples();
3985 MCAuto<DataArrayDouble> ret0=DataArrayDouble::New(); ret0->alloc(nbOfPts,1);
3986 MCAuto<DataArrayInt> ret1=DataArrayInt::New(); ret1->alloc(nbOfPts,1);
3987 const int *nc=_nodal_connec->begin(),*ncI=_nodal_connec_index->begin(); const double *coords=_coords->begin();
3988 double *ret0Ptr=ret0->getPointer(); int *ret1Ptr=ret1->getPointer(); const double *ptsPtr=pts->begin();
3989 MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree());
3990 const double *bbox(bboxArr->begin());
3995 BBTreeDst<3> myTree(bbox,0,0,nbCells);
3996 for(int i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=3)
3998 double x=std::numeric_limits<double>::max();
3999 std::vector<int> elems;
4000 myTree.getMinDistanceOfMax(ptsPtr,x);
4001 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4002 DistanceToPoint3DSurfAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4008 BBTreeDst<2> myTree(bbox,0,0,nbCells);
4009 for(int i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=2)
4011 double x=std::numeric_limits<double>::max();
4012 std::vector<int> elems;
4013 myTree.getMinDistanceOfMax(ptsPtr,x);
4014 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4015 DistanceToPoint2DCurveAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4020 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only spacedim 2 and 3 supported !");
4022 cellIds=ret1.retn();
4031 * Finds cells in contact with a ball (i.e. a point with precision).
4032 * 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.
4033 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4035 * \warning This method is suitable if the caller intends to evaluate only one
4036 * point, for more points getCellsContainingPoints() is recommended as it is
4038 * \param [in] pos - array of coordinates of the ball central point.
4039 * \param [in] eps - ball radius.
4040 * \return int - a smallest id of cells being in contact with the ball, -1 in case
4041 * if there are no such cells.
4042 * \throw If the coordinates array is not set.
4043 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4045 int MEDCouplingUMesh::getCellContainingPoint(const double *pos, double eps) const
4047 std::vector<int> elts;
4048 getCellsContainingPoint(pos,eps,elts);
4051 return elts.front();
4055 * Finds cells in contact with a ball (i.e. a point with precision).
4056 * 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.
4057 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4058 * \warning This method is suitable if the caller intends to evaluate only one
4059 * point, for more points getCellsContainingPoints() is recommended as it is
4061 * \param [in] pos - array of coordinates of the ball central point.
4062 * \param [in] eps - ball radius.
4063 * \param [out] elts - vector returning ids of the found cells. It is cleared
4064 * before inserting ids.
4065 * \throw If the coordinates array is not set.
4066 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4068 * \if ENABLE_EXAMPLES
4069 * \ref cpp_mcumesh_getCellsContainingPoint "Here is a C++ example".<br>
4070 * \ref py_mcumesh_getCellsContainingPoint "Here is a Python example".
4073 void MEDCouplingUMesh::getCellsContainingPoint(const double *pos, double eps, std::vector<int>& elts) const
4075 MCAuto<DataArrayInt> eltsUg,eltsIndexUg;
4076 getCellsContainingPoints(pos,1,eps,eltsUg,eltsIndexUg);
4077 elts.clear(); elts.insert(elts.end(),eltsUg->begin(),eltsUg->end());
4081 * Finds cells in contact with several balls (i.e. points with precision).
4082 * This method is an extension of getCellContainingPoint() and
4083 * getCellsContainingPoint() for the case of multiple points.
4084 * 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.
4085 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4086 * \param [in] pos - an array of coordinates of points in full interlace mode :
4087 * X0,Y0,Z0,X1,Y1,Z1,... Size of the array must be \a
4088 * this->getSpaceDimension() * \a nbOfPoints
4089 * \param [in] nbOfPoints - number of points to locate within \a this mesh.
4090 * \param [in] eps - radius of balls (i.e. the precision).
4091 * \param [out] elts - vector returning ids of found cells.
4092 * \param [out] eltsIndex - an array, of length \a nbOfPoints + 1,
4093 * dividing cell ids in \a elts into groups each referring to one
4094 * point. Its every element (except the last one) is an index pointing to the
4095 * first id of a group of cells. For example cells in contact with the *i*-th
4096 * point are described by following range of indices:
4097 * [ \a eltsIndex[ *i* ], \a eltsIndex[ *i*+1 ] ) and the cell ids are
4098 * \a elts[ \a eltsIndex[ *i* ]], \a elts[ \a eltsIndex[ *i* ] + 1 ], ...
4099 * Number of cells in contact with the *i*-th point is
4100 * \a eltsIndex[ *i*+1 ] - \a eltsIndex[ *i* ].
4101 * \throw If the coordinates array is not set.
4102 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4104 * \if ENABLE_EXAMPLES
4105 * \ref cpp_mcumesh_getCellsContainingPoints "Here is a C++ example".<br>
4106 * \ref py_mcumesh_getCellsContainingPoints "Here is a Python example".
4109 void MEDCouplingUMesh::getCellsContainingPoints(const double *pos, int nbOfPoints, double eps,
4110 MCAuto<DataArrayInt>& elts, MCAuto<DataArrayInt>& eltsIndex) const
4112 int spaceDim=getSpaceDimension();
4113 int mDim=getMeshDimension();
4118 const double *coords=_coords->getConstPointer();
4119 getCellsContainingPointsAlg<3>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4126 throw INTERP_KERNEL::Exception("For spaceDim==3 only meshDim==3 implemented for getelementscontainingpoints !");
4128 else if(spaceDim==2)
4132 const double *coords=_coords->getConstPointer();
4133 getCellsContainingPointsAlg<2>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4136 throw INTERP_KERNEL::Exception("For spaceDim==2 only meshDim==2 implemented for getelementscontainingpoints !");
4138 else if(spaceDim==1)
4142 const double *coords=_coords->getConstPointer();
4143 getCellsContainingPointsAlg<1>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4146 throw INTERP_KERNEL::Exception("For spaceDim==1 only meshDim==1 implemented for getelementscontainingpoints !");
4149 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPoints : not managed for mdim not in [1,2,3] !");
4153 * Finds butterfly cells in \a this mesh. A 2D cell is considered to be butterfly if at
4154 * least two its edges intersect each other anywhere except their extremities. An
4155 * INTERP_KERNEL::NORM_NORI3 cell can \b not be butterfly.
4156 * \param [in,out] cells - a vector returning ids of the found cells. It is not
4157 * cleared before filling in.
4158 * \param [in] eps - precision.
4159 * \throw If \a this->getMeshDimension() != 2.
4160 * \throw If \a this->getSpaceDimension() != 2 && \a this->getSpaceDimension() != 3.
4162 void MEDCouplingUMesh::checkButterflyCells(std::vector<int>& cells, double eps) const
4164 const char msg[]="Butterfly detection work only for 2D cells with spaceDim==2 or 3!";
4165 if(getMeshDimension()!=2)
4166 throw INTERP_KERNEL::Exception(msg);
4167 int spaceDim=getSpaceDimension();
4168 if(spaceDim!=2 && spaceDim!=3)
4169 throw INTERP_KERNEL::Exception(msg);
4170 const int *conn=_nodal_connec->getConstPointer();
4171 const int *connI=_nodal_connec_index->getConstPointer();
4172 int nbOfCells=getNumberOfCells();
4173 std::vector<double> cell2DinS2;
4174 for(int i=0;i<nbOfCells;i++)
4176 int offset=connI[i];
4177 int nbOfNodesForCell=connI[i+1]-offset-1;
4178 if(nbOfNodesForCell<=3)
4180 bool isQuad=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[offset]).isQuadratic();
4181 project2DCellOnXY(conn+offset+1,conn+connI[i+1],cell2DinS2);
4182 if(isButterfly2DCell(cell2DinS2,isQuad,eps))
4189 * This method is typically requested to unbutterfly 2D linear cells in \b this.
4191 * 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.
4192 * 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.
4194 * For each 2D linear cell in \b this, this method builds the convex envelop (or the convex hull) of the current cell.
4195 * This convex envelop is computed using Jarvis march algorithm.
4196 * The coordinates and the number of cells of \b this remain unchanged on invocation of this method.
4197 * 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)
4198 * 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.
4200 * \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.
4201 * \sa MEDCouplingUMesh::colinearize2D
4203 DataArrayInt *MEDCouplingUMesh::convexEnvelop2D()
4205 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
4206 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convexEnvelop2D works only for meshDim=2 and spaceDim=2 !");
4207 checkFullyDefined();
4208 const double *coords=getCoords()->getConstPointer();
4209 int nbOfCells=getNumberOfCells();
4210 MCAuto<DataArrayInt> nodalConnecIndexOut=DataArrayInt::New();
4211 nodalConnecIndexOut->alloc(nbOfCells+1,1);
4212 MCAuto<DataArrayInt> nodalConnecOut(DataArrayInt::New());
4213 int *workIndexOut=nodalConnecIndexOut->getPointer();
4215 const int *nodalConnecIn=_nodal_connec->getConstPointer();
4216 const int *nodalConnecIndexIn=_nodal_connec_index->getConstPointer();
4217 std::set<INTERP_KERNEL::NormalizedCellType> types;
4218 MCAuto<DataArrayInt> isChanged(DataArrayInt::New());
4219 isChanged->alloc(0,1);
4220 for(int i=0;i<nbOfCells;i++,workIndexOut++)
4222 int pos=nodalConnecOut->getNumberOfTuples();
4223 if(BuildConvexEnvelopOf2DCellJarvis(coords,nodalConnecIn+nodalConnecIndexIn[i],nodalConnecIn+nodalConnecIndexIn[i+1],nodalConnecOut))
4224 isChanged->pushBackSilent(i);
4225 types.insert((INTERP_KERNEL::NormalizedCellType)nodalConnecOut->getIJ(pos,0));
4226 workIndexOut[1]=nodalConnecOut->getNumberOfTuples();
4228 if(isChanged->empty())
4230 setConnectivity(nodalConnecOut,nodalConnecIndexOut,false);
4232 return isChanged.retn();
4236 * This method is \b NOT const because it can modify \a this.
4237 * \a this is expected to be an unstructured mesh with meshDim==2 and spaceDim==3. If not an exception will be thrown.
4238 * \param mesh1D is an unstructured mesh with MeshDim==1 and spaceDim==3. If not an exception will be thrown.
4239 * \param policy specifies the type of extrusion chosen:
4240 * - \b 0 for translation only (most simple): the cells of the 1D mesh represent the vectors along which the 2D mesh
4241 * will be repeated to build each level
4242 * - \b 1 for translation and rotation: the translation is done as above. For each level, an arc of circle is fitted on
4243 * 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
4244 * 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
4246 * \return an unstructured mesh with meshDim==3 and spaceDim==3. The returned mesh has the same coords than \a this.
4248 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMesh(const MEDCouplingUMesh *mesh1D, int policy)
4250 checkFullyDefined();
4251 mesh1D->checkFullyDefined();
4252 if(!mesh1D->isContiguous1D())
4253 throw INTERP_KERNEL::Exception("buildExtrudedMesh : 1D mesh passed in parameter is not contiguous !");
4254 if(getSpaceDimension()!=mesh1D->getSpaceDimension())
4255 throw INTERP_KERNEL::Exception("Invalid call to buildExtrudedMesh this and mesh1D must have same space dimension !");
4256 if((getMeshDimension()!=2 || getSpaceDimension()!=3) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
4257 throw INTERP_KERNEL::Exception("Invalid 'this' for buildExtrudedMesh method : must be (meshDim==2 and spaceDim==3) or (meshDim==1 and spaceDim==2) !");
4258 if(mesh1D->getMeshDimension()!=1)
4259 throw INTERP_KERNEL::Exception("Invalid 'mesh1D' for buildExtrudedMesh method : must be meshDim==1 !");
4261 if(isPresenceOfQuadratic())
4263 if(mesh1D->isFullyQuadratic())
4266 throw INTERP_KERNEL::Exception("Invalid 2D mesh and 1D mesh because 2D mesh has quadratic cells and 1D is not fully quadratic !");
4268 int oldNbOfNodes(getNumberOfNodes());
4269 MCAuto<DataArrayDouble> newCoords;
4274 newCoords=fillExtCoordsUsingTranslation(mesh1D,isQuad);
4279 newCoords=fillExtCoordsUsingTranslAndAutoRotation(mesh1D,isQuad);
4283 throw INTERP_KERNEL::Exception("Not implemented extrusion policy : must be in (0) !");
4285 setCoords(newCoords);
4286 MCAuto<MEDCouplingUMesh> ret(buildExtrudedMeshFromThisLowLev(oldNbOfNodes,isQuad));
4293 * Checks if \a this mesh is constituted by only quadratic cells.
4294 * \return bool - \c true if there are only quadratic cells in \a this mesh.
4295 * \throw If the coordinates array is not set.
4296 * \throw If the nodal connectivity of cells is not defined.
4298 bool MEDCouplingUMesh::isFullyQuadratic() const
4300 checkFullyDefined();
4302 int nbOfCells=getNumberOfCells();
4303 for(int i=0;i<nbOfCells && ret;i++)
4305 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4306 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4307 ret=cm.isQuadratic();
4313 * Checks if \a this mesh includes any quadratic cell.
4314 * \return bool - \c true if there is at least one quadratic cells in \a this mesh.
4315 * \throw If the coordinates array is not set.
4316 * \throw If the nodal connectivity of cells is not defined.
4318 bool MEDCouplingUMesh::isPresenceOfQuadratic() const
4320 checkFullyDefined();
4322 int nbOfCells=getNumberOfCells();
4323 for(int i=0;i<nbOfCells && !ret;i++)
4325 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4326 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4327 ret=cm.isQuadratic();
4333 * Converts all quadratic cells to linear ones. If there are no quadratic cells in \a
4334 * this mesh, it remains unchanged.
4335 * \throw If the coordinates array is not set.
4336 * \throw If the nodal connectivity of cells is not defined.
4338 void MEDCouplingUMesh::convertQuadraticCellsToLinear()
4340 checkFullyDefined();
4341 int nbOfCells(getNumberOfCells());
4343 const int *iciptr=_nodal_connec_index->begin();
4344 for(int i=0;i<nbOfCells;i++)
4346 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4347 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4348 if(cm.isQuadratic())
4350 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4351 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4352 if(!cml.isDynamic())
4353 delta+=cm.getNumberOfNodes()-cml.getNumberOfNodes();
4355 delta+=(iciptr[i+1]-iciptr[i]-1)/2;
4360 MCAuto<DataArrayInt> newConn(DataArrayInt::New()),newConnI(DataArrayInt::New());
4361 const int *icptr(_nodal_connec->begin());
4362 newConn->alloc(getNodalConnectivityArrayLen()-delta,1);
4363 newConnI->alloc(nbOfCells+1,1);
4364 int *ocptr(newConn->getPointer()),*ociptr(newConnI->getPointer());
4367 for(int i=0;i<nbOfCells;i++,ociptr++)
4369 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)icptr[iciptr[i]];
4370 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4371 if(!cm.isQuadratic())
4373 _types.insert(type);
4374 ocptr=std::copy(icptr+iciptr[i],icptr+iciptr[i+1],ocptr);
4375 ociptr[1]=ociptr[0]+iciptr[i+1]-iciptr[i];
4379 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4380 _types.insert(typel);
4381 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4382 int newNbOfNodes=cml.getNumberOfNodes();
4384 newNbOfNodes=(iciptr[i+1]-iciptr[i]-1)/2;
4385 *ocptr++=(int)typel;
4386 ocptr=std::copy(icptr+iciptr[i]+1,icptr+iciptr[i]+newNbOfNodes+1,ocptr);
4387 ociptr[1]=ociptr[0]+newNbOfNodes+1;
4390 setConnectivity(newConn,newConnI,false);
4394 * This method converts all linear cell in \a this to quadratic one.
4395 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, here it is needed to specify the target
4396 * 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)
4397 * 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.
4398 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, the coordinates in \a this can be become bigger. All created nodes will be put at the
4399 * end of the existing coordinates.
4401 * \param [in] conversionType specifies the type of conversion expected. Only 0 (default) and 1 are supported presently. 0 those that creates the 'most' simple
4402 * corresponding quadratic cells. 1 is those creating the 'most' complex.
4403 * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
4405 * \throw if \a this is not fully defined. It throws too if \a conversionType is not in [0,1].
4407 * \sa MEDCouplingUMesh::convertQuadraticCellsToLinear
4409 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic(int conversionType)
4411 DataArrayInt *conn=0,*connI=0;
4412 DataArrayDouble *coords=0;
4413 std::set<INTERP_KERNEL::NormalizedCellType> types;
4414 checkFullyDefined();
4415 MCAuto<DataArrayInt> ret,connSafe,connISafe;
4416 MCAuto<DataArrayDouble> coordsSafe;
4417 int meshDim=getMeshDimension();
4418 switch(conversionType)
4424 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);
4425 connSafe=conn; connISafe=connI; coordsSafe=coords;
4428 ret=convertLinearCellsToQuadratic2D0(conn,connI,coords,types);
4429 connSafe=conn; connISafe=connI; coordsSafe=coords;
4432 ret=convertLinearCellsToQuadratic3D0(conn,connI,coords,types);
4433 connSafe=conn; connISafe=connI; coordsSafe=coords;
4436 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 0 mesh dimensions available are [1,2,3] !");
4444 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);//it is not a bug. In 1D policy 0 and 1 are equals
4445 connSafe=conn; connISafe=connI; coordsSafe=coords;
4448 ret=convertLinearCellsToQuadratic2D1(conn,connI,coords,types);
4449 connSafe=conn; connISafe=connI; coordsSafe=coords;
4452 ret=convertLinearCellsToQuadratic3D1(conn,connI,coords,types);
4453 connSafe=conn; connISafe=connI; coordsSafe=coords;
4456 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 1 mesh dimensions available are [1,2,3] !");
4461 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion type available are 0 (default, the simplest) and 1 (the most complex) !");
4463 setConnectivity(connSafe,connISafe,false);
4465 setCoords(coordsSafe);
4470 * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
4471 * so that the number of cells remains the same. Quadratic faces are converted to
4472 * polygons. This method works only for 2D meshes in
4473 * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
4474 * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
4475 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
4476 * \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
4477 * a polylinized edge constituting the input polygon.
4478 * \throw If the coordinates array is not set.
4479 * \throw If the nodal connectivity of cells is not defined.
4480 * \throw If \a this->getMeshDimension() != 2.
4481 * \throw If \a this->getSpaceDimension() != 2.
4483 void MEDCouplingUMesh::tessellate2D(double eps)
4485 int meshDim(getMeshDimension()),spaceDim(getSpaceDimension());
4487 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : works only with space dimension equal to 2 !");
4491 return tessellate2DCurveInternal(eps);
4493 return tessellate2DInternal(eps);
4495 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : mesh dimension must be in [1,2] !");
4499 * Tessellates \a this 1D mesh in 2D space by dividing not straight quadratic edges.
4500 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
4501 * \param [in] eps - specifies the maximal angle (in radian) between 2 sub-edges of
4502 * a sub-divided edge.
4503 * \throw If the coordinates array is not set.
4504 * \throw If the nodal connectivity of cells is not defined.
4505 * \throw If \a this->getMeshDimension() != 1.
4506 * \throw If \a this->getSpaceDimension() != 2.
4511 * This method only works if \a this has spaceDimension equal to 2 and meshDimension also equal to 2.
4512 * This method allows to modify connectivity of cells in \a this that shares some edges in \a edgeIdsToBeSplit.
4513 * The nodes to be added in those 2D cells are defined by the pair of \a nodeIdsToAdd and \a nodeIdsIndexToAdd.
4514 * Length of \a nodeIdsIndexToAdd is expected to equal to length of \a edgeIdsToBeSplit + 1.
4515 * The node ids in \a nodeIdsToAdd should be valid. Those nodes have to be sorted exactly following exactly the direction of the edge.
4516 * This method can be seen as the opposite method of colinearize2D.
4517 * 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
4518 * to avoid to modify the numbering of existing nodes.
4520 * \param [in] nodeIdsToAdd - the list of node ids to be added (\a nodeIdsIndexToAdd array allows to walk on this array)
4521 * \param [in] nodeIdsIndexToAdd - the entry point of \a nodeIdsToAdd to point to the corresponding nodes to be added.
4522 * \param [in] mesh1Desc - 1st output of buildDescendingConnectivity2 on \a this.
4523 * \param [in] desc - 2nd output of buildDescendingConnectivity2 on \a this.
4524 * \param [in] descI - 3rd output of buildDescendingConnectivity2 on \a this.
4525 * \param [in] revDesc - 4th output of buildDescendingConnectivity2 on \a this.
4526 * \param [in] revDescI - 5th output of buildDescendingConnectivity2 on \a this.
4528 * \sa buildDescendingConnectivity2
4530 void MEDCouplingUMesh::splitSomeEdgesOf2DMesh(const DataArrayInt *nodeIdsToAdd, const DataArrayInt *nodeIdsIndexToAdd, const DataArrayInt *edgeIdsToBeSplit,
4531 const MEDCouplingUMesh *mesh1Desc, const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *revDesc, const DataArrayInt *revDescI)
4533 if(!nodeIdsToAdd || !nodeIdsIndexToAdd || !edgeIdsToBeSplit || !mesh1Desc || !desc || !descI || !revDesc || !revDescI)
4534 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : input pointers must be not NULL !");
4535 nodeIdsToAdd->checkAllocated(); nodeIdsIndexToAdd->checkAllocated(); edgeIdsToBeSplit->checkAllocated(); desc->checkAllocated(); descI->checkAllocated(); revDesc->checkAllocated(); revDescI->checkAllocated();
4536 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
4537 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : this must have spacedim=meshdim=2 !");
4538 if(mesh1Desc->getSpaceDimension()!=2 || mesh1Desc->getMeshDimension()!=1)
4539 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : mesh1Desc must be the explosion of this with spaceDim=2 and meshDim = 1 !");
4540 //DataArrayInt *out0(0),*outi0(0);
4541 //MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
4542 //MCAuto<DataArrayInt> out0s(out0),outi0s(outi0);
4543 //out0s=out0s->buildUnique(); out0s->sort(true);
4549 * Divides every cell of \a this mesh into simplices (triangles in 2D and tetrahedra in 3D).
4550 * In addition, returns an array mapping new cells to old ones. <br>
4551 * This method typically increases the number of cells in \a this mesh
4552 * but the number of nodes remains \b unchanged.
4553 * That's why the 3D splitting policies
4554 * INTERP_KERNEL::GENERAL_24 and INTERP_KERNEL::GENERAL_48 are not available here.
4555 * \param [in] policy - specifies a pattern used for splitting.
4556 * The semantic of \a policy is:
4557 * - 0 - to split QUAD4 by cutting it along 0-2 diagonal (for 2D mesh only).
4558 * - 1 - to split QUAD4 by cutting it along 1-3 diagonal (for 2D mesh only).
4559 * - INTERP_KERNEL::PLANAR_FACE_5 - to split HEXA8 into 5 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4560 * - INTERP_KERNEL::PLANAR_FACE_6 - to split HEXA8 into 6 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4563 * \return DataArrayInt * - a new instance of DataArrayInt holding, for each new cell,
4564 * an id of old cell producing it. The caller is to delete this array using
4565 * decrRef() as it is no more needed.
4567 * \throw If \a policy is 0 or 1 and \a this->getMeshDimension() != 2.
4568 * \throw If \a policy is INTERP_KERNEL::PLANAR_FACE_5 or INTERP_KERNEL::PLANAR_FACE_6
4569 * and \a this->getMeshDimension() != 3.
4570 * \throw If \a policy is not one of the four discussed above.
4571 * \throw If the nodal connectivity of cells is not defined.
4572 * \sa MEDCouplingUMesh::tetrahedrize, MEDCoupling1SGTUMesh::sortHexa8EachOther
4574 DataArrayInt *MEDCouplingUMesh::simplexize(int policy)
4579 return simplexizePol0();
4581 return simplexizePol1();
4582 case (int) INTERP_KERNEL::PLANAR_FACE_5:
4583 return simplexizePlanarFace5();
4584 case (int) INTERP_KERNEL::PLANAR_FACE_6:
4585 return simplexizePlanarFace6();
4587 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)");
4592 * Checks if \a this mesh is constituted by simplex cells only. Simplex cells are:
4593 * - 1D: INTERP_KERNEL::NORM_SEG2
4594 * - 2D: INTERP_KERNEL::NORM_TRI3
4595 * - 3D: INTERP_KERNEL::NORM_TETRA4.
4597 * This method is useful for users that need to use P1 field services as
4598 * MEDCouplingFieldDouble::getValueOn(), MEDCouplingField::buildMeasureField() etc.
4599 * All these methods need mesh support containing only simplex cells.
4600 * \return bool - \c true if there are only simplex cells in \a this mesh.
4601 * \throw If the coordinates array is not set.
4602 * \throw If the nodal connectivity of cells is not defined.
4603 * \throw If \a this->getMeshDimension() < 1.
4605 bool MEDCouplingUMesh::areOnlySimplexCells() const
4607 checkFullyDefined();
4608 int mdim=getMeshDimension();
4609 if(mdim<1 || mdim>3)
4610 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::areOnlySimplexCells : only available with meshes having a meshdim 1, 2 or 3 !");
4611 int nbCells=getNumberOfCells();
4612 const int *conn=_nodal_connec->begin();
4613 const int *connI=_nodal_connec_index->begin();
4614 for(int i=0;i<nbCells;i++)
4616 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4626 * Converts degenerated 2D or 3D linear cells of \a this mesh into cells of simpler
4627 * type. For example an INTERP_KERNEL::NORM_QUAD4 cell having only three unique nodes in
4628 * its connectivity is transformed into an INTERP_KERNEL::NORM_TRI3 cell. This method
4629 * does \b not perform geometrical checks and checks only nodal connectivity of cells,
4630 * so it can be useful to call mergeNodes() before calling this method.
4631 * \throw If \a this->getMeshDimension() <= 1.
4632 * \throw If the coordinates array is not set.
4633 * \throw If the nodal connectivity of cells is not defined.
4635 void MEDCouplingUMesh::convertDegeneratedCells()
4637 checkFullyDefined();
4638 if(getMeshDimension()<=1)
4639 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4640 int nbOfCells=getNumberOfCells();
4643 int initMeshLgth=getNodalConnectivityArrayLen();
4644 int *conn=_nodal_connec->getPointer();
4645 int *index=_nodal_connec_index->getPointer();
4649 for(int i=0;i<nbOfCells;i++)
4651 lgthOfCurCell=index[i+1]-posOfCurCell;
4652 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4654 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
4655 conn+newPos+1,newLgth);
4656 conn[newPos]=newType;
4658 posOfCurCell=index[i+1];
4661 if(newPos!=initMeshLgth)
4662 _nodal_connec->reAlloc(newPos);
4667 * Finds incorrectly oriented cells of this 2D mesh in 3D space.
4668 * A cell is considered to be oriented correctly if an angle between its
4669 * normal vector and a given vector is less than \c PI / \c 2.
4670 * \param [in] vec - 3 components of the vector specifying the correct orientation of
4672 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
4674 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
4675 * is not cleared before filling in.
4676 * \throw If \a this->getMeshDimension() != 2.
4677 * \throw If \a this->getSpaceDimension() != 3.
4679 * \if ENABLE_EXAMPLES
4680 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
4681 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
4684 void MEDCouplingUMesh::are2DCellsNotCorrectlyOriented(const double *vec, bool polyOnly, std::vector<int>& cells) const
4686 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
4687 throw INTERP_KERNEL::Exception("Invalid mesh to apply are2DCellsNotCorrectlyOriented on it : must be meshDim==2 and spaceDim==3 !");
4688 int nbOfCells=getNumberOfCells();
4689 const int *conn=_nodal_connec->begin();
4690 const int *connI=_nodal_connec_index->begin();
4691 const double *coordsPtr=_coords->begin();
4692 for(int i=0;i<nbOfCells;i++)
4694 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4695 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
4697 bool isQuadratic=INTERP_KERNEL::CellModel::GetCellModel(type).isQuadratic();
4698 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4705 * Reverse connectivity of 2D cells whose orientation is not correct. A cell is
4706 * considered to be oriented correctly if an angle between its normal vector and a
4707 * given vector is less than \c PI / \c 2.
4708 * \param [in] vec - 3 components of the vector specifying the correct orientation of
4710 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
4712 * \throw If \a this->getMeshDimension() != 2.
4713 * \throw If \a this->getSpaceDimension() != 3.
4715 * \if ENABLE_EXAMPLES
4716 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
4717 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
4720 * \sa changeOrientationOfCells
4722 void MEDCouplingUMesh::orientCorrectly2DCells(const double *vec, bool polyOnly)
4724 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
4725 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectly2DCells on it : must be meshDim==2 and spaceDim==3 !");
4726 int nbOfCells(getNumberOfCells()),*conn(_nodal_connec->getPointer());
4727 const int *connI(_nodal_connec_index->begin());
4728 const double *coordsPtr(_coords->begin());
4729 bool isModified(false);
4730 for(int i=0;i<nbOfCells;i++)
4732 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4733 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
4735 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
4736 bool isQuadratic(cm.isQuadratic());
4737 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4740 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
4745 _nodal_connec->declareAsNew();
4750 * This method change the orientation of cells in \a this without any consideration of coordinates. Only connectivity is impacted.
4752 * \sa orientCorrectly2DCells
4754 void MEDCouplingUMesh::changeOrientationOfCells()
4756 int mdim(getMeshDimension());
4757 if(mdim!=2 && mdim!=1)
4758 throw INTERP_KERNEL::Exception("Invalid mesh to apply changeOrientationOfCells on it : must be meshDim==2 or meshDim==1 !");
4759 int nbOfCells(getNumberOfCells()),*conn(_nodal_connec->getPointer());
4760 const int *connI(_nodal_connec_index->begin());
4763 for(int i=0;i<nbOfCells;i++)
4765 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4766 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
4767 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
4772 for(int i=0;i<nbOfCells;i++)
4774 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4775 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
4776 cm.changeOrientationOf1D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
4782 * Finds incorrectly oriented polyhedral cells, i.e. polyhedrons having correctly
4783 * oriented facets. The normal vector of the facet should point out of the cell.
4784 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
4785 * is not cleared before filling in.
4786 * \throw If \a this->getMeshDimension() != 3.
4787 * \throw If \a this->getSpaceDimension() != 3.
4788 * \throw If the coordinates array is not set.
4789 * \throw If the nodal connectivity of cells is not defined.
4791 * \if ENABLE_EXAMPLES
4792 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
4793 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
4796 void MEDCouplingUMesh::arePolyhedronsNotCorrectlyOriented(std::vector<int>& cells) const
4798 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
4799 throw INTERP_KERNEL::Exception("Invalid mesh to apply arePolyhedronsNotCorrectlyOriented on it : must be meshDim==3 and spaceDim==3 !");
4800 int nbOfCells=getNumberOfCells();
4801 const int *conn=_nodal_connec->begin();
4802 const int *connI=_nodal_connec_index->begin();
4803 const double *coordsPtr=_coords->begin();
4804 for(int i=0;i<nbOfCells;i++)
4806 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4807 if(type==INTERP_KERNEL::NORM_POLYHED)
4809 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4816 * Tries to fix connectivity of polyhedra, so that normal vector of all facets to point
4818 * \throw If \a this->getMeshDimension() != 3.
4819 * \throw If \a this->getSpaceDimension() != 3.
4820 * \throw If the coordinates array is not set.
4821 * \throw If the nodal connectivity of cells is not defined.
4822 * \throw If the reparation fails.
4824 * \if ENABLE_EXAMPLES
4825 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
4826 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
4828 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
4830 void MEDCouplingUMesh::orientCorrectlyPolyhedrons()
4832 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
4833 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectlyPolyhedrons on it : must be meshDim==3 and spaceDim==3 !");
4834 int nbOfCells=getNumberOfCells();
4835 int *conn=_nodal_connec->getPointer();
4836 const int *connI=_nodal_connec_index->begin();
4837 const double *coordsPtr=_coords->begin();
4838 for(int i=0;i<nbOfCells;i++)
4840 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4841 if(type==INTERP_KERNEL::NORM_POLYHED)
4845 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4846 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
4848 catch(INTERP_KERNEL::Exception& e)
4850 std::ostringstream oss; oss << "Something wrong in polyhedron #" << i << " : " << e.what();
4851 throw INTERP_KERNEL::Exception(oss.str());
4859 * This method invert orientation of all cells in \a this.
4860 * After calling this method the absolute value of measure of cells in \a this are the same than before calling.
4861 * This method only operates on the connectivity so coordinates are not touched at all.
4863 void MEDCouplingUMesh::invertOrientationOfAllCells()
4865 checkConnectivityFullyDefined();
4866 std::set<INTERP_KERNEL::NormalizedCellType> gts(getAllGeoTypes());
4867 int *conn(_nodal_connec->getPointer());
4868 const int *conni(_nodal_connec_index->begin());
4869 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator gt=gts.begin();gt!=gts.end();gt++)
4871 INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::OrientationInverter> oi(INTERP_KERNEL::OrientationInverter::BuildInstanceFrom(*gt));
4872 MCAuto<DataArrayInt> cwt(giveCellsWithType(*gt));
4873 for(const int *it=cwt->begin();it!=cwt->end();it++)
4874 oi->operate(conn+conni[*it]+1,conn+conni[*it+1]);
4880 * Finds and fixes incorrectly oriented linear extruded volumes (INTERP_KERNEL::NORM_HEXA8,
4881 * INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXGP12 etc) to respect the MED convention
4882 * according to which the first facet of the cell should be oriented to have the normal vector
4883 * pointing out of cell.
4884 * \return DataArrayInt * - a new instance of DataArrayInt holding ids of fixed
4885 * cells. The caller is to delete this array using decrRef() as it is no more
4887 * \throw If \a this->getMeshDimension() != 3.
4888 * \throw If \a this->getSpaceDimension() != 3.
4889 * \throw If the coordinates array is not set.
4890 * \throw If the nodal connectivity of cells is not defined.
4892 * \if ENABLE_EXAMPLES
4893 * \ref cpp_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a C++ example".<br>
4894 * \ref py_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a Python example".
4896 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
4898 DataArrayInt *MEDCouplingUMesh::findAndCorrectBadOriented3DExtrudedCells()
4900 const char msg[]="check3DCellsWellOriented detection works only for 3D cells !";
4901 if(getMeshDimension()!=3)
4902 throw INTERP_KERNEL::Exception(msg);
4903 int spaceDim=getSpaceDimension();
4905 throw INTERP_KERNEL::Exception(msg);
4907 int nbOfCells=getNumberOfCells();
4908 int *conn=_nodal_connec->getPointer();
4909 const int *connI=_nodal_connec_index->begin();
4910 const double *coo=getCoords()->begin();
4911 MCAuto<DataArrayInt> cells(DataArrayInt::New()); cells->alloc(0,1);
4912 for(int i=0;i<nbOfCells;i++)
4914 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4915 if(cm.isExtruded() && !cm.isDynamic() && !cm.isQuadratic())
4917 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coo))
4919 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
4920 cells->pushBackSilent(i);
4924 return cells.retn();
4928 * This method is a faster method to correct orientation of all 3D cells in \a this.
4929 * 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.
4930 * This method makes the hypothesis that \a this a coherent that is to say MEDCouplingUMesh::checkConsistency should throw no exception.
4932 * \return a newly allocated int array with one components containing cell ids renumbered to fit the convention of MED (MED file and MEDCoupling)
4933 * \sa MEDCouplingUMesh::orientCorrectlyPolyhedrons,
4935 DataArrayInt *MEDCouplingUMesh::findAndCorrectBadOriented3DCells()
4937 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
4938 throw INTERP_KERNEL::Exception("Invalid mesh to apply findAndCorrectBadOriented3DCells on it : must be meshDim==3 and spaceDim==3 !");
4939 int nbOfCells=getNumberOfCells();
4940 int *conn=_nodal_connec->getPointer();
4941 const int *connI=_nodal_connec_index->begin();
4942 const double *coordsPtr=_coords->begin();
4943 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
4944 for(int i=0;i<nbOfCells;i++)
4946 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4949 case INTERP_KERNEL::NORM_TETRA4:
4951 if(!IsTetra4WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4953 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+3));
4954 ret->pushBackSilent(i);
4958 case INTERP_KERNEL::NORM_PYRA5:
4960 if(!IsPyra5WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4962 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+4));
4963 ret->pushBackSilent(i);
4967 case INTERP_KERNEL::NORM_PENTA6:
4968 case INTERP_KERNEL::NORM_HEXA8:
4969 case INTERP_KERNEL::NORM_HEXGP12:
4971 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4973 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
4974 ret->pushBackSilent(i);
4978 case INTERP_KERNEL::NORM_POLYHED:
4980 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4982 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
4983 ret->pushBackSilent(i);
4988 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 !");
4996 * This method has a sense for meshes with spaceDim==3 and meshDim==2.
4997 * If it is not the case an exception will be thrown.
4998 * This method is fast because the first cell of \a this is used to compute the plane.
4999 * \param vec output of size at least 3 used to store the normal vector (with norm equal to Area ) of searched plane.
5000 * \param pos output of size at least 3 used to store a point owned of searched plane.
5002 void MEDCouplingUMesh::getFastAveragePlaneOfThis(double *vec, double *pos) const
5004 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
5005 throw INTERP_KERNEL::Exception("Invalid mesh to apply getFastAveragePlaneOfThis on it : must be meshDim==2 and spaceDim==3 !");
5006 const int *conn=_nodal_connec->begin();
5007 const int *connI=_nodal_connec_index->begin();
5008 const double *coordsPtr=_coords->begin();
5009 INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(conn+1,connI[1]-connI[0]-1,coordsPtr,vec);
5010 std::copy(coordsPtr+3*conn[1],coordsPtr+3*conn[1]+3,pos);
5014 * Creates a new MEDCouplingFieldDouble holding Edge Ratio values of all
5015 * cells. Currently cells of the following types are treated:
5016 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5017 * For a cell of other type an exception is thrown.
5018 * Space dimension of a 2D mesh can be either 2 or 3.
5019 * The Edge Ratio of a cell \f$t\f$ is:
5020 * \f$\frac{|t|_\infty}{|t|_0}\f$,
5021 * where \f$|t|_\infty\f$ and \f$|t|_0\f$ respectively denote the greatest and
5022 * the smallest edge lengths of \f$t\f$.
5023 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5024 * cells and one time, lying on \a this mesh. The caller is to delete this
5025 * field using decrRef() as it is no more needed.
5026 * \throw If the coordinates array is not set.
5027 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5028 * \throw If the connectivity data array has more than one component.
5029 * \throw If the connectivity data array has a named component.
5030 * \throw If the connectivity index data array has more than one component.
5031 * \throw If the connectivity index data array has a named component.
5032 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
5033 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5034 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5036 MEDCouplingFieldDouble *MEDCouplingUMesh::getEdgeRatioField() const
5038 checkConsistencyLight();
5039 int spaceDim=getSpaceDimension();
5040 int meshDim=getMeshDimension();
5041 if(spaceDim!=2 && spaceDim!=3)
5042 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : SpaceDimension must be equal to 2 or 3 !");
5043 if(meshDim!=2 && meshDim!=3)
5044 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : MeshDimension must be equal to 2 or 3 !");
5045 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5047 int nbOfCells=getNumberOfCells();
5048 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5049 arr->alloc(nbOfCells,1);
5050 double *pt=arr->getPointer();
5051 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5052 const int *conn=_nodal_connec->begin();
5053 const int *connI=_nodal_connec_index->begin();
5054 const double *coo=_coords->begin();
5056 for(int i=0;i<nbOfCells;i++,pt++)
5058 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5061 case INTERP_KERNEL::NORM_TRI3:
5063 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5064 *pt=INTERP_KERNEL::triEdgeRatio(tmp);
5067 case INTERP_KERNEL::NORM_QUAD4:
5069 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5070 *pt=INTERP_KERNEL::quadEdgeRatio(tmp);
5073 case INTERP_KERNEL::NORM_TETRA4:
5075 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5076 *pt=INTERP_KERNEL::tetraEdgeRatio(tmp);
5080 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5082 conn+=connI[i+1]-connI[i];
5084 ret->setName("EdgeRatio");
5085 ret->synchronizeTimeWithSupport();
5090 * Creates a new MEDCouplingFieldDouble holding Aspect Ratio values of all
5091 * cells. Currently cells of the following types are treated:
5092 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5093 * For a cell of other type an exception is thrown.
5094 * Space dimension of a 2D mesh can be either 2 or 3.
5095 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5096 * cells and one time, lying on \a this mesh. The caller is to delete this
5097 * field using decrRef() as it is no more needed.
5098 * \throw If the coordinates array is not set.
5099 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5100 * \throw If the connectivity data array has more than one component.
5101 * \throw If the connectivity data array has a named component.
5102 * \throw If the connectivity index data array has more than one component.
5103 * \throw If the connectivity index data array has a named component.
5104 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
5105 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5106 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5108 MEDCouplingFieldDouble *MEDCouplingUMesh::getAspectRatioField() const
5110 checkConsistencyLight();
5111 int spaceDim=getSpaceDimension();
5112 int meshDim=getMeshDimension();
5113 if(spaceDim!=2 && spaceDim!=3)
5114 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : SpaceDimension must be equal to 2 or 3 !");
5115 if(meshDim!=2 && meshDim!=3)
5116 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : MeshDimension must be equal to 2 or 3 !");
5117 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5119 int nbOfCells=getNumberOfCells();
5120 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5121 arr->alloc(nbOfCells,1);
5122 double *pt=arr->getPointer();
5123 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5124 const int *conn=_nodal_connec->begin();
5125 const int *connI=_nodal_connec_index->begin();
5126 const double *coo=_coords->begin();
5128 for(int i=0;i<nbOfCells;i++,pt++)
5130 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5133 case INTERP_KERNEL::NORM_TRI3:
5135 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5136 *pt=INTERP_KERNEL::triAspectRatio(tmp);
5139 case INTERP_KERNEL::NORM_QUAD4:
5141 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5142 *pt=INTERP_KERNEL::quadAspectRatio(tmp);
5145 case INTERP_KERNEL::NORM_TETRA4:
5147 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5148 *pt=INTERP_KERNEL::tetraAspectRatio(tmp);
5152 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5154 conn+=connI[i+1]-connI[i];
5156 ret->setName("AspectRatio");
5157 ret->synchronizeTimeWithSupport();
5162 * Creates a new MEDCouplingFieldDouble holding Warping factor values of all
5163 * cells of \a this 2D mesh in 3D space. It is a measure of the "planarity" of 2D cell
5164 * in 3D space. Currently only cells of the following types are
5165 * treated: INTERP_KERNEL::NORM_QUAD4.
5166 * For a cell of other type an exception is thrown.
5167 * The warp field is computed as follows: let (a,b,c,d) be the points of the quad.
5169 * \f$t=\vec{da}\times\vec{ab}\f$,
5170 * \f$u=\vec{ab}\times\vec{bc}\f$
5171 * \f$v=\vec{bc}\times\vec{cd}\f$
5172 * \f$w=\vec{cd}\times\vec{da}\f$, the warp is defined as \f$W^3\f$ with
5174 * W=min(\frac{t}{|t|}\cdot\frac{v}{|v|}, \frac{u}{|u|}\cdot\frac{w}{|w|})
5176 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5177 * cells and one time, lying on \a this mesh. The caller is to delete this
5178 * field using decrRef() as it is no more needed.
5179 * \throw If the coordinates array is not set.
5180 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5181 * \throw If the connectivity data array has more than one component.
5182 * \throw If the connectivity data array has a named component.
5183 * \throw If the connectivity index data array has more than one component.
5184 * \throw If the connectivity index data array has a named component.
5185 * \throw If \a this->getMeshDimension() != 2.
5186 * \throw If \a this->getSpaceDimension() != 3.
5187 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5189 MEDCouplingFieldDouble *MEDCouplingUMesh::getWarpField() const
5191 checkConsistencyLight();
5192 int spaceDim=getSpaceDimension();
5193 int meshDim=getMeshDimension();
5195 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : SpaceDimension must be equal to 3 !");
5197 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : MeshDimension must be equal to 2 !");
5198 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5200 int nbOfCells=getNumberOfCells();
5201 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5202 arr->alloc(nbOfCells,1);
5203 double *pt=arr->getPointer();
5204 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5205 const int *conn=_nodal_connec->begin();
5206 const int *connI=_nodal_connec_index->begin();
5207 const double *coo=_coords->begin();
5209 for(int i=0;i<nbOfCells;i++,pt++)
5211 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5214 case INTERP_KERNEL::NORM_QUAD4:
5216 FillInCompact3DMode(3,4,conn+1,coo,tmp);
5217 *pt=INTERP_KERNEL::quadWarp(tmp);
5221 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : A cell with not manged type (NORM_QUAD4) has been detected !");
5223 conn+=connI[i+1]-connI[i];
5225 ret->setName("Warp");
5226 ret->synchronizeTimeWithSupport();
5232 * Creates a new MEDCouplingFieldDouble holding Skew factor values of all
5233 * cells of \a this 2D mesh in 3D space. Currently cells of the following types are
5234 * treated: INTERP_KERNEL::NORM_QUAD4.
5235 * The skew is computed as follow for a quad with points (a,b,c,d): let
5236 * \f$u=\vec{ab}+\vec{dc}\f$ and \f$v=\vec{ac}+\vec{bd}\f$
5237 * then the skew is computed as:
5239 * s=\frac{u}{|u|}\cdot\frac{v}{|v|}
5242 * For a cell of other type an exception is thrown.
5243 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5244 * cells and one time, lying on \a this mesh. The caller is to delete this
5245 * field using decrRef() as it is no more needed.
5246 * \throw If the coordinates array is not set.
5247 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5248 * \throw If the connectivity data array has more than one component.
5249 * \throw If the connectivity data array has a named component.
5250 * \throw If the connectivity index data array has more than one component.
5251 * \throw If the connectivity index data array has a named component.
5252 * \throw If \a this->getMeshDimension() != 2.
5253 * \throw If \a this->getSpaceDimension() != 3.
5254 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5256 MEDCouplingFieldDouble *MEDCouplingUMesh::getSkewField() const
5258 checkConsistencyLight();
5259 int spaceDim=getSpaceDimension();
5260 int meshDim=getMeshDimension();
5262 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : SpaceDimension must be equal to 3 !");
5264 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : MeshDimension must be equal to 2 !");
5265 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5267 int nbOfCells=getNumberOfCells();
5268 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5269 arr->alloc(nbOfCells,1);
5270 double *pt=arr->getPointer();
5271 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5272 const int *conn=_nodal_connec->begin();
5273 const int *connI=_nodal_connec_index->begin();
5274 const double *coo=_coords->begin();
5276 for(int i=0;i<nbOfCells;i++,pt++)
5278 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5281 case INTERP_KERNEL::NORM_QUAD4:
5283 FillInCompact3DMode(3,4,conn+1,coo,tmp);
5284 *pt=INTERP_KERNEL::quadSkew(tmp);
5288 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : A cell with not manged type (NORM_QUAD4) has been detected !");
5290 conn+=connI[i+1]-connI[i];
5292 ret->setName("Skew");
5293 ret->synchronizeTimeWithSupport();
5298 * 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.
5300 * \return a new instance of field containing the result. The returned instance has to be deallocated by the caller.
5302 * \sa getSkewField, getWarpField, getAspectRatioField, getEdgeRatioField
5304 MEDCouplingFieldDouble *MEDCouplingUMesh::computeDiameterField() const
5306 checkConsistencyLight();
5307 MCAuto<MEDCouplingFieldDouble> ret(MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME));
5309 std::set<INTERP_KERNEL::NormalizedCellType> types;
5310 ComputeAllTypesInternal(types,_nodal_connec,_nodal_connec_index);
5311 int spaceDim(getSpaceDimension()),nbCells(getNumberOfCells());
5312 MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
5313 arr->alloc(nbCells,1);
5314 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++)
5316 INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::DiameterCalculator> dc(INTERP_KERNEL::CellModel::GetCellModel(*it).buildInstanceOfDiameterCalulator(spaceDim));
5317 MCAuto<DataArrayInt> cellIds(giveCellsWithType(*it));
5318 dc->computeForListOfCellIdsUMeshFrmt(cellIds->begin(),cellIds->end(),_nodal_connec_index->begin(),_nodal_connec->begin(),getCoords()->begin(),arr->getPointer());
5321 ret->setName("Diameter");
5326 * This method aggregate the bbox of each cell and put it into bbox parameter (xmin,xmax,ymin,ymax,zmin,zmax).
5328 * \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)
5329 * For all other cases this input parameter is ignored.
5330 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5332 * \throw If \a this is not fully set (coordinates and connectivity).
5333 * \throw If a cell in \a this has no valid nodeId.
5334 * \sa MEDCouplingUMesh::getBoundingBoxForBBTreeFast, MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5336 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree(double arcDetEps) const
5338 int mDim(getMeshDimension()),sDim(getSpaceDimension());
5339 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.
5340 return getBoundingBoxForBBTreeFast();
5341 if((mDim==2 && sDim==2) || (mDim==1 && sDim==2))
5343 bool presenceOfQuadratic(false);
5344 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=_types.begin();it!=_types.end();it++)
5346 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(*it));
5347 if(cm.isQuadratic())
5348 presenceOfQuadratic=true;
5350 if(!presenceOfQuadratic)
5351 return getBoundingBoxForBBTreeFast();
5352 if(mDim==2 && sDim==2)
5353 return getBoundingBoxForBBTree2DQuadratic(arcDetEps);
5355 return getBoundingBoxForBBTree1DQuadratic(arcDetEps);
5357 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) !");
5361 * This method aggregate the bbox of each cell only considering the nodes constituting each cell and put it into bbox parameter.
5362 * So meshes having quadratic cells the computed bounding boxes can be invalid !
5364 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5366 * \throw If \a this is not fully set (coordinates and connectivity).
5367 * \throw If a cell in \a this has no valid nodeId.
5369 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTreeFast() const
5371 checkFullyDefined();
5372 int spaceDim(getSpaceDimension()),nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
5373 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5374 double *bbox(ret->getPointer());
5375 for(int i=0;i<nbOfCells*spaceDim;i++)
5377 bbox[2*i]=std::numeric_limits<double>::max();
5378 bbox[2*i+1]=-std::numeric_limits<double>::max();
5380 const double *coordsPtr(_coords->begin());
5381 const int *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5382 for(int i=0;i<nbOfCells;i++)
5384 int offset=connI[i]+1;
5385 int nbOfNodesForCell(connI[i+1]-offset),kk(0);
5386 for(int j=0;j<nbOfNodesForCell;j++)
5388 int nodeId=conn[offset+j];
5389 if(nodeId>=0 && nodeId<nbOfNodes)
5391 for(int k=0;k<spaceDim;k++)
5393 bbox[2*spaceDim*i+2*k]=std::min(bbox[2*spaceDim*i+2*k],coordsPtr[spaceDim*nodeId+k]);
5394 bbox[2*spaceDim*i+2*k+1]=std::max(bbox[2*spaceDim*i+2*k+1],coordsPtr[spaceDim*nodeId+k]);
5401 std::ostringstream oss; oss << "MEDCouplingUMesh::getBoundingBoxForBBTree : cell #" << i << " contains no valid nodeId !";
5402 throw INTERP_KERNEL::Exception(oss.str());
5409 * This method aggregates the bbox of each 2D cell in \a this considering the whole shape. This method is particularly
5410 * useful for 2D meshes having quadratic cells
5411 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5412 * the two extremities of the arc of circle).
5414 * \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)
5415 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5416 * \throw If \a this is not fully defined.
5417 * \throw If \a this is not a mesh with meshDimension equal to 2.
5418 * \throw If \a this is not a mesh with spaceDimension equal to 2.
5419 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic
5421 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic(double arcDetEps) const
5423 checkFullyDefined();
5424 int spaceDim(getSpaceDimension()),mDim(getMeshDimension()),nbOfCells(getNumberOfCells());
5425 if(spaceDim!=2 || mDim!=2)
5426 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic : This method should be applied on mesh with mesh dimension equal to 2 and space dimension also equal to 2!");
5427 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5428 double *bbox(ret->getPointer());
5429 const double *coords(_coords->begin());
5430 const int *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5431 for(int i=0;i<nbOfCells;i++,bbox+=4,connI++)
5433 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5434 int sz(connI[1]-connI[0]-1);
5435 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=arcDetEps;
5436 std::vector<INTERP_KERNEL::Node *> nodes(sz);
5437 INTERP_KERNEL::QuadraticPolygon *pol(0);
5438 for(int j=0;j<sz;j++)
5440 int nodeId(conn[*connI+1+j]);
5441 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5443 if(!cm.isQuadratic())
5444 pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
5446 pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
5447 INTERP_KERNEL::Bounds b; b.prepareForAggregation(); pol->fillBounds(b); delete pol;
5448 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax();
5454 * This method aggregates the bbox of each 1D cell in \a this considering the whole shape. This method is particularly
5455 * useful for 2D meshes having quadratic cells
5456 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5457 * the two extremities of the arc of circle).
5459 * \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)
5460 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5461 * \throw If \a this is not fully defined.
5462 * \throw If \a this is not a mesh with meshDimension equal to 1.
5463 * \throw If \a this is not a mesh with spaceDimension equal to 2.
5464 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5466 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic(double arcDetEps) const
5468 checkFullyDefined();
5469 int spaceDim(getSpaceDimension()),mDim(getMeshDimension()),nbOfCells(getNumberOfCells());
5470 if(spaceDim!=2 || mDim!=1)
5471 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!");
5472 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5473 double *bbox(ret->getPointer());
5474 const double *coords(_coords->begin());
5475 const int *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5476 for(int i=0;i<nbOfCells;i++,bbox+=4,connI++)
5478 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5479 int sz(connI[1]-connI[0]-1);
5480 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=arcDetEps;
5481 std::vector<INTERP_KERNEL::Node *> nodes(sz);
5482 INTERP_KERNEL::Edge *edge(0);
5483 for(int j=0;j<sz;j++)
5485 int nodeId(conn[*connI+1+j]);
5486 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5488 if(!cm.isQuadratic())
5489 edge=INTERP_KERNEL::QuadraticPolygon::BuildLinearEdge(nodes);
5491 edge=INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(nodes);
5492 const INTERP_KERNEL::Bounds& b(edge->getBounds());
5493 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax(); edge->decrRef();
5500 namespace MEDCouplingImpl
5505 ConnReader(const int *c, int val):_conn(c),_val(val) { }
5506 bool operator() (const int& pos) { return _conn[pos]!=_val; }
5515 ConnReader2(const int *c, int val):_conn(c),_val(val) { }
5516 bool operator() (const int& pos) { return _conn[pos]==_val; }
5526 * This method expects that \a this is sorted by types. If not an exception will be thrown.
5527 * This method returns in the same format as code (see MEDCouplingUMesh::checkTypeConsistencyAndContig or MEDCouplingUMesh::splitProfilePerType) how
5528 * \a this is composed in cell types.
5529 * The returned array is of size 3*n where n is the number of different types present in \a this.
5530 * For every k in [0,n] ret[3*k+2]==-1 because it has no sense here.
5531 * This parameter is kept only for compatibility with other methode listed above.
5533 std::vector<int> MEDCouplingUMesh::getDistributionOfTypes() const
5535 checkConnectivityFullyDefined();
5536 const int *conn=_nodal_connec->begin();
5537 const int *connI=_nodal_connec_index->begin();
5538 const int *work=connI;
5539 int nbOfCells=getNumberOfCells();
5540 std::size_t n=getAllGeoTypes().size();
5541 std::vector<int> ret(3*n,-1); //ret[3*k+2]==-1 because it has no sense here
5542 std::set<INTERP_KERNEL::NormalizedCellType> types;
5543 for(std::size_t i=0;work!=connI+nbOfCells;i++)
5545 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn[*work];
5546 if(types.find(typ)!=types.end())
5548 std::ostringstream oss; oss << "MEDCouplingUMesh::getDistributionOfTypes : Type " << INTERP_KERNEL::CellModel::GetCellModel(typ).getRepr();
5549 oss << " is not contiguous !";
5550 throw INTERP_KERNEL::Exception(oss.str());
5554 const int *work2=std::find_if(work+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,typ));
5555 ret[3*i+1]=(int)std::distance(work,work2);
5562 * This method is used to check that this has contiguous cell type in same order than described in \a code.
5563 * only for types cell, type node is not managed.
5564 * Format of \a code is the following. \a code should be of size 3*n and non empty. If not an exception is thrown.
5565 * foreach k in [0,n) on 3*k pos represent the geometric type and 3*k+1 number of elements of type 3*k.
5566 * 3*k+2 refers if different from -1 the pos in 'idsPerType' to get the corresponding array.
5567 * If 2 or more same geometric type is in \a code and exception is thrown too.
5569 * This method firstly checks
5570 * If it exists k so that 3*k geometric type is not in geometric types of this an exception will be thrown.
5571 * If it exists k so that 3*k geometric type exists but the number of consecutive cell types does not match,
5572 * an exception is thrown too.
5574 * If all geometric types in \a code are exactly those in \a this null pointer is returned.
5575 * If it exists a geometric type in \a this \b not in \a code \b no exception is thrown
5576 * and a DataArrayInt instance is returned that the user has the responsability to deallocate.
5578 DataArrayInt *MEDCouplingUMesh::checkTypeConsistencyAndContig(const std::vector<int>& code, const std::vector<const DataArrayInt *>& idsPerType) const
5581 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code is empty, should not !");
5582 std::size_t sz=code.size();
5585 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code size is NOT %3 !");
5586 std::vector<INTERP_KERNEL::NormalizedCellType> types;
5588 bool isNoPflUsed=true;
5589 for(std::size_t i=0;i<n;i++)
5590 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)code[3*i])==types.end())
5592 types.push_back((INTERP_KERNEL::NormalizedCellType)code[3*i]);
5594 if(_types.find((INTERP_KERNEL::NormalizedCellType)code[3*i])==_types.end())
5595 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : expected geo types not in this !");
5596 isNoPflUsed=isNoPflUsed && (code[3*i+2]==-1);
5599 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code contains duplication of types in unstructured mesh !");
5602 if(!checkConsecutiveCellTypesAndOrder(&types[0],&types[0]+types.size()))
5603 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : non contiguous type !");
5604 if(types.size()==_types.size())
5607 MCAuto<DataArrayInt> ret=DataArrayInt::New();
5609 int *retPtr=ret->getPointer();
5610 const int *connI=_nodal_connec_index->begin();
5611 const int *conn=_nodal_connec->begin();
5612 int nbOfCells=getNumberOfCells();
5615 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++,kk++)
5617 i=std::find_if(i,connI+nbOfCells,MEDCouplingImpl::ConnReader2(conn,(int)(*it)));
5618 int offset=(int)std::distance(connI,i);
5619 const int *j=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)(*it)));
5620 int nbOfCellsOfCurType=(int)std::distance(i,j);
5621 if(code[3*kk+2]==-1)
5622 for(int k=0;k<nbOfCellsOfCurType;k++)
5626 int idInIdsPerType=code[3*kk+2];
5627 if(idInIdsPerType>=0 && idInIdsPerType<(int)idsPerType.size())
5629 const DataArrayInt *zePfl=idsPerType[idInIdsPerType];
5632 zePfl->checkAllocated();
5633 if(zePfl->getNumberOfComponents()==1)
5635 for(const int *k=zePfl->begin();k!=zePfl->end();k++,retPtr++)
5637 if(*k>=0 && *k<nbOfCellsOfCurType)
5638 *retPtr=(*k)+offset;
5641 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : the section " << kk << " points to the profile #" << idInIdsPerType;
5642 oss << ", and this profile contains a value " << *k << " should be in [0," << nbOfCellsOfCurType << ") !";
5643 throw INTERP_KERNEL::Exception(oss.str());
5648 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of a profile with nb of compo != 1 !");
5651 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of null profile !");
5655 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : at section " << kk << " of code it points to the array #" << idInIdsPerType;
5656 oss << " should be in [0," << idsPerType.size() << ") !";
5657 throw INTERP_KERNEL::Exception(oss.str());
5666 * This method makes the hypothesis that \a this is sorted by type. If not an exception will be thrown.
5667 * 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.
5668 * 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.
5669 * This method has 1 input \a profile and 3 outputs \a code \a idsInPflPerType and \a idsPerType.
5671 * \param [in] profile
5672 * \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.
5673 * \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,
5674 * \a idsInPflPerType[i] stores the tuple ids in \a profile that correspond to the geometric type code[3*i+0]
5675 * \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.
5676 * This vector can be empty in case of all geometric type cells are fully covered in ascending in the given input \a profile.
5677 * \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
5679 void MEDCouplingUMesh::splitProfilePerType(const DataArrayInt *profile, std::vector<int>& code, std::vector<DataArrayInt *>& idsInPflPerType, std::vector<DataArrayInt *>& idsPerType) const
5682 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile is NULL !");
5683 if(profile->getNumberOfComponents()!=1)
5684 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile should have exactly one component !");
5685 checkConnectivityFullyDefined();
5686 const int *conn=_nodal_connec->begin();
5687 const int *connI=_nodal_connec_index->begin();
5688 int nbOfCells=getNumberOfCells();
5689 std::vector<INTERP_KERNEL::NormalizedCellType> types;
5690 std::vector<int> typeRangeVals(1);
5691 for(const int *i=connI;i!=connI+nbOfCells;)
5693 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5694 if(std::find(types.begin(),types.end(),curType)!=types.end())
5696 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : current mesh is not sorted by type !");
5698 types.push_back(curType);
5699 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
5700 typeRangeVals.push_back((int)std::distance(connI,i));
5703 DataArrayInt *castArr=0,*rankInsideCast=0,*castsPresent=0;
5704 profile->splitByValueRange(&typeRangeVals[0],&typeRangeVals[0]+typeRangeVals.size(),castArr,rankInsideCast,castsPresent);
5705 MCAuto<DataArrayInt> tmp0=castArr;
5706 MCAuto<DataArrayInt> tmp1=rankInsideCast;
5707 MCAuto<DataArrayInt> tmp2=castsPresent;
5709 int nbOfCastsFinal=castsPresent->getNumberOfTuples();
5710 code.resize(3*nbOfCastsFinal);
5711 std::vector< MCAuto<DataArrayInt> > idsInPflPerType2;
5712 std::vector< MCAuto<DataArrayInt> > idsPerType2;
5713 for(int i=0;i<nbOfCastsFinal;i++)
5715 int castId=castsPresent->getIJ(i,0);
5716 MCAuto<DataArrayInt> tmp3=castArr->findIdsEqual(castId);
5717 idsInPflPerType2.push_back(tmp3);
5718 code[3*i]=(int)types[castId];
5719 code[3*i+1]=tmp3->getNumberOfTuples();
5720 MCAuto<DataArrayInt> tmp4=rankInsideCast->selectByTupleId(tmp3->begin(),tmp3->begin()+tmp3->getNumberOfTuples());
5721 if(!tmp4->isIota(typeRangeVals[castId+1]-typeRangeVals[castId]))
5723 tmp4->copyStringInfoFrom(*profile);
5724 idsPerType2.push_back(tmp4);
5725 code[3*i+2]=(int)idsPerType2.size()-1;
5732 std::size_t sz2=idsInPflPerType2.size();
5733 idsInPflPerType.resize(sz2);
5734 for(std::size_t i=0;i<sz2;i++)
5736 DataArrayInt *locDa=idsInPflPerType2[i];
5738 idsInPflPerType[i]=locDa;
5740 std::size_t sz=idsPerType2.size();
5741 idsPerType.resize(sz);
5742 for(std::size_t i=0;i<sz;i++)
5744 DataArrayInt *locDa=idsPerType2[i];
5746 idsPerType[i]=locDa;
5751 * This method is here too emulate the MEDMEM behaviour on BDC (buildDescendingConnectivity). Hoping this method becomes deprecated very soon.
5752 * This method make the assumption that \a this and 'nM1LevMesh' mesh lyies on same coords (same pointer) as MED and MEDMEM does.
5753 * The following equality should be verified 'nM1LevMesh->getMeshDimension()==this->getMeshDimension()-1'
5754 * 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.
5756 MEDCouplingUMesh *MEDCouplingUMesh::emulateMEDMEMBDC(const MEDCouplingUMesh *nM1LevMesh, DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *&revDesc, DataArrayInt *&revDescIndx, DataArrayInt *& nM1LevMeshIds, DataArrayInt *&meshnM1Old2New) const
5758 checkFullyDefined();
5759 nM1LevMesh->checkFullyDefined();
5760 if(getMeshDimension()-1!=nM1LevMesh->getMeshDimension())
5761 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : The mesh passed as first argument should have a meshDim equal to this->getMeshDimension()-1 !" );
5762 if(_coords!=nM1LevMesh->getCoords())
5763 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : 'this' and mesh in first argument should share the same coords : Use tryToShareSameCoords method !");
5764 MCAuto<DataArrayInt> tmp0=DataArrayInt::New();
5765 MCAuto<DataArrayInt> tmp1=DataArrayInt::New();
5766 MCAuto<MEDCouplingUMesh> ret1=buildDescendingConnectivity(desc,descIndx,tmp0,tmp1);
5767 MCAuto<DataArrayInt> ret0=ret1->sortCellsInMEDFileFrmt();
5768 desc->transformWithIndArr(ret0->begin(),ret0->begin()+ret0->getNbOfElems());
5769 MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
5770 tmp->setConnectivity(tmp0,tmp1);
5771 tmp->renumberCells(ret0->begin(),false);
5772 revDesc=tmp->getNodalConnectivity();
5773 revDescIndx=tmp->getNodalConnectivityIndex();
5774 DataArrayInt *ret=0;
5775 if(!ret1->areCellsIncludedIn(nM1LevMesh,2,ret))
5778 ret->getMaxValue(tmp2);
5780 std::ostringstream oss; oss << "MEDCouplingUMesh::emulateMEDMEMBDC : input N-1 mesh present a cell not in descending mesh ... Id of cell is " << tmp2 << " !";
5781 throw INTERP_KERNEL::Exception(oss.str());
5786 revDescIndx->incrRef();
5789 meshnM1Old2New=ret0;
5794 * Permutes the nodal connectivity arrays so that the cells are sorted by type, which is
5795 * necessary for writing the mesh to MED file. Additionally returns a permutation array
5796 * in "Old to New" mode.
5797 * \return DataArrayInt * - a new instance of DataArrayInt. The caller is to delete
5798 * this array using decrRef() as it is no more needed.
5799 * \throw If the nodal connectivity of cells is not defined.
5801 DataArrayInt *MEDCouplingUMesh::sortCellsInMEDFileFrmt()
5803 checkConnectivityFullyDefined();
5804 MCAuto<DataArrayInt> ret=getRenumArrForMEDFileFrmt();
5805 renumberCells(ret->begin(),false);
5810 * This methods checks that cells are sorted by their types.
5811 * This method makes asumption (no check) that connectivity is correctly set before calling.
5813 bool MEDCouplingUMesh::checkConsecutiveCellTypes() const
5815 checkFullyDefined();
5816 const int *conn=_nodal_connec->begin();
5817 const int *connI=_nodal_connec_index->begin();
5818 int nbOfCells=getNumberOfCells();
5819 std::set<INTERP_KERNEL::NormalizedCellType> types;
5820 for(const int *i=connI;i!=connI+nbOfCells;)
5822 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5823 if(types.find(curType)!=types.end())
5825 types.insert(curType);
5826 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
5832 * This method is a specialization of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method that is called here.
5833 * The geometric type order is specified by MED file.
5835 * \sa MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder
5837 bool MEDCouplingUMesh::checkConsecutiveCellTypesForMEDFileFrmt() const
5839 return checkConsecutiveCellTypesAndOrder(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
5843 * This method performs the same job as checkConsecutiveCellTypes except that the order of types sequence is analyzed to check
5844 * that the order is specified in array defined by [ \a orderBg , \a orderEnd ).
5845 * If there is some geo types in \a this \b NOT in [ \a orderBg, \a orderEnd ) it is OK (return true) if contiguous.
5846 * If there is some geo types in [ \a orderBg, \a orderEnd ) \b NOT in \a this it is OK too (return true) if contiguous.
5848 bool MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
5850 checkFullyDefined();
5851 const int *conn=_nodal_connec->begin();
5852 const int *connI=_nodal_connec_index->begin();
5853 int nbOfCells=getNumberOfCells();
5857 std::set<INTERP_KERNEL::NormalizedCellType> sg;
5858 for(const int *i=connI;i!=connI+nbOfCells;)
5860 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5861 const INTERP_KERNEL::NormalizedCellType *isTypeExists=std::find(orderBg,orderEnd,curType);
5862 if(isTypeExists!=orderEnd)
5864 int pos=(int)std::distance(orderBg,isTypeExists);
5868 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
5872 if(sg.find(curType)==sg.end())
5874 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
5885 * This method returns 2 newly allocated DataArrayInt instances. The first is an array of size 'this->getNumberOfCells()' with one component,
5886 * 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
5887 * 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'.
5889 DataArrayInt *MEDCouplingUMesh::getLevArrPerCellTypes(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd, DataArrayInt *&nbPerType) const
5891 checkConnectivityFullyDefined();
5892 int nbOfCells=getNumberOfCells();
5893 const int *conn=_nodal_connec->begin();
5894 const int *connI=_nodal_connec_index->begin();
5895 MCAuto<DataArrayInt> tmpa=DataArrayInt::New();
5896 MCAuto<DataArrayInt> tmpb=DataArrayInt::New();
5897 tmpa->alloc(nbOfCells,1);
5898 tmpb->alloc((int)std::distance(orderBg,orderEnd),1);
5899 tmpb->fillWithZero();
5900 int *tmp=tmpa->getPointer();
5901 int *tmp2=tmpb->getPointer();
5902 for(const int *i=connI;i!=connI+nbOfCells;i++)
5904 const INTERP_KERNEL::NormalizedCellType *where=std::find(orderBg,orderEnd,(INTERP_KERNEL::NormalizedCellType)conn[*i]);
5907 int pos=(int)std::distance(orderBg,where);
5909 tmp[std::distance(connI,i)]=pos;
5913 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*i]);
5914 std::ostringstream oss; oss << "MEDCouplingUMesh::getLevArrPerCellTypes : Cell #" << std::distance(connI,i);
5915 oss << " has a type " << cm.getRepr() << " not in input array of type !";
5916 throw INTERP_KERNEL::Exception(oss.str());
5919 nbPerType=tmpb.retn();
5924 * This method behaves exactly as MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec but the order is those defined in MED file spec.
5926 * \return a new object containing the old to new correspondance.
5928 * \sa MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec, MEDCouplingUMesh::sortCellsInMEDFileFrmt.
5930 DataArrayInt *MEDCouplingUMesh::getRenumArrForMEDFileFrmt() const
5932 return getRenumArrForConsecutiveCellTypesSpec(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
5936 * 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.
5937 * This method returns an array of size getNumberOfCells() that gives a renumber array old2New that can be used as input of MEDCouplingMesh::renumberCells.
5938 * The mesh after this call to MEDCouplingMesh::renumberCells will pass the test of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder with the same inputs.
5939 * The returned array minimizes the permutations that is to say the order of cells inside same geometric type remains the same.
5941 DataArrayInt *MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
5943 DataArrayInt *nbPerType=0;
5944 MCAuto<DataArrayInt> tmpa=getLevArrPerCellTypes(orderBg,orderEnd,nbPerType);
5945 nbPerType->decrRef();
5946 return tmpa->buildPermArrPerLevel();
5950 * This method reorganize the cells of \a this so that the cells with same geometric types are put together.
5951 * The number of cells remains unchanged after the call of this method.
5952 * This method tries to minimizes the number of needed permutations. So, this method behaves not exactly as
5953 * MEDCouplingUMesh::sortCellsInMEDFileFrmt.
5955 * \return the array giving the correspondance old to new.
5957 DataArrayInt *MEDCouplingUMesh::rearrange2ConsecutiveCellTypes()
5959 checkFullyDefined();
5961 const int *conn=_nodal_connec->begin();
5962 const int *connI=_nodal_connec_index->begin();
5963 int nbOfCells=getNumberOfCells();
5964 std::vector<INTERP_KERNEL::NormalizedCellType> types;
5965 for(const int *i=connI;i!=connI+nbOfCells && (types.size()!=_types.size());)
5966 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)conn[*i])==types.end())
5968 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5969 types.push_back(curType);
5970 for(i++;i!=connI+nbOfCells && (INTERP_KERNEL::NormalizedCellType)conn[*i]==curType;i++);
5972 DataArrayInt *ret=DataArrayInt::New();
5973 ret->alloc(nbOfCells,1);
5974 int *retPtr=ret->getPointer();
5975 std::fill(retPtr,retPtr+nbOfCells,-1);
5977 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
5979 for(const int *i=connI;i!=connI+nbOfCells;i++)
5980 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
5981 retPtr[std::distance(connI,i)]=newCellId++;
5983 renumberCells(retPtr,false);
5988 * This method splits \a this into as mush as untructured meshes that consecutive set of same type cells.
5989 * So this method has typically a sense if MEDCouplingUMesh::checkConsecutiveCellTypes has a sense.
5990 * This method makes asumption that connectivity is correctly set before calling.
5992 std::vector<MEDCouplingUMesh *> MEDCouplingUMesh::splitByType() const
5994 checkConnectivityFullyDefined();
5995 const int *conn=_nodal_connec->begin();
5996 const int *connI=_nodal_connec_index->begin();
5997 int nbOfCells=getNumberOfCells();
5998 std::vector<MEDCouplingUMesh *> ret;
5999 for(const int *i=connI;i!=connI+nbOfCells;)
6001 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6002 int beginCellId=(int)std::distance(connI,i);
6003 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
6004 int endCellId=(int)std::distance(connI,i);
6005 int sz=endCellId-beginCellId;
6006 int *cells=new int[sz];
6007 for(int j=0;j<sz;j++)
6008 cells[j]=beginCellId+j;
6009 MEDCouplingUMesh *m=(MEDCouplingUMesh *)buildPartOfMySelf(cells,cells+sz,true);
6017 * This method performs the opposite operation than those in MEDCoupling1SGTUMesh::buildUnstructured.
6018 * If \a this is a single geometric type unstructured mesh, it will be converted into a more compact data structure,
6019 * MEDCoupling1GTUMesh instance. The returned instance will aggregate the same DataArrayDouble instance of coordinates than \a this.
6021 * \return a newly allocated instance, that the caller must manage.
6022 * \throw If \a this contains more than one geometric type.
6023 * \throw If the nodal connectivity of \a this is not fully defined.
6024 * \throw If the internal data is not coherent.
6026 MEDCoupling1GTUMesh *MEDCouplingUMesh::convertIntoSingleGeoTypeMesh() const
6028 checkConnectivityFullyDefined();
6029 if(_types.size()!=1)
6030 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6031 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6032 MCAuto<MEDCoupling1GTUMesh> ret=MEDCoupling1GTUMesh::New(getName(),typ);
6033 ret->setCoords(getCoords());
6034 MEDCoupling1SGTUMesh *retC=dynamic_cast<MEDCoupling1SGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6037 MCAuto<DataArrayInt> c=convertNodalConnectivityToStaticGeoTypeMesh();
6038 retC->setNodalConnectivity(c);
6042 MEDCoupling1DGTUMesh *retD=dynamic_cast<MEDCoupling1DGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6044 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : Internal error !");
6045 DataArrayInt *c=0,*ci=0;
6046 convertNodalConnectivityToDynamicGeoTypeMesh(c,ci);
6047 MCAuto<DataArrayInt> cs(c),cis(ci);
6048 retD->setNodalConnectivity(cs,cis);
6053 DataArrayInt *MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh() const
6055 checkConnectivityFullyDefined();
6056 if(_types.size()!=1)
6057 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6058 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6059 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6062 std::ostringstream oss; oss << "MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : this contains a single geo type (" << cm.getRepr() << ") but ";
6063 oss << "this type is dynamic ! Only static geometric type is possible for that type ! call convertNodalConnectivityToDynamicGeoTypeMesh instead !";
6064 throw INTERP_KERNEL::Exception(oss.str());
6066 int nbCells=getNumberOfCells();
6068 int nbNodesPerCell=(int)cm.getNumberOfNodes();
6069 MCAuto<DataArrayInt> connOut=DataArrayInt::New(); connOut->alloc(nbCells*nbNodesPerCell,1);
6070 int *outPtr=connOut->getPointer();
6071 const int *conn=_nodal_connec->begin();
6072 const int *connI=_nodal_connec_index->begin();
6074 for(int i=0;i<nbCells;i++,connI++)
6076 if(conn[connI[0]]==typi && connI[1]-connI[0]==nbNodesPerCell)
6077 outPtr=std::copy(conn+connI[0]+1,conn+connI[1],outPtr);
6080 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 << ") !";
6081 throw INTERP_KERNEL::Exception(oss.str());
6084 return connOut.retn();
6088 * Convert the nodal connectivity of the mesh so that all the cells are of dynamic types (polygon or quadratic
6089 * polygon). This returns the corresponding new nodal connectivity in \ref numbering-indirect format.
6093 void MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh(DataArrayInt *&nodalConn, DataArrayInt *&nodalConnIndex) const
6095 static const char msg0[]="MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : nodal connectivity in this are invalid ! Call checkConsistency !";
6096 checkConnectivityFullyDefined();
6097 if(_types.size()!=1)
6098 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6099 int nbCells=getNumberOfCells(),lgth=_nodal_connec->getNumberOfTuples();
6101 throw INTERP_KERNEL::Exception(msg0);
6102 MCAuto<DataArrayInt> c(DataArrayInt::New()),ci(DataArrayInt::New());
6103 c->alloc(lgth-nbCells,1); ci->alloc(nbCells+1,1);
6104 int *cp(c->getPointer()),*cip(ci->getPointer());
6105 const int *incp(_nodal_connec->begin()),*incip(_nodal_connec_index->begin());
6107 for(int i=0;i<nbCells;i++,cip++,incip++)
6109 int strt(incip[0]+1),stop(incip[1]);//+1 to skip geo type
6110 int delta(stop-strt);
6113 if((strt>=0 && strt<lgth) && (stop>=0 && stop<=lgth))
6114 cp=std::copy(incp+strt,incp+stop,cp);
6116 throw INTERP_KERNEL::Exception(msg0);
6119 throw INTERP_KERNEL::Exception(msg0);
6120 cip[1]=cip[0]+delta;
6122 nodalConn=c.retn(); nodalConnIndex=ci.retn();
6126 * This method takes in input a vector of MEDCouplingUMesh instances lying on the same coordinates with same mesh dimensions.
6127 * Each mesh in \b ms must be sorted by type with the same order (typically using MEDCouplingUMesh::sortCellsInMEDFileFrmt).
6128 * This method is particulary useful for MED file interaction. It allows to aggregate several meshes and keeping the type sorting
6129 * and the track of the permutation by chunk of same geotype cells to retrieve it. The traditional formats old2new and new2old
6130 * are not used here to avoid the build of big permutation array.
6132 * \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
6133 * those specified in MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6134 * \param [out] szOfCellGrpOfSameType is a newly allocated DataArrayInt instance whose number of tuples is equal to the number of chunks of same geotype
6135 * in all meshes in \b ms. The accumulation of all values of this array is equal to the number of cells of returned mesh.
6136 * \param [out] idInMsOfCellGrpOfSameType is a newly allocated DataArrayInt instance having the same size than \b szOfCellGrpOfSameType. This
6137 * output array gives for each chunck of same type the corresponding mesh id in \b ms.
6138 * \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
6139 * is sorted by type following the geo cell types order of MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6141 MEDCouplingUMesh *MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& ms,
6142 DataArrayInt *&szOfCellGrpOfSameType,
6143 DataArrayInt *&idInMsOfCellGrpOfSameType)
6145 std::vector<const MEDCouplingUMesh *> ms2;
6146 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms.begin();it!=ms.end();it++)
6149 (*it)->checkConnectivityFullyDefined();
6153 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : input vector is empty !");
6154 const DataArrayDouble *refCoo=ms2[0]->getCoords();
6155 int meshDim=ms2[0]->getMeshDimension();
6156 std::vector<const MEDCouplingUMesh *> m1ssm;
6157 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmAuto;
6159 std::vector<const MEDCouplingUMesh *> m1ssmSingle;
6160 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmSingleAuto;
6162 MCAuto<DataArrayInt> ret1(DataArrayInt::New()),ret2(DataArrayInt::New());
6163 ret1->alloc(0,1); ret2->alloc(0,1);
6164 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms2.begin();it!=ms2.end();it++,rk++)
6166 if(meshDim!=(*it)->getMeshDimension())
6167 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshdims mismatch !");
6168 if(refCoo!=(*it)->getCoords())
6169 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshes are not shared by a single coordinates coords !");
6170 std::vector<MEDCouplingUMesh *> sp=(*it)->splitByType();
6171 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<const MEDCouplingUMesh *> >(m1ssm));
6172 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<MCAuto<MEDCouplingUMesh> > >(m1ssmAuto));
6173 for(std::vector<MEDCouplingUMesh *>::const_iterator it2=sp.begin();it2!=sp.end();it2++)
6175 MEDCouplingUMesh *singleCell=static_cast<MEDCouplingUMesh *>((*it2)->buildPartOfMySelf(&fake,&fake+1,true));
6176 m1ssmSingleAuto.push_back(singleCell);
6177 m1ssmSingle.push_back(singleCell);
6178 ret1->pushBackSilent((*it2)->getNumberOfCells()); ret2->pushBackSilent(rk);
6181 MCAuto<MEDCouplingUMesh> m1ssmSingle2=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmSingle);
6182 MCAuto<DataArrayInt> renum=m1ssmSingle2->sortCellsInMEDFileFrmt();
6183 std::vector<const MEDCouplingUMesh *> m1ssmfinal(m1ssm.size());
6184 for(std::size_t i=0;i<m1ssm.size();i++)
6185 m1ssmfinal[renum->getIJ(i,0)]=m1ssm[i];
6186 MCAuto<MEDCouplingUMesh> ret0=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmfinal);
6187 szOfCellGrpOfSameType=ret1->renumber(renum->begin());
6188 idInMsOfCellGrpOfSameType=ret2->renumber(renum->begin());
6193 * This method returns a newly created DataArrayInt instance.
6194 * This method retrieves cell ids in [ \a begin, \a end ) that have the type \a type.
6196 DataArrayInt *MEDCouplingUMesh::keepCellIdsByType(INTERP_KERNEL::NormalizedCellType type, const int *begin, const int *end) const
6198 checkFullyDefined();
6199 const int *conn=_nodal_connec->begin();
6200 const int *connIndex=_nodal_connec_index->begin();
6201 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(0,1);
6202 for(const int *w=begin;w!=end;w++)
6203 if((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]==type)
6204 ret->pushBackSilent(*w);
6209 * This method makes the assumption that da->getNumberOfTuples()<this->getNumberOfCells(). This method makes the assumption that ids contained in 'da'
6210 * are in [0:getNumberOfCells())
6212 DataArrayInt *MEDCouplingUMesh::convertCellArrayPerGeoType(const DataArrayInt *da) const
6214 checkFullyDefined();
6215 const int *conn=_nodal_connec->begin();
6216 const int *connI=_nodal_connec_index->begin();
6217 int nbOfCells=getNumberOfCells();
6218 std::set<INTERP_KERNEL::NormalizedCellType> types(getAllGeoTypes());
6219 int *tmp=new int[nbOfCells];
6220 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
6223 for(const int *i=connI;i!=connI+nbOfCells;i++)
6224 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
6225 tmp[std::distance(connI,i)]=j++;
6227 DataArrayInt *ret=DataArrayInt::New();
6228 ret->alloc(da->getNumberOfTuples(),da->getNumberOfComponents());
6229 ret->copyStringInfoFrom(*da);
6230 int *retPtr=ret->getPointer();
6231 const int *daPtr=da->begin();
6232 int nbOfElems=da->getNbOfElems();
6233 for(int k=0;k<nbOfElems;k++)
6234 retPtr[k]=tmp[daPtr[k]];
6240 * This method reduced number of cells of this by keeping cells whose type is different from 'type' and if type=='type'
6241 * This method \b works \b for mesh sorted by type.
6242 * cells whose ids is in 'idsPerGeoType' array.
6243 * This method conserves coords and name of mesh.
6245 MEDCouplingUMesh *MEDCouplingUMesh::keepSpecifiedCells(INTERP_KERNEL::NormalizedCellType type, const int *idsPerGeoTypeBg, const int *idsPerGeoTypeEnd) const
6247 std::vector<int> code=getDistributionOfTypes();
6248 std::size_t nOfTypesInThis=code.size()/3;
6249 int sz=0,szOfType=0;
6250 for(std::size_t i=0;i<nOfTypesInThis;i++)
6255 szOfType=code[3*i+1];
6257 for(const int *work=idsPerGeoTypeBg;work!=idsPerGeoTypeEnd;work++)
6258 if(*work<0 || *work>=szOfType)
6260 std::ostringstream oss; oss << "MEDCouplingUMesh::keepSpecifiedCells : Request on type " << type << " at place #" << std::distance(idsPerGeoTypeBg,work) << " value " << *work;
6261 oss << ". It should be in [0," << szOfType << ") !";
6262 throw INTERP_KERNEL::Exception(oss.str());
6264 MCAuto<DataArrayInt> idsTokeep=DataArrayInt::New(); idsTokeep->alloc(sz+(int)std::distance(idsPerGeoTypeBg,idsPerGeoTypeEnd),1);
6265 int *idsPtr=idsTokeep->getPointer();
6267 for(std::size_t i=0;i<nOfTypesInThis;i++)
6270 for(int j=0;j<code[3*i+1];j++)
6273 idsPtr=std::transform(idsPerGeoTypeBg,idsPerGeoTypeEnd,idsPtr,std::bind2nd(std::plus<int>(),offset));
6274 offset+=code[3*i+1];
6276 MCAuto<MEDCouplingUMesh> ret=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(idsTokeep->begin(),idsTokeep->end(),true));
6277 ret->copyTinyInfoFrom(this);
6282 * This method returns a vector of size 'this->getNumberOfCells()'.
6283 * This method retrieves for each cell in \a this if it is linear (false) or quadratic(true).
6285 std::vector<bool> MEDCouplingUMesh::getQuadraticStatus() const
6287 int ncell=getNumberOfCells();
6288 std::vector<bool> ret(ncell);
6289 const int *cI=getNodalConnectivityIndex()->begin();
6290 const int *c=getNodalConnectivity()->begin();
6291 for(int i=0;i<ncell;i++)
6293 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[i]];
6294 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6295 ret[i]=cm.isQuadratic();
6301 * Returns a newly created mesh (with ref count ==1) that contains merge of \a this and \a other.
6303 MEDCouplingMesh *MEDCouplingUMesh::mergeMyselfWith(const MEDCouplingMesh *other) const
6305 if(other->getType()!=UNSTRUCTURED)
6306 throw INTERP_KERNEL::Exception("Merge of umesh only available with umesh each other !");
6307 const MEDCouplingUMesh *otherC=static_cast<const MEDCouplingUMesh *>(other);
6308 return MergeUMeshes(this,otherC);
6312 * Returns a new DataArrayDouble holding barycenters of all cells. The barycenter is
6313 * computed by averaging coordinates of cell nodes, so this method is not a right
6314 * choice for degnerated meshes (not well oriented, cells with measure close to zero).
6315 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
6316 * this->getNumberOfCells() tuples per \a this->getSpaceDimension()
6317 * components. The caller is to delete this array using decrRef() as it is
6319 * \throw If the coordinates array is not set.
6320 * \throw If the nodal connectivity of cells is not defined.
6321 * \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
6323 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMass() const
6325 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6326 int spaceDim=getSpaceDimension();
6327 int nbOfCells=getNumberOfCells();
6328 ret->alloc(nbOfCells,spaceDim);
6329 ret->copyStringInfoFrom(*getCoords());
6330 double *ptToFill=ret->getPointer();
6331 const int *nodal=_nodal_connec->begin();
6332 const int *nodalI=_nodal_connec_index->begin();
6333 const double *coor=_coords->begin();
6334 for(int i=0;i<nbOfCells;i++)
6336 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6337 INTERP_KERNEL::computeBarycenter2<int,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[i]+1,nodalI[i+1]-nodalI[i]-1,coor,spaceDim,ptToFill);
6344 * This method computes for each cell in \a this, the location of the iso barycenter of nodes constituting
6345 * the cell. Contrary to badly named MEDCouplingUMesh::computeCellCenterOfMass method that returns the center of inertia of the
6347 * \return a newly allocated DataArrayDouble instance that the caller has to deal with. The returned
6348 * DataArrayDouble instance will have \c this->getNumberOfCells() tuples and \c this->getSpaceDimension() components.
6350 * \sa MEDCouplingUMesh::computeCellCenterOfMass
6351 * \throw If \a this is not fully defined (coordinates and connectivity)
6352 * \throw If there is presence in nodal connectivity in \a this of node ids not in [0, \c this->getNumberOfNodes() )
6354 DataArrayDouble *MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell() const
6356 checkFullyDefined();
6357 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6358 int spaceDim=getSpaceDimension();
6359 int nbOfCells=getNumberOfCells();
6360 int nbOfNodes=getNumberOfNodes();
6361 ret->alloc(nbOfCells,spaceDim);
6362 double *ptToFill=ret->getPointer();
6363 const int *nodal=_nodal_connec->begin();
6364 const int *nodalI=_nodal_connec_index->begin();
6365 const double *coor=_coords->begin();
6366 for(int i=0;i<nbOfCells;i++,ptToFill+=spaceDim)
6368 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6369 std::fill(ptToFill,ptToFill+spaceDim,0.);
6370 if(type!=INTERP_KERNEL::NORM_POLYHED)
6372 for(const int *conn=nodal+nodalI[i]+1;conn!=nodal+nodalI[i+1];conn++)
6374 if(*conn>=0 && *conn<nbOfNodes)
6375 std::transform(coor+spaceDim*conn[0],coor+spaceDim*(conn[0]+1),ptToFill,ptToFill,std::plus<double>());
6378 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of nodeId #" << *conn << " should be in [0," << nbOfNodes << ") !";
6379 throw INTERP_KERNEL::Exception(oss.str());
6382 int nbOfNodesInCell=nodalI[i+1]-nodalI[i]-1;
6383 if(nbOfNodesInCell>0)
6384 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies<double>(),1./(double)nbOfNodesInCell));
6387 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of cell with no nodes !";
6388 throw INTERP_KERNEL::Exception(oss.str());
6393 std::set<int> s(nodal+nodalI[i]+1,nodal+nodalI[i+1]);
6395 for(std::set<int>::const_iterator it=s.begin();it!=s.end();it++)
6397 if(*it>=0 && *it<nbOfNodes)
6398 std::transform(coor+spaceDim*(*it),coor+spaceDim*((*it)+1),ptToFill,ptToFill,std::plus<double>());
6401 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell polyhedron cell #" << i << " presence of nodeId #" << *it << " should be in [0," << nbOfNodes << ") !";
6402 throw INTERP_KERNEL::Exception(oss.str());
6406 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies<double>(),1./(double)s.size()));
6409 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on polyhedron cell #" << i << " there are no nodes !";
6410 throw INTERP_KERNEL::Exception(oss.str());
6418 * Returns a new DataArrayDouble holding barycenters of specified cells. The
6419 * barycenter is computed by averaging coordinates of cell nodes. The cells to treat
6420 * are specified via an array of cell ids.
6421 * \warning Validity of the specified cell ids is not checked!
6422 * Valid range is [ 0, \a this->getNumberOfCells() ).
6423 * \param [in] begin - an array of cell ids of interest.
6424 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
6425 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size ( \a
6426 * end - \a begin ) tuples per \a this->getSpaceDimension() components. The
6427 * caller is to delete this array using decrRef() as it is no more needed.
6428 * \throw If the coordinates array is not set.
6429 * \throw If the nodal connectivity of cells is not defined.
6431 * \if ENABLE_EXAMPLES
6432 * \ref cpp_mcumesh_getPartBarycenterAndOwner "Here is a C++ example".<br>
6433 * \ref py_mcumesh_getPartBarycenterAndOwner "Here is a Python example".
6436 DataArrayDouble *MEDCouplingUMesh::getPartBarycenterAndOwner(const int *begin, const int *end) const
6438 DataArrayDouble *ret=DataArrayDouble::New();
6439 int spaceDim=getSpaceDimension();
6440 int nbOfTuple=(int)std::distance(begin,end);
6441 ret->alloc(nbOfTuple,spaceDim);
6442 double *ptToFill=ret->getPointer();
6443 double *tmp=new double[spaceDim];
6444 const int *nodal=_nodal_connec->begin();
6445 const int *nodalI=_nodal_connec_index->begin();
6446 const double *coor=_coords->begin();
6447 for(const int *w=begin;w!=end;w++)
6449 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[*w]];
6450 INTERP_KERNEL::computeBarycenter2<int,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[*w]+1,nodalI[*w+1]-nodalI[*w]-1,coor,spaceDim,ptToFill);
6458 * 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".
6459 * So the returned instance will have 4 components and \c this->getNumberOfCells() tuples.
6460 * So this method expects that \a this has a spaceDimension equal to 3 and meshDimension equal to 2.
6461 * The computation of the plane equation is done using each time the 3 first nodes of 2D cells.
6462 * This method is useful to detect 2D cells in 3D space that are not coplanar.
6464 * \return DataArrayDouble * - a new instance of DataArrayDouble having 4 components and a number of tuples equal to number of cells in \a this.
6465 * \throw If spaceDim!=3 or meshDim!=2.
6466 * \throw If connectivity of \a this is invalid.
6467 * \throw If connectivity of a cell in \a this points to an invalid node.
6469 DataArrayDouble *MEDCouplingUMesh::computePlaneEquationOf3DFaces() const
6471 MCAuto<DataArrayDouble> ret(DataArrayDouble::New());
6472 int nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
6473 if(getSpaceDimension()!=3 || getMeshDimension()!=2)
6474 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computePlaneEquationOf3DFaces : This method must be applied on a mesh having meshDimension equal 2 and a spaceDimension equal to 3 !");
6475 ret->alloc(nbOfCells,4);
6476 double *retPtr(ret->getPointer());
6477 const int *nodal(_nodal_connec->begin()),*nodalI(_nodal_connec_index->begin());
6478 const double *coor(_coords->begin());
6479 for(int i=0;i<nbOfCells;i++,nodalI++,retPtr+=4)
6481 double matrix[16]={0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,0},matrix2[16];
6482 if(nodalI[1]-nodalI[0]>=4)
6484 double aa[3]={coor[nodal[nodalI[0]+1+1]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6485 coor[nodal[nodalI[0]+1+1]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6486 coor[nodal[nodalI[0]+1+1]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]}
6487 ,bb[3]={coor[nodal[nodalI[0]+1+2]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6488 coor[nodal[nodalI[0]+1+2]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6489 coor[nodal[nodalI[0]+1+2]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]};
6490 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]};
6491 for(int j=0;j<3;j++)
6493 int nodeId(nodal[nodalI[0]+1+j]);
6494 if(nodeId>=0 && nodeId<nbOfNodes)
6495 std::copy(coor+nodeId*3,coor+(nodeId+1)*3,matrix+4*j);
6498 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! This cell points to an invalid nodeId : " << nodeId << " !";
6499 throw INTERP_KERNEL::Exception(oss.str());
6502 if(sqrt(cc[0]*cc[0]+cc[1]*cc[1]+cc[2]*cc[2])>1e-7)
6504 INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6505 retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6509 if(nodalI[1]-nodalI[0]==4)
6511 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : cell" << i << " : Presence of The 3 colinear points !";
6512 throw INTERP_KERNEL::Exception(oss.str());
6515 double dd[3]={0.,0.,0.};
6516 for(int offset=nodalI[0]+1;offset<nodalI[1];offset++)
6517 std::transform(coor+3*nodal[offset],coor+3*(nodal[offset]+1),dd,dd,std::plus<double>());
6518 int nbOfNodesInCell(nodalI[1]-nodalI[0]-1);
6519 std::transform(dd,dd+3,dd,std::bind2nd(std::multiplies<double>(),1./(double)nbOfNodesInCell));
6520 std::copy(dd,dd+3,matrix+4*2);
6521 INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6522 retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6527 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! Must be constitued by more than 3 nodes !";
6528 throw INTERP_KERNEL::Exception(oss.str());
6535 * This method expects as input a DataArrayDouble non nul instance 'da' that should be allocated. If not an exception is thrown.
6538 MEDCouplingUMesh *MEDCouplingUMesh::Build0DMeshFromCoords(DataArrayDouble *da)
6541 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build0DMeshFromCoords : instance of DataArrayDouble must be not null !");
6542 da->checkAllocated();
6543 std::string name(da->getName());
6544 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New(name,0));
6546 ret->setName("Mesh");
6548 int nbOfTuples(da->getNumberOfTuples());
6549 MCAuto<DataArrayInt> c(DataArrayInt::New()),cI(DataArrayInt::New());
6550 c->alloc(2*nbOfTuples,1);
6551 cI->alloc(nbOfTuples+1,1);
6552 int *cp(c->getPointer()),*cip(cI->getPointer());
6554 for(int i=0;i<nbOfTuples;i++)
6556 *cp++=INTERP_KERNEL::NORM_POINT1;
6560 ret->setConnectivity(c,cI,true);
6564 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::Build1DMeshFromCoords(DataArrayDouble *da)
6567 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build01MeshFromCoords : instance of DataArrayDouble must be not null !");
6568 da->checkAllocated();
6569 std::string name(da->getName());
6570 MCAuto<MEDCouplingUMesh> ret;
6572 MCAuto<MEDCouplingCMesh> tmp(MEDCouplingCMesh::New());
6573 MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
6574 arr->alloc(da->getNumberOfTuples());
6575 tmp->setCoordsAt(0,arr);
6576 ret=tmp->buildUnstructured();
6580 ret->setName("Mesh");
6587 * Creates a new MEDCouplingUMesh by concatenating two given meshes of the same dimension.
6588 * Cells and nodes of
6589 * the first mesh precede cells and nodes of the second mesh within the result mesh.
6590 * \param [in] mesh1 - the first mesh.
6591 * \param [in] mesh2 - the second mesh.
6592 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6593 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6594 * is no more needed.
6595 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
6596 * \throw If the coordinates array is not set in none of the meshes.
6597 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
6598 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
6600 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
6602 std::vector<const MEDCouplingUMesh *> tmp(2);
6603 tmp[0]=const_cast<MEDCouplingUMesh *>(mesh1); tmp[1]=const_cast<MEDCouplingUMesh *>(mesh2);
6604 return MergeUMeshes(tmp);
6608 * Creates a new MEDCouplingUMesh by concatenating all given meshes of the same dimension.
6609 * Cells and nodes of
6610 * the *i*-th mesh precede cells and nodes of the (*i*+1)-th mesh within the result mesh.
6611 * \param [in] a - a vector of meshes (MEDCouplingUMesh) to concatenate.
6612 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6613 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6614 * is no more needed.
6615 * \throw If \a a.size() == 0.
6616 * \throw If \a a[ *i* ] == NULL.
6617 * \throw If the coordinates array is not set in none of the meshes.
6618 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
6619 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
6621 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const std::vector<const MEDCouplingUMesh *>& a)
6623 std::size_t sz=a.size();
6625 return MergeUMeshesLL(a);
6626 for(std::size_t ii=0;ii<sz;ii++)
6629 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshes : item #" << ii << " in input array of size "<< sz << " is empty !";
6630 throw INTERP_KERNEL::Exception(oss.str());
6632 std::vector< MCAuto<MEDCouplingUMesh> > bb(sz);
6633 std::vector< const MEDCouplingUMesh * > aa(sz);
6635 for(std::size_t i=0;i<sz && spaceDim==-3;i++)
6637 const MEDCouplingUMesh *cur=a[i];
6638 const DataArrayDouble *coo=cur->getCoords();
6640 spaceDim=coo->getNumberOfComponents();
6643 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : no spaceDim specified ! unable to perform merge !");
6644 for(std::size_t i=0;i<sz;i++)
6646 bb[i]=a[i]->buildSetInstanceFromThis(spaceDim);
6649 return MergeUMeshesLL(aa);
6653 * Creates a new MEDCouplingUMesh by concatenating cells of two given meshes of same
6654 * dimension and sharing the node coordinates array.
6655 * All cells of the first mesh precede all cells of the second mesh
6656 * within the result mesh.
6657 * \param [in] mesh1 - the first mesh.
6658 * \param [in] mesh2 - the second mesh.
6659 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6660 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6661 * is no more needed.
6662 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
6663 * \throw If the meshes do not share the node coordinates array.
6664 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
6665 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
6667 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
6669 std::vector<const MEDCouplingUMesh *> tmp(2);
6670 tmp[0]=mesh1; tmp[1]=mesh2;
6671 return MergeUMeshesOnSameCoords(tmp);
6675 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
6676 * dimension and sharing the node coordinates array.
6677 * All cells of the *i*-th mesh precede all cells of the
6678 * (*i*+1)-th mesh within the result mesh.
6679 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
6680 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6681 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6682 * is no more needed.
6683 * \throw If \a a.size() == 0.
6684 * \throw If \a a[ *i* ] == NULL.
6685 * \throw If the meshes do not share the node coordinates array.
6686 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
6687 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
6689 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes)
6692 throw INTERP_KERNEL::Exception("meshes input parameter is expected to be non empty.");
6693 for(std::size_t ii=0;ii<meshes.size();ii++)
6696 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshesOnSameCoords : item #" << ii << " in input array of size "<< meshes.size() << " is empty !";
6697 throw INTERP_KERNEL::Exception(oss.str());
6699 const DataArrayDouble *coords=meshes.front()->getCoords();
6700 int meshDim=meshes.front()->getMeshDimension();
6701 std::vector<const MEDCouplingUMesh *>::const_iterator iter=meshes.begin();
6703 int meshIndexLgth=0;
6704 for(;iter!=meshes.end();iter++)
6706 if(coords!=(*iter)->getCoords())
6707 throw INTERP_KERNEL::Exception("meshes does not share the same coords ! Try using tryToShareSameCoords method !");
6708 if(meshDim!=(*iter)->getMeshDimension())
6709 throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, FuseUMeshesOnSameCoords impossible !");
6710 meshLgth+=(*iter)->getNodalConnectivityArrayLen();
6711 meshIndexLgth+=(*iter)->getNumberOfCells();
6713 MCAuto<DataArrayInt> nodal=DataArrayInt::New();
6714 nodal->alloc(meshLgth,1);
6715 int *nodalPtr=nodal->getPointer();
6716 MCAuto<DataArrayInt> nodalIndex=DataArrayInt::New();
6717 nodalIndex->alloc(meshIndexLgth+1,1);
6718 int *nodalIndexPtr=nodalIndex->getPointer();
6720 for(iter=meshes.begin();iter!=meshes.end();iter++)
6722 const int *nod=(*iter)->getNodalConnectivity()->begin();
6723 const int *index=(*iter)->getNodalConnectivityIndex()->begin();
6724 int nbOfCells=(*iter)->getNumberOfCells();
6725 int meshLgth2=(*iter)->getNodalConnectivityArrayLen();
6726 nodalPtr=std::copy(nod,nod+meshLgth2,nodalPtr);
6727 if(iter!=meshes.begin())
6728 nodalIndexPtr=std::transform(index+1,index+nbOfCells+1,nodalIndexPtr,std::bind2nd(std::plus<int>(),offset));
6730 nodalIndexPtr=std::copy(index,index+nbOfCells+1,nodalIndexPtr);
6733 MEDCouplingUMesh *ret=MEDCouplingUMesh::New();
6734 ret->setName("merge");
6735 ret->setMeshDimension(meshDim);
6736 ret->setConnectivity(nodal,nodalIndex,true);
6737 ret->setCoords(coords);
6742 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
6743 * dimension and sharing the node coordinates array. Cells of the *i*-th mesh precede
6744 * cells of the (*i*+1)-th mesh within the result mesh. Duplicates of cells are
6745 * removed from \a this mesh and arrays mapping between new and old cell ids in "Old to
6746 * New" mode are returned for each input mesh.
6747 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
6748 * \param [in] compType - specifies a cell comparison technique. For meaning of its
6749 * valid values [0,1,2], see zipConnectivityTraducer().
6750 * \param [in,out] corr - an array of DataArrayInt, of the same size as \a
6751 * meshes. The *i*-th array describes cell ids mapping for \a meshes[ *i* ]
6752 * mesh. The caller is to delete each of the arrays using decrRef() as it is
6754 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6755 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6756 * is no more needed.
6757 * \throw If \a meshes.size() == 0.
6758 * \throw If \a meshes[ *i* ] == NULL.
6759 * \throw If the meshes do not share the node coordinates array.
6760 * \throw If \a meshes[ *i* ]->getMeshDimension() < 0.
6761 * \throw If the \a meshes are of different dimension (getMeshDimension()).
6762 * \throw If the nodal connectivity of cells of any of \a meshes is not defined.
6763 * \throw If the nodal connectivity any of \a meshes includes an invalid id.
6765 MEDCouplingUMesh *MEDCouplingUMesh::FuseUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes, int compType, std::vector<DataArrayInt *>& corr)
6767 //All checks are delegated to MergeUMeshesOnSameCoords
6768 MCAuto<MEDCouplingUMesh> ret=MergeUMeshesOnSameCoords(meshes);
6769 MCAuto<DataArrayInt> o2n=ret->zipConnectivityTraducer(compType);
6770 corr.resize(meshes.size());
6771 std::size_t nbOfMeshes=meshes.size();
6773 const int *o2nPtr=o2n->begin();
6774 for(std::size_t i=0;i<nbOfMeshes;i++)
6776 DataArrayInt *tmp=DataArrayInt::New();
6777 int curNbOfCells=meshes[i]->getNumberOfCells();
6778 tmp->alloc(curNbOfCells,1);
6779 std::copy(o2nPtr+offset,o2nPtr+offset+curNbOfCells,tmp->getPointer());
6780 offset+=curNbOfCells;
6781 tmp->setName(meshes[i]->getName());
6788 * Makes all given meshes share the nodal connectivity array. The common connectivity
6789 * array is created by concatenating the connectivity arrays of all given meshes. All
6790 * the given meshes must be of the same space dimension but dimension of cells **can
6791 * differ**. This method is particulary useful in MEDLoader context to build a \ref
6792 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
6793 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
6794 * \param [in,out] meshes - a vector of meshes to update.
6795 * \throw If any of \a meshes is NULL.
6796 * \throw If the coordinates array is not set in any of \a meshes.
6797 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
6798 * \throw If \a meshes are of different space dimension.
6800 void MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords(const std::vector<MEDCouplingUMesh *>& meshes)
6802 std::size_t sz=meshes.size();
6805 std::vector< const DataArrayDouble * > coords(meshes.size());
6806 std::vector< const DataArrayDouble * >::iterator it2=coords.begin();
6807 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++,it2++)
6811 (*it)->checkConnectivityFullyDefined();
6812 const DataArrayDouble *coo=(*it)->getCoords();
6817 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
6818 oss << " has no coordinate array defined !";
6819 throw INTERP_KERNEL::Exception(oss.str());
6824 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
6825 oss << " is null !";
6826 throw INTERP_KERNEL::Exception(oss.str());
6829 MCAuto<DataArrayDouble> res=DataArrayDouble::Aggregate(coords);
6830 std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();
6831 int offset=(*it)->getNumberOfNodes();
6832 (*it++)->setCoords(res);
6833 for(;it!=meshes.end();it++)
6835 int oldNumberOfNodes=(*it)->getNumberOfNodes();
6836 (*it)->setCoords(res);
6837 (*it)->shiftNodeNumbersInConn(offset);
6838 offset+=oldNumberOfNodes;
6843 * Merges nodes coincident with a given precision within all given meshes that share
6844 * the nodal connectivity array. The given meshes **can be of different** mesh
6845 * dimension. This method is particulary useful in MEDLoader context to build a \ref
6846 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
6847 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
6848 * \param [in,out] meshes - a vector of meshes to update.
6849 * \param [in] eps - the precision used to detect coincident nodes (infinite norm).
6850 * \throw If any of \a meshes is NULL.
6851 * \throw If the \a meshes do not share the same node coordinates array.
6852 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
6854 void MEDCouplingUMesh::MergeNodesOnUMeshesSharingSameCoords(const std::vector<MEDCouplingUMesh *>& meshes, double eps)
6858 std::set<const DataArrayDouble *> s;
6859 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
6862 s.insert((*it)->getCoords());
6865 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 !";
6866 throw INTERP_KERNEL::Exception(oss.str());
6871 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 !";
6872 throw INTERP_KERNEL::Exception(oss.str());
6874 const DataArrayDouble *coo=*(s.begin());
6878 DataArrayInt *comm,*commI;
6879 coo->findCommonTuples(eps,-1,comm,commI);
6880 MCAuto<DataArrayInt> tmp1(comm),tmp2(commI);
6881 int oldNbOfNodes=coo->getNumberOfTuples();
6883 MCAuto<DataArrayInt> o2n=DataArrayInt::ConvertIndexArrayToO2N(oldNbOfNodes,comm->begin(),commI->begin(),commI->end(),newNbOfNodes);
6884 if(oldNbOfNodes==newNbOfNodes)
6886 MCAuto<DataArrayDouble> newCoords=coo->renumberAndReduce(o2n->begin(),newNbOfNodes);
6887 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
6889 (*it)->renumberNodesInConn(o2n->begin());
6890 (*it)->setCoords(newCoords);
6896 * This static operates only for coords in 3D. The polygon is specfied by its connectivity nodes in [ \a begin , \a end ).
6898 bool MEDCouplingUMesh::IsPolygonWellOriented(bool isQuadratic, const double *vec, const int *begin, const int *end, const double *coords)
6901 double v[3]={0.,0.,0.};
6902 std::size_t sz=std::distance(begin,end);
6907 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];
6908 v[1]+=coords[3*begin[i]+2]*coords[3*begin[(i+1)%sz]]-coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+2];
6909 v[2]+=coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+1]-coords[3*begin[i]+1]*coords[3*begin[(i+1)%sz]];
6911 double ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
6913 // Try using quadratic points if standard points are degenerated (for example a QPOLYG with two
6914 // SEG3 forming a circle):
6915 if (fabs(ret) < INTERP_KERNEL::DEFAULT_ABS_TOL && isQuadratic)
6917 v[0] = 0.0; v[1] = 0.0; v[2] = 0.0;
6918 for(std::size_t j=0;j<sz;j++)
6920 if (j%2) // current point i is quadratic, next point i+1 is standard
6923 ip1 = (j+1)%sz; // ip1 = "i+1"
6925 else // current point i is standard, next point i+1 is quadratic
6930 v[0]+=coords[3*begin[i]+1]*coords[3*begin[ip1]+2]-coords[3*begin[i]+2]*coords[3*begin[ip1]+1];
6931 v[1]+=coords[3*begin[i]+2]*coords[3*begin[ip1]]-coords[3*begin[i]]*coords[3*begin[ip1]+2];
6932 v[2]+=coords[3*begin[i]]*coords[3*begin[ip1]+1]-coords[3*begin[i]+1]*coords[3*begin[ip1]];
6934 ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
6940 * The polyhedron is specfied by its connectivity nodes in [ \a begin , \a end ).
6942 bool MEDCouplingUMesh::IsPolyhedronWellOriented(const int *begin, const int *end, const double *coords)
6944 std::vector<std::pair<int,int> > edges;
6945 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
6946 const int *bgFace=begin;
6947 for(std::size_t i=0;i<nbOfFaces;i++)
6949 const int *endFace=std::find(bgFace+1,end,-1);
6950 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
6951 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
6953 std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
6954 if(std::find(edges.begin(),edges.end(),p1)!=edges.end())
6956 edges.push_back(p1);
6960 return INTERP_KERNEL::calculateVolumeForPolyh2<int,INTERP_KERNEL::ALL_C_MODE>(begin,(int)std::distance(begin,end),coords)>-EPS_FOR_POLYH_ORIENTATION;
6964 * The 3D extruded static cell (PENTA6,HEXA8,HEXAGP12...) its connectivity nodes in [ \a begin , \a end ).
6966 bool MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented(const int *begin, const int *end, const double *coords)
6968 double vec0[3],vec1[3];
6969 std::size_t sz=std::distance(begin,end);
6971 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented : the length of nodal connectivity of extruded cell is not even !");
6972 int nbOfNodes=(int)sz/2;
6973 INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(begin,nbOfNodes,coords,vec0);
6974 const double *pt0=coords+3*begin[0];
6975 const double *pt1=coords+3*begin[nbOfNodes];
6976 vec1[0]=pt1[0]-pt0[0]; vec1[1]=pt1[1]-pt0[1]; vec1[2]=pt1[2]-pt0[2];
6977 return (vec0[0]*vec1[0]+vec0[1]*vec1[1]+vec0[2]*vec1[2])<0.;
6980 void MEDCouplingUMesh::CorrectExtrudedStaticCell(int *begin, int *end)
6982 std::size_t sz=std::distance(begin,end);
6983 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz];
6984 std::size_t nbOfNodes(sz/2);
6985 std::copy(begin,end,(int *)tmp);
6986 for(std::size_t j=1;j<nbOfNodes;j++)
6988 begin[j]=tmp[nbOfNodes-j];
6989 begin[j+nbOfNodes]=tmp[nbOfNodes+nbOfNodes-j];
6993 bool MEDCouplingUMesh::IsTetra4WellOriented(const int *begin, const int *end, const double *coords)
6995 std::size_t sz=std::distance(begin,end);
6997 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsTetra4WellOriented : Tetra4 cell with not 4 nodes ! Call checkConsistency !");
6998 double vec0[3],vec1[3];
6999 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[1],*pt2=coords+3*begin[2],*pt3=coords+3*begin[3];
7000 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];
7001 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;
7004 bool MEDCouplingUMesh::IsPyra5WellOriented(const int *begin, const int *end, const double *coords)
7006 std::size_t sz=std::distance(begin,end);
7008 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsPyra5WellOriented : Pyra5 cell with not 5 nodes ! Call checkConsistency !");
7010 INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(begin,4,coords,vec0);
7011 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[4];
7012 return (vec0[0]*(pt1[0]-pt0[0])+vec0[1]*(pt1[1]-pt0[1])+vec0[2]*(pt1[2]-pt0[2]))<0.;
7016 * 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 )
7017 * 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
7020 * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not.
7021 * \param [in] coords the coordinates with nb of components exactly equal to 3
7022 * \param [in] begin begin of the nodal connectivity (geometric type included) of a single polyhedron cell
7023 * \param [in] end end of nodal connectivity of a single polyhedron cell (excluded)
7024 * \param [out] res the result is put at the end of the vector without any alteration of the data.
7026 void MEDCouplingUMesh::SimplifyPolyhedronCell(double eps, const DataArrayDouble *coords, const int *begin, const int *end, DataArrayInt *res)
7028 int nbFaces=std::count(begin+1,end,-1)+1;
7029 MCAuto<DataArrayDouble> v=DataArrayDouble::New(); v->alloc(nbFaces,3);
7030 double *vPtr=v->getPointer();
7031 MCAuto<DataArrayDouble> p=DataArrayDouble::New(); p->alloc(nbFaces,1);
7032 double *pPtr=p->getPointer();
7033 const int *stFaceConn=begin+1;
7034 for(int i=0;i<nbFaces;i++,vPtr+=3,pPtr++)
7036 const int *endFaceConn=std::find(stFaceConn,end,-1);
7037 ComputeVecAndPtOfFace(eps,coords->begin(),stFaceConn,endFaceConn,vPtr,pPtr);
7038 stFaceConn=endFaceConn+1;
7040 pPtr=p->getPointer(); vPtr=v->getPointer();
7041 DataArrayInt *comm1=0,*commI1=0;
7042 v->findCommonTuples(eps,-1,comm1,commI1);
7043 MCAuto<DataArrayInt> comm1Auto(comm1),commI1Auto(commI1);
7044 const int *comm1Ptr=comm1->begin();
7045 const int *commI1Ptr=commI1->begin();
7046 int nbOfGrps1=commI1Auto->getNumberOfTuples()-1;
7047 res->pushBackSilent((int)INTERP_KERNEL::NORM_POLYHED);
7049 MCAuto<MEDCouplingUMesh> mm=MEDCouplingUMesh::New("",3);
7050 mm->setCoords(const_cast<DataArrayDouble *>(coords)); mm->allocateCells(1); mm->insertNextCell(INTERP_KERNEL::NORM_POLYHED,(int)std::distance(begin+1,end),begin+1);
7051 mm->finishInsertingCells();
7053 for(int i=0;i<nbOfGrps1;i++)
7055 int vecId=comm1Ptr[commI1Ptr[i]];
7056 MCAuto<DataArrayDouble> tmpgrp2=p->selectByTupleId(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7057 DataArrayInt *comm2=0,*commI2=0;
7058 tmpgrp2->findCommonTuples(eps,-1,comm2,commI2);
7059 MCAuto<DataArrayInt> comm2Auto(comm2),commI2Auto(commI2);
7060 const int *comm2Ptr=comm2->begin();
7061 const int *commI2Ptr=commI2->begin();
7062 int nbOfGrps2=commI2Auto->getNumberOfTuples()-1;
7063 for(int j=0;j<nbOfGrps2;j++)
7065 if(commI2Ptr[j+1]-commI2Ptr[j]<=1)
7067 res->insertAtTheEnd(begin,end);
7068 res->pushBackSilent(-1);
7072 int pointId=comm1Ptr[commI1Ptr[i]+comm2Ptr[commI2Ptr[j]]];
7073 MCAuto<DataArrayInt> ids2=comm2->selectByTupleIdSafeSlice(commI2Ptr[j],commI2Ptr[j+1],1);
7074 ids2->transformWithIndArr(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7075 DataArrayInt *tmp0=DataArrayInt::New(),*tmp1=DataArrayInt::New(),*tmp2=DataArrayInt::New(),*tmp3=DataArrayInt::New();
7076 MCAuto<MEDCouplingUMesh> mm2=mm->buildDescendingConnectivity(tmp0,tmp1,tmp2,tmp3); tmp0->decrRef(); tmp1->decrRef(); tmp2->decrRef(); tmp3->decrRef();
7077 MCAuto<MEDCouplingUMesh> mm3=static_cast<MEDCouplingUMesh *>(mm2->buildPartOfMySelf(ids2->begin(),ids2->end(),true));
7078 MCAuto<DataArrayInt> idsNodeTmp=mm3->zipCoordsTraducer();
7079 MCAuto<DataArrayInt> idsNode=idsNodeTmp->invertArrayO2N2N2O(mm3->getNumberOfNodes());
7080 const int *idsNodePtr=idsNode->begin();
7081 double center[3]; center[0]=pPtr[pointId]*vPtr[3*vecId]; center[1]=pPtr[pointId]*vPtr[3*vecId+1]; center[2]=pPtr[pointId]*vPtr[3*vecId+2];
7082 double vec[3]; vec[0]=vPtr[3*vecId+1]; vec[1]=-vPtr[3*vecId]; vec[2]=0.;
7083 double norm=vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2];
7084 if(std::abs(norm)>eps)
7086 double angle=INTERP_KERNEL::EdgeArcCircle::SafeAsin(norm);
7087 mm3->rotate(center,vec,angle);
7089 mm3->changeSpaceDimension(2);
7090 MCAuto<MEDCouplingUMesh> mm4=mm3->buildSpreadZonesWithPoly();
7091 const int *conn4=mm4->getNodalConnectivity()->begin();
7092 const int *connI4=mm4->getNodalConnectivityIndex()->begin();
7093 int nbOfCells=mm4->getNumberOfCells();
7094 for(int k=0;k<nbOfCells;k++)
7097 for(const int *work=conn4+connI4[k]+1;work!=conn4+connI4[k+1];work++,l++)
7098 res->pushBackSilent(idsNodePtr[*work]);
7099 res->pushBackSilent(-1);
7104 res->popBackSilent();
7108 * 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
7109 * through origin. The plane is defined by its nodal connectivity [ \b begin, \b end ).
7111 * \param [in] eps below that value the dot product of 2 vectors is considered as colinears
7112 * \param [in] coords coordinates expected to have 3 components.
7113 * \param [in] begin start of the nodal connectivity of the face.
7114 * \param [in] end end of the nodal connectivity (excluded) of the face.
7115 * \param [out] v the normalized vector of size 3
7116 * \param [out] p the pos of plane
7118 void MEDCouplingUMesh::ComputeVecAndPtOfFace(double eps, const double *coords, const int *begin, const int *end, double *v, double *p)
7120 std::size_t nbPoints=std::distance(begin,end);
7122 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeVecAndPtOfFace : < of 3 points in face ! not able to find a plane on that face !");
7123 double vec[3]={0.,0.,0.};
7125 bool refFound=false;
7126 for(;j<nbPoints-1 && !refFound;j++)
7128 vec[0]=coords[3*begin[j+1]]-coords[3*begin[j]];
7129 vec[1]=coords[3*begin[j+1]+1]-coords[3*begin[j]+1];
7130 vec[2]=coords[3*begin[j+1]+2]-coords[3*begin[j]+2];
7131 double norm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
7135 vec[0]/=norm; vec[1]/=norm; vec[2]/=norm;
7138 for(std::size_t i=j;i<nbPoints-1;i++)
7141 curVec[0]=coords[3*begin[i+1]]-coords[3*begin[i]];
7142 curVec[1]=coords[3*begin[i+1]+1]-coords[3*begin[i]+1];
7143 curVec[2]=coords[3*begin[i+1]+2]-coords[3*begin[i]+2];
7144 double norm=sqrt(curVec[0]*curVec[0]+curVec[1]*curVec[1]+curVec[2]*curVec[2]);
7147 curVec[0]/=norm; curVec[1]/=norm; curVec[2]/=norm;
7148 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];
7149 norm=sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
7152 v[0]/=norm; v[1]/=norm; v[2]/=norm;
7153 *p=v[0]*coords[3*begin[i]]+v[1]*coords[3*begin[i]+1]+v[2]*coords[3*begin[i]+2];
7157 throw INTERP_KERNEL::Exception("Not able to find a normal vector of that 3D face !");
7161 * This method tries to obtain a well oriented polyhedron.
7162 * If the algorithm fails, an exception will be thrown.
7164 void MEDCouplingUMesh::TryToCorrectPolyhedronOrientation(int *begin, int *end, const double *coords)
7166 std::list< std::pair<int,int> > edgesOK,edgesFinished;
7167 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
7168 std::vector<bool> isPerm(nbOfFaces,false);//field on faces False: I don't know, True : oriented
7170 int *bgFace=begin,*endFace=std::find(begin+1,end,-1);
7171 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
7172 for(std::size_t l=0;l<nbOfEdgesInFace;l++) { std::pair<int,int> p1(bgFace[l],bgFace[(l+1)%nbOfEdgesInFace]); edgesOK.push_back(p1); }
7174 while(std::find(isPerm.begin(),isPerm.end(),false)!=isPerm.end())
7177 std::size_t smthChanged=0;
7178 for(std::size_t i=0;i<nbOfFaces;i++)
7180 endFace=std::find(bgFace+1,end,-1);
7181 nbOfEdgesInFace=std::distance(bgFace,endFace);
7185 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7187 std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7188 std::pair<int,int> p2(p1.second,p1.first);
7189 bool b1=std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end();
7190 bool b2=std::find(edgesOK.begin(),edgesOK.end(),p2)!=edgesOK.end();
7191 if(b1 || b2) { b=b2; isPerm[i]=true; smthChanged++; break; }
7196 std::reverse(bgFace+1,endFace);
7197 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7199 std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7200 std::pair<int,int> p2(p1.second,p1.first);
7201 if(std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end())
7202 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7203 if(std::find(edgesFinished.begin(),edgesFinished.end(),p1)!=edgesFinished.end() || std::find(edgesFinished.begin(),edgesFinished.end(),p2)!=edgesFinished.end())
7204 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7205 std::list< std::pair<int,int> >::iterator it=std::find(edgesOK.begin(),edgesOK.end(),p2);
7206 if(it!=edgesOK.end())
7209 edgesFinished.push_back(p1);
7212 edgesOK.push_back(p1);
7219 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired !"); }
7221 if(!edgesOK.empty())
7222 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired : Some edges are shared only once !"); }
7223 if(INTERP_KERNEL::calculateVolumeForPolyh2<int,INTERP_KERNEL::ALL_C_MODE>(begin,(int)std::distance(begin,end),coords)<-EPS_FOR_POLYH_ORIENTATION)
7224 {//not lucky ! The first face was not correctly oriented : reorient all faces...
7226 for(std::size_t i=0;i<nbOfFaces;i++)
7228 endFace=std::find(bgFace+1,end,-1);
7229 std::reverse(bgFace+1,endFace);
7237 * This method makes the assumption spacedimension == meshdimension == 2.
7238 * This method works only for linear cells.
7240 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYGON in pos#0)
7242 DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMesh() const
7244 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
7245 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : meshdimension, spacedimension must be equal to 2 !");
7246 MCAuto<MEDCouplingUMesh> skin(computeSkin());
7247 int oldNbOfNodes(skin->getNumberOfNodes());
7248 MCAuto<DataArrayInt> o2n(skin->zipCoordsTraducer());
7249 int nbOfNodesExpected(skin->getNumberOfNodes());
7250 MCAuto<DataArrayInt> n2o(o2n->invertArrayO2N2N2O(oldNbOfNodes));
7251 int nbCells(skin->getNumberOfCells());
7252 if(nbCells==nbOfNodesExpected)
7253 return buildUnionOf2DMeshLinear(skin,n2o);
7254 else if(2*nbCells==nbOfNodesExpected)
7255 return buildUnionOf2DMeshQuadratic(skin,n2o);
7257 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : the mesh 2D in input appears to be not in a single part of a 2D mesh !");
7261 * This method makes the assumption spacedimension == meshdimension == 3.
7262 * This method works only for linear cells.
7264 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYHED in pos#0)
7266 DataArrayInt *MEDCouplingUMesh::buildUnionOf3DMesh() const
7268 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
7269 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf3DMesh : meshdimension, spacedimension must be equal to 2 !");
7270 MCAuto<MEDCouplingUMesh> m=computeSkin();
7271 const int *conn=m->getNodalConnectivity()->begin();
7272 const int *connI=m->getNodalConnectivityIndex()->begin();
7273 int nbOfCells=m->getNumberOfCells();
7274 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(m->getNodalConnectivity()->getNumberOfTuples(),1);
7275 int *work=ret->getPointer(); *work++=INTERP_KERNEL::NORM_POLYHED;
7278 work=std::copy(conn+connI[0]+1,conn+connI[1],work);
7279 for(int i=1;i<nbOfCells;i++)
7282 work=std::copy(conn+connI[i]+1,conn+connI[i+1],work);
7288 * \brief Creates a graph of cell neighbors
7289 * \return MEDCouplingSkyLineArray * - an sky line array the user should delete.
7290 * In the sky line array, graph arcs are stored in terms of (index,value) notation.
7292 * - index: 0 3 5 6 6
7293 * - value: 1 2 3 2 3 3
7294 * means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7295 * Arcs are not doubled but reflexive (1,1) arcs are present for each cell
7297 MEDCouplingSkyLineArray* MEDCouplingUMesh::generateGraph() const
7299 checkConnectivityFullyDefined();
7301 int meshDim = this->getMeshDimension();
7302 MEDCoupling::DataArrayInt* indexr=MEDCoupling::DataArrayInt::New();
7303 MEDCoupling::DataArrayInt* revConn=MEDCoupling::DataArrayInt::New();
7304 this->getReverseNodalConnectivity(revConn,indexr);
7305 const int* indexr_ptr=indexr->begin();
7306 const int* revConn_ptr=revConn->begin();
7308 const MEDCoupling::DataArrayInt* index;
7309 const MEDCoupling::DataArrayInt* conn;
7310 conn=this->getNodalConnectivity(); // it includes a type as the 1st element!!!
7311 index=this->getNodalConnectivityIndex();
7312 int nbCells=this->getNumberOfCells();
7313 const int* index_ptr=index->begin();
7314 const int* conn_ptr=conn->begin();
7316 //creating graph arcs (cell to cell relations)
7317 //arcs are stored in terms of (index,value) notation
7320 // means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7321 // in present version arcs are not doubled but reflexive (1,1) arcs are present for each cell
7323 //warning here one node have less than or equal effective number of cell with it
7324 //but cell could have more than effective nodes
7325 //because other equals nodes in other domain (with other global inode)
7326 std::vector <int> cell2cell_index(nbCells+1,0);
7327 std::vector <int> cell2cell;
7328 cell2cell.reserve(3*nbCells);
7330 for (int icell=0; icell<nbCells;icell++)
7332 std::map<int,int > counter;
7333 for (int iconn=index_ptr[icell]+1; iconn<index_ptr[icell+1];iconn++)
7335 int inode=conn_ptr[iconn];
7336 for (int iconnr=indexr_ptr[inode]; iconnr<indexr_ptr[inode+1];iconnr++)
7338 int icell2=revConn_ptr[iconnr];
7339 std::map<int,int>::iterator iter=counter.find(icell2);
7340 if (iter!=counter.end()) (iter->second)++;
7341 else counter.insert(std::make_pair(icell2,1));
7344 for (std::map<int,int>::const_iterator iter=counter.begin();
7345 iter!=counter.end(); iter++)
7346 if (iter->second >= meshDim)
7348 cell2cell_index[icell+1]++;
7349 cell2cell.push_back(iter->first);
7354 cell2cell_index[0]=0;
7355 for (int icell=0; icell<nbCells;icell++)
7356 cell2cell_index[icell+1]=cell2cell_index[icell]+cell2cell_index[icell+1];
7358 //filling up index and value to create skylinearray structure
7359 MEDCouplingSkyLineArray * array(MEDCouplingSkyLineArray::New(cell2cell_index,cell2cell));
7364 void MEDCouplingUMesh::writeVTKLL(std::ostream& ofs, const std::string& cellData, const std::string& pointData, DataArrayByte *byteData) const
7366 int nbOfCells=getNumberOfCells();
7368 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::writeVTK : the unstructured mesh has no cells !");
7369 ofs << " <" << getVTKDataSetType() << ">\n";
7370 ofs << " <Piece NumberOfPoints=\"" << getNumberOfNodes() << "\" NumberOfCells=\"" << nbOfCells << "\">\n";
7371 ofs << " <PointData>\n" << pointData << std::endl;
7372 ofs << " </PointData>\n";
7373 ofs << " <CellData>\n" << cellData << std::endl;
7374 ofs << " </CellData>\n";
7375 ofs << " <Points>\n";
7376 if(getSpaceDimension()==3)
7377 _coords->writeVTK(ofs,8,"Points",byteData);
7380 MCAuto<DataArrayDouble> coo=_coords->changeNbOfComponents(3,0.);
7381 coo->writeVTK(ofs,8,"Points",byteData);
7383 ofs << " </Points>\n";
7384 ofs << " <Cells>\n";
7385 const int *cPtr=_nodal_connec->begin();
7386 const int *cIPtr=_nodal_connec_index->begin();
7387 MCAuto<DataArrayInt> faceoffsets=DataArrayInt::New(); faceoffsets->alloc(nbOfCells,1);
7388 MCAuto<DataArrayInt> types=DataArrayInt::New(); types->alloc(nbOfCells,1);
7389 MCAuto<DataArrayInt> offsets=DataArrayInt::New(); offsets->alloc(nbOfCells,1);
7390 MCAuto<DataArrayInt> connectivity=DataArrayInt::New(); connectivity->alloc(_nodal_connec->getNumberOfTuples()-nbOfCells,1);
7391 int *w1=faceoffsets->getPointer(),*w2=types->getPointer(),*w3=offsets->getPointer(),*w4=connectivity->getPointer();
7392 int szFaceOffsets=0,szConn=0;
7393 for(int i=0;i<nbOfCells;i++,w1++,w2++,w3++)
7396 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]!=INTERP_KERNEL::NORM_POLYHED)
7399 *w3=szConn+cIPtr[i+1]-cIPtr[i]-1; szConn+=cIPtr[i+1]-cIPtr[i]-1;
7400 w4=std::copy(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],w4);
7404 int deltaFaceOffset=cIPtr[i+1]-cIPtr[i]+1;
7405 *w1=szFaceOffsets+deltaFaceOffset; szFaceOffsets+=deltaFaceOffset;
7406 std::set<int> c(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1]); c.erase(-1);
7407 *w3=szConn+(int)c.size(); szConn+=(int)c.size();
7408 w4=std::copy(c.begin(),c.end(),w4);
7411 types->transformWithIndArr(MEDCOUPLING2VTKTYPETRADUCER,MEDCOUPLING2VTKTYPETRADUCER+INTERP_KERNEL::NORM_MAXTYPE+1);
7412 types->writeVTK(ofs,8,"UInt8","types",byteData);
7413 offsets->writeVTK(ofs,8,"Int32","offsets",byteData);
7414 if(szFaceOffsets!=0)
7415 {//presence of Polyhedra
7416 connectivity->reAlloc(szConn);
7417 faceoffsets->writeVTK(ofs,8,"Int32","faceoffsets",byteData);
7418 MCAuto<DataArrayInt> faces=DataArrayInt::New(); faces->alloc(szFaceOffsets,1);
7419 w1=faces->getPointer();
7420 for(int i=0;i<nbOfCells;i++)
7421 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]==INTERP_KERNEL::NORM_POLYHED)
7423 int nbFaces=std::count(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],-1)+1;
7425 const int *w6=cPtr+cIPtr[i]+1,*w5=0;
7426 for(int j=0;j<nbFaces;j++)
7428 w5=std::find(w6,cPtr+cIPtr[i+1],-1);
7429 *w1++=(int)std::distance(w6,w5);
7430 w1=std::copy(w6,w5,w1);
7434 faces->writeVTK(ofs,8,"Int32","faces",byteData);
7436 connectivity->writeVTK(ofs,8,"Int32","connectivity",byteData);
7437 ofs << " </Cells>\n";
7438 ofs << " </Piece>\n";
7439 ofs << " </" << getVTKDataSetType() << ">\n";
7442 void MEDCouplingUMesh::reprQuickOverview(std::ostream& stream) const
7444 stream << "MEDCouplingUMesh C++ instance at " << this << ". Name : \"" << getName() << "\".";
7446 { stream << " Not set !"; return ; }
7447 stream << " Mesh dimension : " << _mesh_dim << ".";
7451 { stream << " No coordinates set !"; return ; }
7452 if(!_coords->isAllocated())
7453 { stream << " Coordinates set but not allocated !"; return ; }
7454 stream << " Space dimension : " << _coords->getNumberOfComponents() << "." << std::endl;
7455 stream << "Number of nodes : " << _coords->getNumberOfTuples() << ".";
7456 if(!_nodal_connec_index)
7457 { stream << std::endl << "Nodal connectivity NOT set !"; return ; }
7458 if(!_nodal_connec_index->isAllocated())
7459 { stream << std::endl << "Nodal connectivity set but not allocated !"; return ; }
7460 int lgth=_nodal_connec_index->getNumberOfTuples();
7461 int cpt=_nodal_connec_index->getNumberOfComponents();
7462 if(cpt!=1 || lgth<1)
7464 stream << std::endl << "Number of cells : " << lgth-1 << ".";
7467 std::string MEDCouplingUMesh::getVTKDataSetType() const
7469 return std::string("UnstructuredGrid");
7472 std::string MEDCouplingUMesh::getVTKFileExtension() const
7474 return std::string("vtu");
7480 * Provides a renumbering of the cells of this (which has to be a piecewise connected 1D line), so that
7481 * the segments of the line are indexed in consecutive order (i.e. cells \a i and \a i+1 are neighbors).
7482 * This doesn't modify the mesh. This method only works using nodal connectivity consideration. Coordinates of nodes are ignored here.
7483 * The caller is to deal with the resulting DataArrayInt.
7484 * \throw If the coordinate array is not set.
7485 * \throw If the nodal connectivity of the cells is not defined.
7486 * \throw If m1 is not a mesh of dimension 2, or m1 is not a mesh of dimension 1
7487 * \throw If m2 is not a (piecewise) line (i.e. if a point has more than 2 adjacent segments)
7489 * \sa DataArrayInt::sortEachPairToMakeALinkedList
7491 DataArrayInt *MEDCouplingUMesh::orderConsecutiveCells1D() const
7493 checkFullyDefined();
7494 if(getMeshDimension()!=1)
7495 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D works on unstructured mesh with meshdim = 1 !");
7497 // Check that this is a line (and not a more complex 1D mesh) - each point is used at most by 2 segments:
7498 MCAuto<DataArrayInt> _d(DataArrayInt::New()),_dI(DataArrayInt::New());
7499 MCAuto<DataArrayInt> _rD(DataArrayInt::New()),_rDI(DataArrayInt::New());
7500 MCAuto<MEDCouplingUMesh> m_points(buildDescendingConnectivity(_d, _dI, _rD, _rDI));
7501 const int *d(_d->begin()), *dI(_dI->begin());
7502 const int *rD(_rD->begin()), *rDI(_rDI->begin());
7503 MCAuto<DataArrayInt> _dsi(_rDI->deltaShiftIndex());
7504 const int * dsi(_dsi->begin());
7505 MCAuto<DataArrayInt> dsii = _dsi->findIdsNotInRange(0,3);
7507 if (dsii->getNumberOfTuples())
7508 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D only work with a mesh being a (piecewise) connected line!");
7510 int nc(getNumberOfCells());
7511 MCAuto<DataArrayInt> result(DataArrayInt::New());
7512 result->alloc(nc,1);
7514 // set of edges not used so far
7515 std::set<int> edgeSet;
7516 for (int i=0; i<nc; edgeSet.insert(i), i++);
7520 // while we have points with only one neighbor segments
7523 std::list<int> linePiece;
7524 // fills a list of consecutive segment linked to startSeg. This can go forward or backward.
7525 for (int direction=0;direction<2;direction++) // direction=0 --> forward, direction=1 --> backward
7527 // Fill the list forward (resp. backward) from the start segment:
7528 int activeSeg = startSeg;
7529 int prevPointId = -20;
7531 while (!edgeSet.empty())
7533 if (!(direction == 1 && prevPointId==-20)) // prevent adding twice startSeg
7536 linePiece.push_back(activeSeg);
7538 linePiece.push_front(activeSeg);
7539 edgeSet.erase(activeSeg);
7542 int ptId1 = d[dI[activeSeg]], ptId2 = d[dI[activeSeg]+1];
7543 ptId = direction ? (ptId1 == prevPointId ? ptId2 : ptId1) : (ptId2 == prevPointId ? ptId1 : ptId2);
7544 if (dsi[ptId] == 1) // hitting the end of the line
7547 int seg1 = rD[rDI[ptId]], seg2 = rD[rDI[ptId]+1];
7548 activeSeg = (seg1 == activeSeg) ? seg2 : seg1;
7551 // Done, save final piece into DA:
7552 std::copy(linePiece.begin(), linePiece.end(), result->getPointer()+newIdx);
7553 newIdx += linePiece.size();
7555 // identify next valid start segment (one which is not consumed)
7556 if(!edgeSet.empty())
7557 startSeg = *(edgeSet.begin());
7559 while (!edgeSet.empty());
7560 return result.retn();
7564 * This method split some of edges of 2D cells in \a this. The edges to be split are specified in \a subNodesInSeg
7565 * and in \a subNodesInSegI using \ref numbering-indirect storage mode.
7566 * To do the work this method can optionally needs information about middle of subedges for quadratic cases if
7567 * a minimal creation of new nodes is wanted.
7568 * So this method try to reduce at most the number of new nodes. The only case that can lead this method to add
7569 * nodes if a SEG3 is split without information of middle.
7570 * \b WARNING : is returned value is different from 0 a call to MEDCouplingUMesh::mergeNodes is necessary to
7571 * avoid to have a non conform mesh.
7573 * \return int - the number of new nodes created (in most of cases 0).
7575 * \throw If \a this is not coherent.
7576 * \throw If \a this has not spaceDim equal to 2.
7577 * \throw If \a this has not meshDim equal to 2.
7578 * \throw If some subcells needed to be split are orphan.
7579 * \sa MEDCouplingUMesh::conformize2D
7581 int MEDCouplingUMesh::split2DCells(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI, const DataArrayInt *midOpt, const DataArrayInt *midOptI)
7583 if(!desc || !descI || !subNodesInSeg || !subNodesInSegI)
7584 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : the 4 first arrays must be not null !");
7585 desc->checkAllocated(); descI->checkAllocated(); subNodesInSeg->checkAllocated(); subNodesInSegI->checkAllocated();
7586 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
7587 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : This method only works for meshes with spaceDim=2 and meshDim=2 !");
7588 if(midOpt==0 && midOptI==0)
7590 split2DCellsLinear(desc,descI,subNodesInSeg,subNodesInSegI);
7593 else if(midOpt!=0 && midOptI!=0)
7594 return split2DCellsQuadratic(desc,descI,subNodesInSeg,subNodesInSegI,midOpt,midOptI);
7596 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : middle parameters must be set to null for all or not null for all.");
7600 * 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
7601 * 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
7602 * the geometric cell type set to INTERP_KERNEL::NORM_POLYGON.
7603 * 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
7604 * 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.
7606 * \return false if the input connectivity represents already the convex hull, true if the input cell needs to be reordered.
7608 bool MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis(const double *coords, const int *nodalConnBg, const int *nodalConnEnd, DataArrayInt *nodalConnecOut)
7610 std::size_t sz=std::distance(nodalConnBg,nodalConnEnd);
7613 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)*nodalConnBg);
7614 if(cm.getDimension()==2)
7616 const int *node=nodalConnBg+1;
7617 int startNode=*node++;
7618 double refX=coords[2*startNode];
7619 for(;node!=nodalConnEnd;node++)
7621 if(coords[2*(*node)]<refX)
7624 refX=coords[2*startNode];
7627 std::vector<int> tmpOut; tmpOut.reserve(sz); tmpOut.push_back(startNode);
7631 double angle0=-M_PI/2;
7636 double angleNext=0.;
7637 while(nextNode!=startNode)
7641 for(node=nodalConnBg+1;node!=nodalConnEnd;node++)
7643 if(*node!=tmpOut.back() && *node!=prevNode)
7645 tmp2[0]=coords[2*(*node)]-coords[2*tmpOut.back()]; tmp2[1]=coords[2*(*node)+1]-coords[2*tmpOut.back()+1];
7646 double angleM=INTERP_KERNEL::EdgeArcCircle::GetAbsoluteAngle(tmp2,tmp1);
7651 res=angle0-angleM+2.*M_PI;
7660 if(nextNode!=startNode)
7662 angle0=angleNext-M_PI;
7665 prevNode=tmpOut.back();
7666 tmpOut.push_back(nextNode);
7669 std::vector<int> tmp3(2*(sz-1));
7670 std::vector<int>::iterator it=std::copy(nodalConnBg+1,nodalConnEnd,tmp3.begin());
7671 std::copy(nodalConnBg+1,nodalConnEnd,it);
7672 if(std::search(tmp3.begin(),tmp3.end(),tmpOut.begin(),tmpOut.end())!=tmp3.end())
7674 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
7677 if(std::search(tmp3.rbegin(),tmp3.rend(),tmpOut.begin(),tmpOut.end())!=tmp3.rend())
7679 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
7684 nodalConnecOut->pushBackSilent((int)INTERP_KERNEL::NORM_POLYGON);
7685 nodalConnecOut->insertAtTheEnd(tmpOut.begin(),tmpOut.end());
7690 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
7693 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
7697 * This method works on an input pair (\b arr, \b arrIndx) where \b arr indexes is in \b arrIndx.
7698 * 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.
7700 * \param [in] idsToRemoveBg begin of set of ids to remove in \b arr (included)
7701 * \param [in] idsToRemoveEnd end of set of ids to remove in \b arr (excluded)
7702 * \param [in,out] arr array in which the remove operation will be done.
7703 * \param [in,out] arrIndx array in the remove operation will modify
7704 * \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])
7705 * \return true if \b arr and \b arrIndx have been modified, false if not.
7707 bool MEDCouplingUMesh::RemoveIdsFromIndexedArrays(const int *idsToRemoveBg, const int *idsToRemoveEnd, DataArrayInt *arr, DataArrayInt *arrIndx, int offsetForRemoval)
7709 if(!arrIndx || !arr)
7710 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::RemoveIdsFromIndexedArrays : some input arrays are empty !");
7711 if(offsetForRemoval<0)
7712 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::RemoveIdsFromIndexedArrays : offsetForRemoval should be >=0 !");
7713 std::set<int> s(idsToRemoveBg,idsToRemoveEnd);
7714 int nbOfGrps=arrIndx->getNumberOfTuples()-1;
7715 int *arrIPtr=arrIndx->getPointer();
7718 const int *arrPtr=arr->begin();
7719 std::vector<int> arrOut;//no utility to switch to DataArrayInt because copy always needed
7720 for(int i=0;i<nbOfGrps;i++,arrIPtr++)
7722 if(*arrIPtr-previousArrI>offsetForRemoval)
7724 for(const int *work=arrPtr+previousArrI+offsetForRemoval;work!=arrPtr+*arrIPtr;work++)
7726 if(s.find(*work)==s.end())
7727 arrOut.push_back(*work);
7730 previousArrI=*arrIPtr;
7731 *arrIPtr=(int)arrOut.size();
7733 if(arr->getNumberOfTuples()==(int)arrOut.size())
7735 arr->alloc((int)arrOut.size(),1);
7736 std::copy(arrOut.begin(),arrOut.end(),arr->getPointer());
7741 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn
7742 * (\ref numbering-indirect).
7743 * This method returns the result of the extraction ( specified by a set of ids in [\b idsOfSelectBg , \b idsOfSelectEnd ) ).
7744 * The selection of extraction is done standardly in new2old format.
7745 * This method returns indexed arrays (\ref numbering-indirect) using 2 arrays (arrOut,arrIndexOut).
7747 * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
7748 * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
7749 * \param [in] arrIn arr origin array from which the extraction will be done.
7750 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7751 * \param [out] arrOut the resulting array
7752 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
7753 * \sa MEDCouplingUMesh::ExtractFromIndexedArraysSlice
7755 void MEDCouplingUMesh::ExtractFromIndexedArrays(const int *idsOfSelectBg, const int *idsOfSelectEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
7756 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
7758 if(!arrIn || !arrIndxIn)
7759 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : input pointer is NULL !");
7760 arrIn->checkAllocated(); arrIndxIn->checkAllocated();
7761 if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1)
7762 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : input arrays must have exactly one component !");
7763 std::size_t sz=std::distance(idsOfSelectBg,idsOfSelectEnd);
7764 const int *arrInPtr=arrIn->begin();
7765 const int *arrIndxPtr=arrIndxIn->begin();
7766 int nbOfGrps=arrIndxIn->getNumberOfTuples()-1;
7768 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : The format of \"arrIndxIn\" is invalid ! Its nb of tuples should be >=1 !");
7769 int maxSizeOfArr=arrIn->getNumberOfTuples();
7770 MCAuto<DataArrayInt> arro=DataArrayInt::New();
7771 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
7772 arrIo->alloc((int)(sz+1),1);
7773 const int *idsIt=idsOfSelectBg;
7774 int *work=arrIo->getPointer();
7777 for(std::size_t i=0;i<sz;i++,work++,idsIt++)
7779 if(*idsIt>=0 && *idsIt<nbOfGrps)
7780 lgth+=arrIndxPtr[*idsIt+1]-arrIndxPtr[*idsIt];
7783 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " ! Must be in [0," << nbOfGrps << ") !";
7784 throw INTERP_KERNEL::Exception(oss.str());
7790 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " and at this pos arrIndxIn[" << *idsIt;
7791 oss << "+1]-arrIndxIn[" << *idsIt << "] < 0 ! The input index array is bugged !";
7792 throw INTERP_KERNEL::Exception(oss.str());
7795 arro->alloc(lgth,1);
7796 work=arro->getPointer();
7797 idsIt=idsOfSelectBg;
7798 for(std::size_t i=0;i<sz;i++,idsIt++)
7800 if(arrIndxPtr[*idsIt]>=0 && arrIndxPtr[*idsIt+1]<=maxSizeOfArr)
7801 work=std::copy(arrInPtr+arrIndxPtr[*idsIt],arrInPtr+arrIndxPtr[*idsIt+1],work);
7804 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " arrIndx[" << *idsIt << "] must be >= 0 and arrIndx[";
7805 oss << *idsIt << "+1] <= " << maxSizeOfArr << " (the size of arrIn)!";
7806 throw INTERP_KERNEL::Exception(oss.str());
7810 arrIndexOut=arrIo.retn();
7814 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn
7815 * (\ref numbering-indirect).
7816 * 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 ).
7817 * The selection of extraction is done standardly in new2old format.
7818 * This method returns indexed arrays (\ref numbering-indirect) using 2 arrays (arrOut,arrIndexOut).
7820 * \param [in] idsOfSelectStart begin of set of ids of the input extraction (included)
7821 * \param [in] idsOfSelectStop end of set of ids of the input extraction (excluded)
7822 * \param [in] idsOfSelectStep
7823 * \param [in] arrIn arr origin array from which the extraction will be done.
7824 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7825 * \param [out] arrOut the resulting array
7826 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
7827 * \sa MEDCouplingUMesh::ExtractFromIndexedArrays
7829 void MEDCouplingUMesh::ExtractFromIndexedArraysSlice(int idsOfSelectStart, int idsOfSelectStop, int idsOfSelectStep, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
7830 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
7832 if(!arrIn || !arrIndxIn)
7833 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : input pointer is NULL !");
7834 arrIn->checkAllocated(); arrIndxIn->checkAllocated();
7835 if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1)
7836 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : input arrays must have exactly one component !");
7837 int sz=DataArrayInt::GetNumberOfItemGivenBESRelative(idsOfSelectStart,idsOfSelectStop,idsOfSelectStep,"MEDCouplingUMesh::ExtractFromIndexedArraysSlice : Input slice ");
7838 const int *arrInPtr=arrIn->begin();
7839 const int *arrIndxPtr=arrIndxIn->begin();
7840 int nbOfGrps=arrIndxIn->getNumberOfTuples()-1;
7842 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : The format of \"arrIndxIn\" is invalid ! Its nb of tuples should be >=1 !");
7843 int maxSizeOfArr=arrIn->getNumberOfTuples();
7844 MCAuto<DataArrayInt> arro=DataArrayInt::New();
7845 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
7846 arrIo->alloc((int)(sz+1),1);
7847 int idsIt=idsOfSelectStart;
7848 int *work=arrIo->getPointer();
7851 for(int i=0;i<sz;i++,work++,idsIt+=idsOfSelectStep)
7853 if(idsIt>=0 && idsIt<nbOfGrps)
7854 lgth+=arrIndxPtr[idsIt+1]-arrIndxPtr[idsIt];
7857 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " ! Must be in [0," << nbOfGrps << ") !";
7858 throw INTERP_KERNEL::Exception(oss.str());
7864 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " and at this pos arrIndxIn[" << idsIt;
7865 oss << "+1]-arrIndxIn[" << idsIt << "] < 0 ! The input index array is bugged !";
7866 throw INTERP_KERNEL::Exception(oss.str());
7869 arro->alloc(lgth,1);
7870 work=arro->getPointer();
7871 idsIt=idsOfSelectStart;
7872 for(int i=0;i<sz;i++,idsIt+=idsOfSelectStep)
7874 if(arrIndxPtr[idsIt]>=0 && arrIndxPtr[idsIt+1]<=maxSizeOfArr)
7875 work=std::copy(arrInPtr+arrIndxPtr[idsIt],arrInPtr+arrIndxPtr[idsIt+1],work);
7878 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " arrIndx[" << idsIt << "] must be >= 0 and arrIndx[";
7879 oss << idsIt << "+1] <= " << maxSizeOfArr << " (the size of arrIn)!";
7880 throw INTERP_KERNEL::Exception(oss.str());
7884 arrIndexOut=arrIo.retn();
7888 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
7889 * 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
7890 * cellIds \b in [ \b idsOfSelectBg , \b idsOfSelectEnd ) a copy coming from the corresponding values in input pair (\b srcArr, \b srcArrIndex).
7891 * This method is an generalization of MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx that performs the same thing but by without building explicitely a result output arrays.
7893 * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
7894 * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
7895 * \param [in] arrIn arr origin array from which the extraction will be done.
7896 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7897 * \param [in] srcArr input array that will be used as source of copy for ids in [ \b idsOfSelectBg, \b idsOfSelectEnd )
7898 * \param [in] srcArrIndex index array of \b srcArr
7899 * \param [out] arrOut the resulting array
7900 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
7902 * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx
7904 void MEDCouplingUMesh::SetPartOfIndexedArrays(const int *idsOfSelectBg, const int *idsOfSelectEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
7905 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex,
7906 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
7908 if(arrIn==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
7909 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArrays : presence of null pointer in input parameter !");
7910 MCAuto<DataArrayInt> arro=DataArrayInt::New();
7911 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
7912 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
7913 std::vector<bool> v(nbOfTuples,true);
7915 const int *arrIndxInPtr=arrIndxIn->begin();
7916 const int *srcArrIndexPtr=srcArrIndex->begin();
7917 for(const int *it=idsOfSelectBg;it!=idsOfSelectEnd;it++,srcArrIndexPtr++)
7919 if(*it>=0 && *it<nbOfTuples)
7922 offset+=(srcArrIndexPtr[1]-srcArrIndexPtr[0])-(arrIndxInPtr[*it+1]-arrIndxInPtr[*it]);
7926 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArrays : On pos #" << std::distance(idsOfSelectBg,it) << " value is " << *it << " not in [0," << nbOfTuples << ") !";
7927 throw INTERP_KERNEL::Exception(oss.str());
7930 srcArrIndexPtr=srcArrIndex->begin();
7931 arrIo->alloc(nbOfTuples+1,1);
7932 arro->alloc(arrIn->getNumberOfTuples()+offset,1);
7933 const int *arrInPtr=arrIn->begin();
7934 const int *srcArrPtr=srcArr->begin();
7935 int *arrIoPtr=arrIo->getPointer(); *arrIoPtr++=0;
7936 int *arroPtr=arro->getPointer();
7937 for(int ii=0;ii<nbOfTuples;ii++,arrIoPtr++)
7941 arroPtr=std::copy(arrInPtr+arrIndxInPtr[ii],arrInPtr+arrIndxInPtr[ii+1],arroPtr);
7942 *arrIoPtr=arrIoPtr[-1]+(arrIndxInPtr[ii+1]-arrIndxInPtr[ii]);
7946 std::size_t pos=std::distance(idsOfSelectBg,std::find(idsOfSelectBg,idsOfSelectEnd,ii));
7947 arroPtr=std::copy(srcArrPtr+srcArrIndexPtr[pos],srcArrPtr+srcArrIndexPtr[pos+1],arroPtr);
7948 *arrIoPtr=arrIoPtr[-1]+(srcArrIndexPtr[pos+1]-srcArrIndexPtr[pos]);
7952 arrIndexOut=arrIo.retn();
7956 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
7957 * This method is an specialization of MEDCouplingUMesh::SetPartOfIndexedArrays in the case of assignement do not modify the index in \b arrIndxIn.
7959 * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
7960 * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
7961 * \param [in,out] arrInOut arr origin array from which the extraction will be done.
7962 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7963 * \param [in] srcArr input array that will be used as source of copy for ids in [ \b idsOfSelectBg , \b idsOfSelectEnd )
7964 * \param [in] srcArrIndex index array of \b srcArr
7966 * \sa MEDCouplingUMesh::SetPartOfIndexedArrays
7968 void MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx(const int *idsOfSelectBg, const int *idsOfSelectEnd, DataArrayInt *arrInOut, const DataArrayInt *arrIndxIn,
7969 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex)
7971 if(arrInOut==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
7972 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx : presence of null pointer in input parameter !");
7973 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
7974 const int *arrIndxInPtr=arrIndxIn->begin();
7975 const int *srcArrIndexPtr=srcArrIndex->begin();
7976 int *arrInOutPtr=arrInOut->getPointer();
7977 const int *srcArrPtr=srcArr->begin();
7978 for(const int *it=idsOfSelectBg;it!=idsOfSelectEnd;it++,srcArrIndexPtr++)
7980 if(*it>=0 && *it<nbOfTuples)
7982 if(srcArrIndexPtr[1]-srcArrIndexPtr[0]==arrIndxInPtr[*it+1]-arrIndxInPtr[*it])
7983 std::copy(srcArrPtr+srcArrIndexPtr[0],srcArrPtr+srcArrIndexPtr[1],arrInOutPtr+arrIndxInPtr[*it]);
7986 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] !";
7987 throw INTERP_KERNEL::Exception(oss.str());
7992 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx : On pos #" << std::distance(idsOfSelectBg,it) << " value is " << *it << " not in [0," << nbOfTuples << ") !";
7993 throw INTERP_KERNEL::Exception(oss.str());
7999 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
8000 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
8001 * 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]].
8002 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
8003 * A negative value in \b arrIn means that it is ignored.
8004 * 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.
8006 * \param [in] arrIn arr origin array from which the extraction will be done.
8007 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
8008 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
8009 * \sa MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed, MEDCouplingUMesh::partitionBySpreadZone
8011 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGradually(const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn)
8013 int seed=0,nbOfDepthPeelingPerformed=0;
8014 return ComputeSpreadZoneGraduallyFromSeed(&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfDepthPeelingPerformed);
8018 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
8019 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
8020 * 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]].
8021 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
8022 * A negative value in \b arrIn means that it is ignored.
8023 * 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.
8024 * \param [in] seedBg the begin pointer (included) of an array containing the seed of the search zone
8025 * \param [in] seedEnd the end pointer (not included) of an array containing the seed of the search zone
8026 * \param [in] arrIn arr origin array from which the extraction will be done.
8027 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
8028 * \param [in] nbOfDepthPeeling the max number of peels requested in search. By default -1, that is to say, no limit.
8029 * \param [out] nbOfDepthPeelingPerformed the number of peels effectively performed. May be different from \a nbOfDepthPeeling
8030 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
8031 * \sa MEDCouplingUMesh::partitionBySpreadZone
8033 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(const int *seedBg, const int *seedEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn, int nbOfDepthPeeling, int& nbOfDepthPeelingPerformed)
8035 nbOfDepthPeelingPerformed=0;
8037 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed : arrIndxIn input pointer is NULL !");
8038 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
8041 DataArrayInt *ret=DataArrayInt::New(); ret->alloc(0,1);
8045 std::vector<bool> fetched(nbOfTuples,false);
8046 return ComputeSpreadZoneGraduallyFromSeedAlg(fetched,seedBg,seedEnd,arrIn,arrIndxIn,nbOfDepthPeeling,nbOfDepthPeelingPerformed);
8051 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
8052 * 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
8053 * cellIds \b in [\b idsOfSelectBg, \b idsOfSelectEnd) a copy coming from the corresponding values in input pair (\b srcArr, \b srcArrIndex).
8054 * This method is an generalization of MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx that performs the same thing but by without building explicitely a result output arrays.
8056 * \param [in] start begin of set of ids of the input extraction (included)
8057 * \param [in] end end of set of ids of the input extraction (excluded)
8058 * \param [in] step step of the set of ids in range mode.
8059 * \param [in] arrIn arr origin array from which the extraction will be done.
8060 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
8061 * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd)
8062 * \param [in] srcArrIndex index array of \b srcArr
8063 * \param [out] arrOut the resulting array
8064 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
8066 * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx MEDCouplingUMesh::SetPartOfIndexedArrays
8068 void MEDCouplingUMesh::SetPartOfIndexedArraysSlice(int start, int end, int step, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
8069 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex,
8070 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
8072 if(arrIn==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
8073 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSlice : presence of null pointer in input parameter !");
8074 MCAuto<DataArrayInt> arro=DataArrayInt::New();
8075 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
8076 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
8078 const int *arrIndxInPtr=arrIndxIn->begin();
8079 const int *srcArrIndexPtr=srcArrIndex->begin();
8080 int nbOfElemsToSet=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::SetPartOfIndexedArraysSlice : ");
8082 for(int i=0;i<nbOfElemsToSet;i++,srcArrIndexPtr++,it+=step)
8084 if(it>=0 && it<nbOfTuples)
8085 offset+=(srcArrIndexPtr[1]-srcArrIndexPtr[0])-(arrIndxInPtr[it+1]-arrIndxInPtr[it]);
8088 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSlice : On pos #" << i << " value is " << it << " not in [0," << nbOfTuples << ") !";
8089 throw INTERP_KERNEL::Exception(oss.str());
8092 srcArrIndexPtr=srcArrIndex->begin();
8093 arrIo->alloc(nbOfTuples+1,1);
8094 arro->alloc(arrIn->getNumberOfTuples()+offset,1);
8095 const int *arrInPtr=arrIn->begin();
8096 const int *srcArrPtr=srcArr->begin();
8097 int *arrIoPtr=arrIo->getPointer(); *arrIoPtr++=0;
8098 int *arroPtr=arro->getPointer();
8099 for(int ii=0;ii<nbOfTuples;ii++,arrIoPtr++)
8101 int pos=DataArray::GetPosOfItemGivenBESRelativeNoThrow(ii,start,end,step);
8104 arroPtr=std::copy(arrInPtr+arrIndxInPtr[ii],arrInPtr+arrIndxInPtr[ii+1],arroPtr);
8105 *arrIoPtr=arrIoPtr[-1]+(arrIndxInPtr[ii+1]-arrIndxInPtr[ii]);
8109 arroPtr=std::copy(srcArrPtr+srcArrIndexPtr[pos],srcArrPtr+srcArrIndexPtr[pos+1],arroPtr);
8110 *arrIoPtr=arrIoPtr[-1]+(srcArrIndexPtr[pos+1]-srcArrIndexPtr[pos]);
8114 arrIndexOut=arrIo.retn();
8118 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
8119 * This method is an specialization of MEDCouplingUMesh::SetPartOfIndexedArrays in the case of assignement do not modify the index in \b arrIndxIn.
8121 * \param [in] start begin of set of ids of the input extraction (included)
8122 * \param [in] end end of set of ids of the input extraction (excluded)
8123 * \param [in] step step of the set of ids in range mode.
8124 * \param [in,out] arrInOut arr origin array from which the extraction will be done.
8125 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
8126 * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd)
8127 * \param [in] srcArrIndex index array of \b srcArr
8129 * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSlice MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx
8131 void MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice(int start, int end, int step, DataArrayInt *arrInOut, const DataArrayInt *arrIndxIn,
8132 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex)
8134 if(arrInOut==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
8135 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : presence of null pointer in input parameter !");
8136 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
8137 const int *arrIndxInPtr=arrIndxIn->begin();
8138 const int *srcArrIndexPtr=srcArrIndex->begin();
8139 int *arrInOutPtr=arrInOut->getPointer();
8140 const int *srcArrPtr=srcArr->begin();
8141 int nbOfElemsToSet=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : ");
8143 for(int i=0;i<nbOfElemsToSet;i++,srcArrIndexPtr++,it+=step)
8145 if(it>=0 && it<nbOfTuples)
8147 if(srcArrIndexPtr[1]-srcArrIndexPtr[0]==arrIndxInPtr[it+1]-arrIndxInPtr[it])
8148 std::copy(srcArrPtr+srcArrIndexPtr[0],srcArrPtr+srcArrIndexPtr[1],arrInOutPtr+arrIndxInPtr[it]);
8151 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : On pos #" << i << " id (idsOfSelectBg[" << i << "]) is " << it << " arrIndxIn[id+1]-arrIndxIn[id]!=srcArrIndex[pos+1]-srcArrIndex[pos] !";
8152 throw INTERP_KERNEL::Exception(oss.str());
8157 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : On pos #" << i << " value is " << it << " not in [0," << nbOfTuples << ") !";
8158 throw INTERP_KERNEL::Exception(oss.str());
8164 * \b this is expected to be a mesh fully defined whose spaceDim==meshDim.
8165 * It returns a new allocated mesh having the same mesh dimension and lying on same coordinates.
8166 * The returned mesh contains as poly cells as number of contiguous zone (regarding connectivity).
8167 * A spread contiguous zone is built using poly cells (polyhedra in 3D, polygons in 2D and polyline in 1D).
8168 * The sum of measure field of returned mesh is equal to the sum of measure field of this.
8170 * \return a newly allocated mesh lying on the same coords than \b this with same meshdimension than \b this.
8172 MEDCouplingUMesh *MEDCouplingUMesh::buildSpreadZonesWithPoly() const
8174 checkFullyDefined();
8175 int mdim=getMeshDimension();
8176 int spaceDim=getSpaceDimension();
8178 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension and spacedimension do not match !");
8179 std::vector<DataArrayInt *> partition=partitionBySpreadZone();
8180 std::vector< MCAuto<DataArrayInt> > partitionAuto; partitionAuto.reserve(partition.size());
8181 std::copy(partition.begin(),partition.end(),std::back_insert_iterator<std::vector< MCAuto<DataArrayInt> > >(partitionAuto));
8182 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
8183 ret->setCoords(getCoords());
8184 ret->allocateCells((int)partition.size());
8186 for(std::vector<DataArrayInt *>::const_iterator it=partition.begin();it!=partition.end();it++)
8188 MCAuto<MEDCouplingUMesh> tmp=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf((*it)->begin(),(*it)->end(),true));
8189 MCAuto<DataArrayInt> cell;
8193 cell=tmp->buildUnionOf2DMesh();
8196 cell=tmp->buildUnionOf3DMesh();
8199 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension supported are [2,3] ! Not implemented yet for others !");
8202 ret->insertNextCell((INTERP_KERNEL::NormalizedCellType)cell->getIJSafe(0,0),cell->getNumberOfTuples()-1,cell->begin()+1);
8205 ret->finishInsertingCells();
8210 * This method partitions \b this into contiguous zone.
8211 * This method only needs a well defined connectivity. Coordinates are not considered here.
8212 * This method returns a vector of \b newly allocated arrays that the caller has to deal with.
8214 std::vector<DataArrayInt *> MEDCouplingUMesh::partitionBySpreadZone() const
8216 DataArrayInt *neigh=0,*neighI=0;
8217 computeNeighborsOfCells(neigh,neighI);
8218 MCAuto<DataArrayInt> neighAuto(neigh),neighIAuto(neighI);
8219 return PartitionBySpreadZone(neighAuto,neighIAuto);
8222 std::vector<DataArrayInt *> MEDCouplingUMesh::PartitionBySpreadZone(const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn)
8224 if(!arrIn || !arrIndxIn)
8225 throw INTERP_KERNEL::Exception("PartitionBySpreadZone : null input pointers !");
8226 arrIn->checkAllocated(); arrIndxIn->checkAllocated();
8227 int nbOfTuples(arrIndxIn->getNumberOfTuples());
8228 if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1 || nbOfTuples<1)
8229 throw INTERP_KERNEL::Exception("PartitionBySpreadZone : invalid arrays in input !");
8230 int nbOfCellsCur(nbOfTuples-1);
8231 std::vector<DataArrayInt *> ret;
8234 std::vector<bool> fetchedCells(nbOfCellsCur,false);
8235 std::vector< MCAuto<DataArrayInt> > ret2;
8237 while(seed<nbOfCellsCur)
8239 int nbOfPeelPerformed=0;
8240 ret2.push_back(ComputeSpreadZoneGraduallyFromSeedAlg(fetchedCells,&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfPeelPerformed));
8241 seed=(int)std::distance(fetchedCells.begin(),std::find(fetchedCells.begin()+seed,fetchedCells.end(),false));
8243 for(std::vector< MCAuto<DataArrayInt> >::iterator it=ret2.begin();it!=ret2.end();it++)
8244 ret.push_back((*it).retn());
8249 * This method returns given a distribution of cell type (returned for example by MEDCouplingUMesh::getDistributionOfTypes method and customized after) a
8250 * newly allocated DataArrayInt instance with 2 components ready to be interpreted as input of DataArrayInt::findRangeIdForEachTuple method.
8252 * \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.
8253 * \return a newly allocated DataArrayInt to be managed by the caller.
8254 * \throw In case of \a code has not the right format (typically of size 3*n)
8256 DataArrayInt *MEDCouplingUMesh::ComputeRangesFromTypeDistribution(const std::vector<int>& code)
8258 MCAuto<DataArrayInt> ret=DataArrayInt::New();
8259 std::size_t nb=code.size()/3;
8260 if(code.size()%3!=0)
8261 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeRangesFromTypeDistribution : invalid input code !");
8262 ret->alloc((int)nb,2);
8263 int *retPtr=ret->getPointer();
8264 for(std::size_t i=0;i<nb;i++,retPtr+=2)
8266 retPtr[0]=code[3*i+2];
8267 retPtr[1]=code[3*i+2]+code[3*i+1];
8273 * This method expects that \a this a 3D mesh (spaceDim=3 and meshDim=3) with all coordinates and connectivities set.
8274 * All cells in \a this are expected to be linear 3D cells.
8275 * This method will split **all** 3D cells in \a this into INTERP_KERNEL::NORM_TETRA4 cells and put them in the returned mesh.
8276 * It leads to an increase to number of cells.
8277 * This method contrary to MEDCouplingUMesh::simplexize can append coordinates in \a this to perform its work.
8278 * The \a nbOfAdditionalPoints returned value informs about it. If > 0, the coordinates array in returned mesh will have \a nbOfAdditionalPoints
8279 * more tuples (nodes) than in \a this. Anyway, all the nodes in \a this (with the same order) will be in the returned mesh.
8281 * \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.
8282 * For all other cells, the splitting policy will be ignored. See INTERP_KERNEL::SplittingPolicy for the images.
8283 * \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.
8284 * \param [out] n2oCells - A new instance of DataArrayInt holding, for each new cell,
8285 * an id of old cell producing it. The caller is to delete this array using
8286 * decrRef() as it is no more needed.
8287 * \return MEDCoupling1SGTUMesh * - the mesh containing only INTERP_KERNEL::NORM_TETRA4 cells.
8289 * \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
8290 * the policy PLANAR_FACE_6 should be used on a mesh sorted with MEDCoupling1SGTUMesh::sortHexa8EachOther.
8292 * \throw If \a this is not a 3D mesh (spaceDim==3 and meshDim==3).
8293 * \throw If \a this is not fully constituted with linear 3D cells.
8294 * \sa MEDCouplingUMesh::simplexize, MEDCoupling1SGTUMesh::sortHexa8EachOther
8296 MEDCoupling1SGTUMesh *MEDCouplingUMesh::tetrahedrize(int policy, DataArrayInt *& n2oCells, int& nbOfAdditionalPoints) const
8298 INTERP_KERNEL::SplittingPolicy pol((INTERP_KERNEL::SplittingPolicy)policy);
8299 checkConnectivityFullyDefined();
8300 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
8301 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tetrahedrize : only available for mesh with meshdim == 3 and spacedim == 3 !");
8302 int nbOfCells(getNumberOfCells()),nbNodes(getNumberOfNodes());
8303 MCAuto<MEDCoupling1SGTUMesh> ret0(MEDCoupling1SGTUMesh::New(getName(),INTERP_KERNEL::NORM_TETRA4));
8304 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(nbOfCells,1);
8305 int *retPt(ret->getPointer());
8306 MCAuto<DataArrayInt> newConn(DataArrayInt::New()); newConn->alloc(0,1);
8307 MCAuto<DataArrayDouble> addPts(DataArrayDouble::New()); addPts->alloc(0,1);
8308 const int *oldc(_nodal_connec->begin());
8309 const int *oldci(_nodal_connec_index->begin());
8310 const double *coords(_coords->begin());
8311 for(int i=0;i<nbOfCells;i++,oldci++,retPt++)
8313 std::vector<int> a; std::vector<double> b;
8314 INTERP_KERNEL::SplitIntoTetras(pol,(INTERP_KERNEL::NormalizedCellType)oldc[oldci[0]],oldc+oldci[0]+1,oldc+oldci[1],coords,a,b);
8315 std::size_t nbOfTet(a.size()/4); *retPt=(int)nbOfTet;
8316 const int *aa(&a[0]);
8319 for(std::vector<int>::iterator it=a.begin();it!=a.end();it++)
8321 *it=(-(*(it))-1+nbNodes);
8322 addPts->insertAtTheEnd(b.begin(),b.end());
8323 nbNodes+=(int)b.size()/3;
8325 for(std::size_t j=0;j<nbOfTet;j++,aa+=4)
8326 newConn->insertAtTheEnd(aa,aa+4);
8328 if(!addPts->empty())
8330 addPts->rearrange(3);
8331 nbOfAdditionalPoints=addPts->getNumberOfTuples();
8332 addPts=DataArrayDouble::Aggregate(getCoords(),addPts);
8333 ret0->setCoords(addPts);
8337 nbOfAdditionalPoints=0;
8338 ret0->setCoords(getCoords());
8340 ret0->setNodalConnectivity(newConn);
8342 ret->computeOffsetsFull();
8343 n2oCells=ret->buildExplicitArrOfSliceOnScaledArr(0,nbOfCells,1);
8347 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),
8348 _own_cell(true),_cell_id(-1),_nb_cell(0)
8353 _nb_cell=mesh->getNumberOfCells();
8357 MEDCouplingUMeshCellIterator::~MEDCouplingUMeshCellIterator()
8365 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh, MEDCouplingUMeshCell *itc, int bg, int end):_mesh(mesh),_cell(itc),
8366 _own_cell(false),_cell_id(bg-1),
8373 MEDCouplingUMeshCell *MEDCouplingUMeshCellIterator::nextt()
8376 if(_cell_id<_nb_cell)
8385 MEDCouplingUMeshCellByTypeEntry::MEDCouplingUMeshCellByTypeEntry(MEDCouplingUMesh *mesh):_mesh(mesh)
8391 MEDCouplingUMeshCellByTypeIterator *MEDCouplingUMeshCellByTypeEntry::iterator()
8393 return new MEDCouplingUMeshCellByTypeIterator(_mesh);
8396 MEDCouplingUMeshCellByTypeEntry::~MEDCouplingUMeshCellByTypeEntry()
8402 MEDCouplingUMeshCellEntry::MEDCouplingUMeshCellEntry(MEDCouplingUMesh *mesh, INTERP_KERNEL::NormalizedCellType type, MEDCouplingUMeshCell *itc, int bg, int end):_mesh(mesh),_type(type),
8410 MEDCouplingUMeshCellEntry::~MEDCouplingUMeshCellEntry()
8416 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCellEntry::getType() const
8421 int MEDCouplingUMeshCellEntry::getNumberOfElems() const
8426 MEDCouplingUMeshCellIterator *MEDCouplingUMeshCellEntry::iterator()
8428 return new MEDCouplingUMeshCellIterator(_mesh,_itc,_bg,_end);
8431 MEDCouplingUMeshCellByTypeIterator::MEDCouplingUMeshCellByTypeIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),_cell_id(0),_nb_cell(0)
8436 _nb_cell=mesh->getNumberOfCells();
8440 MEDCouplingUMeshCellByTypeIterator::~MEDCouplingUMeshCellByTypeIterator()
8447 MEDCouplingUMeshCellEntry *MEDCouplingUMeshCellByTypeIterator::nextt()
8449 const int *c=_mesh->getNodalConnectivity()->begin();
8450 const int *ci=_mesh->getNodalConnectivityIndex()->begin();
8451 if(_cell_id<_nb_cell)
8453 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[_cell_id]];
8454 int nbOfElems=(int)std::distance(ci+_cell_id,std::find_if(ci+_cell_id,ci+_nb_cell,MEDCouplingImpl::ConnReader(c,type)));
8455 int startId=_cell_id;
8456 _cell_id+=nbOfElems;
8457 return new MEDCouplingUMeshCellEntry(_mesh,type,_cell,startId,_cell_id);
8463 MEDCouplingUMeshCell::MEDCouplingUMeshCell(MEDCouplingUMesh *mesh):_conn(0),_conn_indx(0),_conn_lgth(NOTICABLE_FIRST_VAL)
8467 _conn=mesh->getNodalConnectivity()->getPointer();
8468 _conn_indx=mesh->getNodalConnectivityIndex()->getPointer();
8472 void MEDCouplingUMeshCell::next()
8474 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8479 _conn_lgth=_conn_indx[1]-_conn_indx[0];
8482 std::string MEDCouplingUMeshCell::repr() const
8484 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8486 std::ostringstream oss; oss << "Cell Type " << INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)_conn[0]).getRepr();
8488 std::copy(_conn+1,_conn+_conn_lgth,std::ostream_iterator<int>(oss," "));
8492 return std::string("MEDCouplingUMeshCell::repr : Invalid pos");
8495 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCell::getType() const
8497 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8498 return (INTERP_KERNEL::NormalizedCellType)_conn[0];
8500 return INTERP_KERNEL::NORM_ERROR;
8503 const int *MEDCouplingUMeshCell::getAllConn(int& lgth) const
8506 if(_conn_lgth!=NOTICABLE_FIRST_VAL)