1 // Copyright (C) 2007-2019 CEA/DEN, EDF R&D
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 // Author : Anthony Geay (EDF R&D)
21 #include "MEDCouplingUMesh.txx"
22 #include "MEDCouplingCMesh.hxx"
23 #include "MEDCoupling1GTUMesh.hxx"
24 #include "MEDCouplingFieldDouble.hxx"
25 #include "MEDCouplingSkyLineArray.hxx"
26 #include "CellModel.hxx"
27 #include "VolSurfUser.txx"
28 #include "InterpolationUtils.hxx"
29 #include "PointLocatorAlgos.txx"
31 #include "BBTreeDst.txx"
32 #include "SplitterTetra.hxx"
33 #include "DiameterCalculator.hxx"
34 #include "DirectedBoundingBox.hxx"
35 #include "InterpKernelMatrixTools.hxx"
36 #include "InterpKernelMeshQuality.hxx"
37 #include "InterpKernelCellSimplify.hxx"
38 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
39 #include "InterpKernelAutoPtr.hxx"
40 #include "InterpKernelGeo2DNode.hxx"
41 #include "InterpKernelGeo2DEdgeLin.hxx"
42 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
43 #include "InterpKernelGeo2DQuadraticPolygon.hxx"
44 #include "OrientationInverter.hxx"
45 #include "MEDCouplingUMesh_internal.hxx"
54 using namespace MEDCoupling;
56 double MEDCouplingUMesh::EPS_FOR_POLYH_ORIENTATION=1.e-14;
59 const INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::MEDMEM_ORDER[N_MEDMEM_ORDER] = { INTERP_KERNEL::NORM_POINT1, INTERP_KERNEL::NORM_SEG2, INTERP_KERNEL::NORM_SEG3, INTERP_KERNEL::NORM_SEG4, INTERP_KERNEL::NORM_POLYL, INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4, INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_TRI7, INTERP_KERNEL::NORM_QUAD8, INTERP_KERNEL::NORM_QUAD9, INTERP_KERNEL::NORM_POLYGON, INTERP_KERNEL::NORM_QPOLYG, INTERP_KERNEL::NORM_TETRA4, INTERP_KERNEL::NORM_PYRA5, INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXA8, INTERP_KERNEL::NORM_HEXGP12, INTERP_KERNEL::NORM_TETRA10, INTERP_KERNEL::NORM_PYRA13, INTERP_KERNEL::NORM_PENTA15, INTERP_KERNEL::NORM_PENTA18, INTERP_KERNEL::NORM_HEXA20, INTERP_KERNEL::NORM_HEXA27, INTERP_KERNEL::NORM_POLYHED };
60 const int MEDCouplingUMesh::MEDCOUPLING2VTKTYPETRADUCER[INTERP_KERNEL::NORM_MAXTYPE+1]={1,3,21,5,9,7,22,34,23,28,-1,-1,-1,-1,10,14,13,-1,12,-1,24,-1,16,27,-1,26,-1,29,32,-1,25,42,36,4};
63 MEDCouplingUMesh *MEDCouplingUMesh::New()
65 return new MEDCouplingUMesh;
68 MEDCouplingUMesh *MEDCouplingUMesh::New(const std::string& meshName, int meshDim)
70 MEDCouplingUMesh *ret=new MEDCouplingUMesh;
71 ret->setName(meshName);
72 ret->setMeshDimension(meshDim);
77 * Returns a new MEDCouplingUMesh which is a full copy of \a this one. No data is shared
78 * between \a this and the new mesh.
79 * \return MEDCouplingUMesh * - a new instance of MEDCouplingMesh. The caller is to
80 * delete this mesh using decrRef() as it is no more needed.
82 MEDCouplingUMesh *MEDCouplingUMesh::deepCopy() const
89 * Returns a new MEDCouplingUMesh which is a copy of \a this one.
90 * \param [in] recDeepCpy - if \a true, the copy is deep, else all data arrays of \a
91 * this mesh are shared by the new mesh.
92 * \return MEDCouplingUMesh * - a new instance of MEDCouplingMesh. The caller is to
93 * delete this mesh using decrRef() as it is no more needed.
95 MEDCouplingUMesh *MEDCouplingUMesh::clone(bool recDeepCpy) const
97 return new MEDCouplingUMesh(*this,recDeepCpy);
101 * This method behaves mostly like MEDCouplingUMesh::deepCopy method, except that only nodal connectivity arrays are deeply copied.
102 * The coordinates are shared between \a this and the returned instance.
104 * \return MEDCouplingUMesh * - A new object instance holding the copy of \a this (deep for connectivity, shallow for coordiantes)
105 * \sa MEDCouplingUMesh::deepCopy
107 MEDCouplingUMesh *MEDCouplingUMesh::deepCopyConnectivityOnly() const
109 checkConnectivityFullyDefined();
110 MCAuto<MEDCouplingUMesh> ret=clone(false);
111 MCAuto<DataArrayInt> c(getNodalConnectivity()->deepCopy()),ci(getNodalConnectivityIndex()->deepCopy());
112 ret->setConnectivity(c,ci);
116 void MEDCouplingUMesh::shallowCopyConnectivityFrom(const MEDCouplingPointSet *other)
119 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is null !");
120 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
122 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is not an MEDCouplingUMesh instance !");
123 MEDCouplingUMesh *otherC2=const_cast<MEDCouplingUMesh *>(otherC);//sorry :(
124 setConnectivity(otherC2->getNodalConnectivity(),otherC2->getNodalConnectivityIndex(),true);
127 std::size_t MEDCouplingUMesh::getHeapMemorySizeWithoutChildren() const
129 std::size_t ret(MEDCouplingPointSet::getHeapMemorySizeWithoutChildren());
133 std::vector<const BigMemoryObject *> MEDCouplingUMesh::getDirectChildrenWithNull() const
135 std::vector<const BigMemoryObject *> ret(MEDCouplingPointSet::getDirectChildrenWithNull());
136 ret.push_back(_nodal_connec);
137 ret.push_back(_nodal_connec_index);
141 void MEDCouplingUMesh::updateTime() const
143 MEDCouplingPointSet::updateTime();
146 updateTimeWith(*_nodal_connec);
148 if(_nodal_connec_index)
150 updateTimeWith(*_nodal_connec_index);
154 MEDCouplingUMesh::MEDCouplingUMesh():_mesh_dim(-2),_nodal_connec(0),_nodal_connec_index(0)
159 * Checks if \a this mesh is well defined. If no exception is thrown by this method,
160 * then \a this mesh is most probably is writable, exchangeable and available for most
161 * of algorithms. When a mesh is constructed from scratch, it is a good habit to call
162 * this method to check that all is in order with \a this mesh.
163 * \throw If the mesh dimension is not set.
164 * \throw If the coordinates array is not set (if mesh dimension != -1 ).
165 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
166 * \throw If the connectivity data array has more than one component.
167 * \throw If the connectivity data array has a named component.
168 * \throw If the connectivity index data array has more than one component.
169 * \throw If the connectivity index data array has a named component.
171 void MEDCouplingUMesh::checkConsistencyLight() const
174 throw INTERP_KERNEL::Exception("No mesh dimension specified !");
176 MEDCouplingPointSet::checkConsistencyLight();
177 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
179 if((int)INTERP_KERNEL::CellModel::GetCellModel(*iter).getDimension()!=_mesh_dim)
181 std::ostringstream message;
182 message << "Mesh invalid because dimension is " << _mesh_dim << " and there is presence of cell(s) with type " << (*iter);
183 throw INTERP_KERNEL::Exception(message.str().c_str());
188 if(_nodal_connec->getNumberOfComponents()!=1)
189 throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to be with number of components set to one !");
190 if(_nodal_connec->getInfoOnComponent(0)!="")
191 throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to have no info on its single component !");
195 throw INTERP_KERNEL::Exception("Nodal connectivity array is not defined !");
196 if(_nodal_connec_index)
198 if(_nodal_connec_index->getNumberOfComponents()!=1)
199 throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to be with number of components set to one !");
200 if(_nodal_connec_index->getInfoOnComponent(0)!="")
201 throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to have no info on its single component !");
205 throw INTERP_KERNEL::Exception("Nodal connectivity index array is not defined !");
209 * Checks if \a this mesh is well defined. If no exception is thrown by this method,
210 * then \a this mesh is most probably is writable, exchangeable and available for all
211 * algorithms. <br> In addition to the checks performed by checkConsistencyLight(), this
212 * method thoroughly checks the nodal connectivity.
213 * \param [in] eps - a not used parameter.
214 * \throw If the mesh dimension is not set.
215 * \throw If the coordinates array is not set (if mesh dimension != -1 ).
216 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
217 * \throw If the connectivity data array has more than one component.
218 * \throw If the connectivity data array has a named component.
219 * \throw If the connectivity index data array has more than one component.
220 * \throw If the connectivity index data array has a named component.
221 * \throw If number of nodes defining an element does not correspond to the type of element.
222 * \throw If the nodal connectivity includes an invalid node id.
224 void MEDCouplingUMesh::checkConsistency(double eps) const
226 checkConsistencyLight();
229 int meshDim=getMeshDimension();
230 int nbOfNodes=getNumberOfNodes();
231 int nbOfCells=getNumberOfCells();
232 const int *ptr=_nodal_connec->getConstPointer();
233 const int *ptrI=_nodal_connec_index->getConstPointer();
234 for(int i=0;i<nbOfCells;i++)
236 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)ptr[ptrI[i]]);
237 if((int)cm.getDimension()!=meshDim)
239 std::ostringstream oss;
240 oss << "MEDCouplingUMesh::checkConsistency : cell << #" << i<< " with type Type " << cm.getRepr() << " in 'this' whereas meshdim == " << meshDim << " !";
241 throw INTERP_KERNEL::Exception(oss.str());
243 int nbOfNodesInCell=ptrI[i+1]-ptrI[i]-1;
245 if(nbOfNodesInCell!=(int)cm.getNumberOfNodes())
247 std::ostringstream oss;
248 oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with static Type '" << cm.getRepr() << "' has " << cm.getNumberOfNodes();
249 oss << " nodes whereas in connectivity there is " << nbOfNodesInCell << " nodes ! Looks very bad !";
250 throw INTERP_KERNEL::Exception(oss.str());
252 if(cm.isQuadratic() && cm.isDynamic() && meshDim == 2)
253 if (nbOfNodesInCell % 2 || nbOfNodesInCell < 4)
255 std::ostringstream oss;
256 oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with quadratic type '" << cm.getRepr() << "' has " << nbOfNodesInCell;
257 oss << " nodes. This should be even, and greater or equal than 4!! Looks very bad!";
258 throw INTERP_KERNEL::Exception(oss.str());
260 for(const int *w=ptr+ptrI[i]+1;w!=ptr+ptrI[i+1];w++)
265 if(nodeId>=nbOfNodes)
267 std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " whereas there are only " << nbOfNodes << " nodes in the mesh !";
268 throw INTERP_KERNEL::Exception(oss.str());
273 std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " in connectivity ! sounds bad !";
274 throw INTERP_KERNEL::Exception(oss.str());
278 if((INTERP_KERNEL::NormalizedCellType)(ptr[ptrI[i]])!=INTERP_KERNEL::NORM_POLYHED)
280 std::ostringstream oss; oss << "Cell #" << i << " is built with node #-1 in connectivity ! sounds bad !";
281 throw INTERP_KERNEL::Exception(oss.str());
289 * Sets dimension of \a this mesh. The mesh dimension in general depends on types of
290 * elements contained in the mesh. For more info on the mesh dimension see
291 * \ref MEDCouplingUMeshPage.
292 * \param [in] meshDim - a new mesh dimension.
293 * \throw If \a meshDim is invalid. A valid range is <em> -1 <= meshDim <= 3</em>.
295 void MEDCouplingUMesh::setMeshDimension(int meshDim)
297 if(meshDim<-1 || meshDim>3)
298 throw INTERP_KERNEL::Exception("Invalid meshDim specified ! Must be greater or equal to -1 and lower or equal to 3 !");
304 * Allocates memory to store an estimation of the given number of cells.
305 * The closer the estimation to the number of cells effectively inserted, the less need the library requires
306 * to reallocate memory. If the number of cells to be inserted is not known simply assign 0 to this parameter.
307 * If a nodal connectivity previously existed before the call of this method, it will be reset.
309 * \param [in] nbOfCells - estimation of the number of cell \a this mesh will contain.
311 * \if ENABLE_EXAMPLES
312 * \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
313 * \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
316 void MEDCouplingUMesh::allocateCells(int nbOfCells)
319 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::allocateCells : the input number of cells should be >= 0 !");
320 if(_nodal_connec_index)
322 _nodal_connec_index->decrRef();
326 _nodal_connec->decrRef();
328 _nodal_connec_index=DataArrayInt::New();
329 _nodal_connec_index->reserve(nbOfCells+1);
330 _nodal_connec_index->pushBackSilent(0);
331 _nodal_connec=DataArrayInt::New();
332 _nodal_connec->reserve(2*nbOfCells);
338 * Appends a cell to the connectivity array. For deeper understanding what is
339 * happening see \ref MEDCouplingUMeshNodalConnectivity.
340 * \param [in] type - type of cell to add.
341 * \param [in] size - number of nodes constituting this cell.
342 * \param [in] nodalConnOfCell - the connectivity of the cell to add.
344 * \if ENABLE_EXAMPLES
345 * \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
346 * \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
349 void MEDCouplingUMesh::insertNextCell(INTERP_KERNEL::NormalizedCellType type, int size, const int *nodalConnOfCell)
351 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
352 if(_nodal_connec_index==0)
353 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::insertNextCell : nodal connectivity not set ! invoke allocateCells before calling insertNextCell !");
354 if((int)cm.getDimension()==_mesh_dim)
357 if(size!=(int)cm.getNumberOfNodes())
359 std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : Trying to push a " << cm.getRepr() << " cell with a size of " << size;
360 oss << " ! Expecting " << cm.getNumberOfNodes() << " !";
361 throw INTERP_KERNEL::Exception(oss.str());
363 int idx=_nodal_connec_index->back();
365 _nodal_connec_index->pushBackSilent(val);
366 _nodal_connec->writeOnPlace(idx,type,nodalConnOfCell,size);
371 std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : cell type " << cm.getRepr() << " has a dimension " << cm.getDimension();
372 oss << " whereas Mesh Dimension of current UMesh instance is set to " << _mesh_dim << " ! Please invoke \"setMeshDimension\" method before or invoke ";
373 oss << "\"MEDCouplingUMesh::New\" static method with 2 parameters name and meshDimension !";
374 throw INTERP_KERNEL::Exception(oss.str());
379 * Compacts data arrays to release unused memory. This method is to be called after
380 * finishing cell insertion using \a this->insertNextCell().
382 * \if ENABLE_EXAMPLES
383 * \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
384 * \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
387 void MEDCouplingUMesh::finishInsertingCells()
389 _nodal_connec->pack();
390 _nodal_connec_index->pack();
391 _nodal_connec->declareAsNew();
392 _nodal_connec_index->declareAsNew();
397 * Entry point for iteration over cells of this. Warning the returned cell iterator should be deallocated.
398 * Useful for python users.
400 MEDCouplingUMeshCellIterator *MEDCouplingUMesh::cellIterator()
402 return new MEDCouplingUMeshCellIterator(this);
406 * Entry point for iteration over cells groups geo types per geotypes. Warning the returned cell iterator should be deallocated.
407 * If \a this is not so that the cells are grouped by geo types, this method will throw an exception.
408 * In this case MEDCouplingUMesh::sortCellsInMEDFileFrmt or MEDCouplingUMesh::rearrange2ConsecutiveCellTypes methods for example can be called before invoking this method.
409 * Useful for python users.
411 MEDCouplingUMeshCellByTypeEntry *MEDCouplingUMesh::cellsByType()
413 if(!checkConsecutiveCellTypes())
414 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::cellsByType : this mesh is not sorted by type !");
415 return new MEDCouplingUMeshCellByTypeEntry(this);
419 * Returns a set of all cell types available in \a this mesh.
420 * \return std::set<INTERP_KERNEL::NormalizedCellType> - the set of cell types.
421 * \warning this method does not throw any exception even if \a this is not defined.
422 * \sa MEDCouplingUMesh::getAllGeoTypesSorted
424 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypes() const
430 * This method returns the sorted list of geometric types in \a this.
431 * 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
432 * having the same geometric type. So a same geometric type can appear more than once if the cells are not sorted per geometric type.
434 * \throw if connectivity in \a this is not correctly defined.
436 * \sa MEDCouplingMesh::getAllGeoTypes
438 std::vector<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypesSorted() const
440 std::vector<INTERP_KERNEL::NormalizedCellType> ret;
441 checkConnectivityFullyDefined();
442 int nbOfCells(getNumberOfCells());
445 if(getNodalConnectivityArrayLen()<1)
446 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAllGeoTypesSorted : the connectivity in this seems invalid !");
447 const int *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin());
448 ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci++]);
449 for(int i=1;i<nbOfCells;i++,ci++)
450 if(ret.back()!=((INTERP_KERNEL::NormalizedCellType)c[*ci]))
451 ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci]);
456 * This method is a method that compares \a this and \a other.
457 * This method compares \b all attributes, even names and component names.
459 bool MEDCouplingUMesh::isEqualIfNotWhy(const MEDCouplingMesh *other, double prec, std::string& reason) const
462 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isEqualIfNotWhy : input other pointer is null !");
463 std::ostringstream oss; oss.precision(15);
464 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
467 reason="mesh given in input is not castable in MEDCouplingUMesh !";
470 if(!MEDCouplingPointSet::isEqualIfNotWhy(other,prec,reason))
472 if(_mesh_dim!=otherC->_mesh_dim)
474 oss << "umesh dimension mismatch : this mesh dimension=" << _mesh_dim << " other mesh dimension=" << otherC->_mesh_dim;
478 if(_types!=otherC->_types)
480 oss << "umesh geometric type mismatch :\nThis geometric types are :";
481 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
482 { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
483 oss << "\nOther geometric types are :";
484 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=otherC->_types.begin();iter!=otherC->_types.end();iter++)
485 { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
489 if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
490 if(_nodal_connec==0 || otherC->_nodal_connec==0)
492 reason="Only one UMesh between the two this and other has its nodal connectivity DataArrayInt defined !";
495 if(_nodal_connec!=otherC->_nodal_connec)
496 if(!_nodal_connec->isEqualIfNotWhy(*otherC->_nodal_connec,reason))
498 reason.insert(0,"Nodal connectivity DataArrayInt differ : ");
501 if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
502 if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
504 reason="Only one UMesh between the two this and other has its nodal connectivity index DataArrayInt defined !";
507 if(_nodal_connec_index!=otherC->_nodal_connec_index)
508 if(!_nodal_connec_index->isEqualIfNotWhy(*otherC->_nodal_connec_index,reason))
510 reason.insert(0,"Nodal connectivity index DataArrayInt differ : ");
517 * Checks if data arrays of this mesh (node coordinates, nodal
518 * connectivity of cells, etc) of two meshes are same. Textual data like name etc. are
520 * \param [in] other - the mesh to compare with.
521 * \param [in] prec - precision value used to compare node coordinates.
522 * \return bool - \a true if the two meshes are same.
524 bool MEDCouplingUMesh::isEqualWithoutConsideringStr(const MEDCouplingMesh *other, double prec) const
526 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
529 if(!MEDCouplingPointSet::isEqualWithoutConsideringStr(other,prec))
531 if(_mesh_dim!=otherC->_mesh_dim)
533 if(_types!=otherC->_types)
535 if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
536 if(_nodal_connec==0 || otherC->_nodal_connec==0)
538 if(_nodal_connec!=otherC->_nodal_connec)
539 if(!_nodal_connec->isEqualWithoutConsideringStr(*otherC->_nodal_connec))
541 if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
542 if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
544 if(_nodal_connec_index!=otherC->_nodal_connec_index)
545 if(!_nodal_connec_index->isEqualWithoutConsideringStr(*otherC->_nodal_connec_index))
551 * Checks if \a this and \a other meshes are geometrically equivalent with high
552 * probability, else an exception is thrown. The meshes are considered equivalent if
553 * (1) meshes contain the same number of nodes and the same number of elements of the
554 * same types (2) three cells of the two meshes (first, last and middle) are based
555 * on coincident nodes (with a specified precision).
556 * \param [in] other - the mesh to compare with.
557 * \param [in] prec - the precision used to compare nodes of the two meshes.
558 * \throw If the two meshes do not match.
560 void MEDCouplingUMesh::checkFastEquivalWith(const MEDCouplingMesh *other, double prec) const
562 MEDCouplingPointSet::checkFastEquivalWith(other,prec);
563 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
565 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkFastEquivalWith : Two meshes are not not unstructured !");
569 * Returns the reverse nodal connectivity. The reverse nodal connectivity enumerates
570 * cells each node belongs to.
571 * \warning For speed reasons, this method does not check if node ids in the nodal
572 * connectivity correspond to the size of node coordinates array.
573 * \param [in,out] revNodal - an array holding ids of cells sharing each node.
574 * \param [in,out] revNodalIndx - an array, of length \a this->getNumberOfNodes() + 1,
575 * dividing cell ids in \a revNodal into groups each referring to one
576 * node. Its every element (except the last one) is an index pointing to the
577 * first id of a group of cells. For example cells sharing the node #1 are
578 * described by following range of indices:
579 * [ \a revNodalIndx[1], \a revNodalIndx[2] ) and the cell ids are
580 * \a revNodal[ \a revNodalIndx[1] ], \a revNodal[ \a revNodalIndx[1] + 1], ...
581 * Number of cells sharing the *i*-th node is
582 * \a revNodalIndx[ *i*+1 ] - \a revNodalIndx[ *i* ].
583 * \throw If the coordinates array is not set.
584 * \throw If the nodal connectivity of cells is not defined.
586 * \if ENABLE_EXAMPLES
587 * \ref cpp_mcumesh_getReverseNodalConnectivity "Here is a C++ example".<br>
588 * \ref py_mcumesh_getReverseNodalConnectivity "Here is a Python example".
591 void MEDCouplingUMesh::getReverseNodalConnectivity(DataArrayInt *revNodal, DataArrayInt *revNodalIndx) const
594 int nbOfNodes(getNumberOfNodes());
595 int *revNodalIndxPtr=(int *)malloc((nbOfNodes+1)*sizeof(int));
596 revNodalIndx->useArray(revNodalIndxPtr,true,DeallocType::C_DEALLOC,nbOfNodes+1,1);
597 std::fill(revNodalIndxPtr,revNodalIndxPtr+nbOfNodes+1,0);
598 const int *conn(_nodal_connec->begin()),*connIndex(_nodal_connec_index->begin());
599 int nbOfCells(getNumberOfCells()),nbOfEltsInRevNodal(0);
600 for(int eltId=0;eltId<nbOfCells;eltId++)
602 const int *strtNdlConnOfCurCell(conn+connIndex[eltId]+1),*endNdlConnOfCurCell(conn+connIndex[eltId+1]);
603 for(const int *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
604 if(*iter>=0)//for polyhedrons
606 nbOfEltsInRevNodal++;
607 revNodalIndxPtr[(*iter)+1]++;
610 std::transform(revNodalIndxPtr+1,revNodalIndxPtr+nbOfNodes+1,revNodalIndxPtr,revNodalIndxPtr+1,std::plus<int>());
611 int *revNodalPtr=(int *)malloc((nbOfEltsInRevNodal)*sizeof(int));
612 revNodal->useArray(revNodalPtr,true,DeallocType::C_DEALLOC,nbOfEltsInRevNodal,1);
613 std::fill(revNodalPtr,revNodalPtr+nbOfEltsInRevNodal,-1);
614 for(int eltId=0;eltId<nbOfCells;eltId++)
616 const int *strtNdlConnOfCurCell=conn+connIndex[eltId]+1;
617 const int *endNdlConnOfCurCell=conn+connIndex[eltId+1];
618 for(const int *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
619 if(*iter>=0)//for polyhedrons
620 *std::find_if(revNodalPtr+revNodalIndxPtr[*iter],revNodalPtr+revNodalIndxPtr[*iter+1],std::bind2nd(std::equal_to<int>(),-1))=eltId;
625 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
626 * this->getMeshDimension(), that bound cells of \a this mesh. In addition arrays
627 * describing correspondence between cells of \a this and the result meshes are
628 * returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending connectivity,
629 * i.e. enumerate cells of the result mesh bounding each cell of \a this mesh. The
630 * arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
631 * i.e. enumerate cells of \a this mesh bounded by each cell of the result mesh.
632 * \warning For speed reasons, this method does not check if node ids in the nodal
633 * connectivity correspond to the size of node coordinates array.
634 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
635 * to write this mesh to the MED file, its cells must be sorted using
636 * sortCellsInMEDFileFrmt().
637 * \param [in,out] desc - the array containing cell ids of the result mesh bounding
638 * each cell of \a this mesh.
639 * \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
640 * dividing cell ids in \a desc into groups each referring to one
641 * cell of \a this mesh. Its every element (except the last one) is an index
642 * pointing to the first id of a group of cells. For example cells of the
643 * result mesh bounding the cell #1 of \a this mesh are described by following
645 * [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
646 * \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
647 * Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
648 * \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
649 * \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
650 * by each cell of the result mesh.
651 * \param [in,out] revDescIndx - the array, of length one more than number of cells
652 * in the result mesh,
653 * dividing cell ids in \a revDesc into groups each referring to one
654 * cell of the result mesh the same way as \a descIndx divides \a desc.
655 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is to
656 * delete this mesh using decrRef() as it is no more needed.
657 * \throw If the coordinates array is not set.
658 * \throw If the nodal connectivity of cells is node defined.
659 * \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
660 * revDescIndx == NULL.
662 * \if ENABLE_EXAMPLES
663 * \ref cpp_mcumesh_buildDescendingConnectivity "Here is a C++ example".<br>
664 * \ref py_mcumesh_buildDescendingConnectivity "Here is a Python example".
666 * \sa buildDescendingConnectivity2()
668 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
670 return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
674 * \a this has to have a mesh dimension equal to 3. If it is not the case an INTERP_KERNEL::Exception will be thrown.
675 * This behaves exactly as MEDCouplingUMesh::buildDescendingConnectivity does except that this method compute directly the transition from mesh dimension 3 to sub edges (dimension 1)
676 * in one shot. That is to say that this method is equivalent to 2 successive calls to MEDCouplingUMesh::buildDescendingConnectivity.
677 * This method returns 4 arrays and a mesh as MEDCouplingUMesh::buildDescendingConnectivity does.
678 * \sa MEDCouplingUMesh::buildDescendingConnectivity
680 MEDCouplingUMesh *MEDCouplingUMesh::explode3DMeshTo1D(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
683 if(getMeshDimension()!=3)
684 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explode3DMeshTo1D : This has to have a mesh dimension to 3 !");
685 return buildDescendingConnectivityGen<MinusTwoSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
689 * 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.
690 * This method works for both meshes with mesh dimension equal to 2 or 3. Dynamical cells are not supported (polygons, polyhedrons...)
692 * \sa explode3DMeshTo1D, buildDescendingConnectiviy
694 MEDCouplingUMesh *MEDCouplingUMesh::explodeMeshIntoMicroEdges(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
697 switch(getMeshDimension())
700 return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
702 return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
704 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explodeMeshIntoMicroEdges : Only 2D and 3D supported !");
709 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
710 * this->getMeshDimension(), that bound cells of \a this mesh. In
711 * addition arrays describing correspondence between cells of \a this and the result
712 * meshes are returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending
713 * connectivity, i.e. enumerate cells of the result mesh bounding each cell of \a this
714 * mesh. This method differs from buildDescendingConnectivity() in that apart
715 * from cell ids, \a desc returns mutual orientation of cells in \a this and the
716 * result meshes. So a positive id means that order of nodes in corresponding cells
717 * of two meshes is same, and a negative id means a reverse order of nodes. Since a
718 * cell with id #0 can't be negative, the array \a desc returns ids in FORTRAN mode,
719 * i.e. cell ids are one-based.
720 * Arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
721 * i.e. enumerate cells of \a this mesh bounded by each cell of the result mesh.
722 * \warning For speed reasons, this method does not check if node ids in the nodal
723 * connectivity correspond to the size of node coordinates array.
724 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
725 * to write this mesh to the MED file, its cells must be sorted using
726 * sortCellsInMEDFileFrmt().
727 * \param [in,out] desc - the array containing cell ids of the result mesh bounding
728 * each cell of \a this mesh.
729 * \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
730 * dividing cell ids in \a desc into groups each referring to one
731 * cell of \a this mesh. Its every element (except the last one) is an index
732 * pointing to the first id of a group of cells. For example cells of the
733 * result mesh bounding the cell #1 of \a this mesh are described by following
735 * [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
736 * \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
737 * Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
738 * \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
739 * \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
740 * by each cell of the result mesh.
741 * \param [in,out] revDescIndx - the array, of length one more than number of cells
742 * in the result mesh,
743 * dividing cell ids in \a revDesc into groups each referring to one
744 * cell of the result mesh the same way as \a descIndx divides \a desc.
745 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This result mesh
746 * shares the node coordinates array with \a this mesh. The caller is to
747 * delete this mesh using decrRef() as it is no more needed.
748 * \throw If the coordinates array is not set.
749 * \throw If the nodal connectivity of cells is node defined.
750 * \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
751 * revDescIndx == NULL.
753 * \if ENABLE_EXAMPLES
754 * \ref cpp_mcumesh_buildDescendingConnectivity2 "Here is a C++ example".<br>
755 * \ref py_mcumesh_buildDescendingConnectivity2 "Here is a Python example".
757 * \sa buildDescendingConnectivity()
759 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity2(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
761 return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingOrientationSensitiveNbrer);
765 * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
766 * For speed reasons no check of this will be done. This method calls
767 * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
768 * This method lists cell by cell in \b this which are its neighbors. To compute the result
769 * only connectivities are considered.
770 * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
771 * The format of return is hence \ref numbering-indirect.
773 * \param [out] neighbors is an array storing all the neighbors of all cells in \b this. This array is newly
774 * allocated and should be dealt by the caller. \b neighborsIndx 2nd output
775 * parameter allows to select the right part in this array (\ref numbering-indirect). The number of tuples
776 * is equal to the last values in \b neighborsIndx.
777 * \param [out] neighborsIndx is an array of size this->getNumberOfCells()+1 newly allocated and should be
778 * dealt by the caller. This arrays allow to use the first output parameter \b neighbors (\ref numbering-indirect).
780 void MEDCouplingUMesh::computeNeighborsOfCells(DataArrayInt *&neighbors, DataArrayInt *&neighborsIndx) const
782 MCAuto<DataArrayInt> desc=DataArrayInt::New();
783 MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
784 MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
785 MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
786 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
788 ComputeNeighborsOfCellsAdv(desc,descIndx,revDesc,revDescIndx,neighbors,neighborsIndx);
791 void MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne(const DataArrayInt *nodeNeigh, const DataArrayInt *nodeNeighI, MCAuto<DataArrayInt>& cellNeigh, MCAuto<DataArrayInt>& cellNeighIndex) const
793 if(!nodeNeigh || !nodeNeighI)
794 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : null pointer !");
795 checkConsistencyLight();
796 nodeNeigh->checkAllocated(); nodeNeighI->checkAllocated();
797 nodeNeigh->checkNbOfComps(1,"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : node neigh");
798 nodeNeighI->checkNbOfComps(1,"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : node neigh index");
799 nodeNeighI->checkNbOfTuples(1+getNumberOfNodes(),"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : invalid length");
800 int nbCells(getNumberOfCells());
801 const int *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin()),*ne(nodeNeigh->begin()),*nei(nodeNeighI->begin());
802 cellNeigh=DataArrayInt::New(); cellNeigh->alloc(0,1); cellNeighIndex=DataArrayInt::New(); cellNeighIndex->alloc(1,1); cellNeighIndex->setIJ(0,0,0);
803 for(int i=0;i<nbCells;i++)
806 for(const int *it=c+ci[i]+1;it!=c+ci[i+1];it++)
808 s.insert(ne+nei[*it],ne+nei[*it+1]);
810 cellNeigh->insertAtTheEnd(s.begin(),s.end());
811 cellNeighIndex->pushBackSilent(cellNeigh->getNumberOfTuples());
816 * This method is called by MEDCouplingUMesh::computeNeighborsOfCells. This methods performs the algorithm
817 * of MEDCouplingUMesh::computeNeighborsOfCells.
818 * This method is useful for users that want to reduce along a criterion the set of neighbours cell. This is
819 * typically the case to extract a set a neighbours,
820 * excluding a set of meshdim-1 cells in input descending connectivity.
821 * Typically \b desc, \b descIndx, \b revDesc and \b revDescIndx (\ref numbering-indirect) input params are
822 * the result of MEDCouplingUMesh::buildDescendingConnectivity.
823 * This method lists cell by cell in \b this which are its neighbors. To compute the result only connectivities
825 * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
827 * \param [in] desc descending connectivity array.
828 * \param [in] descIndx descending connectivity index array used to walk through \b desc (\ref numbering-indirect).
829 * \param [in] revDesc reverse descending connectivity array.
830 * \param [in] revDescIndx reverse descending connectivity index array used to walk through \b revDesc (\ref numbering-indirect).
831 * \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
832 * parameter allows to select the right part in this array. The number of tuples is equal to the last values in \b neighborsIndx.
833 * \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.
835 void MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(const DataArrayInt *desc, const DataArrayInt *descIndx, const DataArrayInt *revDesc, const DataArrayInt *revDescIndx,
836 DataArrayInt *&neighbors, DataArrayInt *&neighborsIndx)
838 if(!desc || !descIndx || !revDesc || !revDescIndx)
839 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeNeighborsOfCellsAdv some input array is empty !");
840 const int *descPtr=desc->begin();
841 const int *descIPtr=descIndx->begin();
842 const int *revDescPtr=revDesc->begin();
843 const int *revDescIPtr=revDescIndx->begin();
845 int nbCells=descIndx->getNumberOfTuples()-1;
846 MCAuto<DataArrayInt> out0=DataArrayInt::New();
847 MCAuto<DataArrayInt> out1=DataArrayInt::New(); out1->alloc(nbCells+1,1);
848 int *out1Ptr=out1->getPointer();
850 out0->reserve(desc->getNumberOfTuples());
851 for(int i=0;i<nbCells;i++,descIPtr++,out1Ptr++)
853 for(const int *w1=descPtr+descIPtr[0];w1!=descPtr+descIPtr[1];w1++)
855 std::set<int> s(revDescPtr+revDescIPtr[*w1],revDescPtr+revDescIPtr[(*w1)+1]);
857 out0->insertAtTheEnd(s.begin(),s.end());
859 *out1Ptr=out0->getNumberOfTuples();
861 neighbors=out0.retn();
862 neighborsIndx=out1.retn();
866 * Explodes \a this into edges whatever its dimension.
868 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::explodeIntoEdges(MCAuto<DataArrayInt>& desc, MCAuto<DataArrayInt>& descIndex, MCAuto<DataArrayInt>& revDesc, MCAuto<DataArrayInt>& revDescIndx) const
871 int mdim(getMeshDimension());
872 desc=DataArrayInt::New(); descIndex=DataArrayInt::New(); revDesc=DataArrayInt::New(); revDescIndx=DataArrayInt::New();
873 MCAuto<MEDCouplingUMesh> mesh1D;
878 mesh1D=explode3DMeshTo1D(desc,descIndex,revDesc,revDescIndx);
883 mesh1D=buildDescendingConnectivity(desc,descIndex,revDesc,revDescIndx);
888 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2] !");
895 * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
896 * For speed reasons no check of this will be done. This method calls
897 * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
898 * This method lists node by node in \b this which are its neighbors. To compute the result
899 * only connectivities are considered.
900 * The neighbor nodes of node having id 'nodeId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
902 * \param [out] neighbors is an array storing all the neighbors of all nodes in \b this. This array
903 * is newly allocated and should be dealt by the caller. \b neighborsIndx 2nd output
904 * parameter allows to select the right part in this array (\ref numbering-indirect).
905 * The number of tuples is equal to the last values in \b neighborsIndx.
906 * \param [out] neighborsIdx is an array of size this->getNumberOfCells()+1 newly allocated and should
907 * be dealt by the caller. This arrays allow to use the first output parameter \b neighbors.
909 * \sa MEDCouplingUMesh::computeEnlargedNeighborsOfNodes
911 void MEDCouplingUMesh::computeNeighborsOfNodes(DataArrayInt *&neighbors, DataArrayInt *&neighborsIdx) const
914 int mdim(getMeshDimension()),nbNodes(getNumberOfNodes());
915 MCAuto<DataArrayInt> desc(DataArrayInt::New()),descIndx(DataArrayInt::New()),revDesc(DataArrayInt::New()),revDescIndx(DataArrayInt::New());
916 MCConstAuto<MEDCouplingUMesh> mesh1D;
921 mesh1D=explode3DMeshTo1D(desc,descIndx,revDesc,revDescIndx);
926 mesh1D=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
931 mesh1D.takeRef(this);
936 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2,1] !");
939 desc=DataArrayInt::New(); descIndx=DataArrayInt::New(); revDesc=0; revDescIndx=0;
940 mesh1D->getReverseNodalConnectivity(desc,descIndx);
941 MCAuto<DataArrayInt> ret0(DataArrayInt::New());
942 ret0->alloc(desc->getNumberOfTuples(),1);
943 int *r0Pt(ret0->getPointer());
944 const int *c1DPtr(mesh1D->getNodalConnectivity()->begin()),*rn(desc->begin()),*rni(descIndx->begin());
945 for(int i=0;i<nbNodes;i++,rni++)
947 for(const int *oneDCellIt=rn+rni[0];oneDCellIt!=rn+rni[1];oneDCellIt++)
948 *r0Pt++=c1DPtr[3*(*oneDCellIt)+1]==i?c1DPtr[3*(*oneDCellIt)+2]:c1DPtr[3*(*oneDCellIt)+1];
950 neighbors=ret0.retn();
951 neighborsIdx=descIndx.retn();
955 * 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.
956 * 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.
957 * This method is useful to find ghost cells of a part of a mesh with a code based on fields on nodes.
959 * \sa MEDCouplingUMesh::computeNeighborsOfNodes
961 void MEDCouplingUMesh::computeEnlargedNeighborsOfNodes(MCAuto<DataArrayInt> &neighbors, MCAuto<DataArrayInt>& neighborsIdx) const
964 int nbOfNodes(getNumberOfNodes());
965 const int *conn(_nodal_connec->begin()),*connIndex(_nodal_connec_index->begin());
966 int nbOfCells(getNumberOfCells());
967 std::vector< std::set<int> > st0(nbOfNodes);
968 for(int eltId=0;eltId<nbOfCells;eltId++)
970 const int *strtNdlConnOfCurCell(conn+connIndex[eltId]+1),*endNdlConnOfCurCell(conn+connIndex[eltId+1]);
971 std::set<int> s(strtNdlConnOfCurCell,endNdlConnOfCurCell); s.erase(-1); //for polyhedrons
972 for(std::set<int>::const_iterator iter2=s.begin();iter2!=s.end();iter2++)
973 st0[*iter2].insert(s.begin(),s.end());
975 neighborsIdx=DataArrayInt::New(); neighborsIdx->alloc(nbOfNodes+1,1); neighborsIdx->setIJ(0,0,0);
977 int *neighIdx(neighborsIdx->getPointer());
978 for(std::vector< std::set<int> >::const_iterator it=st0.begin();it!=st0.end();it++,neighIdx++)
981 neighIdx[1]=neighIdx[0];
983 neighIdx[1]=neighIdx[0]+(*it).size()-1;
986 neighbors=DataArrayInt::New(); neighbors->alloc(neighborsIdx->back(),1);
988 const int *neighIdx(neighborsIdx->begin());
989 int *neigh(neighbors->getPointer()),nodeId(0);
990 for(std::vector< std::set<int> >::const_iterator it=st0.begin();it!=st0.end();it++,neighIdx++,nodeId++)
992 std::set<int> s(*it); s.erase(nodeId);
993 std::copy(s.begin(),s.end(),neigh+*neighIdx);
999 * Converts specified cells to either polygons (if \a this is a 2D mesh) or
1000 * polyhedrons (if \a this is a 3D mesh). The cells to convert are specified by an
1001 * array of cell ids. Pay attention that after conversion all algorithms work slower
1002 * with \a this mesh than before conversion. <br> If an exception is thrown during the
1003 * conversion due presence of invalid ids in the array of cells to convert, as a
1004 * result \a this mesh contains some already converted elements. In this case the 2D
1005 * mesh remains valid but 3D mesh becomes \b inconsistent!
1006 * \warning This method can significantly modify the order of geometric types in \a this,
1007 * hence, to write this mesh to the MED file, its cells must be sorted using
1008 * sortCellsInMEDFileFrmt().
1009 * \param [in] cellIdsToConvertBg - the array holding ids of cells to convert.
1010 * \param [in] cellIdsToConvertEnd - a pointer to the last-plus-one-th element of \a
1011 * cellIdsToConvertBg.
1012 * \throw If the coordinates array is not set.
1013 * \throw If the nodal connectivity of cells is node defined.
1014 * \throw If dimension of \a this mesh is not either 2 or 3.
1016 * \if ENABLE_EXAMPLES
1017 * \ref cpp_mcumesh_convertToPolyTypes "Here is a C++ example".<br>
1018 * \ref py_mcumesh_convertToPolyTypes "Here is a Python example".
1021 void MEDCouplingUMesh::convertToPolyTypes(const int *cellIdsToConvertBg, const int *cellIdsToConvertEnd)
1023 checkFullyDefined();
1024 int dim=getMeshDimension();
1026 throw INTERP_KERNEL::Exception("Invalid mesh dimension : must be 2 or 3 !");
1027 int nbOfCells(getNumberOfCells());
1030 const int *connIndex=_nodal_connec_index->begin();
1031 int *conn=_nodal_connec->getPointer();
1032 for(const int *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1034 if(*iter>=0 && *iter<nbOfCells)
1036 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*iter]]);
1037 if(!cm.isQuadratic())
1038 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_POLYGON;
1040 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_QPOLYG;
1044 std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1045 oss << " in range [0," << nbOfCells << ") !";
1046 throw INTERP_KERNEL::Exception(oss.str());
1052 int *connIndex(_nodal_connec_index->getPointer());
1053 const int *connOld(_nodal_connec->getConstPointer());
1054 MCAuto<DataArrayInt> connNew(DataArrayInt::New()),connNewI(DataArrayInt::New()); connNew->alloc(0,1); connNewI->alloc(1,1); connNewI->setIJ(0,0,0);
1055 std::vector<bool> toBeDone(nbOfCells,false);
1056 for(const int *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1058 if(*iter>=0 && *iter<nbOfCells)
1059 toBeDone[*iter]=true;
1062 std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1063 oss << " in range [0," << nbOfCells << ") !";
1064 throw INTERP_KERNEL::Exception(oss.str());
1067 for(int cellId=0;cellId<nbOfCells;cellId++)
1069 int pos(connIndex[cellId]),posP1(connIndex[cellId+1]);
1070 int lgthOld(posP1-pos-1);
1071 if(toBeDone[cellId])
1073 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connOld[pos]);
1074 unsigned nbOfFaces(cm.getNumberOfSons2(connOld+pos+1,lgthOld));
1075 int *tmp(new int[nbOfFaces*lgthOld+1]);
1076 int *work=tmp; *work++=INTERP_KERNEL::NORM_POLYHED;
1077 for(unsigned j=0;j<nbOfFaces;j++)
1079 INTERP_KERNEL::NormalizedCellType type;
1080 unsigned offset=cm.fillSonCellNodalConnectivity2(j,connOld+pos+1,lgthOld,work,type);
1084 std::size_t newLgth(std::distance(tmp,work)-1);//-1 for last -1
1085 connNew->pushBackValsSilent(tmp,tmp+newLgth);
1086 connNewI->pushBackSilent(connNewI->back()+(int)newLgth);
1091 connNew->pushBackValsSilent(connOld+pos,connOld+posP1);
1092 connNewI->pushBackSilent(connNewI->back()+posP1-pos);
1095 setConnectivity(connNew,connNewI,false);//false because computeTypes called just behind.
1101 * Converts all cells to either polygons (if \a this is a 2D mesh) or
1102 * polyhedrons (if \a this is a 3D mesh).
1103 * \warning As this method is purely for user-friendliness and no optimization is
1104 * done to avoid construction of a useless vector, this method can be costly
1106 * \throw If the coordinates array is not set.
1107 * \throw If the nodal connectivity of cells is node defined.
1108 * \throw If dimension of \a this mesh is not either 2 or 3.
1110 void MEDCouplingUMesh::convertAllToPoly()
1112 int nbOfCells=getNumberOfCells();
1113 std::vector<int> cellIds(nbOfCells);
1114 for(int i=0;i<nbOfCells;i++)
1116 convertToPolyTypes(&cellIds[0],&cellIds[0]+cellIds.size());
1120 * Fixes nodal connectivity of invalid cells of type NORM_POLYHED. This method
1121 * expects that all NORM_POLYHED cells have connectivity similar to that of prismatic
1122 * volumes like NORM_HEXA8, NORM_PENTA6 etc., i.e. the first half of nodes describes a
1123 * base facet of the volume and the second half of nodes describes an opposite facet
1124 * having the same number of nodes as the base one. This method converts such
1125 * connectivity to a valid polyhedral format where connectivity of each facet is
1126 * explicitly described and connectivity of facets are separated by -1. If \a this mesh
1127 * contains a NORM_POLYHED cell with a valid connectivity, or an invalid connectivity is
1128 * not as expected, an exception is thrown and the mesh remains unchanged. Care of
1129 * a correct orientation of the first facet of a polyhedron, else orientation of a
1130 * corrected cell is reverse.<br>
1131 * This method is useful to build an extruded unstructured mesh with polyhedrons as
1132 * it releases the user from boring description of polyhedra connectivity in the valid
1134 * \throw If \a this->getMeshDimension() != 3.
1135 * \throw If \a this->getSpaceDimension() != 3.
1136 * \throw If the nodal connectivity of cells is not defined.
1137 * \throw If the coordinates array is not set.
1138 * \throw If \a this mesh contains polyhedrons with the valid connectivity.
1139 * \throw If \a this mesh contains polyhedrons with odd number of nodes.
1141 * \if ENABLE_EXAMPLES
1142 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
1143 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
1146 void MEDCouplingUMesh::convertExtrudedPolyhedra()
1148 checkFullyDefined();
1149 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1150 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertExtrudedPolyhedra works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
1151 int nbOfCells=getNumberOfCells();
1152 MCAuto<DataArrayInt> newCi=DataArrayInt::New();
1153 newCi->alloc(nbOfCells+1,1);
1154 int *newci=newCi->getPointer();
1155 const int *ci=_nodal_connec_index->getConstPointer();
1156 const int *c=_nodal_connec->getConstPointer();
1158 for(int i=0;i<nbOfCells;i++)
1160 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1161 if(type==INTERP_KERNEL::NORM_POLYHED)
1163 if(std::count(c+ci[i]+1,c+ci[i+1],-1)!=0)
1165 std::ostringstream oss; oss << "MEDCouplingUMesh::convertExtrudedPolyhedra : cell # " << i << " is a polhedron BUT it has NOT exactly 1 face !";
1166 throw INTERP_KERNEL::Exception(oss.str());
1168 std::size_t n2=std::distance(c+ci[i]+1,c+ci[i+1]);
1171 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 !";
1172 throw INTERP_KERNEL::Exception(oss.str());
1175 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)
1178 newci[i+1]=(ci[i+1]-ci[i])+newci[i];
1180 MCAuto<DataArrayInt> newC=DataArrayInt::New();
1181 newC->alloc(newci[nbOfCells],1);
1182 int *newc=newC->getPointer();
1183 for(int i=0;i<nbOfCells;i++)
1185 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1186 if(type==INTERP_KERNEL::NORM_POLYHED)
1188 std::size_t n1=std::distance(c+ci[i]+1,c+ci[i+1])/2;
1189 newc=std::copy(c+ci[i],c+ci[i]+n1+1,newc);
1191 for(std::size_t j=0;j<n1;j++)
1193 newc[j]=c[ci[i]+1+n1+(n1-j)%n1];
1195 newc[n1+5*j+1]=c[ci[i]+1+j];
1196 newc[n1+5*j+2]=c[ci[i]+1+j+n1];
1197 newc[n1+5*j+3]=c[ci[i]+1+(j+1)%n1+n1];
1198 newc[n1+5*j+4]=c[ci[i]+1+(j+1)%n1];
1203 newc=std::copy(c+ci[i],c+ci[i+1],newc);
1205 _nodal_connec_index->decrRef(); _nodal_connec_index=newCi.retn();
1206 _nodal_connec->decrRef(); _nodal_connec=newC.retn();
1211 * Converts all polygons (if \a this is a 2D mesh) or polyhedrons (if \a this is a 3D
1212 * mesh) to cells of classical types. This method is opposite to convertToPolyTypes().
1213 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
1214 * to write this mesh to the MED file, its cells must be sorted using
1215 * sortCellsInMEDFileFrmt().
1216 * \warning Cells (and most notably polyhedrons) must be correctly oriented for this to work
1217 * properly. See orientCorrectlyPolyhedrons() and arePolyhedronsNotCorrectlyOriented().
1218 * \return \c true if at least one cell has been converted, \c false else. In the
1219 * last case the nodal connectivity remains unchanged.
1220 * \throw If the coordinates array is not set.
1221 * \throw If the nodal connectivity of cells is not defined.
1222 * \throw If \a this->getMeshDimension() < 0.
1224 bool MEDCouplingUMesh::unPolyze()
1226 checkFullyDefined();
1227 int mdim=getMeshDimension();
1229 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::unPolyze works on umeshes with meshdim equals to 0, 1 2 or 3 !");
1232 int nbOfCells=getNumberOfCells();
1235 int initMeshLgth=getNodalConnectivityArrayLen();
1236 int *conn=_nodal_connec->getPointer();
1237 int *index=_nodal_connec_index->getPointer();
1242 for(int i=0;i<nbOfCells;i++)
1244 lgthOfCurCell=index[i+1]-posOfCurCell;
1245 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
1246 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
1247 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::NORM_ERROR;
1251 switch(cm.getDimension())
1255 INTERP_KERNEL::AutoPtr<int> tmp=new int[lgthOfCurCell-1];
1256 std::copy(conn+posOfCurCell+1,conn+posOfCurCell+lgthOfCurCell,(int *)tmp);
1257 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly2D(cm.isQuadratic(),tmp,lgthOfCurCell-1,conn+newPos+1,newLgth);
1262 int nbOfFaces,lgthOfPolyhConn;
1263 INTERP_KERNEL::AutoPtr<int> zipFullReprOfPolyh=INTERP_KERNEL::CellSimplify::getFullPolyh3DCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,nbOfFaces,lgthOfPolyhConn);
1264 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly3D(zipFullReprOfPolyh,nbOfFaces,lgthOfPolyhConn,conn+newPos+1,newLgth);
1269 newType=(lgthOfCurCell==3)?INTERP_KERNEL::NORM_SEG2:INTERP_KERNEL::NORM_POLYL;
1273 ret=ret || (newType!=type);
1274 conn[newPos]=newType;
1276 posOfCurCell=index[i+1];
1281 std::copy(conn+posOfCurCell,conn+posOfCurCell+lgthOfCurCell,conn+newPos);
1282 newPos+=lgthOfCurCell;
1283 posOfCurCell+=lgthOfCurCell;
1287 if(newPos!=initMeshLgth)
1288 _nodal_connec->reAlloc(newPos);
1295 * This method expects that spaceDimension is equal to 3 and meshDimension equal to 3.
1296 * This method performs operation only on polyhedrons in \b this. If no polyhedrons exists in \b this, \b this remains unchanged.
1297 * This method allows to merge if any coplanar 3DSurf cells that may appear in some polyhedrons cells.
1299 * \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
1302 void MEDCouplingUMesh::simplifyPolyhedra(double eps)
1304 checkFullyDefined();
1305 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1306 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplifyPolyhedra : works on meshdimension 3 and spaceDimension 3 !");
1307 MCAuto<DataArrayDouble> coords=getCoords()->deepCopy();
1308 coords->recenterForMaxPrecision(eps);
1310 int nbOfCells=getNumberOfCells();
1311 const int *conn=_nodal_connec->getConstPointer();
1312 const int *index=_nodal_connec_index->getConstPointer();
1313 MCAuto<DataArrayInt> connINew=DataArrayInt::New();
1314 connINew->alloc(nbOfCells+1,1);
1315 int *connINewPtr=connINew->getPointer(); *connINewPtr++=0;
1316 MCAuto<DataArrayInt> connNew=DataArrayInt::New(); connNew->alloc(0,1);
1317 MCAuto<DataArrayInt> E_Fi(DataArrayInt::New()), E_F(DataArrayInt::New()), F_Ei(DataArrayInt::New()), F_E(DataArrayInt::New());
1318 MCAuto<MEDCouplingUMesh> m_faces(buildDescendingConnectivity(E_F, E_Fi, F_E, F_Ei));
1320 for(int i=0;i<nbOfCells;i++,connINewPtr++)
1322 if(conn[index[i]]==(int)INTERP_KERNEL::NORM_POLYHED)
1324 SimplifyPolyhedronCell(eps,coords, i,connNew, m_faces, E_Fi, E_F, F_Ei, F_E);
1328 connNew->insertAtTheEnd(conn+index[i],conn+index[i+1]);
1329 *connINewPtr=connNew->getNumberOfTuples();
1332 setConnectivity(connNew,connINew,false);
1336 * This method returns all node ids used in the connectivity of \b this. The data array returned has to be dealt by the caller.
1337 * The returned node ids are sorted ascendingly. This method is close to MEDCouplingUMesh::getNodeIdsInUse except
1338 * the format of the returned DataArrayInt instance.
1340 * \return a newly allocated DataArrayInt sorted ascendingly of fetched node ids.
1341 * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1343 DataArrayInt *MEDCouplingUMesh::computeFetchedNodeIds() const
1345 checkConnectivityFullyDefined();
1346 const int *maxEltPt(std::max_element(_nodal_connec->begin(),_nodal_connec->end()));
1347 int maxElt(maxEltPt==_nodal_connec->end()?0:std::abs(*maxEltPt)+1);
1348 std::vector<bool> retS(maxElt,false);
1349 computeNodeIdsAlg(retS);
1350 return DataArrayInt::BuildListOfSwitchedOn(retS);
1354 * \param [in,out] nodeIdsInUse an array of size typically equal to nbOfNodes.
1355 * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1357 void MEDCouplingUMesh::computeNodeIdsAlg(std::vector<bool>& nodeIdsInUse) const
1359 int nbOfNodes((int)nodeIdsInUse.size()),nbOfCells(getNumberOfCells());
1360 const int *connIndex(_nodal_connec_index->getConstPointer()),*conn(_nodal_connec->getConstPointer());
1361 for(int i=0;i<nbOfCells;i++)
1362 for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1365 if(conn[j]<nbOfNodes)
1366 nodeIdsInUse[conn[j]]=true;
1369 std::ostringstream oss; oss << "MEDCouplingUMesh::computeNodeIdsAlg : In cell #" << i << " presence of node id " << conn[j] << " not in [0," << nbOfNodes << ") !";
1370 throw INTERP_KERNEL::Exception(oss.str());
1377 struct MEDCouplingAccVisit
1379 MEDCouplingAccVisit():_new_nb_of_nodes(0) { }
1380 int operator()(int val) { if(val!=-1) return _new_nb_of_nodes++; else return -1; }
1381 int _new_nb_of_nodes;
1387 * Finds nodes not used in any cell and returns an array giving a new id to every node
1388 * by excluding the unused nodes, for which the array holds -1. The result array is
1389 * a mapping in "Old to New" mode.
1390 * \param [out] nbrOfNodesInUse - number of node ids present in the nodal connectivity.
1391 * \return DataArrayInt * - a new instance of DataArrayInt. Its length is \a
1392 * this->getNumberOfNodes(). It holds for each node of \a this mesh either -1
1393 * if the node is unused or a new id else. The caller is to delete this
1394 * array using decrRef() as it is no more needed.
1395 * \throw If the coordinates array is not set.
1396 * \throw If the nodal connectivity of cells is not defined.
1397 * \throw If the nodal connectivity includes an invalid id.
1399 * \if ENABLE_EXAMPLES
1400 * \ref cpp_mcumesh_getNodeIdsInUse "Here is a C++ example".<br>
1401 * \ref py_mcumesh_getNodeIdsInUse "Here is a Python example".
1403 * \sa computeFetchedNodeIds, computeNodeIdsAlg()
1405 DataArrayInt *MEDCouplingUMesh::getNodeIdsInUse(int& nbrOfNodesInUse) const
1408 int nbOfNodes(getNumberOfNodes());
1409 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1410 ret->alloc(nbOfNodes,1);
1411 int *traducer=ret->getPointer();
1412 std::fill(traducer,traducer+nbOfNodes,-1);
1413 int nbOfCells=getNumberOfCells();
1414 const int *connIndex=_nodal_connec_index->getConstPointer();
1415 const int *conn=_nodal_connec->getConstPointer();
1416 for(int i=0;i<nbOfCells;i++)
1417 for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1420 if(conn[j]<nbOfNodes)
1421 traducer[conn[j]]=1;
1424 std::ostringstream oss; oss << "MEDCouplingUMesh::getNodeIdsInUse : In cell #" << i << " presence of node id " << conn[j] << " not in [0," << nbOfNodes << ") !";
1425 throw INTERP_KERNEL::Exception(oss.str());
1428 nbrOfNodesInUse=(int)std::count(traducer,traducer+nbOfNodes,1);
1429 std::transform(traducer,traducer+nbOfNodes,traducer,MEDCouplingAccVisit());
1434 * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1435 * For each cell in \b this the number of nodes constituting cell is computed.
1436 * For each polyhedron cell, the sum of the number of nodes of each face constituting polyhedron cell is returned.
1437 * So for pohyhedrons some nodes can be counted several times in the returned result.
1439 * \return a newly allocated array
1440 * \sa MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell
1442 DataArrayInt *MEDCouplingUMesh::computeNbOfNodesPerCell() const
1444 checkConnectivityFullyDefined();
1445 int nbOfCells=getNumberOfCells();
1446 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1447 ret->alloc(nbOfCells,1);
1448 int *retPtr=ret->getPointer();
1449 const int *conn=getNodalConnectivity()->getConstPointer();
1450 const int *connI=getNodalConnectivityIndex()->getConstPointer();
1451 for(int i=0;i<nbOfCells;i++,retPtr++)
1453 if(conn[connI[i]]!=(int)INTERP_KERNEL::NORM_POLYHED)
1454 *retPtr=connI[i+1]-connI[i]-1;
1456 *retPtr=connI[i+1]-connI[i]-1-std::count(conn+connI[i]+1,conn+connI[i+1],-1);
1462 * This method computes effective number of nodes per cell. That is to say nodes appearing several times in nodal connectivity of a cell,
1463 * will be counted only once here whereas it will be counted several times in MEDCouplingUMesh::computeNbOfNodesPerCell method.
1465 * \return DataArrayInt * - new object to be deallocated by the caller.
1466 * \sa MEDCouplingUMesh::computeNbOfNodesPerCell
1468 DataArrayInt *MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell() const
1470 checkConnectivityFullyDefined();
1471 int nbOfCells=getNumberOfCells();
1472 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1473 ret->alloc(nbOfCells,1);
1474 int *retPtr=ret->getPointer();
1475 const int *conn=getNodalConnectivity()->getConstPointer();
1476 const int *connI=getNodalConnectivityIndex()->getConstPointer();
1477 for(int i=0;i<nbOfCells;i++,retPtr++)
1479 std::set<int> s(conn+connI[i]+1,conn+connI[i+1]);
1480 if(conn[connI[i]]!=(int)INTERP_KERNEL::NORM_POLYHED)
1481 *retPtr=(int)s.size();
1485 *retPtr=(int)s.size();
1492 * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1493 * For each cell in \b this the number of faces constituting (entity of dimension this->getMeshDimension()-1) cell is computed.
1495 * \return a newly allocated array
1497 DataArrayInt *MEDCouplingUMesh::computeNbOfFacesPerCell() const
1499 checkConnectivityFullyDefined();
1500 int nbOfCells=getNumberOfCells();
1501 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1502 ret->alloc(nbOfCells,1);
1503 int *retPtr=ret->getPointer();
1504 const int *conn=getNodalConnectivity()->getConstPointer();
1505 const int *connI=getNodalConnectivityIndex()->getConstPointer();
1506 for(int i=0;i<nbOfCells;i++,retPtr++,connI++)
1508 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]);
1509 *retPtr=cm.getNumberOfSons2(conn+connI[0]+1,connI[1]-connI[0]-1);
1515 * Removes unused nodes (the node coordinates array is shorten) and returns an array
1516 * mapping between new and old node ids in "Old to New" mode. -1 values in the returned
1517 * array mean that the corresponding old node is no more used.
1518 * \return DataArrayInt * - a new instance of DataArrayInt of length \a
1519 * this->getNumberOfNodes() before call of this method. The caller is to
1520 * delete this array using decrRef() as it is no more needed.
1521 * \throw If the coordinates array is not set.
1522 * \throw If the nodal connectivity of cells is not defined.
1523 * \throw If the nodal connectivity includes an invalid id.
1524 * \sa areAllNodesFetched
1526 * \if ENABLE_EXAMPLES
1527 * \ref cpp_mcumesh_zipCoordsTraducer "Here is a C++ example".<br>
1528 * \ref py_mcumesh_zipCoordsTraducer "Here is a Python example".
1531 DataArrayInt *MEDCouplingUMesh::zipCoordsTraducer()
1533 return MEDCouplingPointSet::zipCoordsTraducer();
1537 * This method stands if 'cell1' and 'cell2' are equals regarding 'compType' policy.
1538 * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1540 int MEDCouplingUMesh::AreCellsEqual(const int *conn, const int *connI, int cell1, int cell2, int compType)
1545 return AreCellsEqualPolicy0(conn,connI,cell1,cell2);
1547 return AreCellsEqualPolicy1(conn,connI,cell1,cell2);
1549 return AreCellsEqualPolicy2(conn,connI,cell1,cell2);
1551 return AreCellsEqualPolicy2NoType(conn,connI,cell1,cell2);
1553 return AreCellsEqualPolicy7(conn,connI,cell1,cell2);
1555 throw INTERP_KERNEL::Exception("Unknown comparison asked ! Must be in 0,1,2,3 or 7.");
1559 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 0.
1561 int MEDCouplingUMesh::AreCellsEqualPolicy0(const int *conn, const int *connI, int cell1, int cell2)
1563 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1564 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;
1569 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 1.
1571 int MEDCouplingUMesh::AreCellsEqualPolicy1(const int *conn, const int *connI, int cell1, int cell2)
1573 int sz=connI[cell1+1]-connI[cell1];
1574 if(sz==connI[cell2+1]-connI[cell2])
1576 if(conn[connI[cell1]]==conn[connI[cell2]])
1578 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1579 unsigned dim=cm.getDimension();
1585 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz1];
1586 int *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(int *)tmp);
1587 std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1588 work=std::search((int *)tmp,(int *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1589 return work!=tmp+sz1?1:0;
1592 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;//case of SEG2 and SEG3
1595 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy1 : not implemented yet for meshdim == 3 !");
1602 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 2.
1604 int MEDCouplingUMesh::AreCellsEqualPolicy2(const int *conn, const int *connI, int cell1, int cell2)
1606 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1608 if(conn[connI[cell1]]==conn[connI[cell2]])
1610 std::set<int> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1611 std::set<int> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1619 * This method is less restrictive than AreCellsEqualPolicy2. Here the geometric type is absolutely not taken into account !
1621 int MEDCouplingUMesh::AreCellsEqualPolicy2NoType(const int *conn, const int *connI, int cell1, int cell2)
1623 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1625 std::set<int> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1626 std::set<int> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1633 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 7.
1635 int MEDCouplingUMesh::AreCellsEqualPolicy7(const int *conn, const int *connI, int cell1, int cell2)
1637 int sz=connI[cell1+1]-connI[cell1];
1638 if(sz==connI[cell2+1]-connI[cell2])
1640 if(conn[connI[cell1]]==conn[connI[cell2]])
1642 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1643 unsigned dim=cm.getDimension();
1649 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz1];
1650 int *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(int *)tmp);
1651 std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1652 work=std::search((int *)tmp,(int *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1657 std::reverse_iterator<int *> it1((int *)tmp+sz1);
1658 std::reverse_iterator<int *> it2((int *)tmp);
1659 if(std::search(it1,it2,conn+connI[cell2]+1,conn+connI[cell2+1])!=it2)
1665 return work!=tmp+sz1?1:0;
1668 {//case of SEG2 and SEG3
1669 if(std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1))
1671 if(!cm.isQuadratic())
1673 std::reverse_iterator<const int *> it1(conn+connI[cell1+1]);
1674 std::reverse_iterator<const int *> it2(conn+connI[cell1]+1);
1675 if(std::equal(it1,it2,conn+connI[cell2]+1))
1681 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])
1688 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy7 : not implemented yet for meshdim == 3 !");
1696 * This method find cells that are equal (regarding \a compType) in \a this. The comparison is specified
1698 * This method keeps the coordiantes of \a this. This method is time consuming.
1700 * \param [in] compType input specifying the technique used to compare cells each other.
1701 * - 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.
1702 * - 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)
1703 * and their type equal. For 1D mesh the policy 1 is equivalent to 0.
1704 * - 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
1705 * can be used for users not sensitive to orientation of cell
1706 * \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.
1707 * \param [out] commonCellsArr common cells ids (\ref numbering-indirect)
1708 * \param [out] commonCellsIArr common cells ids (\ref numbering-indirect)
1709 * \return the correspondence array old to new in a newly allocated array.
1712 void MEDCouplingUMesh::findCommonCells(int compType, int startCellId, DataArrayInt *& commonCellsArr, DataArrayInt *& commonCellsIArr) const
1714 MCAuto<DataArrayInt> revNodal=DataArrayInt::New(),revNodalI=DataArrayInt::New();
1715 getReverseNodalConnectivity(revNodal,revNodalI);
1716 FindCommonCellsAlg(compType,startCellId,_nodal_connec,_nodal_connec_index,revNodal,revNodalI,commonCellsArr,commonCellsIArr);
1719 void MEDCouplingUMesh::FindCommonCellsAlg(int compType, int startCellId, const DataArrayInt *nodal, const DataArrayInt *nodalI, const DataArrayInt *revNodal, const DataArrayInt *revNodalI,
1720 DataArrayInt *& commonCellsArr, DataArrayInt *& commonCellsIArr)
1722 MCAuto<DataArrayInt> commonCells=DataArrayInt::New(),commonCellsI=DataArrayInt::New(); commonCells->alloc(0,1);
1723 int nbOfCells=nodalI->getNumberOfTuples()-1;
1724 commonCellsI->reserve(1); commonCellsI->pushBackSilent(0);
1725 const int *revNodalPtr=revNodal->getConstPointer(),*revNodalIPtr=revNodalI->getConstPointer();
1726 const int *connPtr=nodal->getConstPointer(),*connIPtr=nodalI->getConstPointer();
1727 std::vector<bool> isFetched(nbOfCells,false);
1730 for(int i=0;i<nbOfCells;i++)
1734 const int *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind2nd(std::not_equal_to<int>(),-1));
1735 std::vector<int> v,v2;
1736 if(connOfNode!=connPtr+connIPtr[i+1])
1738 const int *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1739 v2.insert(v2.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1]);
1742 for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1746 const int *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1747 std::vector<int>::iterator it=std::set_intersection(v.begin(),v.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1748 v2.resize(std::distance(v2.begin(),it));
1752 if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1754 int pos=commonCellsI->back();
1755 commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1756 for(const int *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1757 isFetched[*it]=true;
1765 for(int i=startCellId;i<nbOfCells;i++)
1769 const int *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind2nd(std::not_equal_to<int>(),-1));
1770 std::vector<int> v,v2;
1771 if(connOfNode!=connPtr+connIPtr[i+1])
1773 v2.insert(v2.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1]);
1776 for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1780 std::vector<int>::iterator it=std::set_intersection(v.begin(),v.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1781 v2.resize(std::distance(v2.begin(),it));
1785 if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1787 int pos=commonCellsI->back();
1788 commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1789 for(const int *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1790 isFetched[*it]=true;
1796 commonCellsArr=commonCells.retn();
1797 commonCellsIArr=commonCellsI.retn();
1801 * Checks if \a this mesh includes all cells of an \a other mesh, and returns an array
1802 * giving for each cell of the \a other an id of a cell in \a this mesh. A value larger
1803 * than \a this->getNumberOfCells() in the returned array means that there is no
1804 * corresponding cell in \a this mesh.
1805 * It is expected that \a this and \a other meshes share the same node coordinates
1806 * array, if it is not so an exception is thrown.
1807 * \param [in] other - the mesh to compare with.
1808 * \param [in] compType - specifies a cell comparison technique. For meaning of its
1809 * valid values [0,1,2], see zipConnectivityTraducer().
1810 * \param [out] arr - a new instance of DataArrayInt returning correspondence
1811 * between cells of the two meshes. It contains \a other->getNumberOfCells()
1812 * values. The caller is to delete this array using
1813 * decrRef() as it is no more needed.
1814 * \return bool - \c true if all cells of \a other mesh are present in the \a this
1817 * \if ENABLE_EXAMPLES
1818 * \ref cpp_mcumesh_areCellsIncludedIn "Here is a C++ example".<br>
1819 * \ref py_mcumesh_areCellsIncludedIn "Here is a Python example".
1821 * \sa checkDeepEquivalOnSameNodesWith()
1822 * \sa checkGeoEquivalWith()
1824 bool MEDCouplingUMesh::areCellsIncludedIn(const MEDCouplingUMesh *other, int compType, DataArrayInt *& arr) const
1826 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1827 int nbOfCells=getNumberOfCells();
1828 static const int possibleCompType[]={0,1,2};
1829 if(std::find(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),compType)==possibleCompType+sizeof(possibleCompType)/sizeof(int))
1831 std::ostringstream oss; oss << "MEDCouplingUMesh::areCellsIncludedIn : only following policies are possible : ";
1832 std::copy(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),std::ostream_iterator<int>(oss," "));
1834 throw INTERP_KERNEL::Exception(oss.str());
1836 MCAuto<DataArrayInt> o2n=mesh->zipConnectivityTraducer(compType,nbOfCells);
1837 arr=o2n->subArray(nbOfCells);
1838 arr->setName(other->getName());
1840 if(other->getNumberOfCells()==0)
1842 return arr->getMaxValue(tmp)<nbOfCells;
1846 * This method makes the assumption that \a this and \a other share the same coords. If not an exception will be thrown !
1847 * This method tries to determine if \b other is fully included in \b this.
1848 * The main difference is that this method is not expected to throw exception.
1849 * This method has two outputs :
1851 * \param other other mesh
1852 * \param arr is an output parameter that returns a \b newly created instance. This array is of size 'other->getNumberOfCells()'.
1853 * \return If \a other is fully included in 'this 'true is returned. If not false is returned.
1855 bool MEDCouplingUMesh::areCellsIncludedInPolicy7(const MEDCouplingUMesh *other, DataArrayInt *& arr) const
1857 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1858 DataArrayInt *commonCells=0,*commonCellsI=0;
1859 int thisNbCells=getNumberOfCells();
1860 mesh->findCommonCells(7,thisNbCells,commonCells,commonCellsI);
1861 MCAuto<DataArrayInt> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1862 const int *commonCellsPtr=commonCells->getConstPointer(),*commonCellsIPtr=commonCellsI->getConstPointer();
1863 int otherNbCells=other->getNumberOfCells();
1864 MCAuto<DataArrayInt> arr2=DataArrayInt::New();
1865 arr2->alloc(otherNbCells,1);
1866 arr2->fillWithZero();
1867 int *arr2Ptr=arr2->getPointer();
1868 int nbOfCommon=commonCellsI->getNumberOfTuples()-1;
1869 for(int i=0;i<nbOfCommon;i++)
1871 int start=commonCellsPtr[commonCellsIPtr[i]];
1872 if(start<thisNbCells)
1874 for(int j=commonCellsIPtr[i]+1;j!=commonCellsIPtr[i+1];j++)
1876 int sig=commonCellsPtr[j]>0?1:-1;
1877 int val=std::abs(commonCellsPtr[j])-1;
1878 if(val>=thisNbCells)
1879 arr2Ptr[val-thisNbCells]=sig*(start+1);
1883 arr2->setName(other->getName());
1884 if(arr2->presenceOfValue(0))
1890 MEDCouplingUMesh *MEDCouplingUMesh::mergeMyselfWithOnSameCoords(const MEDCouplingPointSet *other) const
1893 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : input other is null !");
1894 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
1896 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : the input other mesh is not of type unstructured !");
1897 std::vector<const MEDCouplingUMesh *> ms(2);
1900 return MergeUMeshesOnSameCoords(ms);
1904 * Build a sub part of \b this lying or not on the same coordinates than \b this (regarding value of \b keepCoords).
1905 * By default coordinates are kept. This method is close to MEDCouplingUMesh::buildPartOfMySelf except that here input
1906 * cellIds is not given explicitly but by a range python like.
1911 * \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.
1912 * \return a newly allocated
1914 * \warning This method modifies can generate an unstructured mesh whose cells are not sorted by geometric type order.
1915 * In view of the MED file writing, a renumbering of cells of returned unstructured mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
1917 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfSlice(int start, int end, int step, bool keepCoords) const
1919 if(getMeshDimension()!=-1)
1920 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelfSlice(start,end,step,keepCoords));
1923 int newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfSlice for -1 dimension mesh ");
1925 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
1927 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
1929 return const_cast<MEDCouplingUMesh *>(this);
1934 * Creates a new MEDCouplingUMesh containing specified cells of \a this mesh.
1935 * The result mesh shares or not the node coordinates array with \a this mesh depending
1936 * on \a keepCoords parameter.
1937 * \warning Cells of the result mesh can be \b not sorted by geometric type, hence,
1938 * to write this mesh to the MED file, its cells must be sorted using
1939 * sortCellsInMEDFileFrmt().
1940 * \param [in] begin - an array of cell ids to include to the new mesh.
1941 * \param [in] end - a pointer to last-plus-one-th element of \a begin.
1942 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
1943 * array of \a this mesh, else "free" nodes are removed from the result mesh
1944 * by calling zipCoords().
1945 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
1946 * to delete this mesh using decrRef() as it is no more needed.
1947 * \throw If the coordinates array is not set.
1948 * \throw If the nodal connectivity of cells is not defined.
1949 * \throw If any cell id in the array \a begin is not valid.
1951 * \if ENABLE_EXAMPLES
1952 * \ref cpp_mcumesh_buildPartOfMySelf "Here is a C++ example".<br>
1953 * \ref py_mcumesh_buildPartOfMySelf "Here is a Python example".
1956 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelf(const int *begin, const int *end, bool keepCoords) const
1958 if(getMeshDimension()!=-1)
1959 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelf(begin,end,keepCoords));
1963 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
1965 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
1967 return const_cast<MEDCouplingUMesh *>(this);
1972 * This method operates only on nodal connectivity on \b this. Coordinates of \b this is completely ignored here.
1974 * 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.
1975 * Size of [ \b cellIdsBg, \b cellIdsEnd ) ) must be equal to the number of cells of otherOnSameCoordsThanThis.
1976 * The number of cells of \b this will remain the same with this method.
1978 * \param [in] cellIdsBg begin of cell ids (included) of cells in this to assign
1979 * \param [in] cellIdsEnd end of cell ids (excluded) of cells in this to assign
1980 * \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 ).
1981 * Coordinate pointer of \b this and those of \b otherOnSameCoordsThanThis must be the same
1983 void MEDCouplingUMesh::setPartOfMySelf(const int *cellIdsBg, const int *cellIdsEnd, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
1985 checkConnectivityFullyDefined();
1986 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
1987 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
1988 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelf : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
1989 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
1991 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
1992 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
1993 throw INTERP_KERNEL::Exception(oss.str());
1995 std::size_t nbOfCellsToModify(std::distance(cellIdsBg,cellIdsEnd));
1996 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
1998 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
1999 throw INTERP_KERNEL::Exception(oss.str());
2001 std::size_t nbOfCells(getNumberOfCells());
2002 bool easyAssign(true);
2003 const int *connI(_nodal_connec_index->begin());
2004 const int *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->begin();
2005 for(const int *it=cellIdsBg;it!=cellIdsEnd && easyAssign;it++,connIOther++)
2007 if(*it>=0 && *it<(int)nbOfCells)
2009 easyAssign=(connIOther[1]-connIOther[0])==(connI[*it+1]-connI[*it]);
2013 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : On pos #" << std::distance(cellIdsBg,it) << " id is equal to " << *it << " which is not in [0," << nbOfCells << ") !";
2014 throw INTERP_KERNEL::Exception(oss.str());
2019 MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2024 DataArrayInt *arrOut=0,*arrIOut=0;
2025 MEDCouplingUMesh::SetPartOfIndexedArrays(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2027 MCAuto<DataArrayInt> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2028 setConnectivity(arrOut,arrIOut,true);
2032 void MEDCouplingUMesh::setPartOfMySelfSlice(int start, int end, int step, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2034 checkConnectivityFullyDefined();
2035 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2036 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2037 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelfSlice : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2038 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2040 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2041 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2042 throw INTERP_KERNEL::Exception(oss.str());
2044 int nbOfCellsToModify=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::setPartOfMySelfSlice : ");
2045 if(nbOfCellsToModify!=(int)otherOnSameCoordsThanThis.getNumberOfCells())
2047 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2048 throw INTERP_KERNEL::Exception(oss.str());
2050 int nbOfCells=getNumberOfCells();
2051 bool easyAssign=true;
2052 const int *connI=_nodal_connec_index->getConstPointer();
2053 const int *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2055 for(int i=0;i<nbOfCellsToModify && easyAssign;i++,it+=step,connIOther++)
2057 if(it>=0 && it<nbOfCells)
2059 easyAssign=(connIOther[1]-connIOther[0])==(connI[it+1]-connI[it]);
2063 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : On pos #" << i << " id is equal to " << it << " which is not in [0," << nbOfCells << ") !";
2064 throw INTERP_KERNEL::Exception(oss.str());
2069 MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2074 DataArrayInt *arrOut=0,*arrIOut=0;
2075 MEDCouplingUMesh::SetPartOfIndexedArraysSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2077 MCAuto<DataArrayInt> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2078 setConnectivity(arrOut,arrIOut,true);
2084 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2085 * this->getMeshDimension(), that bound some cells of \a this mesh.
2086 * The cells of lower dimension to include to the result mesh are selected basing on
2087 * specified node ids and the value of \a fullyIn parameter. If \a fullyIn ==\c true, a
2088 * cell is copied if its all nodes are in the array \a begin of node ids. If \a fullyIn
2089 * ==\c false, a cell is copied if any its node is in the array of node ids. The
2090 * created mesh shares the node coordinates array with \a this mesh.
2091 * \param [in] begin - the array of node ids.
2092 * \param [in] end - a pointer to the (last+1)-th element of \a begin.
2093 * \param [in] fullyIn - if \c true, then cells whose all nodes are in the
2094 * array \a begin are added, else cells whose any node is in the
2095 * array \a begin are added.
2096 * \return MEDCouplingUMesh * - new instance of MEDCouplingUMesh. The caller is
2097 * to delete this mesh using decrRef() as it is no more needed.
2098 * \throw If the coordinates array is not set.
2099 * \throw If the nodal connectivity of cells is not defined.
2100 * \throw If any node id in \a begin is not valid.
2102 * \if ENABLE_EXAMPLES
2103 * \ref cpp_mcumesh_buildFacePartOfMySelfNode "Here is a C++ example".<br>
2104 * \ref py_mcumesh_buildFacePartOfMySelfNode "Here is a Python example".
2107 MEDCouplingUMesh *MEDCouplingUMesh::buildFacePartOfMySelfNode(const int *begin, const int *end, bool fullyIn) const
2109 MCAuto<DataArrayInt> desc,descIndx,revDesc,revDescIndx;
2110 desc=DataArrayInt::New(); descIndx=DataArrayInt::New(); revDesc=DataArrayInt::New(); revDescIndx=DataArrayInt::New();
2111 MCAuto<MEDCouplingUMesh> subMesh=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2112 desc=0; descIndx=0; revDesc=0; revDescIndx=0;
2113 return static_cast<MEDCouplingUMesh*>(subMesh->buildPartOfMySelfNode(begin,end,fullyIn));
2117 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2118 * this->getMeshDimension(), which bound only one cell of \a this mesh.
2119 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2120 * array of \a this mesh, else "free" nodes are removed from the result mesh
2121 * by calling zipCoords().
2122 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2123 * to delete this mesh using decrRef() as it is no more needed.
2124 * \throw If the coordinates array is not set.
2125 * \throw If the nodal connectivity of cells is not defined.
2127 * \if ENABLE_EXAMPLES
2128 * \ref cpp_mcumesh_buildBoundaryMesh "Here is a C++ example".<br>
2129 * \ref py_mcumesh_buildBoundaryMesh "Here is a Python example".
2132 MEDCouplingUMesh *MEDCouplingUMesh::buildBoundaryMesh(bool keepCoords) const
2134 DataArrayInt *desc=DataArrayInt::New();
2135 DataArrayInt *descIndx=DataArrayInt::New();
2136 DataArrayInt *revDesc=DataArrayInt::New();
2137 DataArrayInt *revDescIndx=DataArrayInt::New();
2139 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2142 descIndx->decrRef();
2143 int nbOfCells=meshDM1->getNumberOfCells();
2144 const int *revDescIndxC=revDescIndx->getConstPointer();
2145 std::vector<int> boundaryCells;
2146 for(int i=0;i<nbOfCells;i++)
2147 if(revDescIndxC[i+1]-revDescIndxC[i]==1)
2148 boundaryCells.push_back(i);
2149 revDescIndx->decrRef();
2150 MEDCouplingUMesh *ret=meshDM1->buildPartOfMySelf(&boundaryCells[0],&boundaryCells[0]+boundaryCells.size(),keepCoords);
2155 * This method returns a newly created DataArrayInt instance containing ids of cells located in boundary.
2156 * A cell is detected to be on boundary if it contains one or more than one face having only one father.
2157 * This method makes the assumption that \a this is fully defined (coords,connectivity). If not an exception will be thrown.
2159 DataArrayInt *MEDCouplingUMesh::findCellIdsOnBoundary() const
2161 checkFullyDefined();
2162 MCAuto<DataArrayInt> desc=DataArrayInt::New();
2163 MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
2164 MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
2165 MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
2167 buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx)->decrRef();
2168 desc=(DataArrayInt*)0; descIndx=(DataArrayInt*)0;
2170 MCAuto<DataArrayInt> tmp=revDescIndx->deltaShiftIndex();
2171 MCAuto<DataArrayInt> faceIds=tmp->findIdsEqual(1); tmp=(DataArrayInt*)0;
2172 const int *revDescPtr=revDesc->getConstPointer();
2173 const int *revDescIndxPtr=revDescIndx->getConstPointer();
2174 int nbOfCells=getNumberOfCells();
2175 std::vector<bool> ret1(nbOfCells,false);
2177 for(const int *pt=faceIds->begin();pt!=faceIds->end();pt++)
2178 if(!ret1[revDescPtr[revDescIndxPtr[*pt]]])
2179 { ret1[revDescPtr[revDescIndxPtr[*pt]]]=true; sz++; }
2181 DataArrayInt *ret2=DataArrayInt::New();
2183 int *ret2Ptr=ret2->getPointer();
2185 for(std::vector<bool>::const_iterator it=ret1.begin();it!=ret1.end();it++,sz++)
2188 ret2->setName("BoundaryCells");
2193 * This method finds in \b this the cell ids that lie on mesh \b otherDimM1OnSameCoords.
2194 * \b this and \b otherDimM1OnSameCoords have to lie on the same coordinate array pointer. The coherency of that coords array with connectivity
2195 * of \b this and \b otherDimM1OnSameCoords is not important here because this method works only on connectivity.
2196 * this->getMeshDimension() - 1 must be equal to otherDimM1OnSameCoords.getMeshDimension()
2198 * s0 is the cell ids set in \b this lying on at least one node in the fetched nodes in \b otherDimM1OnSameCoords.
2199 * 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
2200 * equals a cell in \b otherDimM1OnSameCoords.
2202 * \throw if \b otherDimM1OnSameCoords is not part of constituent of \b this, or if coordinate pointer of \b this and \b otherDimM1OnSameCoords
2203 * are not same, or if this->getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension()
2205 * \param [in] otherDimM1OnSameCoords
2206 * \param [out] cellIdsRk0 a newly allocated array containing the cell ids of s0 (which are cell ids of \b this) in the above algorithm.
2207 * \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
2208 * cellIdsRk1->transformWithIndArr(cellIdsRk0->begin(),cellIdsRk0->end());
2210 void MEDCouplingUMesh::findCellIdsLyingOn(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayInt *&cellIdsRk0, DataArrayInt *&cellIdsRk1) const
2212 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2213 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : coordinates pointer are not the same ! Use tryToShareSameCoords method !");
2214 checkConnectivityFullyDefined();
2215 otherDimM1OnSameCoords.checkConnectivityFullyDefined();
2216 if(getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension())
2217 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : invalid mesh dimension of input mesh regarding meshdimesion of this !");
2218 MCAuto<DataArrayInt> fetchedNodeIds1=otherDimM1OnSameCoords.computeFetchedNodeIds();
2219 MCAuto<DataArrayInt> s0arr=getCellIdsLyingOnNodes(fetchedNodeIds1->begin(),fetchedNodeIds1->end(),false);
2220 MCAuto<MEDCouplingUMesh> thisPart=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(s0arr->begin(),s0arr->end(),true));
2221 MCAuto<DataArrayInt> descThisPart=DataArrayInt::New(),descIThisPart=DataArrayInt::New(),revDescThisPart=DataArrayInt::New(),revDescIThisPart=DataArrayInt::New();
2222 MCAuto<MEDCouplingUMesh> thisPartConsti=thisPart->buildDescendingConnectivity(descThisPart,descIThisPart,revDescThisPart,revDescIThisPart);
2223 const int *revDescThisPartPtr=revDescThisPart->getConstPointer(),*revDescIThisPartPtr=revDescIThisPart->getConstPointer();
2224 DataArrayInt *idsOtherInConsti=0;
2225 bool b=thisPartConsti->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsOtherInConsti);
2226 MCAuto<DataArrayInt> idsOtherInConstiAuto(idsOtherInConsti);
2228 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : the given mdim-1 mesh in other is not a constituent of this !");
2230 for(const int *idOther=idsOtherInConsti->begin();idOther!=idsOtherInConsti->end();idOther++)
2231 s1.insert(revDescThisPartPtr+revDescIThisPartPtr[*idOther],revDescThisPartPtr+revDescIThisPartPtr[*idOther+1]);
2232 MCAuto<DataArrayInt> s1arr_renum1=DataArrayInt::New(); s1arr_renum1->alloc((int)s1.size(),1); std::copy(s1.begin(),s1.end(),s1arr_renum1->getPointer());
2233 s1arr_renum1->sort();
2234 cellIdsRk0=s0arr.retn();
2235 //cellIdsRk1=s_renum1.retn();
2236 cellIdsRk1=s1arr_renum1.retn();
2240 * 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
2241 * returned. This subpart of meshdim-1 mesh is built using meshdim-1 cells in it shared only one cell in \b this.
2243 * \return a newly allocated mesh lying on the same coordinates than \b this. The caller has to deal with returned mesh.
2245 MEDCouplingUMesh *MEDCouplingUMesh::computeSkin() const
2247 MCAuto<DataArrayInt> desc=DataArrayInt::New();
2248 MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
2249 MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
2250 MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
2252 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2253 revDesc=0; desc=0; descIndx=0;
2254 MCAuto<DataArrayInt> revDescIndx2=revDescIndx->deltaShiftIndex();
2255 MCAuto<DataArrayInt> part=revDescIndx2->findIdsEqual(1);
2256 return static_cast<MEDCouplingUMesh *>(meshDM1->buildPartOfMySelf(part->begin(),part->end(),true));
2260 * Finds nodes lying on the boundary of \a this mesh.
2261 * \return DataArrayInt * - a new instance of DataArrayInt holding ids of found
2262 * nodes. The caller is to delete this array using decrRef() as it is no
2264 * \throw If the coordinates array is not set.
2265 * \throw If the nodal connectivity of cells is node defined.
2267 * \if ENABLE_EXAMPLES
2268 * \ref cpp_mcumesh_findBoundaryNodes "Here is a C++ example".<br>
2269 * \ref py_mcumesh_findBoundaryNodes "Here is a Python example".
2272 DataArrayInt *MEDCouplingUMesh::findBoundaryNodes() const
2274 MCAuto<MEDCouplingUMesh> skin=computeSkin();
2275 return skin->computeFetchedNodeIds();
2278 MEDCouplingUMesh *MEDCouplingUMesh::buildUnstructured() const
2281 return const_cast<MEDCouplingUMesh *>(this);
2285 * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2286 * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2287 * 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.
2288 * If a node is in the boundary of \b this \b and in the boundary of \b otherDimM1OnSameCoords this node is considered as needed to be duplicated.
2289 * 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.
2291 * \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
2292 * parameter is altered during the call.
2293 * \param [out] nodeIdsToDuplicate node ids needed to be duplicated following the algorithm explain above.
2294 * \param [out] cellIdsNeededToBeRenum cell ids in \b this in which the renumber of nodes should be performed.
2295 * \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.
2297 * \warning This method modifies param \b otherDimM1OnSameCoords (for speed reasons).
2299 void MEDCouplingUMesh::findNodesToDuplicate(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayInt *& nodeIdsToDuplicate,
2300 DataArrayInt *& cellIdsNeededToBeRenum, DataArrayInt *& cellIdsNotModified) const
2302 typedef MCAuto<DataArrayInt> DAInt;
2303 typedef MCAuto<MEDCouplingUMesh> MCUMesh;
2305 checkFullyDefined();
2306 otherDimM1OnSameCoords.checkFullyDefined();
2307 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2308 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : meshes do not share the same coords array !");
2309 if(otherDimM1OnSameCoords.getMeshDimension()!=getMeshDimension()-1)
2310 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the mesh given in other parameter must have this->getMeshDimension()-1 !");
2312 // Checking star-shaped M1 group:
2313 DAInt dt0=DataArrayInt::New(),dit0=DataArrayInt::New(),rdt0=DataArrayInt::New(),rdit0=DataArrayInt::New();
2314 MCUMesh meshM2 = otherDimM1OnSameCoords.buildDescendingConnectivity(dt0, dit0, rdt0, rdit0);
2315 DAInt dsi = rdit0->deltaShiftIndex();
2316 DAInt idsTmp0 = dsi->findIdsNotInRange(-1, 3);
2317 if(idsTmp0->getNumberOfTuples())
2318 throw INTERP_KERNEL::Exception("MEDFileUMesh::buildInnerBoundaryAlongM1Group: group is too complex: some points (or edges) have more than two connected segments (or faces)!");
2319 dt0=0; dit0=0; rdt0=0; rdit0=0; idsTmp0=0;
2321 // Get extreme nodes from the group (they won't be duplicated), ie nodes belonging to boundary cells of M1
2322 DAInt xtremIdsM2 = dsi->findIdsEqual(1); dsi = 0;
2323 MCUMesh meshM2Part = static_cast<MEDCouplingUMesh *>(meshM2->buildPartOfMySelf(xtremIdsM2->begin(), xtremIdsM2->end(),true));
2324 DAInt xtrem = meshM2Part->computeFetchedNodeIds();
2325 // Remove from the list points on the boundary of the M0 mesh (those need duplication!)
2326 dt0=DataArrayInt::New(),dit0=DataArrayInt::New(),rdt0=DataArrayInt::New(),rdit0=DataArrayInt::New();
2327 MCUMesh m0desc = buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); dt0=0; dit0=0; rdt0=0;
2328 dsi = rdit0->deltaShiftIndex();
2329 DAInt boundSegs = dsi->findIdsEqual(1); // boundary segs/faces of the M0 mesh
2330 MCUMesh m0descSkin = static_cast<MEDCouplingUMesh *>(m0desc->buildPartOfMySelf(boundSegs->begin(),boundSegs->end(), true));
2331 DAInt fNodes = m0descSkin->computeFetchedNodeIds();
2332 // In 3D, some points on the boundary of M0 still need duplication:
2334 if (getMeshDimension() == 3)
2336 DAInt dnu1=DataArrayInt::New(), dnu2=DataArrayInt::New(), dnu3=DataArrayInt::New(), dnu4=DataArrayInt::New();
2337 MCUMesh m0descSkinDesc = m0descSkin->buildDescendingConnectivity(dnu1, dnu2, dnu3, dnu4);
2338 dnu1=0;dnu2=0;dnu3=0;dnu4=0;
2339 DataArrayInt * corresp=0;
2340 meshM2->areCellsIncludedIn(m0descSkinDesc,2,corresp);
2341 DAInt validIds = corresp->findIdsInRange(0, meshM2->getNumberOfCells());
2343 if (validIds->getNumberOfTuples())
2345 MCUMesh m1IntersecSkin = static_cast<MEDCouplingUMesh *>(m0descSkinDesc->buildPartOfMySelf(validIds->begin(), validIds->end(), true));
2346 DAInt notDuplSkin = m1IntersecSkin->findBoundaryNodes();
2347 DAInt fNodes1 = fNodes->buildSubstraction(notDuplSkin);
2348 notDup = xtrem->buildSubstraction(fNodes1);
2351 notDup = xtrem->buildSubstraction(fNodes);
2354 notDup = xtrem->buildSubstraction(fNodes);
2356 // Now compute cells around group (i.e. cells where we will do the propagation to identify the two sub-sets delimited by the group)
2357 DAInt m1Nodes = otherDimM1OnSameCoords.computeFetchedNodeIds();
2358 DAInt dupl = m1Nodes->buildSubstraction(notDup);
2359 DAInt cellsAroundGroup = getCellIdsLyingOnNodes(dupl->begin(), dupl->end(), false); // false= take cell in, even if not all nodes are in notDup
2362 MCUMesh m0Part2=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(cellsAroundGroup->begin(),cellsAroundGroup->end(),true));
2363 int nCells2 = m0Part2->getNumberOfCells();
2364 DAInt desc00=DataArrayInt::New(),descI00=DataArrayInt::New(),revDesc00=DataArrayInt::New(),revDescI00=DataArrayInt::New();
2365 MCUMesh m01=m0Part2->buildDescendingConnectivity(desc00,descI00,revDesc00,revDescI00);
2367 // Neighbor information of the mesh without considering the crack (serves to count how many connex pieces it is made of)
2368 DataArrayInt *tmp00=0,*tmp11=0;
2369 MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00, tmp00, tmp11);
2370 DAInt neighInit00(tmp00);
2371 DAInt neighIInit00(tmp11);
2372 // Neighbor information of the mesh WITH the crack (some neighbors are removed):
2373 DataArrayInt *idsTmp=0;
2374 m01->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsTmp);
2376 // In the neighbor information remove the connection between high dimension cells and its low level constituents which are part
2377 // of the frontier given in parameter (i.e. the cells of low dimension from the group delimiting the crack):
2378 MEDCouplingUMesh::RemoveIdsFromIndexedArrays(ids->begin(),ids->end(),desc00,descI00);
2379 DataArrayInt *tmp0=0,*tmp1=0;
2380 // Compute the neighbor of each cell in m0Part2, taking into account the broken link above. Two
2381 // cells on either side of the crack (defined by the mesh of low dimension) are not neighbor anymore.
2382 ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00,tmp0,tmp1);
2383 DAInt neigh00(tmp0);
2384 DAInt neighI00(tmp1);
2386 // For each initial connex part of the sub-mesh (or said differently for each independent crack):
2387 int seed = 0, nIter = 0;
2388 int nIterMax = nCells2+1; // Safety net for the loop
2389 DAInt hitCells = DataArrayInt::New(); hitCells->alloc(nCells2);
2390 hitCells->fillWithValue(-1);
2391 DAInt cellsToModifyConn0_torenum = DataArrayInt::New();
2392 cellsToModifyConn0_torenum->alloc(0,1);
2393 while (nIter < nIterMax)
2395 DAInt t = hitCells->findIdsEqual(-1);
2396 if (!t->getNumberOfTuples())
2398 // Connex zone without the crack (to compute the next seed really)
2400 DAInt connexCheck = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neighInit00,neighIInit00, -1, dnu);
2402 for (int * ptr = connexCheck->getPointer(); cnt < connexCheck->getNumberOfTuples(); ptr++, cnt++)
2403 hitCells->setIJ(*ptr,0,1);
2404 // Connex zone WITH the crack (to identify cells lying on either part of the crack)
2405 DAInt spreadZone = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neigh00,neighI00, -1, dnu);
2406 cellsToModifyConn0_torenum = DataArrayInt::Aggregate(cellsToModifyConn0_torenum, spreadZone, 0);
2407 // Compute next seed, i.e. a cell in another connex part, which was not covered by the previous iterations
2408 DAInt comple = cellsToModifyConn0_torenum->buildComplement(nCells2);
2409 DAInt nonHitCells = hitCells->findIdsEqual(-1);
2410 DAInt intersec = nonHitCells->buildIntersection(comple);
2411 if (intersec->getNumberOfTuples())
2412 { seed = intersec->getIJ(0,0); }
2417 if (nIter >= nIterMax)
2418 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate(): internal error - too many iterations.");
2420 DAInt cellsToModifyConn1_torenum=cellsToModifyConn0_torenum->buildComplement(neighI00->getNumberOfTuples()-1);
2421 cellsToModifyConn0_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2422 cellsToModifyConn1_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2424 cellIdsNeededToBeRenum=cellsToModifyConn0_torenum.retn();
2425 cellIdsNotModified=cellsToModifyConn1_torenum.retn();
2426 nodeIdsToDuplicate=dupl.retn();
2430 * This method operates a modification of the connectivity and coords in \b this.
2431 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2432 * its ids will be modified to id this->getNumberOfNodes()+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2433 * More explicitly the renumber array in nodes is not explicitly given in old2new to avoid to build a big array of renumbering whereas typically few node ids needs to be
2434 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id this->getNumberOfNodes()+0, node id nodeIdsToDuplicateBg[1] will have id this->getNumberOfNodes()+1,
2435 * node id nodeIdsToDuplicateBg[2] will have id this->getNumberOfNodes()+2...
2437 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2439 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2440 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2442 void MEDCouplingUMesh::duplicateNodes(const int *nodeIdsToDuplicateBg, const int *nodeIdsToDuplicateEnd)
2444 int nbOfNodes=getNumberOfNodes();
2445 duplicateNodesInCoords(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd);
2446 duplicateNodesInConn(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,nbOfNodes);
2450 * This method renumbers only nodal connectivity in \a this. The renumbering is only an offset applied. So this method is a specialization of
2451 * \a renumberNodesInConn. \b WARNING, this method does not check that the resulting node ids in the nodal connectivity is in a valid range !
2453 * \param [in] offset - specifies the offset to be applied on each element of connectivity.
2455 * \sa renumberNodesInConn
2457 void MEDCouplingUMesh::renumberNodesWithOffsetInConn(int offset)
2459 checkConnectivityFullyDefined();
2460 int *conn(getNodalConnectivity()->getPointer());
2461 const int *connIndex(getNodalConnectivityIndex()->getConstPointer());
2462 int nbOfCells(getNumberOfCells());
2463 for(int i=0;i<nbOfCells;i++)
2464 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2466 int& node=conn[iconn];
2467 if(node>=0)//avoid polyhedron separator
2472 _nodal_connec->declareAsNew();
2477 * Same than renumberNodesInConn(const int *) except that here the format of old-to-new traducer is using map instead
2478 * 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
2481 void MEDCouplingUMesh::renumberNodesInConn(const INTERP_KERNEL::HashMap<int,int>& newNodeNumbersO2N)
2483 this->renumberNodesInConnT< INTERP_KERNEL::HashMap<int,int> >(newNodeNumbersO2N);
2487 * Same than renumberNodesInConn(const int *) except that here the format of old-to-new traducer is using map instead
2488 * 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
2491 void MEDCouplingUMesh::renumberNodesInConn(const std::map<int,int>& newNodeNumbersO2N)
2493 this->renumberNodesInConnT< std::map<int,int> >(newNodeNumbersO2N);
2497 * Changes ids of nodes within the nodal connectivity arrays according to a permutation
2498 * array in "Old to New" mode. The node coordinates array is \b not changed by this method.
2499 * This method is a generalization of shiftNodeNumbersInConn().
2500 * \warning This method performs no check of validity of new ids. **Use it with care !**
2501 * \param [in] newNodeNumbersO2N - a permutation array, of length \a
2502 * this->getNumberOfNodes(), in "Old to New" mode.
2503 * See \ref numbering for more info on renumbering modes.
2504 * \throw If the nodal connectivity of cells is not defined.
2506 * \if ENABLE_EXAMPLES
2507 * \ref cpp_mcumesh_renumberNodesInConn "Here is a C++ example".<br>
2508 * \ref py_mcumesh_renumberNodesInConn "Here is a Python example".
2511 void MEDCouplingUMesh::renumberNodesInConn(const int *newNodeNumbersO2N)
2513 checkConnectivityFullyDefined();
2514 int *conn=getNodalConnectivity()->getPointer();
2515 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2516 int nbOfCells(getNumberOfCells());
2517 for(int i=0;i<nbOfCells;i++)
2518 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2520 int& node=conn[iconn];
2521 if(node>=0)//avoid polyhedron separator
2523 node=newNodeNumbersO2N[node];
2526 _nodal_connec->declareAsNew();
2531 * This method renumbers nodes \b in \b connectivity \b only \b without \b any \b reference \b to \b coords.
2532 * This method performs no check on the fact that new coordinate ids are valid. \b Use \b it \b with \b care !
2533 * This method is an specialization of \ref MEDCoupling::MEDCouplingUMesh::renumberNodesInConn "renumberNodesInConn method".
2535 * \param [in] delta specifies the shift size applied to nodeId in nodal connectivity in \b this.
2537 void MEDCouplingUMesh::shiftNodeNumbersInConn(int delta)
2539 checkConnectivityFullyDefined();
2540 int *conn=getNodalConnectivity()->getPointer();
2541 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2542 int nbOfCells=getNumberOfCells();
2543 for(int i=0;i<nbOfCells;i++)
2544 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2546 int& node=conn[iconn];
2547 if(node>=0)//avoid polyhedron separator
2552 _nodal_connec->declareAsNew();
2557 * This method operates a modification of the connectivity in \b this.
2558 * 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.
2559 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2560 * its ids will be modified to id offset+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2561 * More explicitly the renumber array in nodes is not explicitly given in old2new to avoid to build a big array of renumbering whereas typically few node ids needs to be
2562 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id offset+0, node id nodeIdsToDuplicateBg[1] will have id offset+1,
2563 * node id nodeIdsToDuplicateBg[2] will have id offset+2...
2565 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2566 * As an another consequense after the call of this method \b this can be transiently non cohrent.
2568 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2569 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2570 * \param [in] offset the offset applied to all node ids in connectivity that are in [ \a nodeIdsToDuplicateBg, \a nodeIdsToDuplicateEnd ).
2572 void MEDCouplingUMesh::duplicateNodesInConn(const int *nodeIdsToDuplicateBg, const int *nodeIdsToDuplicateEnd, int offset)
2574 checkConnectivityFullyDefined();
2575 std::map<int,int> m;
2577 for(const int *work=nodeIdsToDuplicateBg;work!=nodeIdsToDuplicateEnd;work++,val++)
2579 int *conn=getNodalConnectivity()->getPointer();
2580 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2581 int nbOfCells=getNumberOfCells();
2582 for(int i=0;i<nbOfCells;i++)
2583 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2585 int& node=conn[iconn];
2586 if(node>=0)//avoid polyhedron separator
2588 std::map<int,int>::iterator it=m.find(node);
2597 * This method renumbers cells of \a this using the array specified by [old2NewBg;old2NewBg+getNumberOfCells())
2599 * Contrary to MEDCouplingPointSet::renumberNodes, this method makes a permutation without any fuse of cell.
2600 * After the call of this method the number of cells remains the same as before.
2602 * If 'check' equals true the method will check that any elements in [ \a old2NewBg; \a old2NewEnd ) is unique ; if not
2603 * an INTERP_KERNEL::Exception will be thrown. When 'check' equals true [ \a old2NewBg ; \a old2NewEnd ) is not expected to
2604 * be strictly in [0;this->getNumberOfCells()).
2606 * If 'check' equals false the method will not check the content of [ \a old2NewBg ; \a old2NewEnd ).
2607 * To avoid any throw of SIGSEGV when 'check' equals false, the elements in [ \a old2NewBg ; \a old2NewEnd ) should be unique and
2608 * should be contained in[0;this->getNumberOfCells()).
2610 * \param [in] old2NewBg is expected to be a dynamically allocated pointer of size at least equal to this->getNumberOfCells()
2613 void MEDCouplingUMesh::renumberCells(const int *old2NewBg, bool check)
2615 checkConnectivityFullyDefined();
2616 int nbCells=getNumberOfCells();
2617 const int *array=old2NewBg;
2619 array=DataArrayInt::CheckAndPreparePermutation(old2NewBg,old2NewBg+nbCells);
2621 const int *conn=_nodal_connec->getConstPointer();
2622 const int *connI=_nodal_connec_index->getConstPointer();
2623 MCAuto<DataArrayInt> o2n=DataArrayInt::New(); o2n->useArray(array,false,DeallocType::C_DEALLOC,nbCells,1);
2624 MCAuto<DataArrayInt> n2o=o2n->invertArrayO2N2N2O(nbCells);
2625 const int *n2oPtr=n2o->begin();
2626 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
2627 newConn->alloc(_nodal_connec->getNumberOfTuples(),_nodal_connec->getNumberOfComponents());
2628 newConn->copyStringInfoFrom(*_nodal_connec);
2629 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
2630 newConnI->alloc(_nodal_connec_index->getNumberOfTuples(),_nodal_connec_index->getNumberOfComponents());
2631 newConnI->copyStringInfoFrom(*_nodal_connec_index);
2633 int *newC=newConn->getPointer();
2634 int *newCI=newConnI->getPointer();
2637 for(int i=0;i<nbCells;i++)
2640 int nbOfElts=connI[pos+1]-connI[pos];
2641 newC=std::copy(conn+connI[pos],conn+connI[pos+1],newC);
2646 setConnectivity(newConn,newConnI);
2648 free(const_cast<int *>(array));
2652 * Finds cells whose bounding boxes intersect a given bounding box.
2653 * \param [in] bbox - an array defining the bounding box via coordinates of its
2654 * extremum points in "no interlace" mode, i.e. xMin, xMax, yMin, yMax, zMin,
2656 * \param [in] eps - a factor used to increase size of the bounding box of cell
2657 * before comparing it with \a bbox. This factor is multiplied by the maximal
2658 * extent of the bounding box of cell to produce an addition to this bounding box.
2659 * \return DataArrayInt * - a new instance of DataArrayInt holding ids for found
2660 * cells. The caller is to delete this array using decrRef() as it is no more
2662 * \throw If the coordinates array is not set.
2663 * \throw If the nodal connectivity of cells is not defined.
2665 * \if ENABLE_EXAMPLES
2666 * \ref cpp_mcumesh_getCellsInBoundingBox "Here is a C++ example".<br>
2667 * \ref py_mcumesh_getCellsInBoundingBox "Here is a Python example".
2670 DataArrayInt *MEDCouplingUMesh::getCellsInBoundingBox(const double *bbox, double eps) const
2672 MCAuto<DataArrayInt> elems=DataArrayInt::New(); elems->alloc(0,1);
2673 if(getMeshDimension()==-1)
2675 elems->pushBackSilent(0);
2676 return elems.retn();
2678 int dim=getSpaceDimension();
2679 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2680 const int* conn = getNodalConnectivity()->getConstPointer();
2681 const int* conn_index= getNodalConnectivityIndex()->getConstPointer();
2682 const double* coords = getCoords()->getConstPointer();
2683 int nbOfCells=getNumberOfCells();
2684 for ( int ielem=0; ielem<nbOfCells;ielem++ )
2686 for (int i=0; i<dim; i++)
2688 elem_bb[i*2]=std::numeric_limits<double>::max();
2689 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2692 for (int inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2694 int node= conn[inode];
2695 if(node>=0)//avoid polyhedron separator
2697 for (int idim=0; idim<dim; idim++)
2699 if ( coords[node*dim+idim] < elem_bb[idim*2] )
2701 elem_bb[idim*2] = coords[node*dim+idim] ;
2703 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2705 elem_bb[idim*2+1] = coords[node*dim+idim] ;
2710 if (intersectsBoundingBox(elem_bb, bbox, dim, eps))
2711 elems->pushBackSilent(ielem);
2713 return elems.retn();
2717 * Given a boundary box 'bbox' returns elements 'elems' contained in this 'bbox' or touching 'bbox' (within 'eps' distance).
2718 * Warning 'elems' is incremented during the call so if elems is not empty before call returned elements will be
2719 * added in 'elems' parameter.
2721 DataArrayInt *MEDCouplingUMesh::getCellsInBoundingBox(const INTERP_KERNEL::DirectedBoundingBox& bbox, double eps)
2723 MCAuto<DataArrayInt> elems=DataArrayInt::New(); elems->alloc(0,1);
2724 if(getMeshDimension()==-1)
2726 elems->pushBackSilent(0);
2727 return elems.retn();
2729 int dim=getSpaceDimension();
2730 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2731 const int* conn = getNodalConnectivity()->getConstPointer();
2732 const int* conn_index= getNodalConnectivityIndex()->getConstPointer();
2733 const double* coords = getCoords()->getConstPointer();
2734 int nbOfCells=getNumberOfCells();
2735 for ( int ielem=0; ielem<nbOfCells;ielem++ )
2737 for (int i=0; i<dim; i++)
2739 elem_bb[i*2]=std::numeric_limits<double>::max();
2740 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2743 for (int inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2745 int node= conn[inode];
2746 if(node>=0)//avoid polyhedron separator
2748 for (int idim=0; idim<dim; idim++)
2750 if ( coords[node*dim+idim] < elem_bb[idim*2] )
2752 elem_bb[idim*2] = coords[node*dim+idim] ;
2754 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2756 elem_bb[idim*2+1] = coords[node*dim+idim] ;
2761 if(intersectsBoundingBox(bbox, elem_bb, dim, eps))
2762 elems->pushBackSilent(ielem);
2764 return elems.retn();
2768 * Returns a type of a cell by its id.
2769 * \param [in] cellId - the id of the cell of interest.
2770 * \return INTERP_KERNEL::NormalizedCellType - enumeration item describing the cell type.
2771 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2773 INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::getTypeOfCell(std::size_t cellId) const
2775 const int *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
2776 if(cellId<_nodal_connec_index->getNbOfElems()-1)
2777 return (INTERP_KERNEL::NormalizedCellType) pt[ptI[cellId]];
2780 std::ostringstream oss; oss << "MEDCouplingUMesh::getTypeOfCell : Requesting type of cell #" << cellId << " but it should be in [0," << _nodal_connec_index->getNbOfElems()-1 << ") !";
2781 throw INTERP_KERNEL::Exception(oss.str());
2786 * This method returns a newly allocated array containing cell ids (ascendingly sorted) whose geometric type are equal to type.
2787 * This method does not throw exception if geometric type \a type is not in \a this.
2788 * This method throws an INTERP_KERNEL::Exception if meshdimension of \b this is not equal to those of \b type.
2789 * The coordinates array is not considered here.
2791 * \param [in] type the geometric type
2792 * \return cell ids in this having geometric type \a type.
2794 DataArrayInt *MEDCouplingUMesh::giveCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2797 MCAuto<DataArrayInt> ret=DataArrayInt::New();
2799 checkConnectivityFullyDefined();
2800 int nbCells=getNumberOfCells();
2801 int mdim=getMeshDimension();
2802 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
2803 if(mdim!=(int)cm.getDimension())
2804 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::giveCellsWithType : Mismatch between mesh dimension and dimension of the cell !");
2805 const int *ptI=_nodal_connec_index->getConstPointer();
2806 const int *pt=_nodal_connec->getConstPointer();
2807 for(int i=0;i<nbCells;i++)
2809 if((INTERP_KERNEL::NormalizedCellType)pt[ptI[i]]==type)
2810 ret->pushBackSilent(i);
2816 * Returns nb of cells having the geometric type \a type. No throw if no cells in \a this has the geometric type \a type.
2818 std::size_t MEDCouplingUMesh::getNumberOfCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2820 const int *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
2821 std::size_t nbOfCells(getNumberOfCells()),ret(0);
2822 for(std::size_t i=0;i<nbOfCells;i++)
2823 if((INTERP_KERNEL::NormalizedCellType) pt[ptI[i]]==type)
2829 * Returns the nodal connectivity of a given cell.
2830 * The separator of faces within polyhedron connectivity (-1) is not returned, thus
2831 * all returned node ids can be used in getCoordinatesOfNode().
2832 * \param [in] cellId - an id of the cell of interest.
2833 * \param [in,out] conn - a vector where the node ids are appended. It is not
2834 * cleared before the appending.
2835 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2837 void MEDCouplingUMesh::getNodeIdsOfCell(std::size_t cellId, std::vector<int>& conn) const
2839 const int *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
2840 for(const int *w=pt+ptI[cellId]+1;w!=pt+ptI[cellId+1];w++)
2845 std::string MEDCouplingUMesh::simpleRepr() const
2847 static const char msg0[]="No coordinates specified !";
2848 std::ostringstream ret;
2849 ret << "Unstructured mesh with name : \"" << getName() << "\"\n";
2850 ret << "Description of mesh : \"" << getDescription() << "\"\n";
2852 double tt=getTime(tmpp1,tmpp2);
2853 ret << "Time attached to the mesh [unit] : " << tt << " [" << getTimeUnit() << "]\n";
2854 ret << "Iteration : " << tmpp1 << " Order : " << tmpp2 << "\n";
2856 { ret << "Mesh dimension : " << _mesh_dim << "\nSpace dimension : "; }
2858 { ret << " Mesh dimension has not been set or is invalid !"; }
2861 const int spaceDim=getSpaceDimension();
2862 ret << spaceDim << "\nInfo attached on space dimension : ";
2863 for(int i=0;i<spaceDim;i++)
2864 ret << "\"" << _coords->getInfoOnComponent(i) << "\" ";
2868 ret << msg0 << "\n";
2869 ret << "Number of nodes : ";
2871 ret << getNumberOfNodes() << "\n";
2873 ret << msg0 << "\n";
2874 ret << "Number of cells : ";
2875 if(_nodal_connec!=0 && _nodal_connec_index!=0)
2876 ret << getNumberOfCells() << "\n";
2878 ret << "No connectivity specified !" << "\n";
2879 ret << "Cell types present : ";
2880 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
2882 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter);
2883 ret << cm.getRepr() << " ";
2889 std::string MEDCouplingUMesh::advancedRepr() const
2891 std::ostringstream ret;
2892 ret << simpleRepr();
2893 ret << "\nCoordinates array : \n___________________\n\n";
2895 _coords->reprWithoutNameStream(ret);
2897 ret << "No array set !\n";
2898 ret << "\n\nConnectivity arrays : \n_____________________\n\n";
2899 reprConnectivityOfThisLL(ret);
2904 * This method returns a C++ code that is a dump of \a this.
2905 * This method will throw if this is not fully defined.
2907 std::string MEDCouplingUMesh::cppRepr() const
2909 static const char coordsName[]="coords";
2910 static const char connName[]="conn";
2911 static const char connIName[]="connI";
2912 checkFullyDefined();
2913 std::ostringstream ret; ret << "// coordinates" << std::endl;
2914 _coords->reprCppStream(coordsName,ret); ret << std::endl << "// connectivity" << std::endl;
2915 _nodal_connec->reprCppStream(connName,ret); ret << std::endl;
2916 _nodal_connec_index->reprCppStream(connIName,ret); ret << std::endl;
2917 ret << "MEDCouplingUMesh *mesh=MEDCouplingUMesh::New(\"" << getName() << "\"," << getMeshDimension() << ");" << std::endl;
2918 ret << "mesh->setCoords(" << coordsName << ");" << std::endl;
2919 ret << "mesh->setConnectivity(" << connName << "," << connIName << ",true);" << std::endl;
2920 ret << coordsName << "->decrRef(); " << connName << "->decrRef(); " << connIName << "->decrRef();" << std::endl;
2924 std::string MEDCouplingUMesh::reprConnectivityOfThis() const
2926 std::ostringstream ret;
2927 reprConnectivityOfThisLL(ret);
2932 * This method builds a newly allocated instance (with the same name than \a this) that the caller has the responsibility to deal with.
2933 * This method returns an instance with all arrays allocated (connectivity, connectivity index, coordinates)
2934 * but with length of these arrays set to 0. It allows to define an "empty" mesh (with nor cells nor nodes but compliant with
2937 * This method expects that \a this has a mesh dimension set and higher or equal to 0. If not an exception will be thrown.
2938 * 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
2939 * with number of tuples set to 0, if not the array is taken as this in the returned instance.
2941 MEDCouplingUMesh *MEDCouplingUMesh::buildSetInstanceFromThis(int spaceDim) const
2943 int mdim=getMeshDimension();
2945 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSetInstanceFromThis : invalid mesh dimension ! Should be >= 0 !");
2946 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
2947 MCAuto<DataArrayInt> tmp1,tmp2;
2948 bool needToCpyCT=true;
2951 tmp1=DataArrayInt::New(); tmp1->alloc(0,1);
2959 if(!_nodal_connec_index)
2961 tmp2=DataArrayInt::New(); tmp2->alloc(1,1); tmp2->setIJ(0,0,0);
2966 tmp2=_nodal_connec_index;
2969 ret->setConnectivity(tmp1,tmp2,false);
2974 MCAuto<DataArrayDouble> coords=DataArrayDouble::New(); coords->alloc(0,spaceDim);
2975 ret->setCoords(coords);
2978 ret->setCoords(_coords);
2982 int MEDCouplingUMesh::getNumberOfNodesInCell(int cellId) const
2984 const int *ptI=_nodal_connec_index->getConstPointer();
2985 const int *pt=_nodal_connec->getConstPointer();
2986 if(pt[ptI[cellId]]!=INTERP_KERNEL::NORM_POLYHED)
2987 return ptI[cellId+1]-ptI[cellId]-1;
2989 return (int)std::count_if(pt+ptI[cellId]+1,pt+ptI[cellId+1],std::bind2nd(std::not_equal_to<int>(),-1));
2993 * Returns types of cells of the specified part of \a this mesh.
2994 * This method avoids computing sub-mesh explicitly to get its types.
2995 * \param [in] begin - an array of cell ids of interest.
2996 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
2997 * \return std::set<INTERP_KERNEL::NormalizedCellType> - a set of enumeration items
2998 * describing the cell types.
2999 * \throw If the coordinates array is not set.
3000 * \throw If the nodal connectivity of cells is not defined.
3001 * \sa getAllGeoTypes()
3003 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getTypesOfPart(const int *begin, const int *end) const
3005 checkFullyDefined();
3006 std::set<INTERP_KERNEL::NormalizedCellType> ret;
3007 const int *conn=_nodal_connec->getConstPointer();
3008 const int *connIndex=_nodal_connec_index->getConstPointer();
3009 for(const int *w=begin;w!=end;w++)
3010 ret.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]);
3015 * Defines the nodal connectivity using given connectivity arrays in \ref numbering-indirect format.
3016 * Optionally updates
3017 * a set of types of cells constituting \a this mesh.
3018 * This method is for advanced users having prepared their connectivity before. For
3019 * more info on using this method see \ref MEDCouplingUMeshAdvBuild.
3020 * \param [in] conn - the nodal connectivity array.
3021 * \param [in] connIndex - the nodal connectivity index array.
3022 * \param [in] isComputingTypes - if \c true, the set of types constituting \a this
3025 void MEDCouplingUMesh::setConnectivity(DataArrayInt *conn, DataArrayInt *connIndex, bool isComputingTypes)
3027 DataArrayInt::SetArrayIn(conn,_nodal_connec);
3028 DataArrayInt::SetArrayIn(connIndex,_nodal_connec_index);
3029 if(isComputingTypes)
3035 * Copy constructor. If 'deepCopy' is false \a this is a shallow copy of other.
3036 * If 'deeCpy' is true all arrays (coordinates and connectivities) are deeply copied.
3038 MEDCouplingUMesh::MEDCouplingUMesh(const MEDCouplingUMesh& other, bool deepCpy):MEDCouplingPointSet(other,deepCpy),_mesh_dim(other._mesh_dim),
3039 _nodal_connec(0),_nodal_connec_index(0),
3040 _types(other._types)
3042 if(other._nodal_connec)
3043 _nodal_connec=other._nodal_connec->performCopyOrIncrRef(deepCpy);
3044 if(other._nodal_connec_index)
3045 _nodal_connec_index=other._nodal_connec_index->performCopyOrIncrRef(deepCpy);
3048 MEDCouplingUMesh::~MEDCouplingUMesh()
3051 _nodal_connec->decrRef();
3052 if(_nodal_connec_index)
3053 _nodal_connec_index->decrRef();
3057 * Recomputes a set of cell types of \a this mesh. For more info see
3058 * \ref MEDCouplingUMeshNodalConnectivity.
3060 void MEDCouplingUMesh::computeTypes()
3062 ComputeAllTypesInternal(_types,_nodal_connec,_nodal_connec_index);
3067 * Returns a number of cells constituting \a this mesh.
3068 * \return int - the number of cells in \a this mesh.
3069 * \throw If the nodal connectivity of cells is not defined.
3071 std::size_t MEDCouplingUMesh::getNumberOfCells() const
3073 if(_nodal_connec_index)
3074 return _nodal_connec_index->getNumberOfTuples()-1;
3079 throw INTERP_KERNEL::Exception("Unable to get number of cells because no connectivity specified !");
3083 * Returns a dimension of \a this mesh, i.e. a dimension of cells constituting \a this
3084 * mesh. For more info see \ref meshes.
3085 * \return int - the dimension of \a this mesh.
3086 * \throw If the mesh dimension is not defined using setMeshDimension().
3088 int MEDCouplingUMesh::getMeshDimension() const
3091 throw INTERP_KERNEL::Exception("No mesh dimension specified !");
3096 * Returns a length of the nodal connectivity array.
3097 * This method is for test reason. Normally the integer returned is not useable by
3098 * user. For more info see \ref MEDCouplingUMeshNodalConnectivity.
3099 * \return int - the length of the nodal connectivity array.
3101 int MEDCouplingUMesh::getNodalConnectivityArrayLen() const
3103 return _nodal_connec->getNbOfElems();
3107 * First step of serialization process. Used by ParaMEDMEM and MEDCouplingCorba to transfert data between process.
3109 void MEDCouplingUMesh::getTinySerializationInformation(std::vector<double>& tinyInfoD, std::vector<int>& tinyInfo, std::vector<std::string>& littleStrings) const
3111 MEDCouplingPointSet::getTinySerializationInformation(tinyInfoD,tinyInfo,littleStrings);
3112 tinyInfo.push_back(getMeshDimension());
3113 tinyInfo.push_back(getNumberOfCells());
3115 tinyInfo.push_back(getNodalConnectivityArrayLen());
3117 tinyInfo.push_back(-1);
3121 * First step of unserialization process.
3123 bool MEDCouplingUMesh::isEmptyMesh(const std::vector<int>& tinyInfo) const
3125 return tinyInfo[6]<=0;
3129 * Second step of serialization process.
3130 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3133 * \param littleStrings
3135 void MEDCouplingUMesh::resizeForUnserialization(const std::vector<int>& tinyInfo, DataArrayInt *a1, DataArrayDouble *a2, std::vector<std::string>& littleStrings) const
3137 MEDCouplingPointSet::resizeForUnserialization(tinyInfo,a1,a2,littleStrings);
3139 a1->alloc(tinyInfo[7]+tinyInfo[6]+1,1);
3143 * Third and final step of serialization process.
3145 void MEDCouplingUMesh::serialize(DataArrayInt *&a1, DataArrayDouble *&a2) const
3147 MEDCouplingPointSet::serialize(a1,a2);
3148 if(getMeshDimension()>-1)
3150 a1=DataArrayInt::New();
3151 a1->alloc(getNodalConnectivityArrayLen()+getNumberOfCells()+1,1);
3152 int *ptA1=a1->getPointer();
3153 const int *conn=getNodalConnectivity()->getConstPointer();
3154 const int *index=getNodalConnectivityIndex()->getConstPointer();
3155 ptA1=std::copy(index,index+getNumberOfCells()+1,ptA1);
3156 std::copy(conn,conn+getNodalConnectivityArrayLen(),ptA1);
3163 * Second and final unserialization process.
3164 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3166 void MEDCouplingUMesh::unserialization(const std::vector<double>& tinyInfoD, const std::vector<int>& tinyInfo, const DataArrayInt *a1, DataArrayDouble *a2, const std::vector<std::string>& littleStrings)
3168 MEDCouplingPointSet::unserialization(tinyInfoD,tinyInfo,a1,a2,littleStrings);
3169 setMeshDimension(tinyInfo[5]);
3173 const int *recvBuffer=a1->getConstPointer();
3174 MCAuto<DataArrayInt> myConnecIndex=DataArrayInt::New();
3175 myConnecIndex->alloc(tinyInfo[6]+1,1);
3176 std::copy(recvBuffer,recvBuffer+tinyInfo[6]+1,myConnecIndex->getPointer());
3177 MCAuto<DataArrayInt> myConnec=DataArrayInt::New();
3178 myConnec->alloc(tinyInfo[7],1);
3179 std::copy(recvBuffer+tinyInfo[6]+1,recvBuffer+tinyInfo[6]+1+tinyInfo[7],myConnec->getPointer());
3180 setConnectivity(myConnec, myConnecIndex);
3187 * Returns a new MEDCouplingFieldDouble containing volumes of cells constituting \a this
3189 * For 1D cells, the returned field contains lengths.<br>
3190 * For 2D cells, the returned field contains areas.<br>
3191 * For 3D cells, the returned field contains volumes.
3192 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3193 * orientation, i.e. the volume is always positive.
3194 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on cells
3195 * and one time . The caller is to delete this field using decrRef() as it is no
3198 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureField(bool isAbs) const
3200 std::string name="MeasureOfMesh_";
3202 int nbelem=getNumberOfCells();
3203 MCAuto<MEDCouplingFieldDouble> field=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3204 field->setName(name);
3205 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3206 array->alloc(nbelem,1);
3207 double *area_vol=array->getPointer();
3208 field->setArray(array) ; array=0;
3209 field->setMesh(const_cast<MEDCouplingUMesh *>(this));
3210 field->synchronizeTimeWithMesh();
3211 if(getMeshDimension()!=-1)
3214 INTERP_KERNEL::NormalizedCellType type;
3215 int dim_space=getSpaceDimension();
3216 const double *coords=getCoords()->getConstPointer();
3217 const int *connec=getNodalConnectivity()->getConstPointer();
3218 const int *connec_index=getNodalConnectivityIndex()->getConstPointer();
3219 for(int iel=0;iel<nbelem;iel++)
3221 ipt=connec_index[iel];
3222 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3223 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);
3226 std::transform(area_vol,area_vol+nbelem,area_vol,std::ptr_fun<double,double>(fabs));
3230 area_vol[0]=std::numeric_limits<double>::max();
3232 return field.retn();
3236 * Returns a new DataArrayDouble containing volumes of specified cells of \a this
3238 * For 1D cells, the returned array contains lengths.<br>
3239 * For 2D cells, the returned array contains areas.<br>
3240 * For 3D cells, the returned array contains volumes.
3241 * This method avoids building explicitly a part of \a this mesh to perform the work.
3242 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3243 * orientation, i.e. the volume is always positive.
3244 * \param [in] begin - an array of cell ids of interest.
3245 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3246 * \return DataArrayDouble * - a new instance of DataArrayDouble. The caller is to
3247 * delete this array using decrRef() as it is no more needed.
3249 * \if ENABLE_EXAMPLES
3250 * \ref cpp_mcumesh_getPartMeasureField "Here is a C++ example".<br>
3251 * \ref py_mcumesh_getPartMeasureField "Here is a Python example".
3253 * \sa getMeasureField()
3255 DataArrayDouble *MEDCouplingUMesh::getPartMeasureField(bool isAbs, const int *begin, const int *end) const
3257 std::string name="PartMeasureOfMesh_";
3259 int nbelem=(int)std::distance(begin,end);
3260 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3261 array->setName(name);
3262 array->alloc(nbelem,1);
3263 double *area_vol=array->getPointer();
3264 if(getMeshDimension()!=-1)
3267 INTERP_KERNEL::NormalizedCellType type;
3268 int dim_space=getSpaceDimension();
3269 const double *coords=getCoords()->getConstPointer();
3270 const int *connec=getNodalConnectivity()->getConstPointer();
3271 const int *connec_index=getNodalConnectivityIndex()->getConstPointer();
3272 for(const int *iel=begin;iel!=end;iel++)
3274 ipt=connec_index[*iel];
3275 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3276 *area_vol++=INTERP_KERNEL::computeVolSurfOfCell2<int,INTERP_KERNEL::ALL_C_MODE>(type,connec+ipt+1,connec_index[*iel+1]-ipt-1,coords,dim_space);
3279 std::transform(array->getPointer(),area_vol,array->getPointer(),std::ptr_fun<double,double>(fabs));
3283 area_vol[0]=std::numeric_limits<double>::max();
3285 return array.retn();
3289 * Returns a new MEDCouplingFieldDouble containing volumes of cells of a dual mesh of
3290 * \a this one. The returned field contains the dual cell volume for each corresponding
3291 * node in \a this mesh. In other words, the field returns the getMeasureField() of
3292 * the dual mesh in P1 sens of \a this.<br>
3293 * For 1D cells, the returned field contains lengths.<br>
3294 * For 2D cells, the returned field contains areas.<br>
3295 * For 3D cells, the returned field contains volumes.
3296 * This method is useful to check "P1*" conservative interpolators.
3297 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3298 * orientation, i.e. the volume is always positive.
3299 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3300 * nodes and one time. The caller is to delete this array using decrRef() as
3301 * it is no more needed.
3303 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureFieldOnNode(bool isAbs) const
3305 MCAuto<MEDCouplingFieldDouble> tmp=getMeasureField(isAbs);
3306 std::string name="MeasureOnNodeOfMesh_";
3308 int nbNodes=getNumberOfNodes();
3309 MCAuto<DataArrayDouble> nnpc;
3311 MCAuto<DataArrayInt> tmp(computeNbOfNodesPerCell());
3312 nnpc=tmp->convertToDblArr();
3314 std::for_each(nnpc->rwBegin(),nnpc->rwEnd(),[](double& v) { v=1./v; });
3315 const double *nnpcPtr(nnpc->begin());
3316 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_NODES);
3317 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3318 array->alloc(nbNodes,1);
3319 double *valsToFill=array->getPointer();
3320 std::fill(valsToFill,valsToFill+nbNodes,0.);
3321 const double *values=tmp->getArray()->getConstPointer();
3322 MCAuto<DataArrayInt> da=DataArrayInt::New();
3323 MCAuto<DataArrayInt> daInd=DataArrayInt::New();
3324 getReverseNodalConnectivity(da,daInd);
3325 const int *daPtr=da->getConstPointer();
3326 const int *daIPtr=daInd->getConstPointer();
3327 for(int i=0;i<nbNodes;i++)
3328 for(const int *cell=daPtr+daIPtr[i];cell!=daPtr+daIPtr[i+1];cell++)
3329 valsToFill[i]+=nnpcPtr[*cell]*values[*cell];
3331 ret->setArray(array);
3336 * Returns a new MEDCouplingFieldDouble holding normal vectors to cells of \a this
3337 * mesh. The returned normal vectors to each cell have a norm2 equal to 1.
3338 * The computed vectors have <em> this->getMeshDimension()+1 </em> components
3339 * and are normalized.
3340 * <br> \a this can be either
3341 * - a 2D mesh in 2D or 3D space or
3342 * - an 1D mesh in 2D space.
3344 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3345 * cells and one time. The caller is to delete this field using decrRef() as
3346 * it is no more needed.
3347 * \throw If the nodal connectivity of cells is not defined.
3348 * \throw If the coordinates array is not set.
3349 * \throw If the mesh dimension is not set.
3350 * \throw If the mesh and space dimension is not as specified above.
3352 MEDCouplingFieldDouble *MEDCouplingUMesh::buildOrthogonalField() const
3354 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3355 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3356 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3357 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3358 int nbOfCells=getNumberOfCells();
3359 int nbComp=getMeshDimension()+1;
3360 array->alloc(nbOfCells,nbComp);
3361 double *vals=array->getPointer();
3362 const int *connI=_nodal_connec_index->getConstPointer();
3363 const int *conn=_nodal_connec->getConstPointer();
3364 const double *coords=_coords->getConstPointer();
3365 if(getMeshDimension()==2)
3367 if(getSpaceDimension()==3)
3369 MCAuto<DataArrayDouble> loc=computeCellCenterOfMass();
3370 const double *locPtr=loc->getConstPointer();
3371 for(int i=0;i<nbOfCells;i++,vals+=3)
3373 int offset=connI[i];
3374 INTERP_KERNEL::crossprod<3>(locPtr+3*i,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3375 double n=INTERP_KERNEL::norm<3>(vals);
3376 std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3381 MCAuto<MEDCouplingFieldDouble> isAbs=getMeasureField(false);
3382 const double *isAbsPtr=isAbs->getArray()->begin();
3383 for(int i=0;i<nbOfCells;i++,isAbsPtr++)
3384 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=*isAbsPtr>0.?1.:-1.; }
3387 else//meshdimension==1
3390 for(int i=0;i<nbOfCells;i++)
3392 int offset=connI[i];
3393 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3394 double n=INTERP_KERNEL::norm<2>(tmp);
3395 std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3400 ret->setArray(array);
3402 ret->synchronizeTimeWithSupport();
3407 * Returns a new MEDCouplingFieldDouble holding normal vectors to specified cells of
3408 * \a this mesh. The computed vectors have <em> this->getMeshDimension()+1 </em> components
3409 * and are normalized.
3410 * <br> \a this can be either
3411 * - a 2D mesh in 2D or 3D space or
3412 * - an 1D mesh in 2D space.
3414 * This method avoids building explicitly a part of \a this mesh to perform the work.
3415 * \param [in] begin - an array of cell ids of interest.
3416 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3417 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3418 * cells and one time. The caller is to delete this field using decrRef() as
3419 * it is no more needed.
3420 * \throw If the nodal connectivity of cells is not defined.
3421 * \throw If the coordinates array is not set.
3422 * \throw If the mesh dimension is not set.
3423 * \throw If the mesh and space dimension is not as specified above.
3424 * \sa buildOrthogonalField()
3426 * \if ENABLE_EXAMPLES
3427 * \ref cpp_mcumesh_buildPartOrthogonalField "Here is a C++ example".<br>
3428 * \ref py_mcumesh_buildPartOrthogonalField "Here is a Python example".
3431 MEDCouplingFieldDouble *MEDCouplingUMesh::buildPartOrthogonalField(const int *begin, const int *end) const
3433 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3434 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3435 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3436 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3437 std::size_t nbelems=std::distance(begin,end);
3438 int nbComp=getMeshDimension()+1;
3439 array->alloc((int)nbelems,nbComp);
3440 double *vals=array->getPointer();
3441 const int *connI=_nodal_connec_index->getConstPointer();
3442 const int *conn=_nodal_connec->getConstPointer();
3443 const double *coords=_coords->getConstPointer();
3444 if(getMeshDimension()==2)
3446 if(getSpaceDimension()==3)
3448 MCAuto<DataArrayDouble> loc=getPartBarycenterAndOwner(begin,end);
3449 const double *locPtr=loc->getConstPointer();
3450 for(const int *i=begin;i!=end;i++,vals+=3,locPtr+=3)
3452 int offset=connI[*i];
3453 INTERP_KERNEL::crossprod<3>(locPtr,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3454 double n=INTERP_KERNEL::norm<3>(vals);
3455 std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3460 for(std::size_t i=0;i<nbelems;i++)
3461 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=1.; }
3464 else//meshdimension==1
3467 for(const int *i=begin;i!=end;i++)
3469 int offset=connI[*i];
3470 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3471 double n=INTERP_KERNEL::norm<2>(tmp);
3472 std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3477 ret->setArray(array);
3479 ret->synchronizeTimeWithSupport();
3484 * Returns a new MEDCouplingFieldDouble holding a direction vector for each SEG2 in \a
3485 * this 1D mesh. The computed vectors have <em> this->getSpaceDimension() </em> components
3486 * and are \b not normalized.
3487 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3488 * cells and one time. The caller is to delete this field using decrRef() as
3489 * it is no more needed.
3490 * \throw If the nodal connectivity of cells is not defined.
3491 * \throw If the coordinates array is not set.
3492 * \throw If \a this->getMeshDimension() != 1.
3493 * \throw If \a this mesh includes cells of type other than SEG2.
3495 MEDCouplingFieldDouble *MEDCouplingUMesh::buildDirectionVectorField() const
3497 if(getMeshDimension()!=1)
3498 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for buildDirectionVectorField !");
3499 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3500 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for buildDirectionVectorField !");
3501 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3502 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3503 int nbOfCells=getNumberOfCells();
3504 int spaceDim=getSpaceDimension();
3505 array->alloc(nbOfCells,spaceDim);
3506 double *pt=array->getPointer();
3507 const double *coo=getCoords()->getConstPointer();
3508 std::vector<int> conn;
3510 for(int i=0;i<nbOfCells;i++)
3513 getNodeIdsOfCell(i,conn);
3514 pt=std::transform(coo+conn[1]*spaceDim,coo+(conn[1]+1)*spaceDim,coo+conn[0]*spaceDim,pt,std::minus<double>());
3516 ret->setArray(array);
3518 ret->synchronizeTimeWithSupport();
3523 * Creates a 2D mesh by cutting \a this 3D mesh with a plane. In addition to the mesh,
3524 * returns a new DataArrayInt, of length equal to the number of 2D cells in the result
3525 * mesh, holding, for each cell in the result mesh, an id of a 3D cell it comes
3526 * from. If a result face is shared by two 3D cells, then the face in included twice in
3528 * \param [in] origin - 3 components of a point defining location of the plane.
3529 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3530 * must be greater than 1e-6.
3531 * \param [in] eps - half-thickness of the plane.
3532 * \param [out] cellIds - a new instance of DataArrayInt holding ids of 3D cells
3533 * producing correspondent 2D cells. The caller is to delete this array
3534 * using decrRef() as it is no more needed.
3535 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This mesh does
3536 * not share the node coordinates array with \a this mesh. The caller is to
3537 * delete this mesh using decrRef() as it is no more needed.
3538 * \throw If the coordinates array is not set.
3539 * \throw If the nodal connectivity of cells is not defined.
3540 * \throw If \a this->getMeshDimension() != 3 or \a this->getSpaceDimension() != 3.
3541 * \throw If magnitude of \a vec is less than 1e-6.
3542 * \throw If the plane does not intersect any 3D cell of \a this mesh.
3543 * \throw If \a this includes quadratic cells.
3545 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3D(const double *origin, const double *vec, double eps, DataArrayInt *&cellIds) const
3547 checkFullyDefined();
3548 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3549 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3550 MCAuto<DataArrayInt> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3551 if(candidates->empty())
3552 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane considering bounding boxes !");
3553 std::vector<int> nodes;
3554 DataArrayInt *cellIds1D=0;
3555 MCAuto<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3556 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3557 MCAuto<DataArrayInt> desc1=DataArrayInt::New(),desc2=DataArrayInt::New();
3558 MCAuto<DataArrayInt> descIndx1=DataArrayInt::New(),descIndx2=DataArrayInt::New();
3559 MCAuto<DataArrayInt> revDesc1=DataArrayInt::New(),revDesc2=DataArrayInt::New();
3560 MCAuto<DataArrayInt> revDescIndx1=DataArrayInt::New(),revDescIndx2=DataArrayInt::New();
3561 MCAuto<MEDCouplingUMesh> mDesc2=subMesh->buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2);//meshDim==2 spaceDim==3
3562 revDesc2=0; revDescIndx2=0;
3563 MCAuto<MEDCouplingUMesh> mDesc1=mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3564 revDesc1=0; revDescIndx1=0;
3565 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3566 MCAuto<DataArrayInt> cellIds1DTmp(cellIds1D);
3568 std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3569 for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3571 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3572 std::vector< std::pair<int,int> > cut3DSurf(mDesc2->getNumberOfCells());
3573 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->getConstPointer(),mDesc2->getNodalConnectivityIndex()->getConstPointer(),
3574 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3575 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3576 MCAuto<DataArrayInt> conn(DataArrayInt::New()),connI(DataArrayInt::New()),cellIds2(DataArrayInt::New());
3577 connI->pushBackSilent(0); conn->alloc(0,1); cellIds2->alloc(0,1);
3578 subMesh->assemblyForSplitFrom3DSurf(cut3DSurf,desc2->getConstPointer(),descIndx2->getConstPointer(),conn,connI,cellIds2);
3579 if(cellIds2->empty())
3580 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3581 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3D",2);
3582 ret->setCoords(mDesc1->getCoords());
3583 ret->setConnectivity(conn,connI,true);
3584 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3589 * Creates an 1D mesh by cutting \a this 2D mesh in 3D space with a plane. In
3590 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
3591 from. If a result segment is shared by two 2D cells, then the segment in included twice in
3593 * \param [in] origin - 3 components of a point defining location of the plane.
3594 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3595 * must be greater than 1e-6.
3596 * \param [in] eps - half-thickness of the plane.
3597 * \param [out] cellIds - a new instance of DataArrayInt holding ids of faces
3598 * producing correspondent segments. The caller is to delete this array
3599 * using decrRef() as it is no more needed.
3600 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This is an 1D
3601 * mesh in 3D space. This mesh does not share the node coordinates array with
3602 * \a this mesh. The caller is to delete this mesh using decrRef() as it is
3604 * \throw If the coordinates array is not set.
3605 * \throw If the nodal connectivity of cells is not defined.
3606 * \throw If \a this->getMeshDimension() != 2 or \a this->getSpaceDimension() != 3.
3607 * \throw If magnitude of \a vec is less than 1e-6.
3608 * \throw If the plane does not intersect any 2D cell of \a this mesh.
3609 * \throw If \a this includes quadratic cells.
3611 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3DSurf(const double *origin, const double *vec, double eps, DataArrayInt *&cellIds) const
3613 checkFullyDefined();
3614 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
3615 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf works on umeshes with meshdim equal to 2 and spaceDim equal to 3 !");
3616 MCAuto<DataArrayInt> candidates(getCellIdsCrossingPlane(origin,vec,eps));
3617 if(candidates->empty())
3618 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3D surf cells in this intercepts the specified plane considering bounding boxes !");
3619 std::vector<int> nodes;
3620 DataArrayInt *cellIds1D(0);
3621 MCAuto<MEDCouplingUMesh> subMesh(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3622 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3623 MCAuto<DataArrayInt> desc1(DataArrayInt::New()),descIndx1(DataArrayInt::New()),revDesc1(DataArrayInt::New()),revDescIndx1(DataArrayInt::New());
3624 MCAuto<MEDCouplingUMesh> mDesc1(subMesh->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3625 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3626 MCAuto<DataArrayInt> cellIds1DTmp(cellIds1D);
3628 std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3629 for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3631 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3632 int ncellsSub=subMesh->getNumberOfCells();
3633 std::vector< std::pair<int,int> > cut3DSurf(ncellsSub);
3634 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,subMesh->getNodalConnectivity()->getConstPointer(),subMesh->getNodalConnectivityIndex()->getConstPointer(),
3635 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3636 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3637 MCAuto<DataArrayInt> conn(DataArrayInt::New()),connI(DataArrayInt::New()),cellIds2(DataArrayInt::New()); connI->pushBackSilent(0);
3639 const int *nodal=subMesh->getNodalConnectivity()->getConstPointer();
3640 const int *nodalI=subMesh->getNodalConnectivityIndex()->getConstPointer();
3641 for(int i=0;i<ncellsSub;i++)
3643 if(cut3DSurf[i].first!=-1 && cut3DSurf[i].second!=-1)
3645 if(cut3DSurf[i].first!=-2)
3647 conn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG2); conn->pushBackSilent(cut3DSurf[i].first); conn->pushBackSilent(cut3DSurf[i].second);
3648 connI->pushBackSilent(conn->getNumberOfTuples());
3649 cellIds2->pushBackSilent(i);
3653 int cellId3DSurf=cut3DSurf[i].second;
3654 int offset=nodalI[cellId3DSurf]+1;
3655 int nbOfEdges=nodalI[cellId3DSurf+1]-offset;
3656 for(int j=0;j<nbOfEdges;j++)
3658 conn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG2); conn->pushBackSilent(nodal[offset+j]); conn->pushBackSilent(nodal[offset+(j+1)%nbOfEdges]);
3659 connI->pushBackSilent(conn->getNumberOfTuples());
3660 cellIds2->pushBackSilent(cellId3DSurf);
3665 if(cellIds2->empty())
3666 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3DSurf cells in this intercepts the specified plane !");
3667 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3DSurf",1);
3668 ret->setCoords(mDesc1->getCoords());
3669 ret->setConnectivity(conn,connI,true);
3670 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3674 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::clipSingle3DCellByPlane(const double origin[3], const double vec[3], double eps) const
3676 checkFullyDefined();
3677 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3678 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3679 if(getNumberOfCells()!=1)
3680 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works only on mesh containing exactly one cell !");
3682 std::vector<int> nodes;
3683 findNodesOnPlane(origin,vec,eps,nodes);
3684 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());
3685 MCAuto<MEDCouplingUMesh> mDesc2(buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2));//meshDim==2 spaceDim==3
3686 revDesc2=0; revDescIndx2=0;
3687 MCAuto<MEDCouplingUMesh> mDesc1(mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3688 revDesc1=0; revDescIndx1=0;
3689 DataArrayInt *cellIds1D(0);
3690 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3691 MCAuto<DataArrayInt> cellIds1DTmp(cellIds1D);
3692 std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3693 for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3697 int oldNbNodes(mDesc1->getNumberOfNodes());
3698 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3699 sameNbNodes=(mDesc1->getNumberOfNodes()==oldNbNodes);
3701 std::vector< std::pair<int,int> > cut3DSurf(mDesc2->getNumberOfCells());
3702 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->begin(),mDesc2->getNodalConnectivityIndex()->begin(),
3703 mDesc1->getNodalConnectivity()->begin(),mDesc1->getNodalConnectivityIndex()->begin(),
3704 desc1->begin(),descIndx1->begin(),cut3DSurf);
3705 MCAuto<DataArrayInt> conn(DataArrayInt::New()),connI(DataArrayInt::New());
3706 connI->pushBackSilent(0); conn->alloc(0,1);
3708 MCAuto<DataArrayInt> cellIds2(DataArrayInt::New()); cellIds2->alloc(0,1);
3709 assemblyForSplitFrom3DSurf(cut3DSurf,desc2->begin(),descIndx2->begin(),conn,connI,cellIds2);
3710 if(cellIds2->empty())
3711 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3713 std::vector<std::vector<int> > res;
3714 buildSubCellsFromCut(cut3DSurf,desc2->begin(),descIndx2->begin(),mDesc1->getCoords()->begin(),eps,res);
3715 std::size_t sz(res.size());
3716 if(res.size()==mDesc1->getNumberOfCells() && sameNbNodes)
3717 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane : cell is not clipped !");
3718 for(std::size_t i=0;i<sz;i++)
3720 conn->pushBackSilent((int)INTERP_KERNEL::NORM_POLYGON);
3721 conn->insertAtTheEnd(res[i].begin(),res[i].end());
3722 connI->pushBackSilent(conn->getNumberOfTuples());
3724 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
3725 ret->setCoords(mDesc1->getCoords());
3726 ret->setConnectivity(conn,connI,true);
3727 int nbCellsRet(ret->getNumberOfCells());
3729 MCAuto<DataArrayDouble> vec2(DataArrayDouble::New()); vec2->alloc(1,3); std::copy(vec,vec+3,vec2->getPointer());
3730 MCAuto<MEDCouplingFieldDouble> ortho(ret->buildOrthogonalField());
3731 MCAuto<DataArrayDouble> ortho2(ortho->getArray()->selectByTupleIdSafeSlice(0,1,1));
3732 MCAuto<DataArrayDouble> dott(DataArrayDouble::Dot(ortho2,vec2));
3733 MCAuto<DataArrayDouble> ccm(ret->computeCellCenterOfMass());
3734 MCAuto<DataArrayDouble> occm;
3736 MCAuto<DataArrayDouble> pt(DataArrayDouble::New()); pt->alloc(1,3); std::copy(origin,origin+3,pt->getPointer());
3737 occm=DataArrayDouble::Substract(ccm,pt);
3739 vec2=DataArrayDouble::New(); vec2->alloc(nbCellsRet,3);
3740 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);
3741 MCAuto<DataArrayDouble> dott2(DataArrayDouble::Dot(occm,vec2));
3743 const int *cPtr(ret->getNodalConnectivity()->begin()),*ciPtr(ret->getNodalConnectivityIndex()->begin());
3744 MCAuto<MEDCouplingUMesh> ret2(MEDCouplingUMesh::New("Clip3D",3));
3745 ret2->setCoords(mDesc1->getCoords());
3746 MCAuto<DataArrayInt> conn2(DataArrayInt::New()),conn2I(DataArrayInt::New());
3747 conn2I->pushBackSilent(0); conn2->alloc(0,1);
3748 std::vector<int> cell0(1,(int)INTERP_KERNEL::NORM_POLYHED);
3749 std::vector<int> cell1(1,(int)INTERP_KERNEL::NORM_POLYHED);
3750 if(dott->getIJ(0,0)>0)
3752 cell0.insert(cell0.end(),cPtr+1,cPtr+ciPtr[1]);
3753 std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell1,cell1.end()));
3757 cell1.insert(cell1.end(),cPtr+1,cPtr+ciPtr[1]);
3758 std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell0,cell0.end()));
3760 for(int i=1;i<nbCellsRet;i++)
3762 if(dott2->getIJ(i,0)<0)
3764 if(ciPtr[i+1]-ciPtr[i]>=4)
3766 cell0.push_back(-1);
3767 cell0.insert(cell0.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
3772 if(ciPtr[i+1]-ciPtr[i]>=4)
3774 cell1.push_back(-1);
3775 cell1.insert(cell1.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
3779 conn2->insertAtTheEnd(cell0.begin(),cell0.end());
3780 conn2I->pushBackSilent(conn2->getNumberOfTuples());
3781 conn2->insertAtTheEnd(cell1.begin(),cell1.end());
3782 conn2I->pushBackSilent(conn2->getNumberOfTuples());
3783 ret2->setConnectivity(conn2,conn2I,true);
3784 ret2->checkConsistencyLight();
3785 ret2->orientCorrectlyPolyhedrons();
3790 * Finds cells whose bounding boxes intersect a given plane.
3791 * \param [in] origin - 3 components of a point defining location of the plane.
3792 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3793 * must be greater than 1e-6.
3794 * \param [in] eps - half-thickness of the plane.
3795 * \return DataArrayInt * - a new instance of DataArrayInt holding ids of the found
3796 * cells. The caller is to delete this array using decrRef() as it is no more
3798 * \throw If the coordinates array is not set.
3799 * \throw If the nodal connectivity of cells is not defined.
3800 * \throw If \a this->getSpaceDimension() != 3.
3801 * \throw If magnitude of \a vec is less than 1e-6.
3802 * \sa buildSlice3D()
3804 DataArrayInt *MEDCouplingUMesh::getCellIdsCrossingPlane(const double *origin, const double *vec, double eps) const
3806 checkFullyDefined();
3807 if(getSpaceDimension()!=3)
3808 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with spaceDim equal to 3 !");
3809 double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
3811 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellIdsCrossingPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
3813 vec2[0]=vec[1]; vec2[1]=-vec[0]; vec2[2]=0.;//vec2 is the result of cross product of vec with (0,0,1)
3814 double angle=acos(vec[2]/normm);
3815 MCAuto<DataArrayInt> cellIds;
3819 MCAuto<DataArrayDouble> coo=_coords->deepCopy();
3820 double normm2(sqrt(vec2[0]*vec2[0]+vec2[1]*vec2[1]+vec2[2]*vec2[2]));
3821 if(normm2/normm>1e-6)
3822 DataArrayDouble::Rotate3DAlg(origin,vec2,angle,coo->getNumberOfTuples(),coo->getPointer(),coo->getPointer());
3823 MCAuto<MEDCouplingUMesh> mw=clone(false);//false -> shallow copy
3825 mw->getBoundingBox(bbox);
3826 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3827 cellIds=mw->getCellsInBoundingBox(bbox,eps);
3831 getBoundingBox(bbox);
3832 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3833 cellIds=getCellsInBoundingBox(bbox,eps);
3835 return cellIds.retn();
3839 * This method checks that \a this is a contiguous mesh. The user is expected to call this method on a mesh with meshdim==1.
3840 * If not an exception will thrown. If this is an empty mesh with no cell an exception will be thrown too.
3841 * No consideration of coordinate is done by this method.
3842 * 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)
3843 * If not false is returned. In case that false is returned a call to MEDCoupling::MEDCouplingUMesh::mergeNodes could be useful.
3845 bool MEDCouplingUMesh::isContiguous1D() const
3847 if(getMeshDimension()!=1)
3848 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense only for 1D mesh !");
3849 int nbCells=getNumberOfCells();
3851 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense for non empty mesh !");
3852 const int *connI(_nodal_connec_index->begin()),*conn(_nodal_connec->begin());
3853 int ref=conn[connI[0]+2];
3854 for(int i=1;i<nbCells;i++)
3856 if(conn[connI[i]+1]!=ref)
3858 ref=conn[connI[i]+2];
3864 * This method is only callable on mesh with meshdim == 1 containing only SEG2 and spaceDim==3.
3865 * This method projects this on the 3D line defined by (pt,v). This methods first checks that all SEG2 are along v vector.
3866 * \param pt reference point of the line
3867 * \param v normalized director vector of the line
3868 * \param eps max precision before throwing an exception
3869 * \param res output of size this->getNumberOfCells
3871 void MEDCouplingUMesh::project1D(const double *pt, const double *v, double eps, double *res) const
3873 if(getMeshDimension()!=1)
3874 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for project1D !");
3875 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3876 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for project1D !");
3877 if(getSpaceDimension()!=3)
3878 throw INTERP_KERNEL::Exception("Expected a umesh with spaceDim==3 for project1D !");
3879 MCAuto<MEDCouplingFieldDouble> f=buildDirectionVectorField();
3880 const double *fPtr=f->getArray()->getConstPointer();
3882 for(std::size_t i=0;i<getNumberOfCells();i++)
3884 const double *tmp1=fPtr+3*i;
3885 tmp[0]=tmp1[1]*v[2]-tmp1[2]*v[1];
3886 tmp[1]=tmp1[2]*v[0]-tmp1[0]*v[2];
3887 tmp[2]=tmp1[0]*v[1]-tmp1[1]*v[0];
3888 double n1=INTERP_KERNEL::norm<3>(tmp);
3889 n1/=INTERP_KERNEL::norm<3>(tmp1);
3891 throw INTERP_KERNEL::Exception("UMesh::Projection 1D failed !");
3893 const double *coo=getCoords()->getConstPointer();
3894 for(int i=0;i<getNumberOfNodes();i++)
3896 std::transform(coo+i*3,coo+i*3+3,pt,tmp,std::minus<double>());
3897 std::transform(tmp,tmp+3,v,tmp,std::multiplies<double>());
3898 res[i]=std::accumulate(tmp,tmp+3,0.);
3903 * 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.
3904 * \a this is expected to be a mesh so that its space dimension is equal to its
3905 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
3906 * 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).
3908 * 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
3909 * 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).
3910 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
3912 * So this method is more accurate (so, more costly) than simply searching for the closest point in \a this.
3913 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
3915 * \param [in] ptBg the start pointer (included) of the coordinates of the point
3916 * \param [in] ptEnd the end pointer (not included) of the coordinates of the point
3917 * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
3918 * \return the positive value of the distance.
3919 * \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
3921 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoints
3923 double MEDCouplingUMesh::distanceToPoint(const double *ptBg, const double *ptEnd, int& cellId) const
3925 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
3926 if(meshDim!=spaceDim-1)
3927 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint works only for spaceDim=meshDim+1 !");
3928 if(meshDim!=2 && meshDim!=1)
3929 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint : only mesh dimension 2 and 1 are implemented !");
3930 checkFullyDefined();
3931 if((int)std::distance(ptBg,ptEnd)!=spaceDim)
3932 { 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()); }
3933 DataArrayInt *ret1=0;
3934 MCAuto<DataArrayDouble> pts=DataArrayDouble::New(); pts->useArray(ptBg,false,DeallocType::C_DEALLOC,1,spaceDim);
3935 MCAuto<DataArrayDouble> ret0=distanceToPoints(pts,ret1);
3936 MCAuto<DataArrayInt> ret1Safe(ret1);
3937 cellId=*ret1Safe->begin();
3938 return *ret0->begin();
3942 * This method computes the distance from each point of points serie \a pts (stored in a DataArrayDouble in which each tuple represents a point)
3943 * to \a this and the first \a cellId in \a this corresponding to the returned distance.
3944 * 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
3945 * 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).
3946 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
3948 * \a this is expected to be a mesh so that its space dimension is equal to its
3949 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
3950 * 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).
3952 * So this method is more accurate (so, more costly) than simply searching for each point in \a pts the closest point in \a this.
3953 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
3955 * \param [in] pts the list of points in which each tuple represents a point
3956 * \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.
3957 * \return a newly allocated object to be dealed by the caller that tells for each point in \a pts the distance to \a this.
3958 * \throw if number of components of \a pts is not equal to the space dimension.
3959 * \throw if mesh dimension of \a this is not equal to space dimension - 1.
3960 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoint
3962 DataArrayDouble *MEDCouplingUMesh::distanceToPoints(const DataArrayDouble *pts, DataArrayInt *& cellIds) const
3965 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : input points pointer is NULL !");
3966 pts->checkAllocated();
3967 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
3968 if(meshDim!=spaceDim-1)
3969 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints works only for spaceDim=meshDim+1 !");
3970 if(meshDim!=2 && meshDim!=1)
3971 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only mesh dimension 2 and 1 are implemented !");
3972 if((int)pts->getNumberOfComponents()!=spaceDim)
3974 std::ostringstream oss; oss << "MEDCouplingUMesh::distanceToPoints : input pts DataArrayDouble has " << pts->getNumberOfComponents() << " components whereas it should be equal to " << spaceDim << " (mesh spaceDimension) !";
3975 throw INTERP_KERNEL::Exception(oss.str());
3977 checkFullyDefined();
3978 int nbCells=getNumberOfCells();
3980 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : no cells in this !");
3981 int nbOfPts=pts->getNumberOfTuples();
3982 MCAuto<DataArrayDouble> ret0=DataArrayDouble::New(); ret0->alloc(nbOfPts,1);
3983 MCAuto<DataArrayInt> ret1=DataArrayInt::New(); ret1->alloc(nbOfPts,1);
3984 const int *nc=_nodal_connec->begin(),*ncI=_nodal_connec_index->begin(); const double *coords=_coords->begin();
3985 double *ret0Ptr=ret0->getPointer(); int *ret1Ptr=ret1->getPointer(); const double *ptsPtr=pts->begin();
3986 MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree());
3987 const double *bbox(bboxArr->begin());
3992 BBTreeDst<3> myTree(bbox,0,0,nbCells);
3993 for(int i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=3)
3995 double x=std::numeric_limits<double>::max();
3996 std::vector<int> elems;
3997 myTree.getMinDistanceOfMax(ptsPtr,x);
3998 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
3999 DistanceToPoint3DSurfAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4005 BBTreeDst<2> myTree(bbox,0,0,nbCells);
4006 for(int i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=2)
4008 double x=std::numeric_limits<double>::max();
4009 std::vector<int> elems;
4010 myTree.getMinDistanceOfMax(ptsPtr,x);
4011 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4012 DistanceToPoint2DCurveAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4017 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only spacedim 2 and 3 supported !");
4019 cellIds=ret1.retn();
4028 * Finds cells in contact with a ball (i.e. a point with precision).
4029 * 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.
4030 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4032 * \warning This method is suitable if the caller intends to evaluate only one
4033 * point, for more points getCellsContainingPoints() is recommended as it is
4035 * \param [in] pos - array of coordinates of the ball central point.
4036 * \param [in] eps - ball radius.
4037 * \return int - a smallest id of cells being in contact with the ball, -1 in case
4038 * if there are no such cells.
4039 * \throw If the coordinates array is not set.
4040 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4042 int MEDCouplingUMesh::getCellContainingPoint(const double *pos, double eps) const
4044 std::vector<int> elts;
4045 getCellsContainingPoint(pos,eps,elts);
4048 return elts.front();
4052 * Finds cells in contact with a ball (i.e. a point with precision).
4053 * 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.
4054 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4055 * \warning This method is suitable if the caller intends to evaluate only one
4056 * point, for more points getCellsContainingPoints() is recommended as it is
4058 * \param [in] pos - array of coordinates of the ball central point.
4059 * \param [in] eps - ball radius.
4060 * \param [out] elts - vector returning ids of the found cells. It is cleared
4061 * before inserting ids.
4062 * \throw If the coordinates array is not set.
4063 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4065 * \if ENABLE_EXAMPLES
4066 * \ref cpp_mcumesh_getCellsContainingPoint "Here is a C++ example".<br>
4067 * \ref py_mcumesh_getCellsContainingPoint "Here is a Python example".
4070 void MEDCouplingUMesh::getCellsContainingPoint(const double *pos, double eps, std::vector<int>& elts) const
4072 MCAuto<DataArrayInt> eltsUg,eltsIndexUg;
4073 getCellsContainingPoints(pos,1,eps,eltsUg,eltsIndexUg);
4074 elts.clear(); elts.insert(elts.end(),eltsUg->begin(),eltsUg->end());
4077 void MEDCouplingUMesh::getCellsContainingPointsZeAlg(const double *pos, int nbOfPoints, double eps,
4078 MCAuto<DataArrayInt>& elts, MCAuto<DataArrayInt>& eltsIndex,
4079 std::function<bool(INTERP_KERNEL::NormalizedCellType,int)> sensibilityTo2DQuadraticLinearCellsFunc) const
4081 int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
4086 const double *coords=_coords->getConstPointer();
4087 getCellsContainingPointsAlg<3>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4090 throw INTERP_KERNEL::Exception("For spaceDim==3 only meshDim==3 implemented for getelementscontainingpoints !");
4092 else if(spaceDim==2)
4096 const double *coords=_coords->getConstPointer();
4097 getCellsContainingPointsAlg<2>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4100 throw INTERP_KERNEL::Exception("For spaceDim==2 only meshDim==2 implemented for getelementscontainingpoints !");
4102 else if(spaceDim==1)
4106 const double *coords=_coords->getConstPointer();
4107 getCellsContainingPointsAlg<1>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4110 throw INTERP_KERNEL::Exception("For spaceDim==1 only meshDim==1 implemented for getelementscontainingpoints !");
4113 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPoints : not managed for mdim not in [1,2,3] !");
4117 * Finds cells in contact with several balls (i.e. points with precision).
4118 * This method is an extension of getCellContainingPoint() and
4119 * getCellsContainingPoint() for the case of multiple points.
4120 * 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.
4121 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4122 * \param [in] pos - an array of coordinates of points in full interlace mode :
4123 * X0,Y0,Z0,X1,Y1,Z1,... Size of the array must be \a
4124 * this->getSpaceDimension() * \a nbOfPoints
4125 * \param [in] nbOfPoints - number of points to locate within \a this mesh.
4126 * \param [in] eps - radius of balls (i.e. the precision).
4127 * \param [out] elts - vector returning ids of found cells.
4128 * \param [out] eltsIndex - an array, of length \a nbOfPoints + 1,
4129 * dividing cell ids in \a elts into groups each referring to one
4130 * point. Its every element (except the last one) is an index pointing to the
4131 * first id of a group of cells. For example cells in contact with the *i*-th
4132 * point are described by following range of indices:
4133 * [ \a eltsIndex[ *i* ], \a eltsIndex[ *i*+1 ] ) and the cell ids are
4134 * \a elts[ \a eltsIndex[ *i* ]], \a elts[ \a eltsIndex[ *i* ] + 1 ], ...
4135 * Number of cells in contact with the *i*-th point is
4136 * \a eltsIndex[ *i*+1 ] - \a eltsIndex[ *i* ].
4137 * \throw If the coordinates array is not set.
4138 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4140 * \if ENABLE_EXAMPLES
4141 * \ref cpp_mcumesh_getCellsContainingPoints "Here is a C++ example".<br>
4142 * \ref py_mcumesh_getCellsContainingPoints "Here is a Python example".
4145 void MEDCouplingUMesh::getCellsContainingPoints(const double *pos, int nbOfPoints, double eps,
4146 MCAuto<DataArrayInt>& elts, MCAuto<DataArrayInt>& eltsIndex) const
4148 auto yesImSensibleTo2DQuadraticLinearCellsFunc([](INTERP_KERNEL::NormalizedCellType ct, int mdim) { return INTERP_KERNEL::CellModel::GetCellModel(ct).isQuadratic() && mdim == 2; } );
4149 this->getCellsContainingPointsZeAlg(pos,nbOfPoints,eps,elts,eltsIndex,yesImSensibleTo2DQuadraticLinearCellsFunc);
4153 * Behaves like MEDCouplingMesh::getCellsContainingPoints for cells in \a this that are linear.
4154 * For quadratic cells in \a this, this method behaves by just considering linear part of cells.
4155 * This method is here only for backward compatibility (interpolation GaussPoints to GaussPoints).
4157 * \sa MEDCouplingUMesh::getCellsContainingPoints, MEDCouplingRemapper::prepareNotInterpKernelOnlyGaussGauss
4159 void MEDCouplingUMesh::getCellsContainingPointsLinearPartOnlyOnNonDynType(const double *pos, int nbOfPoints, double eps, MCAuto<DataArrayInt>& elts, MCAuto<DataArrayInt>& eltsIndex) const
4161 auto noImNotSensibleTo2DQuadraticLinearCellsFunc([](INTERP_KERNEL::NormalizedCellType,int) { return false; } );
4162 this->getCellsContainingPointsZeAlg(pos,nbOfPoints,eps,elts,eltsIndex,noImNotSensibleTo2DQuadraticLinearCellsFunc);
4166 * Finds butterfly cells in \a this mesh. A 2D cell is considered to be butterfly if at
4167 * least two its edges intersect each other anywhere except their extremities. An
4168 * INTERP_KERNEL::NORM_NORI3 cell can \b not be butterfly.
4169 * \param [in,out] cells - a vector returning ids of the found cells. It is not
4170 * cleared before filling in.
4171 * \param [in] eps - precision.
4172 * \throw If \a this->getMeshDimension() != 2.
4173 * \throw If \a this->getSpaceDimension() != 2 && \a this->getSpaceDimension() != 3.
4175 void MEDCouplingUMesh::checkButterflyCells(std::vector<int>& cells, double eps) const
4177 const char msg[]="Butterfly detection work only for 2D cells with spaceDim==2 or 3!";
4178 if(getMeshDimension()!=2)
4179 throw INTERP_KERNEL::Exception(msg);
4180 int spaceDim=getSpaceDimension();
4181 if(spaceDim!=2 && spaceDim!=3)
4182 throw INTERP_KERNEL::Exception(msg);
4183 const int *conn=_nodal_connec->getConstPointer();
4184 const int *connI=_nodal_connec_index->getConstPointer();
4185 int nbOfCells=getNumberOfCells();
4186 std::vector<double> cell2DinS2;
4187 for(int i=0;i<nbOfCells;i++)
4189 int offset=connI[i];
4190 int nbOfNodesForCell=connI[i+1]-offset-1;
4191 if(nbOfNodesForCell<=3)
4193 bool isQuad=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[offset]).isQuadratic();
4194 project2DCellOnXY(conn+offset+1,conn+connI[i+1],cell2DinS2);
4195 if(isButterfly2DCell(cell2DinS2,isQuad,eps))
4202 * This method is typically requested to unbutterfly 2D linear cells in \b this.
4204 * 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.
4205 * 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.
4207 * For each 2D linear cell in \b this, this method builds the convex envelop (or the convex hull) of the current cell.
4208 * This convex envelop is computed using Jarvis march algorithm.
4209 * The coordinates and the number of cells of \b this remain unchanged on invocation of this method.
4210 * 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)
4211 * 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.
4213 * \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.
4214 * \sa MEDCouplingUMesh::colinearize2D
4216 DataArrayInt *MEDCouplingUMesh::convexEnvelop2D()
4218 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
4219 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convexEnvelop2D works only for meshDim=2 and spaceDim=2 !");
4220 checkFullyDefined();
4221 const double *coords=getCoords()->getConstPointer();
4222 int nbOfCells=getNumberOfCells();
4223 MCAuto<DataArrayInt> nodalConnecIndexOut=DataArrayInt::New();
4224 nodalConnecIndexOut->alloc(nbOfCells+1,1);
4225 MCAuto<DataArrayInt> nodalConnecOut(DataArrayInt::New());
4226 int *workIndexOut=nodalConnecIndexOut->getPointer();
4228 const int *nodalConnecIn=_nodal_connec->getConstPointer();
4229 const int *nodalConnecIndexIn=_nodal_connec_index->getConstPointer();
4230 std::set<INTERP_KERNEL::NormalizedCellType> types;
4231 MCAuto<DataArrayInt> isChanged(DataArrayInt::New());
4232 isChanged->alloc(0,1);
4233 for(int i=0;i<nbOfCells;i++,workIndexOut++)
4235 int pos=nodalConnecOut->getNumberOfTuples();
4236 if(BuildConvexEnvelopOf2DCellJarvis(coords,nodalConnecIn+nodalConnecIndexIn[i],nodalConnecIn+nodalConnecIndexIn[i+1],nodalConnecOut))
4237 isChanged->pushBackSilent(i);
4238 types.insert((INTERP_KERNEL::NormalizedCellType)nodalConnecOut->getIJ(pos,0));
4239 workIndexOut[1]=nodalConnecOut->getNumberOfTuples();
4241 if(isChanged->empty())
4243 setConnectivity(nodalConnecOut,nodalConnecIndexOut,false);
4245 return isChanged.retn();
4249 * This method is \b NOT const because it can modify \a this.
4250 * \a this is expected to be an unstructured mesh with meshDim==2 and spaceDim==3. If not an exception will be thrown.
4251 * \param mesh1D is an unstructured mesh with MeshDim==1 and spaceDim==3. If not an exception will be thrown.
4252 * \param policy specifies the type of extrusion chosen:
4253 * - \b 0 for translation only (most simple): the cells of the 1D mesh represent the vectors along which the 2D mesh
4254 * will be repeated to build each level
4255 * - \b 1 for translation and rotation: the translation is done as above. For each level, an arc of circle is fitted on
4256 * 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
4257 * 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
4259 * \return an unstructured mesh with meshDim==3 and spaceDim==3. The returned mesh has the same coords than \a this.
4261 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMesh(const MEDCouplingUMesh *mesh1D, int policy)
4263 checkFullyDefined();
4264 mesh1D->checkFullyDefined();
4265 if(!mesh1D->isContiguous1D())
4266 throw INTERP_KERNEL::Exception("buildExtrudedMesh : 1D mesh passed in parameter is not contiguous !");
4267 if(getSpaceDimension()!=mesh1D->getSpaceDimension())
4268 throw INTERP_KERNEL::Exception("Invalid call to buildExtrudedMesh this and mesh1D must have same space dimension !");
4269 if((getMeshDimension()!=2 || getSpaceDimension()!=3) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
4270 throw INTERP_KERNEL::Exception("Invalid 'this' for buildExtrudedMesh method : must be (meshDim==2 and spaceDim==3) or (meshDim==1 and spaceDim==2) !");
4271 if(mesh1D->getMeshDimension()!=1)
4272 throw INTERP_KERNEL::Exception("Invalid 'mesh1D' for buildExtrudedMesh method : must be meshDim==1 !");
4274 if(isPresenceOfQuadratic())
4276 if(mesh1D->isFullyQuadratic())
4279 throw INTERP_KERNEL::Exception("Invalid 2D mesh and 1D mesh because 2D mesh has quadratic cells and 1D is not fully quadratic !");
4281 int oldNbOfNodes(getNumberOfNodes());
4282 MCAuto<DataArrayDouble> newCoords;
4287 newCoords=fillExtCoordsUsingTranslation(mesh1D,isQuad);
4292 newCoords=fillExtCoordsUsingTranslAndAutoRotation(mesh1D,isQuad);
4296 throw INTERP_KERNEL::Exception("Not implemented extrusion policy : must be in (0) !");
4298 setCoords(newCoords);
4299 MCAuto<MEDCouplingUMesh> ret(buildExtrudedMeshFromThisLowLev(oldNbOfNodes,isQuad));
4306 * Checks if \a this mesh is constituted by only quadratic cells.
4307 * \return bool - \c true if there are only quadratic cells in \a this mesh.
4308 * \throw If the coordinates array is not set.
4309 * \throw If the nodal connectivity of cells is not defined.
4311 bool MEDCouplingUMesh::isFullyQuadratic() const
4313 checkFullyDefined();
4315 int nbOfCells=getNumberOfCells();
4316 for(int i=0;i<nbOfCells && ret;i++)
4318 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4319 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4320 ret=cm.isQuadratic();
4326 * Checks if \a this mesh includes any quadratic cell.
4327 * \return bool - \c true if there is at least one quadratic cells in \a this mesh.
4328 * \throw If the coordinates array is not set.
4329 * \throw If the nodal connectivity of cells is not defined.
4331 bool MEDCouplingUMesh::isPresenceOfQuadratic() const
4333 checkFullyDefined();
4335 int nbOfCells=getNumberOfCells();
4336 for(int i=0;i<nbOfCells && !ret;i++)
4338 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4339 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4340 ret=cm.isQuadratic();
4346 * Converts all quadratic cells to linear ones. If there are no quadratic cells in \a
4347 * this mesh, it remains unchanged.
4348 * \throw If the coordinates array is not set.
4349 * \throw If the nodal connectivity of cells is not defined.
4351 void MEDCouplingUMesh::convertQuadraticCellsToLinear()
4353 checkFullyDefined();
4354 int nbOfCells(getNumberOfCells());
4356 const int *iciptr=_nodal_connec_index->begin();
4357 for(int i=0;i<nbOfCells;i++)
4359 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4360 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4361 if(cm.isQuadratic())
4363 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4364 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4365 if(!cml.isDynamic())
4366 delta+=cm.getNumberOfNodes()-cml.getNumberOfNodes();
4368 delta+=(iciptr[i+1]-iciptr[i]-1)/2;
4373 MCAuto<DataArrayInt> newConn(DataArrayInt::New()),newConnI(DataArrayInt::New());
4374 const int *icptr(_nodal_connec->begin());
4375 newConn->alloc(getNodalConnectivityArrayLen()-delta,1);
4376 newConnI->alloc(nbOfCells+1,1);
4377 int *ocptr(newConn->getPointer()),*ociptr(newConnI->getPointer());
4380 for(int i=0;i<nbOfCells;i++,ociptr++)
4382 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)icptr[iciptr[i]];
4383 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4384 if(!cm.isQuadratic())
4386 _types.insert(type);
4387 ocptr=std::copy(icptr+iciptr[i],icptr+iciptr[i+1],ocptr);
4388 ociptr[1]=ociptr[0]+iciptr[i+1]-iciptr[i];
4392 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4393 _types.insert(typel);
4394 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4395 int newNbOfNodes=cml.getNumberOfNodes();
4397 newNbOfNodes=(iciptr[i+1]-iciptr[i]-1)/2;
4398 *ocptr++=(int)typel;
4399 ocptr=std::copy(icptr+iciptr[i]+1,icptr+iciptr[i]+newNbOfNodes+1,ocptr);
4400 ociptr[1]=ociptr[0]+newNbOfNodes+1;
4403 setConnectivity(newConn,newConnI,false);
4407 * This method converts all linear cell in \a this to quadratic one.
4408 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, here it is needed to specify the target
4409 * 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)
4410 * 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.
4411 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, the coordinates in \a this can be become bigger. All created nodes will be put at the
4412 * end of the existing coordinates.
4414 * \param [in] conversionType specifies the type of conversion expected. Only 0 (default) and 1 are supported presently. 0 those that creates the 'most' simple
4415 * corresponding quadratic cells. 1 is those creating the 'most' complex.
4416 * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
4418 * \throw if \a this is not fully defined. It throws too if \a conversionType is not in [0,1].
4420 * \sa MEDCouplingUMesh::convertQuadraticCellsToLinear
4422 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic(int conversionType)
4424 DataArrayInt *conn=0,*connI=0;
4425 DataArrayDouble *coords=0;
4426 std::set<INTERP_KERNEL::NormalizedCellType> types;
4427 checkFullyDefined();
4428 MCAuto<DataArrayInt> ret,connSafe,connISafe;
4429 MCAuto<DataArrayDouble> coordsSafe;
4430 int meshDim=getMeshDimension();
4431 switch(conversionType)
4437 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);
4438 connSafe=conn; connISafe=connI; coordsSafe=coords;
4441 ret=convertLinearCellsToQuadratic2D0(conn,connI,coords,types);
4442 connSafe=conn; connISafe=connI; coordsSafe=coords;
4445 ret=convertLinearCellsToQuadratic3D0(conn,connI,coords,types);
4446 connSafe=conn; connISafe=connI; coordsSafe=coords;
4449 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 0 mesh dimensions available are [1,2,3] !");
4457 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);//it is not a bug. In 1D policy 0 and 1 are equals
4458 connSafe=conn; connISafe=connI; coordsSafe=coords;
4461 ret=convertLinearCellsToQuadratic2D1(conn,connI,coords,types);
4462 connSafe=conn; connISafe=connI; coordsSafe=coords;
4465 ret=convertLinearCellsToQuadratic3D1(conn,connI,coords,types);
4466 connSafe=conn; connISafe=connI; coordsSafe=coords;
4469 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 1 mesh dimensions available are [1,2,3] !");
4474 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion type available are 0 (default, the simplest) and 1 (the most complex) !");
4476 setConnectivity(connSafe,connISafe,false);
4478 setCoords(coordsSafe);
4483 * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
4484 * so that the number of cells remains the same. Quadratic faces are converted to
4485 * polygons. This method works only for 2D meshes in
4486 * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
4487 * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
4488 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
4489 * \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
4490 * a polylinized edge constituting the input polygon.
4491 * \throw If the coordinates array is not set.
4492 * \throw If the nodal connectivity of cells is not defined.
4493 * \throw If \a this->getMeshDimension() != 2.
4494 * \throw If \a this->getSpaceDimension() != 2.
4496 void MEDCouplingUMesh::tessellate2D(double eps)
4498 int meshDim(getMeshDimension()),spaceDim(getSpaceDimension());
4500 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : works only with space dimension equal to 2 !");
4504 return tessellate2DCurveInternal(eps);
4506 return tessellate2DInternal(eps);
4508 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : mesh dimension must be in [1,2] !");
4514 * This method only works if \a this has spaceDimension equal to 2 and meshDimension also equal to 2.
4515 * This method allows to modify connectivity of cells in \a this that shares some edges in \a edgeIdsToBeSplit.
4516 * The nodes to be added in those 2D cells are defined by the pair of \a nodeIdsToAdd and \a nodeIdsIndexToAdd.
4517 * Length of \a nodeIdsIndexToAdd is expected to equal to length of \a edgeIdsToBeSplit + 1.
4518 * The node ids in \a nodeIdsToAdd should be valid. Those nodes have to be sorted exactly following exactly the direction of the edge.
4519 * This method can be seen as the opposite method of colinearize2D.
4520 * This method can be lead to create some new nodes if quadratic polygon cells have to be split. In this case the added nodes will be put at the end
4521 * to avoid to modify the numbering of existing nodes.
4523 * \param [in] nodeIdsToAdd - the list of node ids to be added (\a nodeIdsIndexToAdd array allows to walk on this array)
4524 * \param [in] nodeIdsIndexToAdd - the entry point of \a nodeIdsToAdd to point to the corresponding nodes to be added.
4525 * \param [in] mesh1Desc - 1st output of buildDescendingConnectivity2 on \a this.
4526 * \param [in] desc - 2nd output of buildDescendingConnectivity2 on \a this.
4527 * \param [in] descI - 3rd output of buildDescendingConnectivity2 on \a this.
4528 * \param [in] revDesc - 4th output of buildDescendingConnectivity2 on \a this.
4529 * \param [in] revDescI - 5th output of buildDescendingConnectivity2 on \a this.
4531 * \sa buildDescendingConnectivity2
4533 void MEDCouplingUMesh::splitSomeEdgesOf2DMesh(const DataArrayInt *nodeIdsToAdd, const DataArrayInt *nodeIdsIndexToAdd, const DataArrayInt *edgeIdsToBeSplit,
4534 const MEDCouplingUMesh *mesh1Desc, const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *revDesc, const DataArrayInt *revDescI)
4536 if(!nodeIdsToAdd || !nodeIdsIndexToAdd || !edgeIdsToBeSplit || !mesh1Desc || !desc || !descI || !revDesc || !revDescI)
4537 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : input pointers must be not NULL !");
4538 nodeIdsToAdd->checkAllocated(); nodeIdsIndexToAdd->checkAllocated(); edgeIdsToBeSplit->checkAllocated(); desc->checkAllocated(); descI->checkAllocated(); revDesc->checkAllocated(); revDescI->checkAllocated();
4539 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
4540 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : this must have spacedim=meshdim=2 !");
4541 if(mesh1Desc->getSpaceDimension()!=2 || mesh1Desc->getMeshDimension()!=1)
4542 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : mesh1Desc must be the explosion of this with spaceDim=2 and meshDim = 1 !");
4543 //DataArrayInt *out0(0),*outi0(0);
4544 //MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
4545 //MCAuto<DataArrayInt> out0s(out0),outi0s(outi0);
4546 //out0s=out0s->buildUnique(); out0s->sort(true);
4552 * Divides every cell of \a this mesh into simplices (triangles in 2D and tetrahedra in 3D).
4553 * In addition, returns an array mapping new cells to old ones. <br>
4554 * This method typically increases the number of cells in \a this mesh
4555 * but the number of nodes remains \b unchanged.
4556 * That's why the 3D splitting policies
4557 * INTERP_KERNEL::GENERAL_24 and INTERP_KERNEL::GENERAL_48 are not available here.
4558 * \param [in] policy - specifies a pattern used for splitting.
4559 * The semantic of \a policy is:
4560 * - 0 - to split QUAD4 by cutting it along 0-2 diagonal (for 2D mesh only).
4561 * - 1 - to split QUAD4 by cutting it along 1-3 diagonal (for 2D mesh only).
4562 * - INTERP_KERNEL::PLANAR_FACE_5 - to split HEXA8 into 5 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4563 * - INTERP_KERNEL::PLANAR_FACE_6 - to split HEXA8 into 6 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4566 * \return DataArrayInt * - a new instance of DataArrayInt holding, for each new cell,
4567 * an id of old cell producing it. The caller is to delete this array using
4568 * decrRef() as it is no more needed.
4570 * \throw If \a policy is 0 or 1 and \a this->getMeshDimension() != 2.
4571 * \throw If \a policy is INTERP_KERNEL::PLANAR_FACE_5 or INTERP_KERNEL::PLANAR_FACE_6
4572 * and \a this->getMeshDimension() != 3.
4573 * \throw If \a policy is not one of the four discussed above.
4574 * \throw If the nodal connectivity of cells is not defined.
4575 * \sa MEDCouplingUMesh::tetrahedrize, MEDCoupling1SGTUMesh::sortHexa8EachOther
4577 DataArrayInt *MEDCouplingUMesh::simplexize(int policy)
4582 return simplexizePol0();
4584 return simplexizePol1();
4585 case (int) INTERP_KERNEL::PLANAR_FACE_5:
4586 return simplexizePlanarFace5();
4587 case (int) INTERP_KERNEL::PLANAR_FACE_6:
4588 return simplexizePlanarFace6();
4590 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexize : unrecognized policy ! Must be :\n - 0 or 1 (only available for meshdim=2) \n - PLANAR_FACE_5, PLANAR_FACE_6 (only for meshdim=3)");
4595 * Checks if \a this mesh is constituted by simplex cells only. Simplex cells are:
4596 * - 1D: INTERP_KERNEL::NORM_SEG2
4597 * - 2D: INTERP_KERNEL::NORM_TRI3
4598 * - 3D: INTERP_KERNEL::NORM_TETRA4.
4600 * This method is useful for users that need to use P1 field services as
4601 * MEDCouplingFieldDouble::getValueOn(), MEDCouplingField::buildMeasureField() etc.
4602 * All these methods need mesh support containing only simplex cells.
4603 * \return bool - \c true if there are only simplex cells in \a this mesh.
4604 * \throw If the coordinates array is not set.
4605 * \throw If the nodal connectivity of cells is not defined.
4606 * \throw If \a this->getMeshDimension() < 1.
4608 bool MEDCouplingUMesh::areOnlySimplexCells() const
4610 checkFullyDefined();
4611 int mdim=getMeshDimension();
4612 if(mdim<1 || mdim>3)
4613 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::areOnlySimplexCells : only available with meshes having a meshdim 1, 2 or 3 !");
4614 int nbCells=getNumberOfCells();
4615 const int *conn=_nodal_connec->begin();
4616 const int *connI=_nodal_connec_index->begin();
4617 for(int i=0;i<nbCells;i++)
4619 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4629 * Converts degenerated 2D or 3D linear cells of \a this mesh into cells of simpler
4630 * type. For example an INTERP_KERNEL::NORM_QUAD4 cell having only three unique nodes in
4631 * its connectivity is transformed into an INTERP_KERNEL::NORM_TRI3 cell.
4632 * Quadratic cells in 2D are also handled. In those cells edges where start=end=midpoint are removed.
4633 * This method does \b not perform geometrical checks and checks only nodal connectivity of cells,
4634 * so it can be useful to call mergeNodes() before calling this method.
4635 * \throw If \a this->getMeshDimension() <= 1.
4636 * \throw If the coordinates array is not set.
4637 * \throw If the nodal connectivity of cells is not defined.
4639 void MEDCouplingUMesh::convertDegeneratedCells()
4641 checkFullyDefined();
4642 if(getMeshDimension()<=1)
4643 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4644 int nbOfCells=getNumberOfCells();
4647 int initMeshLgth=getNodalConnectivityArrayLen();
4648 int *conn=_nodal_connec->getPointer();
4649 int *index=_nodal_connec_index->getPointer();
4653 for(int i=0;i<nbOfCells;i++)
4655 lgthOfCurCell=index[i+1]-posOfCurCell;
4656 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4658 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
4659 conn+newPos+1,newLgth);
4660 conn[newPos]=newType;
4662 posOfCurCell=index[i+1];
4665 if(newPos!=initMeshLgth)
4666 _nodal_connec->reAlloc(newPos);
4671 * Same as MEDCouplingUMesh::convertDegeneratedCells() plus deletion of the flat cells.
4672 * A cell is flat in the following cases:
4673 * - for a linear cell, all points in the connectivity are equal
4674 * - for a quadratic cell, either the above, or a quadratic polygon with two (linear) points and two
4675 * identical quadratic points
4676 * \return a new instance of DataArrayInt holding ids of removed cells. The caller is to delete
4677 * this array using decrRef() as it is no more needed.
4679 DataArrayInt *MEDCouplingUMesh::convertDegeneratedCellsAndRemoveFlatOnes()
4681 checkFullyDefined();
4682 if(getMeshDimension()<=1)
4683 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4684 int nbOfCells=getNumberOfCells();
4685 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(0,1);
4688 int initMeshLgth=getNodalConnectivityArrayLen();
4689 int *conn=_nodal_connec->getPointer();
4690 int *index=_nodal_connec_index->getPointer();
4693 int lgthOfCurCell, nbDelCells(0);
4694 for(int i=0;i<nbOfCells;i++)
4696 lgthOfCurCell=index[i+1]-posOfCurCell;
4697 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4699 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
4700 conn+newPos+1,newLgth);
4701 // Shall we delete the cell if it is completely degenerated:
4702 bool delCell=INTERP_KERNEL::CellSimplify::isFlatCell(conn, newPos, newLgth, newType);
4706 ret->pushBackSilent(i);
4708 else //if the cell is to be deleted, simply stay at the same place
4710 conn[newPos]=newType;
4713 posOfCurCell=index[i+1];
4714 index[i+1-nbDelCells]=newPos;
4716 if(newPos!=initMeshLgth)
4717 _nodal_connec->reAlloc(newPos);
4718 const int nCellDel=ret->getNumberOfTuples();
4720 _nodal_connec_index->reAlloc(nbOfCells-nCellDel+1);
4726 * This method remove null 1D cells from \a this. A 1D cell is considered null if start node is equal to end node.
4727 * Only connectivity is considered here.
4729 bool MEDCouplingUMesh::removeDegenerated1DCells()
4731 checkConnectivityFullyDefined();
4732 if(getMeshDimension()!=1)
4733 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::removeDegenerated1DCells works on umeshes with meshdim equals to 1 !");
4734 std::size_t nbCells(getNumberOfCells()),newSize(0),newSize2(0);
4735 const int *conn(getNodalConnectivity()->begin()),*conni(getNodalConnectivityIndex()->begin());
4737 for(std::size_t i=0;i<nbCells;i++)
4739 INTERP_KERNEL::NormalizedCellType ct((INTERP_KERNEL::NormalizedCellType)conn[conni[i]]);
4740 if(ct==INTERP_KERNEL::NORM_SEG2 || ct==INTERP_KERNEL::NORM_SEG3)
4742 if(conn[conni[i]+1]!=conn[conni[i]+2])
4745 newSize2+=conni[i+1]-conni[i];
4750 std::ostringstream oss; oss << "MEDCouplingUMesh::removeDegenerated1DCells : cell #" << i << " in this is not of type SEG2/SEG3 !";
4751 throw INTERP_KERNEL::Exception(oss.str());
4755 if(newSize==nbCells)//no cells has been removed -> do nothing
4757 MCAuto<DataArrayInt> newConn(DataArrayInt::New()),newConnI(DataArrayInt::New()); newConnI->alloc(newSize+1,1); newConn->alloc(newSize2,1);
4758 int *newConnPtr(newConn->getPointer()),*newConnIPtr(newConnI->getPointer()); newConnIPtr[0]=0;
4759 for(std::size_t i=0;i<nbCells;i++)
4761 if(conn[conni[i]+1]!=conn[conni[i]+2])
4763 newConnIPtr[1]=newConnIPtr[0]+conni[i+1]-conni[i];
4764 newConnPtr=std::copy(conn+conni[i],conn+conni[i+1],newConnPtr);
4768 setConnectivity(newConn,newConnI,true);
4773 * Finds incorrectly oriented cells of this 2D mesh in 3D space.
4774 * A cell is considered to be oriented correctly if an angle between its
4775 * normal vector and a given vector is less than \c PI / \c 2.
4776 * \param [in] vec - 3 components of the vector specifying the correct orientation of
4778 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
4780 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
4781 * is not cleared before filling in.
4782 * \throw If \a this->getMeshDimension() != 2.
4783 * \throw If \a this->getSpaceDimension() != 3.
4785 * \if ENABLE_EXAMPLES
4786 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
4787 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
4790 void MEDCouplingUMesh::are2DCellsNotCorrectlyOriented(const double *vec, bool polyOnly, std::vector<int>& cells) const
4792 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
4793 throw INTERP_KERNEL::Exception("Invalid mesh to apply are2DCellsNotCorrectlyOriented on it : must be meshDim==2 and spaceDim==3 !");
4794 int nbOfCells=getNumberOfCells();
4795 const int *conn=_nodal_connec->begin();
4796 const int *connI=_nodal_connec_index->begin();
4797 const double *coordsPtr=_coords->begin();
4798 for(int i=0;i<nbOfCells;i++)
4800 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4801 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
4803 bool isQuadratic=INTERP_KERNEL::CellModel::GetCellModel(type).isQuadratic();
4804 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4811 * Reverse connectivity of 2D cells whose orientation is not correct. A cell is
4812 * considered to be oriented correctly if an angle between its normal vector and a
4813 * given vector is less than \c PI / \c 2.
4814 * \param [in] vec - 3 components of the vector specifying the correct orientation of
4816 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
4818 * \throw If \a this->getMeshDimension() != 2.
4819 * \throw If \a this->getSpaceDimension() != 3.
4821 * \if ENABLE_EXAMPLES
4822 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
4823 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
4826 * \sa changeOrientationOfCells
4828 void MEDCouplingUMesh::orientCorrectly2DCells(const double *vec, bool polyOnly)
4830 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
4831 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectly2DCells on it : must be meshDim==2 and spaceDim==3 !");
4832 int nbOfCells(getNumberOfCells()),*conn(_nodal_connec->getPointer());
4833 const int *connI(_nodal_connec_index->begin());
4834 const double *coordsPtr(_coords->begin());
4835 bool isModified(false);
4836 for(int i=0;i<nbOfCells;i++)
4838 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4839 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
4841 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
4842 bool isQuadratic(cm.isQuadratic());
4843 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4846 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
4851 _nodal_connec->declareAsNew();
4856 * This method change the orientation of cells in \a this without any consideration of coordinates. Only connectivity is impacted.
4858 * \sa orientCorrectly2DCells
4860 void MEDCouplingUMesh::changeOrientationOfCells()
4862 int mdim(getMeshDimension());
4863 if(mdim!=2 && mdim!=1)
4864 throw INTERP_KERNEL::Exception("Invalid mesh to apply changeOrientationOfCells on it : must be meshDim==2 or meshDim==1 !");
4865 int nbOfCells(getNumberOfCells()),*conn(_nodal_connec->getPointer());
4866 const int *connI(_nodal_connec_index->begin());
4869 for(int i=0;i<nbOfCells;i++)
4871 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4872 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
4873 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
4878 for(int i=0;i<nbOfCells;i++)
4880 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4881 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
4882 cm.changeOrientationOf1D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
4888 * Finds incorrectly oriented polyhedral cells, i.e. polyhedrons having correctly
4889 * oriented facets. The normal vector of the facet should point out of the cell.
4890 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
4891 * is not cleared before filling in.
4892 * \throw If \a this->getMeshDimension() != 3.
4893 * \throw If \a this->getSpaceDimension() != 3.
4894 * \throw If the coordinates array is not set.
4895 * \throw If the nodal connectivity of cells is not defined.
4897 * \if ENABLE_EXAMPLES
4898 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
4899 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
4902 void MEDCouplingUMesh::arePolyhedronsNotCorrectlyOriented(std::vector<int>& cells) const
4904 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
4905 throw INTERP_KERNEL::Exception("Invalid mesh to apply arePolyhedronsNotCorrectlyOriented on it : must be meshDim==3 and spaceDim==3 !");
4906 int nbOfCells=getNumberOfCells();
4907 const int *conn=_nodal_connec->begin();
4908 const int *connI=_nodal_connec_index->begin();
4909 const double *coordsPtr=_coords->begin();
4910 for(int i=0;i<nbOfCells;i++)
4912 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4913 if(type==INTERP_KERNEL::NORM_POLYHED)
4915 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4922 * Tries to fix connectivity of polyhedra, so that normal vector of all facets to point
4924 * \throw If \a this->getMeshDimension() != 3.
4925 * \throw If \a this->getSpaceDimension() != 3.
4926 * \throw If the coordinates array is not set.
4927 * \throw If the nodal connectivity of cells is not defined.
4928 * \throw If the reparation fails.
4930 * \if ENABLE_EXAMPLES
4931 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
4932 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
4934 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
4936 void MEDCouplingUMesh::orientCorrectlyPolyhedrons()
4938 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
4939 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectlyPolyhedrons on it : must be meshDim==3 and spaceDim==3 !");
4940 int nbOfCells=getNumberOfCells();
4941 int *conn=_nodal_connec->getPointer();
4942 const int *connI=_nodal_connec_index->begin();
4943 const double *coordsPtr=_coords->begin();
4944 for(int i=0;i<nbOfCells;i++)
4946 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4947 if(type==INTERP_KERNEL::NORM_POLYHED)
4951 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4952 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
4954 catch(INTERP_KERNEL::Exception& e)
4956 std::ostringstream oss; oss << "Something wrong in polyhedron #" << i << " : " << e.what();
4957 throw INTERP_KERNEL::Exception(oss.str());
4965 * This method invert orientation of all cells in \a this.
4966 * After calling this method the absolute value of measure of cells in \a this are the same than before calling.
4967 * This method only operates on the connectivity so coordinates are not touched at all.
4969 void MEDCouplingUMesh::invertOrientationOfAllCells()
4971 checkConnectivityFullyDefined();
4972 std::set<INTERP_KERNEL::NormalizedCellType> gts(getAllGeoTypes());
4973 int *conn(_nodal_connec->getPointer());
4974 const int *conni(_nodal_connec_index->begin());
4975 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator gt=gts.begin();gt!=gts.end();gt++)
4977 INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::OrientationInverter> oi(INTERP_KERNEL::OrientationInverter::BuildInstanceFrom(*gt));
4978 MCAuto<DataArrayInt> cwt(giveCellsWithType(*gt));
4979 for(const int *it=cwt->begin();it!=cwt->end();it++)
4980 oi->operate(conn+conni[*it]+1,conn+conni[*it+1]);
4986 * Finds and fixes incorrectly oriented linear extruded volumes (INTERP_KERNEL::NORM_HEXA8,
4987 * INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXGP12 etc) to respect the MED convention
4988 * according to which the first facet of the cell should be oriented to have the normal vector
4989 * pointing out of cell.
4990 * \return DataArrayInt * - a new instance of DataArrayInt holding ids of fixed
4991 * cells. The caller is to delete this array using decrRef() as it is no more
4993 * \throw If \a this->getMeshDimension() != 3.
4994 * \throw If \a this->getSpaceDimension() != 3.
4995 * \throw If the coordinates array is not set.
4996 * \throw If the nodal connectivity of cells is not defined.
4998 * \if ENABLE_EXAMPLES
4999 * \ref cpp_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a C++ example".<br>
5000 * \ref py_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a Python example".
5002 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
5004 DataArrayInt *MEDCouplingUMesh::findAndCorrectBadOriented3DExtrudedCells()
5006 const char msg[]="check3DCellsWellOriented detection works only for 3D cells !";
5007 if(getMeshDimension()!=3)
5008 throw INTERP_KERNEL::Exception(msg);
5009 int spaceDim=getSpaceDimension();
5011 throw INTERP_KERNEL::Exception(msg);
5013 int nbOfCells=getNumberOfCells();
5014 int *conn=_nodal_connec->getPointer();
5015 const int *connI=_nodal_connec_index->begin();
5016 const double *coo=getCoords()->begin();
5017 MCAuto<DataArrayInt> cells(DataArrayInt::New()); cells->alloc(0,1);
5018 for(int i=0;i<nbOfCells;i++)
5020 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5021 if(cm.isExtruded() && !cm.isDynamic() && !cm.isQuadratic())
5023 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coo))
5025 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
5026 cells->pushBackSilent(i);
5030 return cells.retn();
5034 * This method is a faster method to correct orientation of all 3D cells in \a this.
5035 * 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.
5036 * This method makes the hypothesis that \a this a coherent that is to say MEDCouplingUMesh::checkConsistency should throw no exception.
5038 * \return a newly allocated int array with one components containing cell ids renumbered to fit the convention of MED (MED file and MEDCoupling)
5039 * \sa MEDCouplingUMesh::orientCorrectlyPolyhedrons,
5041 DataArrayInt *MEDCouplingUMesh::findAndCorrectBadOriented3DCells()
5043 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
5044 throw INTERP_KERNEL::Exception("Invalid mesh to apply findAndCorrectBadOriented3DCells on it : must be meshDim==3 and spaceDim==3 !");
5045 int nbOfCells=getNumberOfCells();
5046 int *conn=_nodal_connec->getPointer();
5047 const int *connI=_nodal_connec_index->begin();
5048 const double *coordsPtr=_coords->begin();
5049 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
5050 for(int i=0;i<nbOfCells;i++)
5052 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5055 case INTERP_KERNEL::NORM_TETRA4:
5057 if(!IsTetra4WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5059 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+3));
5060 ret->pushBackSilent(i);
5064 case INTERP_KERNEL::NORM_PYRA5:
5066 if(!IsPyra5WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5068 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+4));
5069 ret->pushBackSilent(i);
5073 case INTERP_KERNEL::NORM_PENTA6:
5074 case INTERP_KERNEL::NORM_HEXA8:
5075 case INTERP_KERNEL::NORM_HEXGP12:
5077 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5079 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
5080 ret->pushBackSilent(i);
5084 case INTERP_KERNEL::NORM_POLYHED:
5086 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5088 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
5089 ret->pushBackSilent(i);
5094 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 !");
5102 * This method has a sense for meshes with spaceDim==3 and meshDim==2.
5103 * If it is not the case an exception will be thrown.
5104 * This method is fast because the first cell of \a this is used to compute the plane.
5105 * \param vec output of size at least 3 used to store the normal vector (with norm equal to Area ) of searched plane.
5106 * \param pos output of size at least 3 used to store a point owned of searched plane.
5108 void MEDCouplingUMesh::getFastAveragePlaneOfThis(double *vec, double *pos) const
5110 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
5111 throw INTERP_KERNEL::Exception("Invalid mesh to apply getFastAveragePlaneOfThis on it : must be meshDim==2 and spaceDim==3 !");
5112 const int *conn=_nodal_connec->begin();
5113 const int *connI=_nodal_connec_index->begin();
5114 const double *coordsPtr=_coords->begin();
5115 INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(conn+1,connI[1]-connI[0]-1,coordsPtr,vec);
5116 std::copy(coordsPtr+3*conn[1],coordsPtr+3*conn[1]+3,pos);
5120 * Creates a new MEDCouplingFieldDouble holding Edge Ratio values of all
5121 * cells. Currently cells of the following types are treated:
5122 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5123 * For a cell of other type an exception is thrown.
5124 * Space dimension of a 2D mesh can be either 2 or 3.
5125 * The Edge Ratio of a cell \f$t\f$ is:
5126 * \f$\frac{|t|_\infty}{|t|_0}\f$,
5127 * where \f$|t|_\infty\f$ and \f$|t|_0\f$ respectively denote the greatest and
5128 * the smallest edge lengths of \f$t\f$.
5129 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5130 * cells and one time, lying on \a this mesh. The caller is to delete this
5131 * field using decrRef() as it is no more needed.
5132 * \throw If the coordinates array is not set.
5133 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5134 * \throw If the connectivity data array has more than one component.
5135 * \throw If the connectivity data array has a named component.
5136 * \throw If the connectivity index data array has more than one component.
5137 * \throw If the connectivity index data array has a named component.
5138 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
5139 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5140 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5142 MEDCouplingFieldDouble *MEDCouplingUMesh::getEdgeRatioField() const
5144 checkConsistencyLight();
5145 int spaceDim=getSpaceDimension();
5146 int meshDim=getMeshDimension();
5147 if(spaceDim!=2 && spaceDim!=3)
5148 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : SpaceDimension must be equal to 2 or 3 !");
5149 if(meshDim!=2 && meshDim!=3)
5150 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : MeshDimension must be equal to 2 or 3 !");
5151 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5153 int nbOfCells=getNumberOfCells();
5154 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5155 arr->alloc(nbOfCells,1);
5156 double *pt=arr->getPointer();
5157 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5158 const int *conn=_nodal_connec->begin();
5159 const int *connI=_nodal_connec_index->begin();
5160 const double *coo=_coords->begin();
5162 for(int i=0;i<nbOfCells;i++,pt++)
5164 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5167 case INTERP_KERNEL::NORM_TRI3:
5169 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5170 *pt=INTERP_KERNEL::triEdgeRatio(tmp);
5173 case INTERP_KERNEL::NORM_QUAD4:
5175 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5176 *pt=INTERP_KERNEL::quadEdgeRatio(tmp);
5179 case INTERP_KERNEL::NORM_TETRA4:
5181 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5182 *pt=INTERP_KERNEL::tetraEdgeRatio(tmp);
5186 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5188 conn+=connI[i+1]-connI[i];
5190 ret->setName("EdgeRatio");
5191 ret->synchronizeTimeWithSupport();
5196 * Creates a new MEDCouplingFieldDouble holding Aspect Ratio values of all
5197 * cells. Currently cells of the following types are treated:
5198 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5199 * For a cell of other type an exception is thrown.
5200 * Space dimension of a 2D mesh can be either 2 or 3.
5201 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5202 * cells and one time, lying on \a this mesh. The caller is to delete this
5203 * field using decrRef() as it is no more needed.
5204 * \throw If the coordinates array is not set.
5205 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5206 * \throw If the connectivity data array has more than one component.
5207 * \throw If the connectivity data array has a named component.
5208 * \throw If the connectivity index data array has more than one component.
5209 * \throw If the connectivity index data array has a named component.
5210 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
5211 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5212 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5214 MEDCouplingFieldDouble *MEDCouplingUMesh::getAspectRatioField() const
5216 checkConsistencyLight();
5217 int spaceDim=getSpaceDimension();
5218 int meshDim=getMeshDimension();
5219 if(spaceDim!=2 && spaceDim!=3)
5220 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : SpaceDimension must be equal to 2 or 3 !");
5221 if(meshDim!=2 && meshDim!=3)
5222 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : MeshDimension must be equal to 2 or 3 !");
5223 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5225 int nbOfCells=getNumberOfCells();
5226 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5227 arr->alloc(nbOfCells,1);
5228 double *pt=arr->getPointer();
5229 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5230 const int *conn=_nodal_connec->begin();
5231 const int *connI=_nodal_connec_index->begin();
5232 const double *coo=_coords->begin();
5234 for(int i=0;i<nbOfCells;i++,pt++)
5236 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5239 case INTERP_KERNEL::NORM_TRI3:
5241 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5242 *pt=INTERP_KERNEL::triAspectRatio(tmp);
5245 case INTERP_KERNEL::NORM_QUAD4:
5247 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5248 *pt=INTERP_KERNEL::quadAspectRatio(tmp);
5251 case INTERP_KERNEL::NORM_TETRA4:
5253 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5254 *pt=INTERP_KERNEL::tetraAspectRatio(tmp);
5258 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5260 conn+=connI[i+1]-connI[i];
5262 ret->setName("AspectRatio");
5263 ret->synchronizeTimeWithSupport();
5268 * Creates a new MEDCouplingFieldDouble holding Warping factor values of all
5269 * cells of \a this 2D mesh in 3D space. It is a measure of the "planarity" of 2D cell
5270 * in 3D space. Currently only cells of the following types are
5271 * treated: INTERP_KERNEL::NORM_QUAD4.
5272 * For a cell of other type an exception is thrown.
5273 * The warp field is computed as follows: let (a,b,c,d) be the points of the quad.
5275 * \f$t=\vec{da}\times\vec{ab}\f$,
5276 * \f$u=\vec{ab}\times\vec{bc}\f$
5277 * \f$v=\vec{bc}\times\vec{cd}\f$
5278 * \f$w=\vec{cd}\times\vec{da}\f$, the warp is defined as \f$W^3\f$ with
5280 * W=min(\frac{t}{|t|}\cdot\frac{v}{|v|}, \frac{u}{|u|}\cdot\frac{w}{|w|})
5282 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5283 * cells and one time, lying on \a this mesh. The caller is to delete this
5284 * field using decrRef() as it is no more needed.
5285 * \throw If the coordinates array is not set.
5286 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5287 * \throw If the connectivity data array has more than one component.
5288 * \throw If the connectivity data array has a named component.
5289 * \throw If the connectivity index data array has more than one component.
5290 * \throw If the connectivity index data array has a named component.
5291 * \throw If \a this->getMeshDimension() != 2.
5292 * \throw If \a this->getSpaceDimension() != 3.
5293 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5295 MEDCouplingFieldDouble *MEDCouplingUMesh::getWarpField() const
5297 checkConsistencyLight();
5298 int spaceDim=getSpaceDimension();
5299 int meshDim=getMeshDimension();
5301 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : SpaceDimension must be equal to 3 !");
5303 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : MeshDimension must be equal to 2 !");
5304 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5306 int nbOfCells=getNumberOfCells();
5307 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5308 arr->alloc(nbOfCells,1);
5309 double *pt=arr->getPointer();
5310 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5311 const int *conn=_nodal_connec->begin();
5312 const int *connI=_nodal_connec_index->begin();
5313 const double *coo=_coords->begin();
5315 for(int i=0;i<nbOfCells;i++,pt++)
5317 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5320 case INTERP_KERNEL::NORM_QUAD4:
5322 FillInCompact3DMode(3,4,conn+1,coo,tmp);
5323 *pt=INTERP_KERNEL::quadWarp(tmp);
5327 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : A cell with not manged type (NORM_QUAD4) has been detected !");
5329 conn+=connI[i+1]-connI[i];
5331 ret->setName("Warp");
5332 ret->synchronizeTimeWithSupport();
5338 * Creates a new MEDCouplingFieldDouble holding Skew factor values of all
5339 * cells of \a this 2D mesh in 3D space. Currently cells of the following types are
5340 * treated: INTERP_KERNEL::NORM_QUAD4.
5341 * The skew is computed as follow for a quad with points (a,b,c,d): let
5342 * \f$u=\vec{ab}+\vec{dc}\f$ and \f$v=\vec{ac}+\vec{bd}\f$
5343 * then the skew is computed as:
5345 * s=\frac{u}{|u|}\cdot\frac{v}{|v|}
5348 * For a cell of other type an exception is thrown.
5349 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5350 * cells and one time, lying on \a this mesh. The caller is to delete this
5351 * field using decrRef() as it is no more needed.
5352 * \throw If the coordinates array is not set.
5353 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5354 * \throw If the connectivity data array has more than one component.
5355 * \throw If the connectivity data array has a named component.
5356 * \throw If the connectivity index data array has more than one component.
5357 * \throw If the connectivity index data array has a named component.
5358 * \throw If \a this->getMeshDimension() != 2.
5359 * \throw If \a this->getSpaceDimension() != 3.
5360 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5362 MEDCouplingFieldDouble *MEDCouplingUMesh::getSkewField() const
5364 checkConsistencyLight();
5365 int spaceDim=getSpaceDimension();
5366 int meshDim=getMeshDimension();
5368 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : SpaceDimension must be equal to 3 !");
5370 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : MeshDimension must be equal to 2 !");
5371 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5373 int nbOfCells=getNumberOfCells();
5374 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5375 arr->alloc(nbOfCells,1);
5376 double *pt=arr->getPointer();
5377 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5378 const int *conn=_nodal_connec->begin();
5379 const int *connI=_nodal_connec_index->begin();
5380 const double *coo=_coords->begin();
5382 for(int i=0;i<nbOfCells;i++,pt++)
5384 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5387 case INTERP_KERNEL::NORM_QUAD4:
5389 FillInCompact3DMode(3,4,conn+1,coo,tmp);
5390 *pt=INTERP_KERNEL::quadSkew(tmp);
5394 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : A cell with not manged type (NORM_QUAD4) has been detected !");
5396 conn+=connI[i+1]-connI[i];
5398 ret->setName("Skew");
5399 ret->synchronizeTimeWithSupport();
5404 * 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.
5406 * \return a new instance of field containing the result. The returned instance has to be deallocated by the caller.
5408 * \sa getSkewField, getWarpField, getAspectRatioField, getEdgeRatioField
5410 MEDCouplingFieldDouble *MEDCouplingUMesh::computeDiameterField() const
5412 checkConsistencyLight();
5413 MCAuto<MEDCouplingFieldDouble> ret(MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME));
5415 std::set<INTERP_KERNEL::NormalizedCellType> types;
5416 ComputeAllTypesInternal(types,_nodal_connec,_nodal_connec_index);
5417 int spaceDim(getSpaceDimension()),nbCells(getNumberOfCells());
5418 MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
5419 arr->alloc(nbCells,1);
5420 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++)
5422 INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::DiameterCalculator> dc(INTERP_KERNEL::CellModel::GetCellModel(*it).buildInstanceOfDiameterCalulator(spaceDim));
5423 MCAuto<DataArrayInt> cellIds(giveCellsWithType(*it));
5424 dc->computeForListOfCellIdsUMeshFrmt(cellIds->begin(),cellIds->end(),_nodal_connec_index->begin(),_nodal_connec->begin(),getCoords()->begin(),arr->getPointer());
5427 ret->setName("Diameter");
5432 * This method aggregate the bbox of each cell and put it into bbox parameter (xmin,xmax,ymin,ymax,zmin,zmax).
5434 * \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)
5435 * For all other cases this input parameter is ignored.
5436 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5438 * \throw If \a this is not fully set (coordinates and connectivity).
5439 * \throw If a cell in \a this has no valid nodeId.
5440 * \sa MEDCouplingUMesh::getBoundingBoxForBBTreeFast, MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5442 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree(double arcDetEps) const
5444 int mDim(getMeshDimension()),sDim(getSpaceDimension());
5445 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.
5446 return getBoundingBoxForBBTreeFast();
5447 if((mDim==2 && sDim==2) || (mDim==1 && sDim==2))
5449 bool presenceOfQuadratic(false);
5450 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=_types.begin();it!=_types.end();it++)
5452 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(*it));
5453 if(cm.isQuadratic())
5454 presenceOfQuadratic=true;
5456 if(!presenceOfQuadratic)
5457 return getBoundingBoxForBBTreeFast();
5458 if(mDim==2 && sDim==2)
5459 return getBoundingBoxForBBTree2DQuadratic(arcDetEps);
5461 return getBoundingBoxForBBTree1DQuadratic(arcDetEps);
5463 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) !");
5467 * This method aggregate the bbox of each cell only considering the nodes constituting each cell and put it into bbox parameter.
5468 * So meshes having quadratic cells the computed bounding boxes can be invalid !
5470 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5472 * \throw If \a this is not fully set (coordinates and connectivity).
5473 * \throw If a cell in \a this has no valid nodeId.
5475 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTreeFast() const
5477 checkFullyDefined();
5478 int spaceDim(getSpaceDimension()),nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
5479 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5480 double *bbox(ret->getPointer());
5481 for(int i=0;i<nbOfCells*spaceDim;i++)
5483 bbox[2*i]=std::numeric_limits<double>::max();
5484 bbox[2*i+1]=-std::numeric_limits<double>::max();
5486 const double *coordsPtr(_coords->begin());
5487 const int *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5488 for(int i=0;i<nbOfCells;i++)
5490 int offset=connI[i]+1;
5491 int nbOfNodesForCell(connI[i+1]-offset),kk(0);
5492 for(int j=0;j<nbOfNodesForCell;j++)
5494 int nodeId=conn[offset+j];
5495 if(nodeId>=0 && nodeId<nbOfNodes)
5497 for(int k=0;k<spaceDim;k++)
5499 bbox[2*spaceDim*i+2*k]=std::min(bbox[2*spaceDim*i+2*k],coordsPtr[spaceDim*nodeId+k]);
5500 bbox[2*spaceDim*i+2*k+1]=std::max(bbox[2*spaceDim*i+2*k+1],coordsPtr[spaceDim*nodeId+k]);
5507 std::ostringstream oss; oss << "MEDCouplingUMesh::getBoundingBoxForBBTree : cell #" << i << " contains no valid nodeId !";
5508 throw INTERP_KERNEL::Exception(oss.str());
5515 * This method aggregates the bbox of each 2D cell in \a this considering the whole shape. This method is particularly
5516 * useful for 2D meshes having quadratic cells
5517 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5518 * the two extremities of the arc of circle).
5520 * \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)
5521 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5522 * \throw If \a this is not fully defined.
5523 * \throw If \a this is not a mesh with meshDimension equal to 2.
5524 * \throw If \a this is not a mesh with spaceDimension equal to 2.
5525 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic
5527 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic(double arcDetEps) const
5529 checkFullyDefined();
5530 INTERP_KERNEL::QuadraticPlanarPrecision arcPrec(arcDetEps);
5532 int spaceDim(getSpaceDimension()),mDim(getMeshDimension()),nbOfCells(getNumberOfCells());
5533 if(spaceDim!=2 || mDim!=2)
5534 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!");
5535 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5536 double *bbox(ret->getPointer());
5537 const double *coords(_coords->begin());
5538 const int *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5539 for(int i=0;i<nbOfCells;i++,bbox+=4,connI++)
5541 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5542 int sz(connI[1]-connI[0]-1);
5543 std::vector<INTERP_KERNEL::Node *> nodes(sz);
5544 INTERP_KERNEL::QuadraticPolygon *pol(0);
5545 for(int j=0;j<sz;j++)
5547 int nodeId(conn[*connI+1+j]);
5548 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5550 if(!cm.isQuadratic())
5551 pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
5553 pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
5554 INTERP_KERNEL::Bounds b; b.prepareForAggregation(); pol->fillBounds(b); delete pol;
5555 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax();
5561 * This method aggregates the bbox of each 1D cell in \a this considering the whole shape. This method is particularly
5562 * useful for 2D meshes having quadratic cells
5563 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5564 * the two extremities of the arc of circle).
5566 * \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)
5567 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5568 * \throw If \a this is not fully defined.
5569 * \throw If \a this is not a mesh with meshDimension equal to 1.
5570 * \throw If \a this is not a mesh with spaceDimension equal to 2.
5571 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5573 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic(double arcDetEps) const
5575 checkFullyDefined();
5576 int spaceDim(getSpaceDimension()),mDim(getMeshDimension()),nbOfCells(getNumberOfCells());
5577 if(spaceDim!=2 || mDim!=1)
5578 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!");
5579 INTERP_KERNEL::QuadraticPlanarPrecision arcPrec(arcDetEps);
5580 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5581 double *bbox(ret->getPointer());
5582 const double *coords(_coords->begin());
5583 const int *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5584 for(int i=0;i<nbOfCells;i++,bbox+=4,connI++)
5586 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5587 int sz(connI[1]-connI[0]-1);
5588 std::vector<INTERP_KERNEL::Node *> nodes(sz);
5589 INTERP_KERNEL::Edge *edge(0);
5590 for(int j=0;j<sz;j++)
5592 int nodeId(conn[*connI+1+j]);
5593 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5595 if(!cm.isQuadratic())
5596 edge=INTERP_KERNEL::QuadraticPolygon::BuildLinearEdge(nodes);
5598 edge=INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(nodes);
5599 const INTERP_KERNEL::Bounds& b(edge->getBounds());
5600 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax(); edge->decrRef();
5607 namespace MEDCouplingImpl
5612 ConnReader(const int *c, int val):_conn(c),_val(val) { }
5613 bool operator() (const int& pos) { return _conn[pos]!=_val; }
5622 ConnReader2(const int *c, int val):_conn(c),_val(val) { }
5623 bool operator() (const int& pos) { return _conn[pos]==_val; }
5633 * This method expects that \a this is sorted by types. If not an exception will be thrown.
5634 * This method returns in the same format as code (see MEDCouplingUMesh::checkTypeConsistencyAndContig or MEDCouplingUMesh::splitProfilePerType) how
5635 * \a this is composed in cell types.
5636 * The returned array is of size 3*n where n is the number of different types present in \a this.
5637 * For every k in [0,n] ret[3*k+2]==-1 because it has no sense here.
5638 * This parameter is kept only for compatibility with other method listed above.
5640 std::vector<int> MEDCouplingUMesh::getDistributionOfTypes() const
5642 checkConnectivityFullyDefined();
5643 const int *conn=_nodal_connec->begin();
5644 const int *connI=_nodal_connec_index->begin();
5645 const int *work=connI;
5646 int nbOfCells=getNumberOfCells();
5647 std::size_t n=getAllGeoTypes().size();
5648 std::vector<int> ret(3*n,-1); //ret[3*k+2]==-1 because it has no sense here
5649 std::set<INTERP_KERNEL::NormalizedCellType> types;
5650 for(std::size_t i=0;work!=connI+nbOfCells;i++)
5652 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn[*work];
5653 if(types.find(typ)!=types.end())
5655 std::ostringstream oss; oss << "MEDCouplingUMesh::getDistributionOfTypes : Type " << INTERP_KERNEL::CellModel::GetCellModel(typ).getRepr();
5656 oss << " is not contiguous !";
5657 throw INTERP_KERNEL::Exception(oss.str());
5661 const int *work2=std::find_if(work+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,typ));
5662 ret[3*i+1]=(int)std::distance(work,work2);
5669 * This method is used to check that this has contiguous cell type in same order than described in \a code.
5670 * only for types cell, type node is not managed.
5671 * Format of \a code is the following. \a code should be of size 3*n and non empty. If not an exception is thrown.
5672 * foreach k in [0,n) on 3*k pos represent the geometric type and 3*k+1 number of elements of type 3*k.
5673 * 3*k+2 refers if different from -1 the pos in 'idsPerType' to get the corresponding array.
5674 * If 2 or more same geometric type is in \a code and exception is thrown too.
5676 * This method firstly checks
5677 * If it exists k so that 3*k geometric type is not in geometric types of this an exception will be thrown.
5678 * If it exists k so that 3*k geometric type exists but the number of consecutive cell types does not match,
5679 * an exception is thrown too.
5681 * If all geometric types in \a code are exactly those in \a this null pointer is returned.
5682 * If it exists a geometric type in \a this \b not in \a code \b no exception is thrown
5683 * and a DataArrayInt instance is returned that the user has the responsibility to deallocate.
5685 DataArrayInt *MEDCouplingUMesh::checkTypeConsistencyAndContig(const std::vector<int>& code, const std::vector<const DataArrayInt *>& idsPerType) const
5688 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code is empty, should not !");
5689 std::size_t sz=code.size();
5692 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code size is NOT %3 !");
5693 std::vector<INTERP_KERNEL::NormalizedCellType> types;
5695 bool isNoPflUsed=true;
5696 for(std::size_t i=0;i<n;i++)
5697 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)code[3*i])==types.end())
5699 types.push_back((INTERP_KERNEL::NormalizedCellType)code[3*i]);
5701 if(_types.find((INTERP_KERNEL::NormalizedCellType)code[3*i])==_types.end())
5702 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : expected geo types not in this !");
5703 isNoPflUsed=isNoPflUsed && (code[3*i+2]==-1);
5706 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code contains duplication of types in unstructured mesh !");
5709 if(!checkConsecutiveCellTypesAndOrder(&types[0],&types[0]+types.size()))
5710 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : non contiguous type !");
5711 if(types.size()==_types.size())
5714 MCAuto<DataArrayInt> ret=DataArrayInt::New();
5716 int *retPtr=ret->getPointer();
5717 const int *connI=_nodal_connec_index->begin();
5718 const int *conn=_nodal_connec->begin();
5719 int nbOfCells=getNumberOfCells();
5722 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++,kk++)
5724 i=std::find_if(i,connI+nbOfCells,MEDCouplingImpl::ConnReader2(conn,(int)(*it)));
5725 int offset=(int)std::distance(connI,i);
5726 const int *j=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)(*it)));
5727 int nbOfCellsOfCurType=(int)std::distance(i,j);
5728 if(code[3*kk+2]==-1)
5729 for(int k=0;k<nbOfCellsOfCurType;k++)
5733 int idInIdsPerType=code[3*kk+2];
5734 if(idInIdsPerType>=0 && idInIdsPerType<(int)idsPerType.size())
5736 const DataArrayInt *zePfl=idsPerType[idInIdsPerType];
5739 zePfl->checkAllocated();
5740 if(zePfl->getNumberOfComponents()==1)
5742 for(const int *k=zePfl->begin();k!=zePfl->end();k++,retPtr++)
5744 if(*k>=0 && *k<nbOfCellsOfCurType)
5745 *retPtr=(*k)+offset;
5748 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : the section " << kk << " points to the profile #" << idInIdsPerType;
5749 oss << ", and this profile contains a value " << *k << " should be in [0," << nbOfCellsOfCurType << ") !";
5750 throw INTERP_KERNEL::Exception(oss.str());
5755 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of a profile with nb of compo != 1 !");
5758 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of null profile !");
5762 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : at section " << kk << " of code it points to the array #" << idInIdsPerType;
5763 oss << " should be in [0," << idsPerType.size() << ") !";
5764 throw INTERP_KERNEL::Exception(oss.str());
5773 * This method makes the hypothesis that \a this is sorted by type. If not an exception will be thrown.
5774 * 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.
5775 * 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.
5776 * This method has 1 input \a profile and 3 outputs \a code \a idsInPflPerType and \a idsPerType.
5778 * \param [in] profile
5779 * \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.
5780 * \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,
5781 * \a idsInPflPerType[i] stores the tuple ids in \a profile that correspond to the geometric type code[3*i+0]
5782 * \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.
5783 * This vector can be empty in case of all geometric type cells are fully covered in ascending in the given input \a profile.
5784 * \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
5786 void MEDCouplingUMesh::splitProfilePerType(const DataArrayInt *profile, std::vector<int>& code, std::vector<DataArrayInt *>& idsInPflPerType, std::vector<DataArrayInt *>& idsPerType, bool smartPflKiller) const
5789 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile is NULL !");
5790 if(profile->getNumberOfComponents()!=1)
5791 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile should have exactly one component !");
5792 checkConnectivityFullyDefined();
5793 const int *conn=_nodal_connec->begin();
5794 const int *connI=_nodal_connec_index->begin();
5795 int nbOfCells=getNumberOfCells();
5796 std::vector<INTERP_KERNEL::NormalizedCellType> types;
5797 std::vector<int> typeRangeVals(1);
5798 for(const int *i=connI;i!=connI+nbOfCells;)
5800 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5801 if(std::find(types.begin(),types.end(),curType)!=types.end())
5803 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : current mesh is not sorted by type !");
5805 types.push_back(curType);
5806 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
5807 typeRangeVals.push_back((int)std::distance(connI,i));
5810 DataArrayInt *castArr=0,*rankInsideCast=0,*castsPresent=0;
5811 profile->splitByValueRange(&typeRangeVals[0],&typeRangeVals[0]+typeRangeVals.size(),castArr,rankInsideCast,castsPresent);
5812 MCAuto<DataArrayInt> tmp0=castArr;
5813 MCAuto<DataArrayInt> tmp1=rankInsideCast;
5814 MCAuto<DataArrayInt> tmp2=castsPresent;
5816 int nbOfCastsFinal=castsPresent->getNumberOfTuples();
5817 code.resize(3*nbOfCastsFinal);
5818 std::vector< MCAuto<DataArrayInt> > idsInPflPerType2;
5819 std::vector< MCAuto<DataArrayInt> > idsPerType2;
5820 for(int i=0;i<nbOfCastsFinal;i++)
5822 int castId=castsPresent->getIJ(i,0);
5823 MCAuto<DataArrayInt> tmp3=castArr->findIdsEqual(castId);
5824 idsInPflPerType2.push_back(tmp3);
5825 code[3*i]=(int)types[castId];
5826 code[3*i+1]=tmp3->getNumberOfTuples();
5827 MCAuto<DataArrayInt> tmp4=rankInsideCast->selectByTupleId(tmp3->begin(),tmp3->begin()+tmp3->getNumberOfTuples());
5828 if(!smartPflKiller || !tmp4->isIota(typeRangeVals[castId+1]-typeRangeVals[castId]))
5830 tmp4->copyStringInfoFrom(*profile);
5831 idsPerType2.push_back(tmp4);
5832 code[3*i+2]=(int)idsPerType2.size()-1;
5839 std::size_t sz2=idsInPflPerType2.size();
5840 idsInPflPerType.resize(sz2);
5841 for(std::size_t i=0;i<sz2;i++)
5843 DataArrayInt *locDa=idsInPflPerType2[i];
5845 idsInPflPerType[i]=locDa;
5847 std::size_t sz=idsPerType2.size();
5848 idsPerType.resize(sz);
5849 for(std::size_t i=0;i<sz;i++)
5851 DataArrayInt *locDa=idsPerType2[i];
5853 idsPerType[i]=locDa;
5858 * This method is here too emulate the MEDMEM behaviour on BDC (buildDescendingConnectivity). Hoping this method becomes deprecated very soon.
5859 * This method make the assumption that \a this and 'nM1LevMesh' mesh lyies on same coords (same pointer) as MED and MEDMEM does.
5860 * The following equality should be verified 'nM1LevMesh->getMeshDimension()==this->getMeshDimension()-1'
5861 * 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.
5863 MEDCouplingUMesh *MEDCouplingUMesh::emulateMEDMEMBDC(const MEDCouplingUMesh *nM1LevMesh, DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *&revDesc, DataArrayInt *&revDescIndx, DataArrayInt *& nM1LevMeshIds, DataArrayInt *&meshnM1Old2New) const
5865 checkFullyDefined();
5866 nM1LevMesh->checkFullyDefined();
5867 if(getMeshDimension()-1!=nM1LevMesh->getMeshDimension())
5868 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : The mesh passed as first argument should have a meshDim equal to this->getMeshDimension()-1 !" );
5869 if(_coords!=nM1LevMesh->getCoords())
5870 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : 'this' and mesh in first argument should share the same coords : Use tryToShareSameCoords method !");
5871 MCAuto<DataArrayInt> tmp0=DataArrayInt::New();
5872 MCAuto<DataArrayInt> tmp1=DataArrayInt::New();
5873 MCAuto<MEDCouplingUMesh> ret1=buildDescendingConnectivity(desc,descIndx,tmp0,tmp1);
5874 MCAuto<DataArrayInt> ret0=ret1->sortCellsInMEDFileFrmt();
5875 desc->transformWithIndArr(ret0->begin(),ret0->begin()+ret0->getNbOfElems());
5876 MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
5877 tmp->setConnectivity(tmp0,tmp1);
5878 tmp->renumberCells(ret0->begin(),false);
5879 revDesc=tmp->getNodalConnectivity();
5880 revDescIndx=tmp->getNodalConnectivityIndex();
5881 DataArrayInt *ret=0;
5882 if(!ret1->areCellsIncludedIn(nM1LevMesh,2,ret))
5885 ret->getMaxValue(tmp2);
5887 std::ostringstream oss; oss << "MEDCouplingUMesh::emulateMEDMEMBDC : input N-1 mesh present a cell not in descending mesh ... Id of cell is " << tmp2 << " !";
5888 throw INTERP_KERNEL::Exception(oss.str());
5893 revDescIndx->incrRef();
5896 meshnM1Old2New=ret0;
5901 * Permutes the nodal connectivity arrays so that the cells are sorted by type, which is
5902 * necessary for writing the mesh to MED file. Additionally returns a permutation array
5903 * in "Old to New" mode.
5904 * \return DataArrayInt * - a new instance of DataArrayInt. The caller is to delete
5905 * this array using decrRef() as it is no more needed.
5906 * \throw If the nodal connectivity of cells is not defined.
5908 DataArrayInt *MEDCouplingUMesh::sortCellsInMEDFileFrmt()
5910 checkConnectivityFullyDefined();
5911 MCAuto<DataArrayInt> ret=getRenumArrForMEDFileFrmt();
5912 renumberCells(ret->begin(),false);
5917 * This methods checks that cells are sorted by their types.
5918 * This method makes asumption (no check) that connectivity is correctly set before calling.
5920 bool MEDCouplingUMesh::checkConsecutiveCellTypes() const
5922 checkFullyDefined();
5923 const int *conn=_nodal_connec->begin();
5924 const int *connI=_nodal_connec_index->begin();
5925 int nbOfCells=getNumberOfCells();
5926 std::set<INTERP_KERNEL::NormalizedCellType> types;
5927 for(const int *i=connI;i!=connI+nbOfCells;)
5929 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5930 if(types.find(curType)!=types.end())
5932 types.insert(curType);
5933 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
5939 * This method is a specialization of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method that is called here.
5940 * The geometric type order is specified by MED file.
5942 * \sa MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder
5944 bool MEDCouplingUMesh::checkConsecutiveCellTypesForMEDFileFrmt() const
5946 return checkConsecutiveCellTypesAndOrder(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
5950 * This method performs the same job as checkConsecutiveCellTypes except that the order of types sequence is analyzed to check
5951 * that the order is specified in array defined by [ \a orderBg , \a orderEnd ).
5952 * If there is some geo types in \a this \b NOT in [ \a orderBg, \a orderEnd ) it is OK (return true) if contiguous.
5953 * If there is some geo types in [ \a orderBg, \a orderEnd ) \b NOT in \a this it is OK too (return true) if contiguous.
5955 bool MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
5957 checkFullyDefined();
5958 const int *conn=_nodal_connec->begin();
5959 const int *connI=_nodal_connec_index->begin();
5960 int nbOfCells=getNumberOfCells();
5964 std::set<INTERP_KERNEL::NormalizedCellType> sg;
5965 for(const int *i=connI;i!=connI+nbOfCells;)
5967 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5968 const INTERP_KERNEL::NormalizedCellType *isTypeExists=std::find(orderBg,orderEnd,curType);
5969 if(isTypeExists!=orderEnd)
5971 int pos=(int)std::distance(orderBg,isTypeExists);
5975 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
5979 if(sg.find(curType)==sg.end())
5981 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
5992 * This method returns 2 newly allocated DataArrayInt instances. The first is an array of size 'this->getNumberOfCells()' with one component,
5993 * 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
5994 * number of tuples than input type array and with one component. This 2nd output array gives type by type the number of occurrence of type in 'this'.
5996 DataArrayInt *MEDCouplingUMesh::getLevArrPerCellTypes(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd, DataArrayInt *&nbPerType) const
5998 checkConnectivityFullyDefined();
5999 int nbOfCells=getNumberOfCells();
6000 const int *conn=_nodal_connec->begin();
6001 const int *connI=_nodal_connec_index->begin();
6002 MCAuto<DataArrayInt> tmpa=DataArrayInt::New();
6003 MCAuto<DataArrayInt> tmpb=DataArrayInt::New();
6004 tmpa->alloc(nbOfCells,1);
6005 tmpb->alloc((int)std::distance(orderBg,orderEnd),1);
6006 tmpb->fillWithZero();
6007 int *tmp=tmpa->getPointer();
6008 int *tmp2=tmpb->getPointer();
6009 for(const int *i=connI;i!=connI+nbOfCells;i++)
6011 const INTERP_KERNEL::NormalizedCellType *where=std::find(orderBg,orderEnd,(INTERP_KERNEL::NormalizedCellType)conn[*i]);
6014 int pos=(int)std::distance(orderBg,where);
6016 tmp[std::distance(connI,i)]=pos;
6020 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*i]);
6021 std::ostringstream oss; oss << "MEDCouplingUMesh::getLevArrPerCellTypes : Cell #" << std::distance(connI,i);
6022 oss << " has a type " << cm.getRepr() << " not in input array of type !";
6023 throw INTERP_KERNEL::Exception(oss.str());
6026 nbPerType=tmpb.retn();
6031 * This method behaves exactly as MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec but the order is those defined in MED file spec.
6033 * \return a new object containing the old to new correspondence.
6035 * \sa MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec, MEDCouplingUMesh::sortCellsInMEDFileFrmt.
6037 DataArrayInt *MEDCouplingUMesh::getRenumArrForMEDFileFrmt() const
6039 return getRenumArrForConsecutiveCellTypesSpec(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
6043 * This method is similar to method MEDCouplingUMesh::rearrange2ConsecutiveCellTypes except that the type order is specified by [ \a orderBg , \a orderEnd ) (as MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method) and that this method is \b const and performs \b NO permutation in \a this.
6044 * This method returns an array of size getNumberOfCells() that gives a renumber array old2New that can be used as input of MEDCouplingMesh::renumberCells.
6045 * The mesh after this call to MEDCouplingMesh::renumberCells will pass the test of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder with the same inputs.
6046 * The returned array minimizes the permutations that is to say the order of cells inside same geometric type remains the same.
6048 DataArrayInt *MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
6050 DataArrayInt *nbPerType=0;
6051 MCAuto<DataArrayInt> tmpa=getLevArrPerCellTypes(orderBg,orderEnd,nbPerType);
6052 nbPerType->decrRef();
6053 return tmpa->buildPermArrPerLevel();
6057 * This method reorganize the cells of \a this so that the cells with same geometric types are put together.
6058 * The number of cells remains unchanged after the call of this method.
6059 * This method tries to minimizes the number of needed permutations. So, this method behaves not exactly as
6060 * MEDCouplingUMesh::sortCellsInMEDFileFrmt.
6062 * \return the array giving the correspondence old to new.
6064 DataArrayInt *MEDCouplingUMesh::rearrange2ConsecutiveCellTypes()
6066 checkFullyDefined();
6068 const int *conn=_nodal_connec->begin();
6069 const int *connI=_nodal_connec_index->begin();
6070 int nbOfCells=getNumberOfCells();
6071 std::vector<INTERP_KERNEL::NormalizedCellType> types;
6072 for(const int *i=connI;i!=connI+nbOfCells && (types.size()!=_types.size());)
6073 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)conn[*i])==types.end())
6075 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6076 types.push_back(curType);
6077 for(i++;i!=connI+nbOfCells && (INTERP_KERNEL::NormalizedCellType)conn[*i]==curType;i++);
6079 DataArrayInt *ret=DataArrayInt::New();
6080 ret->alloc(nbOfCells,1);
6081 int *retPtr=ret->getPointer();
6082 std::fill(retPtr,retPtr+nbOfCells,-1);
6084 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
6086 for(const int *i=connI;i!=connI+nbOfCells;i++)
6087 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
6088 retPtr[std::distance(connI,i)]=newCellId++;
6090 renumberCells(retPtr,false);
6095 * This method splits \a this into as mush as untructured meshes that consecutive set of same type cells.
6096 * So this method has typically a sense if MEDCouplingUMesh::checkConsecutiveCellTypes has a sense.
6097 * This method makes asumption that connectivity is correctly set before calling.
6099 std::vector<MEDCouplingUMesh *> MEDCouplingUMesh::splitByType() const
6101 checkConnectivityFullyDefined();
6102 const int *conn=_nodal_connec->begin();
6103 const int *connI=_nodal_connec_index->begin();
6104 int nbOfCells=getNumberOfCells();
6105 std::vector<MEDCouplingUMesh *> ret;
6106 for(const int *i=connI;i!=connI+nbOfCells;)
6108 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6109 int beginCellId=(int)std::distance(connI,i);
6110 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
6111 int endCellId=(int)std::distance(connI,i);
6112 int sz=endCellId-beginCellId;
6113 int *cells=new int[sz];
6114 for(int j=0;j<sz;j++)
6115 cells[j]=beginCellId+j;
6116 MEDCouplingUMesh *m=(MEDCouplingUMesh *)buildPartOfMySelf(cells,cells+sz,true);
6124 * This method performs the opposite operation than those in MEDCoupling1SGTUMesh::buildUnstructured.
6125 * If \a this is a single geometric type unstructured mesh, it will be converted into a more compact data structure,
6126 * MEDCoupling1GTUMesh instance. The returned instance will aggregate the same DataArrayDouble instance of coordinates than \a this.
6128 * \return a newly allocated instance, that the caller must manage.
6129 * \throw If \a this contains more than one geometric type.
6130 * \throw If the nodal connectivity of \a this is not fully defined.
6131 * \throw If the internal data is not coherent.
6133 MEDCoupling1GTUMesh *MEDCouplingUMesh::convertIntoSingleGeoTypeMesh() const
6135 checkConnectivityFullyDefined();
6136 if(_types.size()!=1)
6137 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6138 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6139 MCAuto<MEDCoupling1GTUMesh> ret=MEDCoupling1GTUMesh::New(getName(),typ);
6140 ret->setCoords(getCoords());
6141 MEDCoupling1SGTUMesh *retC=dynamic_cast<MEDCoupling1SGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6144 MCAuto<DataArrayInt> c=convertNodalConnectivityToStaticGeoTypeMesh();
6145 retC->setNodalConnectivity(c);
6149 MEDCoupling1DGTUMesh *retD=dynamic_cast<MEDCoupling1DGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6151 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : Internal error !");
6152 DataArrayInt *c=0,*ci=0;
6153 convertNodalConnectivityToDynamicGeoTypeMesh(c,ci);
6154 MCAuto<DataArrayInt> cs(c),cis(ci);
6155 retD->setNodalConnectivity(cs,cis);
6160 DataArrayInt *MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh() const
6162 checkConnectivityFullyDefined();
6163 if(_types.size()!=1)
6164 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6165 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6166 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6169 std::ostringstream oss; oss << "MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : this contains a single geo type (" << cm.getRepr() << ") but ";
6170 oss << "this type is dynamic ! Only static geometric type is possible for that type ! call convertNodalConnectivityToDynamicGeoTypeMesh instead !";
6171 throw INTERP_KERNEL::Exception(oss.str());
6173 int nbCells=getNumberOfCells();
6175 int nbNodesPerCell=(int)cm.getNumberOfNodes();
6176 MCAuto<DataArrayInt> connOut=DataArrayInt::New(); connOut->alloc(nbCells*nbNodesPerCell,1);
6177 int *outPtr=connOut->getPointer();
6178 const int *conn=_nodal_connec->begin();
6179 const int *connI=_nodal_connec_index->begin();
6181 for(int i=0;i<nbCells;i++,connI++)
6183 if(conn[connI[0]]==typi && connI[1]-connI[0]==nbNodesPerCell)
6184 outPtr=std::copy(conn+connI[0]+1,conn+connI[1],outPtr);
6187 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 << ") !";
6188 throw INTERP_KERNEL::Exception(oss.str());
6191 return connOut.retn();
6195 * Convert the nodal connectivity of the mesh so that all the cells are of dynamic types (polygon or quadratic
6196 * polygon). This returns the corresponding new nodal connectivity in \ref numbering-indirect format.
6200 void MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh(DataArrayInt *&nodalConn, DataArrayInt *&nodalConnIndex) const
6202 static const char msg0[]="MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : nodal connectivity in this are invalid ! Call checkConsistency !";
6203 checkConnectivityFullyDefined();
6204 if(_types.size()!=1)
6205 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6206 int nbCells=getNumberOfCells(),lgth=_nodal_connec->getNumberOfTuples();
6208 throw INTERP_KERNEL::Exception(msg0);
6209 MCAuto<DataArrayInt> c(DataArrayInt::New()),ci(DataArrayInt::New());
6210 c->alloc(lgth-nbCells,1); ci->alloc(nbCells+1,1);
6211 int *cp(c->getPointer()),*cip(ci->getPointer());
6212 const int *incp(_nodal_connec->begin()),*incip(_nodal_connec_index->begin());
6214 for(int i=0;i<nbCells;i++,cip++,incip++)
6216 int strt(incip[0]+1),stop(incip[1]);//+1 to skip geo type
6217 int delta(stop-strt);
6220 if((strt>=0 && strt<lgth) && (stop>=0 && stop<=lgth))
6221 cp=std::copy(incp+strt,incp+stop,cp);
6223 throw INTERP_KERNEL::Exception(msg0);
6226 throw INTERP_KERNEL::Exception(msg0);
6227 cip[1]=cip[0]+delta;
6229 nodalConn=c.retn(); nodalConnIndex=ci.retn();
6233 * This method takes in input a vector of MEDCouplingUMesh instances lying on the same coordinates with same mesh dimensions.
6234 * Each mesh in \b ms must be sorted by type with the same order (typically using MEDCouplingUMesh::sortCellsInMEDFileFrmt).
6235 * This method is particularly useful for MED file interaction. It allows to aggregate several meshes and keeping the type sorting
6236 * and the track of the permutation by chunk of same geotype cells to retrieve it. The traditional formats old2new and new2old
6237 * are not used here to avoid the build of big permutation array.
6239 * \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
6240 * those specified in MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6241 * \param [out] szOfCellGrpOfSameType is a newly allocated DataArrayInt instance whose number of tuples is equal to the number of chunks of same geotype
6242 * in all meshes in \b ms. The accumulation of all values of this array is equal to the number of cells of returned mesh.
6243 * \param [out] idInMsOfCellGrpOfSameType is a newly allocated DataArrayInt instance having the same size than \b szOfCellGrpOfSameType. This
6244 * output array gives for each chunck of same type the corresponding mesh id in \b ms.
6245 * \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
6246 * is sorted by type following the geo cell types order of MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6248 MEDCouplingUMesh *MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& ms,
6249 DataArrayInt *&szOfCellGrpOfSameType,
6250 DataArrayInt *&idInMsOfCellGrpOfSameType)
6252 std::vector<const MEDCouplingUMesh *> ms2;
6253 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms.begin();it!=ms.end();it++)
6256 (*it)->checkConnectivityFullyDefined();
6260 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : input vector is empty !");
6261 const DataArrayDouble *refCoo=ms2[0]->getCoords();
6262 int meshDim=ms2[0]->getMeshDimension();
6263 std::vector<const MEDCouplingUMesh *> m1ssm;
6264 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmAuto;
6266 std::vector<const MEDCouplingUMesh *> m1ssmSingle;
6267 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmSingleAuto;
6269 MCAuto<DataArrayInt> ret1(DataArrayInt::New()),ret2(DataArrayInt::New());
6270 ret1->alloc(0,1); ret2->alloc(0,1);
6271 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms2.begin();it!=ms2.end();it++,rk++)
6273 if(meshDim!=(*it)->getMeshDimension())
6274 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshdims mismatch !");
6275 if(refCoo!=(*it)->getCoords())
6276 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshes are not shared by a single coordinates coords !");
6277 std::vector<MEDCouplingUMesh *> sp=(*it)->splitByType();
6278 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<const MEDCouplingUMesh *> >(m1ssm));
6279 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<MCAuto<MEDCouplingUMesh> > >(m1ssmAuto));
6280 for(std::vector<MEDCouplingUMesh *>::const_iterator it2=sp.begin();it2!=sp.end();it2++)
6282 MEDCouplingUMesh *singleCell=static_cast<MEDCouplingUMesh *>((*it2)->buildPartOfMySelf(&fake,&fake+1,true));
6283 m1ssmSingleAuto.push_back(singleCell);
6284 m1ssmSingle.push_back(singleCell);
6285 ret1->pushBackSilent((*it2)->getNumberOfCells()); ret2->pushBackSilent(rk);
6288 MCAuto<MEDCouplingUMesh> m1ssmSingle2=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmSingle);
6289 MCAuto<DataArrayInt> renum=m1ssmSingle2->sortCellsInMEDFileFrmt();
6290 std::vector<const MEDCouplingUMesh *> m1ssmfinal(m1ssm.size());
6291 for(std::size_t i=0;i<m1ssm.size();i++)
6292 m1ssmfinal[renum->getIJ(i,0)]=m1ssm[i];
6293 MCAuto<MEDCouplingUMesh> ret0=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmfinal);
6294 szOfCellGrpOfSameType=ret1->renumber(renum->begin());
6295 idInMsOfCellGrpOfSameType=ret2->renumber(renum->begin());
6300 * This method returns a newly created DataArrayInt instance.
6301 * This method retrieves cell ids in [ \a begin, \a end ) that have the type \a type.
6303 DataArrayInt *MEDCouplingUMesh::keepCellIdsByType(INTERP_KERNEL::NormalizedCellType type, const int *begin, const int *end) const
6305 checkFullyDefined();
6306 const int *conn=_nodal_connec->begin();
6307 const int *connIndex=_nodal_connec_index->begin();
6308 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(0,1);
6309 for(const int *w=begin;w!=end;w++)
6310 if((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]==type)
6311 ret->pushBackSilent(*w);
6316 * This method makes the assumption that da->getNumberOfTuples()<this->getNumberOfCells(). This method makes the assumption that ids contained in 'da'
6317 * are in [0:getNumberOfCells())
6319 DataArrayInt *MEDCouplingUMesh::convertCellArrayPerGeoType(const DataArrayInt *da) const
6321 checkFullyDefined();
6322 const int *conn=_nodal_connec->begin();
6323 const int *connI=_nodal_connec_index->begin();
6324 int nbOfCells=getNumberOfCells();
6325 std::set<INTERP_KERNEL::NormalizedCellType> types(getAllGeoTypes());
6326 int *tmp=new int[nbOfCells];
6327 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
6330 for(const int *i=connI;i!=connI+nbOfCells;i++)
6331 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
6332 tmp[std::distance(connI,i)]=j++;
6334 DataArrayInt *ret=DataArrayInt::New();
6335 ret->alloc(da->getNumberOfTuples(),da->getNumberOfComponents());
6336 ret->copyStringInfoFrom(*da);
6337 int *retPtr=ret->getPointer();
6338 const int *daPtr=da->begin();
6339 int nbOfElems=da->getNbOfElems();
6340 for(int k=0;k<nbOfElems;k++)
6341 retPtr[k]=tmp[daPtr[k]];
6347 * This method reduced number of cells of this by keeping cells whose type is different from 'type' and if type=='type'
6348 * This method \b works \b for mesh sorted by type.
6349 * cells whose ids is in 'idsPerGeoType' array.
6350 * This method conserves coords and name of mesh.
6352 MEDCouplingUMesh *MEDCouplingUMesh::keepSpecifiedCells(INTERP_KERNEL::NormalizedCellType type, const int *idsPerGeoTypeBg, const int *idsPerGeoTypeEnd) const
6354 std::vector<int> code=getDistributionOfTypes();
6355 std::size_t nOfTypesInThis=code.size()/3;
6356 int sz=0,szOfType=0;
6357 for(std::size_t i=0;i<nOfTypesInThis;i++)
6362 szOfType=code[3*i+1];
6364 for(const int *work=idsPerGeoTypeBg;work!=idsPerGeoTypeEnd;work++)
6365 if(*work<0 || *work>=szOfType)
6367 std::ostringstream oss; oss << "MEDCouplingUMesh::keepSpecifiedCells : Request on type " << type << " at place #" << std::distance(idsPerGeoTypeBg,work) << " value " << *work;
6368 oss << ". It should be in [0," << szOfType << ") !";
6369 throw INTERP_KERNEL::Exception(oss.str());
6371 MCAuto<DataArrayInt> idsTokeep=DataArrayInt::New(); idsTokeep->alloc(sz+(int)std::distance(idsPerGeoTypeBg,idsPerGeoTypeEnd),1);
6372 int *idsPtr=idsTokeep->getPointer();
6374 for(std::size_t i=0;i<nOfTypesInThis;i++)
6377 for(int j=0;j<code[3*i+1];j++)
6380 idsPtr=std::transform(idsPerGeoTypeBg,idsPerGeoTypeEnd,idsPtr,std::bind2nd(std::plus<int>(),offset));
6381 offset+=code[3*i+1];
6383 MCAuto<MEDCouplingUMesh> ret=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(idsTokeep->begin(),idsTokeep->end(),true));
6384 ret->copyTinyInfoFrom(this);
6389 * This method returns a vector of size 'this->getNumberOfCells()'.
6390 * This method retrieves for each cell in \a this if it is linear (false) or quadratic(true).
6392 std::vector<bool> MEDCouplingUMesh::getQuadraticStatus() const
6394 int ncell=getNumberOfCells();
6395 std::vector<bool> ret(ncell);
6396 const int *cI=getNodalConnectivityIndex()->begin();
6397 const int *c=getNodalConnectivity()->begin();
6398 for(int i=0;i<ncell;i++)
6400 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[i]];
6401 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6402 ret[i]=cm.isQuadratic();
6408 * Returns a newly created mesh (with ref count ==1) that contains merge of \a this and \a other.
6410 MEDCouplingMesh *MEDCouplingUMesh::mergeMyselfWith(const MEDCouplingMesh *other) const
6412 if(other->getType()!=UNSTRUCTURED)
6413 throw INTERP_KERNEL::Exception("Merge of umesh only available with umesh each other !");
6414 const MEDCouplingUMesh *otherC=static_cast<const MEDCouplingUMesh *>(other);
6415 return MergeUMeshes(this,otherC);
6419 * Returns a new DataArrayDouble holding barycenters of all cells. The barycenter is
6420 * computed by averaging coordinates of cell nodes, so this method is not a right
6421 * choice for degenerated meshes (not well oriented, cells with measure close to zero).
6422 * Beware also that for quadratic meshes, degenerated arc of circles are turned into linear edges for the computation.
6423 * This happens with a default detection precision of eps=1.0e-14. If you need control over this use computeCellCenterOfMassWithPrecision().
6424 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
6425 * this->getNumberOfCells() tuples per \a this->getSpaceDimension()
6426 * components. The caller is to delete this array using decrRef() as it is
6428 * \throw If the coordinates array is not set.
6429 * \throw If the nodal connectivity of cells is not defined.
6430 * \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
6431 * \sa MEDCouplingUMesh::computeCellCenterOfMassWithPrecision
6433 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMass() const
6435 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6436 int spaceDim=getSpaceDimension();
6437 int nbOfCells=getNumberOfCells();
6438 ret->alloc(nbOfCells,spaceDim);
6439 ret->copyStringInfoFrom(*getCoords());
6440 double *ptToFill=ret->getPointer();
6441 const int *nodal=_nodal_connec->begin();
6442 const int *nodalI=_nodal_connec_index->begin();
6443 const double *coor=_coords->begin();
6444 for(int i=0;i<nbOfCells;i++)
6446 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6447 INTERP_KERNEL::computeBarycenter2<int,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[i]+1,nodalI[i+1]-nodalI[i]-1,coor,spaceDim,ptToFill);
6455 * See computeCellCenterOfMass().
6456 * \param eps a precision for the detection of degenerated arc of circles.
6457 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
6458 * this->getNumberOfCells() tuples per \a this->getSpaceDimension()
6459 * components. The caller is to delete this array using decrRef() as it is
6461 * \throw If the coordinates array is not set.
6462 * \throw If the nodal connectivity of cells is not defined.
6463 * \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
6464 * \sa MEDCouplingUMesh::computeCellCenterOfMassWithPrecision
6466 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMassWithPrecision(double eps) const
6468 INTERP_KERNEL::QuadraticPlanarPrecision prec(eps);
6469 MCAuto<DataArrayDouble> ret = computeCellCenterOfMass();
6475 * This method computes for each cell in \a this, the location of the iso barycenter of nodes constituting
6476 * the cell. Contrary to badly named MEDCouplingUMesh::computeCellCenterOfMass method that returns the center of inertia of the
6478 * \return a newly allocated DataArrayDouble instance that the caller has to deal with. The returned
6479 * DataArrayDouble instance will have \c this->getNumberOfCells() tuples and \c this->getSpaceDimension() components.
6481 * \sa MEDCouplingUMesh::computeCellCenterOfMass
6482 * \throw If \a this is not fully defined (coordinates and connectivity)
6483 * \throw If there is presence in nodal connectivity in \a this of node ids not in [0, \c this->getNumberOfNodes() )
6485 DataArrayDouble *MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell() const
6487 checkFullyDefined();
6488 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6489 int spaceDim=getSpaceDimension();
6490 int nbOfCells=getNumberOfCells();
6491 int nbOfNodes=getNumberOfNodes();
6492 ret->alloc(nbOfCells,spaceDim);
6493 double *ptToFill=ret->getPointer();
6494 const int *nodal=_nodal_connec->begin();
6495 const int *nodalI=_nodal_connec_index->begin();
6496 const double *coor=_coords->begin();
6497 for(int i=0;i<nbOfCells;i++,ptToFill+=spaceDim)
6499 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6500 std::fill(ptToFill,ptToFill+spaceDim,0.);
6501 if(type!=INTERP_KERNEL::NORM_POLYHED)
6503 for(const int *conn=nodal+nodalI[i]+1;conn!=nodal+nodalI[i+1];conn++)
6505 if(*conn>=0 && *conn<nbOfNodes)
6506 std::transform(coor+spaceDim*conn[0],coor+spaceDim*(conn[0]+1),ptToFill,ptToFill,std::plus<double>());
6509 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of nodeId #" << *conn << " should be in [0," << nbOfNodes << ") !";
6510 throw INTERP_KERNEL::Exception(oss.str());
6513 int nbOfNodesInCell=nodalI[i+1]-nodalI[i]-1;
6514 if(nbOfNodesInCell>0)
6515 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies<double>(),1./(double)nbOfNodesInCell));
6518 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of cell with no nodes !";
6519 throw INTERP_KERNEL::Exception(oss.str());
6524 std::set<int> s(nodal+nodalI[i]+1,nodal+nodalI[i+1]);
6526 for(std::set<int>::const_iterator it=s.begin();it!=s.end();it++)
6528 if(*it>=0 && *it<nbOfNodes)
6529 std::transform(coor+spaceDim*(*it),coor+spaceDim*((*it)+1),ptToFill,ptToFill,std::plus<double>());
6532 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell polyhedron cell #" << i << " presence of nodeId #" << *it << " should be in [0," << nbOfNodes << ") !";
6533 throw INTERP_KERNEL::Exception(oss.str());
6537 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies<double>(),1./(double)s.size()));
6540 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on polyhedron cell #" << i << " there are no nodes !";
6541 throw INTERP_KERNEL::Exception(oss.str());
6549 * Returns a new DataArrayDouble holding barycenters of specified cells. The
6550 * barycenter is computed by averaging coordinates of cell nodes. The cells to treat
6551 * are specified via an array of cell ids.
6552 * \warning Validity of the specified cell ids is not checked!
6553 * Valid range is [ 0, \a this->getNumberOfCells() ).
6554 * \param [in] begin - an array of cell ids of interest.
6555 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
6556 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size ( \a
6557 * end - \a begin ) tuples per \a this->getSpaceDimension() components. The
6558 * caller is to delete this array using decrRef() as it is no more needed.
6559 * \throw If the coordinates array is not set.
6560 * \throw If the nodal connectivity of cells is not defined.
6562 * \if ENABLE_EXAMPLES
6563 * \ref cpp_mcumesh_getPartBarycenterAndOwner "Here is a C++ example".<br>
6564 * \ref py_mcumesh_getPartBarycenterAndOwner "Here is a Python example".
6567 DataArrayDouble *MEDCouplingUMesh::getPartBarycenterAndOwner(const int *begin, const int *end) const
6569 DataArrayDouble *ret=DataArrayDouble::New();
6570 int spaceDim=getSpaceDimension();
6571 int nbOfTuple=(int)std::distance(begin,end);
6572 ret->alloc(nbOfTuple,spaceDim);
6573 double *ptToFill=ret->getPointer();
6574 double *tmp=new double[spaceDim];
6575 const int *nodal=_nodal_connec->begin();
6576 const int *nodalI=_nodal_connec_index->begin();
6577 const double *coor=_coords->begin();
6578 for(const int *w=begin;w!=end;w++)
6580 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[*w]];
6581 INTERP_KERNEL::computeBarycenter2<int,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[*w]+1,nodalI[*w+1]-nodalI[*w]-1,coor,spaceDim,ptToFill);
6589 * 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".
6590 * So the returned instance will have 4 components and \c this->getNumberOfCells() tuples.
6591 * So this method expects that \a this has a spaceDimension equal to 3 and meshDimension equal to 2.
6592 * The computation of the plane equation is done using each time the 3 first nodes of 2D cells.
6593 * This method is useful to detect 2D cells in 3D space that are not coplanar.
6595 * \return DataArrayDouble * - a new instance of DataArrayDouble having 4 components and a number of tuples equal to number of cells in \a this.
6596 * \throw If spaceDim!=3 or meshDim!=2.
6597 * \throw If connectivity of \a this is invalid.
6598 * \throw If connectivity of a cell in \a this points to an invalid node.
6600 DataArrayDouble *MEDCouplingUMesh::computePlaneEquationOf3DFaces() const
6602 MCAuto<DataArrayDouble> ret(DataArrayDouble::New());
6603 int nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
6604 if(getSpaceDimension()!=3 || getMeshDimension()!=2)
6605 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computePlaneEquationOf3DFaces : This method must be applied on a mesh having meshDimension equal 2 and a spaceDimension equal to 3 !");
6606 ret->alloc(nbOfCells,4);
6607 double *retPtr(ret->getPointer());
6608 const int *nodal(_nodal_connec->begin()),*nodalI(_nodal_connec_index->begin());
6609 const double *coor(_coords->begin());
6610 for(int i=0;i<nbOfCells;i++,nodalI++,retPtr+=4)
6612 double matrix[16]={0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,0},matrix2[16];
6613 if(nodalI[1]-nodalI[0]>=4)
6615 double aa[3]={coor[nodal[nodalI[0]+1+1]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6616 coor[nodal[nodalI[0]+1+1]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6617 coor[nodal[nodalI[0]+1+1]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]}
6618 ,bb[3]={coor[nodal[nodalI[0]+1+2]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6619 coor[nodal[nodalI[0]+1+2]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6620 coor[nodal[nodalI[0]+1+2]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]};
6621 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]};
6622 for(int j=0;j<3;j++)
6624 int nodeId(nodal[nodalI[0]+1+j]);
6625 if(nodeId>=0 && nodeId<nbOfNodes)
6626 std::copy(coor+nodeId*3,coor+(nodeId+1)*3,matrix+4*j);
6629 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! This cell points to an invalid nodeId : " << nodeId << " !";
6630 throw INTERP_KERNEL::Exception(oss.str());
6633 if(sqrt(cc[0]*cc[0]+cc[1]*cc[1]+cc[2]*cc[2])>1e-7)
6635 INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6636 retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6640 if(nodalI[1]-nodalI[0]==4)
6642 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : cell" << i << " : Presence of The 3 colinear points !";
6643 throw INTERP_KERNEL::Exception(oss.str());
6646 double dd[3]={0.,0.,0.};
6647 for(int offset=nodalI[0]+1;offset<nodalI[1];offset++)
6648 std::transform(coor+3*nodal[offset],coor+3*(nodal[offset]+1),dd,dd,std::plus<double>());
6649 int nbOfNodesInCell(nodalI[1]-nodalI[0]-1);
6650 std::transform(dd,dd+3,dd,std::bind2nd(std::multiplies<double>(),1./(double)nbOfNodesInCell));
6651 std::copy(dd,dd+3,matrix+4*2);
6652 INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6653 retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6658 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! Must be constitued by more than 3 nodes !";
6659 throw INTERP_KERNEL::Exception(oss.str());
6666 * This method expects as input a DataArrayDouble non nul instance 'da' that should be allocated. If not an exception is thrown.
6669 MEDCouplingUMesh *MEDCouplingUMesh::Build0DMeshFromCoords(DataArrayDouble *da)
6672 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build0DMeshFromCoords : instance of DataArrayDouble must be not null !");
6673 da->checkAllocated();
6674 std::string name(da->getName());
6675 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New(name,0));
6677 ret->setName("Mesh");
6679 int nbOfTuples(da->getNumberOfTuples());
6680 MCAuto<DataArrayInt> c(DataArrayInt::New()),cI(DataArrayInt::New());
6681 c->alloc(2*nbOfTuples,1);
6682 cI->alloc(nbOfTuples+1,1);
6683 int *cp(c->getPointer()),*cip(cI->getPointer());
6685 for(int i=0;i<nbOfTuples;i++)
6687 *cp++=INTERP_KERNEL::NORM_POINT1;
6691 ret->setConnectivity(c,cI,true);
6695 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::Build1DMeshFromCoords(DataArrayDouble *da)
6698 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build01MeshFromCoords : instance of DataArrayDouble must be not null !");
6699 da->checkAllocated();
6700 std::string name(da->getName());
6701 MCAuto<MEDCouplingUMesh> ret;
6703 MCAuto<MEDCouplingCMesh> tmp(MEDCouplingCMesh::New());
6704 MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
6705 arr->alloc(da->getNumberOfTuples());
6706 tmp->setCoordsAt(0,arr);
6707 ret=tmp->buildUnstructured();
6711 ret->setName("Mesh");
6718 * Creates a new MEDCouplingUMesh by concatenating two given meshes of the same dimension.
6719 * Cells and nodes of
6720 * the first mesh precede cells and nodes of the second mesh within the result mesh.
6721 * \param [in] mesh1 - the first mesh.
6722 * \param [in] mesh2 - the second mesh.
6723 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6724 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6725 * is no more needed.
6726 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
6727 * \throw If the coordinates array is not set in none of the meshes.
6728 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
6729 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
6731 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
6733 std::vector<const MEDCouplingUMesh *> tmp(2);
6734 tmp[0]=const_cast<MEDCouplingUMesh *>(mesh1); tmp[1]=const_cast<MEDCouplingUMesh *>(mesh2);
6735 return MergeUMeshes(tmp);
6739 * Creates a new MEDCouplingUMesh by concatenating all given meshes of the same dimension.
6740 * Cells and nodes of
6741 * the *i*-th mesh precede cells and nodes of the (*i*+1)-th mesh within the result mesh.
6742 * \param [in] a - a vector of meshes (MEDCouplingUMesh) to concatenate.
6743 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6744 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6745 * is no more needed.
6746 * \throw If \a a.size() == 0.
6747 * \throw If \a a[ *i* ] == NULL.
6748 * \throw If the coordinates array is not set in none of the meshes.
6749 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
6750 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
6752 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const std::vector<const MEDCouplingUMesh *>& a)
6754 std::size_t sz=a.size();
6756 return MergeUMeshesLL(a);
6757 for(std::size_t ii=0;ii<sz;ii++)
6760 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshes : item #" << ii << " in input array of size "<< sz << " is empty !";
6761 throw INTERP_KERNEL::Exception(oss.str());
6763 std::vector< MCAuto<MEDCouplingUMesh> > bb(sz);
6764 std::vector< const MEDCouplingUMesh * > aa(sz);
6766 for(std::size_t i=0;i<sz && spaceDim==-3;i++)
6768 const MEDCouplingUMesh *cur=a[i];
6769 const DataArrayDouble *coo=cur->getCoords();
6771 spaceDim=coo->getNumberOfComponents();
6774 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : no spaceDim specified ! unable to perform merge !");
6775 for(std::size_t i=0;i<sz;i++)
6777 bb[i]=a[i]->buildSetInstanceFromThis(spaceDim);
6780 return MergeUMeshesLL(aa);
6784 * Creates a new MEDCouplingUMesh by concatenating cells of two given meshes of same
6785 * dimension and sharing the node coordinates array.
6786 * All cells of the first mesh precede all cells of the second mesh
6787 * within the result mesh.
6788 * \param [in] mesh1 - the first mesh.
6789 * \param [in] mesh2 - the second mesh.
6790 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6791 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6792 * is no more needed.
6793 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
6794 * \throw If the meshes do not share the node coordinates array.
6795 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
6796 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
6798 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
6800 std::vector<const MEDCouplingUMesh *> tmp(2);
6801 tmp[0]=mesh1; tmp[1]=mesh2;
6802 return MergeUMeshesOnSameCoords(tmp);
6806 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
6807 * dimension and sharing the node coordinates array.
6808 * All cells of the *i*-th mesh precede all cells of the
6809 * (*i*+1)-th mesh within the result mesh.
6810 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
6811 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6812 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6813 * is no more needed.
6814 * \throw If \a a.size() == 0.
6815 * \throw If \a a[ *i* ] == NULL.
6816 * \throw If the meshes do not share the node coordinates array.
6817 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
6818 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
6820 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes)
6823 throw INTERP_KERNEL::Exception("meshes input parameter is expected to be non empty.");
6824 for(std::size_t ii=0;ii<meshes.size();ii++)
6827 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshesOnSameCoords : item #" << ii << " in input array of size "<< meshes.size() << " is empty !";
6828 throw INTERP_KERNEL::Exception(oss.str());
6830 const DataArrayDouble *coords=meshes.front()->getCoords();
6831 int meshDim=meshes.front()->getMeshDimension();
6832 std::vector<const MEDCouplingUMesh *>::const_iterator iter=meshes.begin();
6834 int meshIndexLgth=0;
6835 for(;iter!=meshes.end();iter++)
6837 if(coords!=(*iter)->getCoords())
6838 throw INTERP_KERNEL::Exception("meshes does not share the same coords ! Try using tryToShareSameCoords method !");
6839 if(meshDim!=(*iter)->getMeshDimension())
6840 throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, FuseUMeshesOnSameCoords impossible !");
6841 meshLgth+=(*iter)->getNodalConnectivityArrayLen();
6842 meshIndexLgth+=(*iter)->getNumberOfCells();
6844 MCAuto<DataArrayInt> nodal=DataArrayInt::New();
6845 nodal->alloc(meshLgth,1);
6846 int *nodalPtr=nodal->getPointer();
6847 MCAuto<DataArrayInt> nodalIndex=DataArrayInt::New();
6848 nodalIndex->alloc(meshIndexLgth+1,1);
6849 int *nodalIndexPtr=nodalIndex->getPointer();
6851 for(iter=meshes.begin();iter!=meshes.end();iter++)
6853 const int *nod=(*iter)->getNodalConnectivity()->begin();
6854 const int *index=(*iter)->getNodalConnectivityIndex()->begin();
6855 int nbOfCells=(*iter)->getNumberOfCells();
6856 int meshLgth2=(*iter)->getNodalConnectivityArrayLen();
6857 nodalPtr=std::copy(nod,nod+meshLgth2,nodalPtr);
6858 if(iter!=meshes.begin())
6859 nodalIndexPtr=std::transform(index+1,index+nbOfCells+1,nodalIndexPtr,std::bind2nd(std::plus<int>(),offset));
6861 nodalIndexPtr=std::copy(index,index+nbOfCells+1,nodalIndexPtr);
6864 MEDCouplingUMesh *ret=MEDCouplingUMesh::New();
6865 ret->setName("merge");
6866 ret->setMeshDimension(meshDim);
6867 ret->setConnectivity(nodal,nodalIndex,true);
6868 ret->setCoords(coords);
6873 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
6874 * dimension and sharing the node coordinates array. Cells of the *i*-th mesh precede
6875 * cells of the (*i*+1)-th mesh within the result mesh. Duplicates of cells are
6876 * removed from \a this mesh and arrays mapping between new and old cell ids in "Old to
6877 * New" mode are returned for each input mesh.
6878 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
6879 * \param [in] compType - specifies a cell comparison technique. For meaning of its
6880 * valid values [0,1,2], see zipConnectivityTraducer().
6881 * \param [in,out] corr - an array of DataArrayInt, of the same size as \a
6882 * meshes. The *i*-th array describes cell ids mapping for \a meshes[ *i* ]
6883 * mesh. The caller is to delete each of the arrays using decrRef() as it is
6885 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6886 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6887 * is no more needed.
6888 * \throw If \a meshes.size() == 0.
6889 * \throw If \a meshes[ *i* ] == NULL.
6890 * \throw If the meshes do not share the node coordinates array.
6891 * \throw If \a meshes[ *i* ]->getMeshDimension() < 0.
6892 * \throw If the \a meshes are of different dimension (getMeshDimension()).
6893 * \throw If the nodal connectivity of cells of any of \a meshes is not defined.
6894 * \throw If the nodal connectivity any of \a meshes includes an invalid id.
6896 MEDCouplingUMesh *MEDCouplingUMesh::FuseUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes, int compType, std::vector<DataArrayInt *>& corr)
6898 //All checks are delegated to MergeUMeshesOnSameCoords
6899 MCAuto<MEDCouplingUMesh> ret=MergeUMeshesOnSameCoords(meshes);
6900 MCAuto<DataArrayInt> o2n=ret->zipConnectivityTraducer(compType);
6901 corr.resize(meshes.size());
6902 std::size_t nbOfMeshes=meshes.size();
6904 const int *o2nPtr=o2n->begin();
6905 for(std::size_t i=0;i<nbOfMeshes;i++)
6907 DataArrayInt *tmp=DataArrayInt::New();
6908 int curNbOfCells=meshes[i]->getNumberOfCells();
6909 tmp->alloc(curNbOfCells,1);
6910 std::copy(o2nPtr+offset,o2nPtr+offset+curNbOfCells,tmp->getPointer());
6911 offset+=curNbOfCells;
6912 tmp->setName(meshes[i]->getName());
6919 * Makes all given meshes share the nodal connectivity array. The common connectivity
6920 * array is created by concatenating the connectivity arrays of all given meshes. All
6921 * the given meshes must be of the same space dimension but dimension of cells **can
6922 * differ**. This method is particularly useful in MEDLoader context to build a \ref
6923 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
6924 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
6925 * \param [in,out] meshes - a vector of meshes to update.
6926 * \throw If any of \a meshes is NULL.
6927 * \throw If the coordinates array is not set in any of \a meshes.
6928 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
6929 * \throw If \a meshes are of different space dimension.
6931 void MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords(const std::vector<MEDCouplingUMesh *>& meshes)
6933 std::size_t sz=meshes.size();
6936 std::vector< const DataArrayDouble * > coords(meshes.size());
6937 std::vector< const DataArrayDouble * >::iterator it2=coords.begin();
6938 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++,it2++)
6942 (*it)->checkConnectivityFullyDefined();
6943 const DataArrayDouble *coo=(*it)->getCoords();
6948 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
6949 oss << " has no coordinate array defined !";
6950 throw INTERP_KERNEL::Exception(oss.str());
6955 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
6956 oss << " is null !";
6957 throw INTERP_KERNEL::Exception(oss.str());
6960 MCAuto<DataArrayDouble> res=DataArrayDouble::Aggregate(coords);
6961 std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();
6962 int offset=(*it)->getNumberOfNodes();
6963 (*it++)->setCoords(res);
6964 for(;it!=meshes.end();it++)
6966 int oldNumberOfNodes=(*it)->getNumberOfNodes();
6967 (*it)->setCoords(res);
6968 (*it)->shiftNodeNumbersInConn(offset);
6969 offset+=oldNumberOfNodes;
6974 * Merges nodes coincident with a given precision within all given meshes that share
6975 * the nodal connectivity array. The given meshes **can be of different** mesh
6976 * dimension. This method is particularly useful in MEDLoader context to build a \ref
6977 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
6978 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
6979 * \param [in,out] meshes - a vector of meshes to update.
6980 * \param [in] eps - the precision used to detect coincident nodes (infinite norm).
6981 * \throw If any of \a meshes is NULL.
6982 * \throw If the \a meshes do not share the same node coordinates array.
6983 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
6985 void MEDCouplingUMesh::MergeNodesOnUMeshesSharingSameCoords(const std::vector<MEDCouplingUMesh *>& meshes, double eps)
6989 std::set<const DataArrayDouble *> s;
6990 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
6993 s.insert((*it)->getCoords());
6996 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 !";
6997 throw INTERP_KERNEL::Exception(oss.str());
7002 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 !";
7003 throw INTERP_KERNEL::Exception(oss.str());
7005 const DataArrayDouble *coo=*(s.begin());
7009 DataArrayInt *comm,*commI;
7010 coo->findCommonTuples(eps,-1,comm,commI);
7011 MCAuto<DataArrayInt> tmp1(comm),tmp2(commI);
7012 int oldNbOfNodes=coo->getNumberOfTuples();
7014 MCAuto<DataArrayInt> o2n=DataArrayInt::ConvertIndexArrayToO2N(oldNbOfNodes,comm->begin(),commI->begin(),commI->end(),newNbOfNodes);
7015 if(oldNbOfNodes==newNbOfNodes)
7017 MCAuto<DataArrayDouble> newCoords=coo->renumberAndReduce(o2n->begin(),newNbOfNodes);
7018 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
7020 (*it)->renumberNodesInConn(o2n->begin());
7021 (*it)->setCoords(newCoords);
7027 * This static operates only for coords in 3D. The polygon is specified by its connectivity nodes in [ \a begin , \a end ).
7029 bool MEDCouplingUMesh::IsPolygonWellOriented(bool isQuadratic, const double *vec, const int *begin, const int *end, const double *coords)
7032 double v[3]={0.,0.,0.};
7033 std::size_t sz=std::distance(begin,end);
7037 // Algorithm: sum in v the cross products of (e1, e2) where e_i it the vector between (0,0,0) and point i
7038 // and e2 is linear point directly following e1 in the connectivity. All points are used.
7039 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];
7040 v[1]+=coords[3*begin[i]+2]*coords[3*begin[(i+1)%sz]]-coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+2];
7041 v[2]+=coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+1]-coords[3*begin[i]+1]*coords[3*begin[(i+1)%sz]];
7045 // Same algorithm as above but also using intermediate quadratic points.
7046 // (taking only linear points might lead to issues if the linearized version of the
7047 // polygon is not convex or self-intersecting ... see testCellOrientation4)
7049 for(std::size_t j=0;j<sz;j++)
7051 if (j%2) // current point i is quadratic, next point i+1 is standard
7054 ip1 = ((j-1)/2 + 1)%hsz; // ip1 means "i+1", i.e. next point
7056 else // current point i is standard, next point i+1 is quadratic
7061 v[0]+=coords[3*begin[i]+1]*coords[3*begin[ip1]+2]-coords[3*begin[i]+2]*coords[3*begin[ip1]+1];
7062 v[1]+=coords[3*begin[i]+2]*coords[3*begin[ip1]]-coords[3*begin[i]]*coords[3*begin[ip1]+2];
7063 v[2]+=coords[3*begin[i]]*coords[3*begin[ip1]+1]-coords[3*begin[i]+1]*coords[3*begin[ip1]];
7066 double ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
7071 * The polyhedron is specified by its connectivity nodes in [ \a begin , \a end ).
7073 bool MEDCouplingUMesh::IsPolyhedronWellOriented(const int *begin, const int *end, const double *coords)
7075 std::vector<std::pair<int,int> > edges;
7076 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
7077 const int *bgFace=begin;
7078 for(std::size_t i=0;i<nbOfFaces;i++)
7080 const int *endFace=std::find(bgFace+1,end,-1);
7081 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
7082 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7084 std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7085 if(std::find(edges.begin(),edges.end(),p1)!=edges.end())
7087 edges.push_back(p1);
7091 return INTERP_KERNEL::calculateVolumeForPolyh2<int,INTERP_KERNEL::ALL_C_MODE>(begin,(int)std::distance(begin,end),coords)>-EPS_FOR_POLYH_ORIENTATION;
7095 * The 3D extruded static cell (PENTA6,HEXA8,HEXAGP12...) its connectivity nodes in [ \a begin , \a end ).
7097 bool MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented(const int *begin, const int *end, const double *coords)
7099 double vec0[3],vec1[3];
7100 std::size_t sz=std::distance(begin,end);
7102 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented : the length of nodal connectivity of extruded cell is not even !");
7103 int nbOfNodes=(int)sz/2;
7104 INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(begin,nbOfNodes,coords,vec0);
7105 const double *pt0=coords+3*begin[0];
7106 const double *pt1=coords+3*begin[nbOfNodes];
7107 vec1[0]=pt1[0]-pt0[0]; vec1[1]=pt1[1]-pt0[1]; vec1[2]=pt1[2]-pt0[2];
7108 return (vec0[0]*vec1[0]+vec0[1]*vec1[1]+vec0[2]*vec1[2])<0.;
7111 void MEDCouplingUMesh::CorrectExtrudedStaticCell(int *begin, int *end)
7113 std::size_t sz=std::distance(begin,end);
7114 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz];
7115 std::size_t nbOfNodes(sz/2);
7116 std::copy(begin,end,(int *)tmp);
7117 for(std::size_t j=1;j<nbOfNodes;j++)
7119 begin[j]=tmp[nbOfNodes-j];
7120 begin[j+nbOfNodes]=tmp[nbOfNodes+nbOfNodes-j];
7124 bool MEDCouplingUMesh::IsTetra4WellOriented(const int *begin, const int *end, const double *coords)
7126 std::size_t sz=std::distance(begin,end);
7128 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsTetra4WellOriented : Tetra4 cell with not 4 nodes ! Call checkConsistency !");
7129 double vec0[3],vec1[3];
7130 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[1],*pt2=coords+3*begin[2],*pt3=coords+3*begin[3];
7131 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];
7132 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;
7135 bool MEDCouplingUMesh::IsPyra5WellOriented(const int *begin, const int *end, const double *coords)
7137 std::size_t sz=std::distance(begin,end);
7139 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsPyra5WellOriented : Pyra5 cell with not 5 nodes ! Call checkConsistency !");
7141 INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(begin,4,coords,vec0);
7142 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[4];
7143 return (vec0[0]*(pt1[0]-pt0[0])+vec0[1]*(pt1[1]-pt0[1])+vec0[2]*(pt1[2]-pt0[2]))<0.;
7147 * 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 )
7148 * 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
7151 * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not.
7152 * \param [in] coords the coordinates with nb of components exactly equal to 3
7153 * \param [in] begin begin of the nodal connectivity (geometric type included) of a single polyhedron cell
7154 * \param [in] end end of nodal connectivity of a single polyhedron cell (excluded)
7155 * \param [out] res the result is put at the end of the vector without any alteration of the data.
7157 void MEDCouplingUMesh::SimplifyPolyhedronCell(double eps, const DataArrayDouble *coords, int index, DataArrayInt *res, MEDCouplingUMesh *faces,
7158 DataArrayInt *E_Fi, DataArrayInt *E_F, DataArrayInt *F_Ei, DataArrayInt *F_E)
7160 int nbFaces = E_Fi->getIJ(index + 1, 0) - E_Fi->getIJ(index, 0);
7161 MCAuto<DataArrayDouble> v=DataArrayDouble::New(); v->alloc(nbFaces,3);
7162 double *vPtr=v->getPointer();
7163 MCAuto<DataArrayDouble> p=DataArrayDouble::New(); p->alloc(nbFaces,2);
7164 double *pPtr=p->getPointer();
7165 int *e_fi = E_Fi->getPointer(), *e_f = E_F->getPointer(), *f_ei = F_Ei->getPointer(), *f_e = F_E->getPointer();
7166 const int *f_idx = faces->getNodalConnectivityIndex()->getPointer(), *f_cnn = faces->getNodalConnectivity()->getPointer();
7167 for(int i=0;i<nbFaces;i++,vPtr+=3,pPtr++)
7169 int face = e_f[e_fi[index] + i];
7170 ComputeVecAndPtOfFace(eps, coords->begin(), f_cnn + f_idx[face] + 1, f_cnn + f_idx[face + 1], vPtr, pPtr);
7171 // to differentiate faces going to different cells:
7173 for (int j = f_ei[face]; j < f_ei[face + 1]; j++)
7176 pPtr=p->getPointer(); vPtr=v->getPointer();
7177 DataArrayInt *comm1=0,*commI1=0;
7178 v->findCommonTuples(eps,-1,comm1,commI1);
7179 for (int i = 0; i < nbFaces; i++)
7180 if (comm1->findIdFirstEqual(i) < 0)
7182 comm1->pushBackSilent(i);
7183 commI1->pushBackSilent(comm1->getNumberOfTuples());
7185 MCAuto<DataArrayInt> comm1Auto(comm1),commI1Auto(commI1);
7186 const int *comm1Ptr=comm1->begin();
7187 const int *commI1Ptr=commI1->begin();
7188 int nbOfGrps1=commI1Auto->getNumberOfTuples()-1;
7189 res->pushBackSilent((int)INTERP_KERNEL::NORM_POLYHED);
7191 for(int i=0;i<nbOfGrps1;i++)
7193 int vecId=comm1Ptr[commI1Ptr[i]];
7194 MCAuto<DataArrayDouble> tmpgrp2=p->selectByTupleId(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7195 DataArrayInt *comm2=0,*commI2=0;
7196 tmpgrp2->findCommonTuples(eps,-1,comm2,commI2);
7197 for (int j = 0; j < commI1Ptr[i+1] - commI1Ptr[i]; j++)
7198 if (comm2->findIdFirstEqual(j) < 0)
7200 comm2->pushBackSilent(j);
7201 commI2->pushBackSilent(comm2->getNumberOfTuples());
7203 MCAuto<DataArrayInt> comm2Auto(comm2),commI2Auto(commI2);
7204 const int *comm2Ptr=comm2->begin();
7205 const int *commI2Ptr=commI2->begin();
7206 int nbOfGrps2=commI2Auto->getNumberOfTuples()-1;
7207 for(int j=0;j<nbOfGrps2;j++)
7209 if(commI2Ptr[j+1] == commI2Ptr[j] + 1)
7211 int face = e_f[e_fi[index] + comm1Ptr[commI1Ptr[i] + comm2Ptr[commI2Ptr[j]]]]; //hmmm
7212 res->insertAtTheEnd(f_cnn + f_idx[face] + 1, f_cnn + f_idx[face + 1]);
7213 res->pushBackSilent(-1);
7217 int pointId=comm1Ptr[commI1Ptr[i]+comm2Ptr[commI2Ptr[j]]];
7218 MCAuto<DataArrayInt> ids2=comm2->selectByTupleIdSafeSlice(commI2Ptr[j],commI2Ptr[j+1],1);
7219 ids2->transformWithIndArr(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7220 ids2->transformWithIndArr(e_f + e_fi[index], e_f + e_fi[index + 1]);
7221 MCAuto<MEDCouplingUMesh> mm3=static_cast<MEDCouplingUMesh *>(faces->buildPartOfMySelf(ids2->begin(),ids2->end(),true));
7222 MCAuto<DataArrayInt> idsNodeTmp=mm3->zipCoordsTraducer();
7223 MCAuto<DataArrayInt> idsNode=idsNodeTmp->invertArrayO2N2N2O(mm3->getNumberOfNodes());
7224 const int *idsNodePtr=idsNode->begin();
7225 double center[3]; center[0]=pPtr[2*pointId]*vPtr[3*vecId]; center[1]=pPtr[2*pointId]*vPtr[3*vecId+1]; center[2]=pPtr[2*pointId]*vPtr[3*vecId+2];
7226 double vec[3]; vec[0]=vPtr[3*vecId+1]; vec[1]=-vPtr[3*vecId]; vec[2]=0.;
7227 double norm=vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2];
7228 if(std::abs(norm)>eps)
7230 double angle=INTERP_KERNEL::EdgeArcCircle::SafeAsin(norm);
7231 mm3->rotate(center,vec,angle);
7233 mm3->changeSpaceDimension(2);
7234 MCAuto<MEDCouplingUMesh> mm4=mm3->buildSpreadZonesWithPoly();
7235 const int *conn4=mm4->getNodalConnectivity()->begin();
7236 const int *connI4=mm4->getNodalConnectivityIndex()->begin();
7237 int nbOfCells=mm4->getNumberOfCells();
7238 for(int k=0;k<nbOfCells;k++)
7241 for(const int *work=conn4+connI4[k]+1;work!=conn4+connI4[k+1];work++,l++)
7242 res->pushBackSilent(idsNodePtr[*work]);
7243 res->pushBackSilent(-1);
7248 res->popBackSilent();
7252 * 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
7253 * through origin. The plane is defined by its nodal connectivity [ \b begin, \b end ).
7255 * \param [in] eps below that value the dot product of 2 vectors is considered as colinears
7256 * \param [in] coords coordinates expected to have 3 components.
7257 * \param [in] begin start of the nodal connectivity of the face.
7258 * \param [in] end end of the nodal connectivity (excluded) of the face.
7259 * \param [out] v the normalized vector of size 3
7260 * \param [out] p the pos of plane
7262 void MEDCouplingUMesh::ComputeVecAndPtOfFace(double eps, const double *coords, const int *begin, const int *end, double *v, double *p)
7264 std::size_t nbPoints=std::distance(begin,end);
7266 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeVecAndPtOfFace : < of 3 points in face ! not able to find a plane on that face !");
7267 double vec[3]={0.,0.,0.};
7269 bool refFound=false;
7270 for(;j<nbPoints-1 && !refFound;j++)
7272 vec[0]=coords[3*begin[j+1]]-coords[3*begin[j]];
7273 vec[1]=coords[3*begin[j+1]+1]-coords[3*begin[j]+1];
7274 vec[2]=coords[3*begin[j+1]+2]-coords[3*begin[j]+2];
7275 double norm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
7279 vec[0]/=norm; vec[1]/=norm; vec[2]/=norm;
7282 for(std::size_t i=j;i<nbPoints-1;i++)
7285 curVec[0]=coords[3*begin[i+1]]-coords[3*begin[i]];
7286 curVec[1]=coords[3*begin[i+1]+1]-coords[3*begin[i]+1];
7287 curVec[2]=coords[3*begin[i+1]+2]-coords[3*begin[i]+2];
7288 double norm=sqrt(curVec[0]*curVec[0]+curVec[1]*curVec[1]+curVec[2]*curVec[2]);
7291 curVec[0]/=norm; curVec[1]/=norm; curVec[2]/=norm;
7292 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];
7293 norm=sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
7296 v[0]/=norm; v[1]/=norm; v[2]/=norm;
7297 *p=v[0]*coords[3*begin[i]]+v[1]*coords[3*begin[i]+1]+v[2]*coords[3*begin[i]+2];
7301 throw INTERP_KERNEL::Exception("Not able to find a normal vector of that 3D face !");
7305 * This method tries to obtain a well oriented polyhedron.
7306 * If the algorithm fails, an exception will be thrown.
7308 void MEDCouplingUMesh::TryToCorrectPolyhedronOrientation(int *begin, int *end, const double *coords)
7310 std::list< std::pair<int,int> > edgesOK,edgesFinished;
7311 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
7312 std::vector<bool> isPerm(nbOfFaces,false);//field on faces False: I don't know, True : oriented
7314 int *bgFace=begin,*endFace=std::find(begin+1,end,-1);
7315 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
7316 for(std::size_t l=0;l<nbOfEdgesInFace;l++) { std::pair<int,int> p1(bgFace[l],bgFace[(l+1)%nbOfEdgesInFace]); edgesOK.push_back(p1); }
7318 while(std::find(isPerm.begin(),isPerm.end(),false)!=isPerm.end())
7321 std::size_t smthChanged=0;
7322 for(std::size_t i=0;i<nbOfFaces;i++)
7324 endFace=std::find(bgFace+1,end,-1);
7325 nbOfEdgesInFace=std::distance(bgFace,endFace);
7329 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7331 std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7332 std::pair<int,int> p2(p1.second,p1.first);
7333 bool b1=std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end();
7334 bool b2=std::find(edgesOK.begin(),edgesOK.end(),p2)!=edgesOK.end();
7335 if(b1 || b2) { b=b2; isPerm[i]=true; smthChanged++; break; }
7340 std::reverse(bgFace+1,endFace);
7341 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7343 std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7344 std::pair<int,int> p2(p1.second,p1.first);
7345 if(std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end())
7346 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7347 if(std::find(edgesFinished.begin(),edgesFinished.end(),p1)!=edgesFinished.end() || std::find(edgesFinished.begin(),edgesFinished.end(),p2)!=edgesFinished.end())
7348 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7349 std::list< std::pair<int,int> >::iterator it=std::find(edgesOK.begin(),edgesOK.end(),p2);
7350 if(it!=edgesOK.end())
7353 edgesFinished.push_back(p1);
7356 edgesOK.push_back(p1);
7363 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired !"); }
7365 if(!edgesOK.empty())
7366 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired : Some edges are shared only once !"); }
7367 if(INTERP_KERNEL::calculateVolumeForPolyh2<int,INTERP_KERNEL::ALL_C_MODE>(begin,(int)std::distance(begin,end),coords)<-EPS_FOR_POLYH_ORIENTATION)
7368 {//not lucky ! The first face was not correctly oriented : reorient all faces...
7370 for(std::size_t i=0;i<nbOfFaces;i++)
7372 endFace=std::find(bgFace+1,end,-1);
7373 std::reverse(bgFace+1,endFace);
7381 * This method makes the assumption spacedimension == meshdimension == 2.
7382 * This method works only for linear cells.
7384 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYGON in pos#0)
7386 DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMesh() const
7388 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
7389 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : meshdimension, spacedimension must be equal to 2 !");
7390 MCAuto<MEDCouplingUMesh> skin(computeSkin());
7391 int oldNbOfNodes(skin->getNumberOfNodes());
7392 MCAuto<DataArrayInt> o2n(skin->zipCoordsTraducer());
7393 int nbOfNodesExpected(skin->getNumberOfNodes());
7394 MCAuto<DataArrayInt> n2o(o2n->invertArrayO2N2N2O(oldNbOfNodes));
7395 int nbCells(skin->getNumberOfCells());
7396 if(nbCells==nbOfNodesExpected)
7397 return buildUnionOf2DMeshLinear(skin,n2o);
7398 else if(2*nbCells==nbOfNodesExpected)
7399 return buildUnionOf2DMeshQuadratic(skin,n2o);
7401 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : the mesh 2D in input appears to be not in a single part of a 2D mesh !");
7405 * This method makes the assumption spacedimension == meshdimension == 3.
7406 * This method works only for linear cells.
7408 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYHED in pos#0)
7410 DataArrayInt *MEDCouplingUMesh::buildUnionOf3DMesh() const
7412 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
7413 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf3DMesh : meshdimension, spacedimension must be equal to 2 !");
7414 MCAuto<MEDCouplingUMesh> m=computeSkin();
7415 const int *conn=m->getNodalConnectivity()->begin();
7416 const int *connI=m->getNodalConnectivityIndex()->begin();
7417 int nbOfCells=m->getNumberOfCells();
7418 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(m->getNodalConnectivity()->getNumberOfTuples(),1);
7419 int *work=ret->getPointer(); *work++=INTERP_KERNEL::NORM_POLYHED;
7422 work=std::copy(conn+connI[0]+1,conn+connI[1],work);
7423 for(int i=1;i<nbOfCells;i++)
7426 work=std::copy(conn+connI[i]+1,conn+connI[i+1],work);
7432 * \brief Creates a graph of cell neighbors
7433 * \return MEDCouplingSkyLineArray * - an sky line array the user should delete.
7434 * In the sky line array, graph arcs are stored in terms of (index,value) notation.
7436 * - index: 0 3 5 6 6
7437 * - value: 1 2 3 2 3 3
7438 * means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7439 * Arcs are not doubled but reflexive (1,1) arcs are present for each cell
7441 MEDCouplingSkyLineArray* MEDCouplingUMesh::generateGraph() const
7443 checkConnectivityFullyDefined();
7445 int meshDim = this->getMeshDimension();
7446 MEDCoupling::DataArrayInt* indexr=MEDCoupling::DataArrayInt::New();
7447 MEDCoupling::DataArrayInt* revConn=MEDCoupling::DataArrayInt::New();
7448 this->getReverseNodalConnectivity(revConn,indexr);
7449 const int* indexr_ptr=indexr->begin();
7450 const int* revConn_ptr=revConn->begin();
7452 const MEDCoupling::DataArrayInt* index;
7453 const MEDCoupling::DataArrayInt* conn;
7454 conn=this->getNodalConnectivity(); // it includes a type as the 1st element!!!
7455 index=this->getNodalConnectivityIndex();
7456 int nbCells=this->getNumberOfCells();
7457 const int* index_ptr=index->begin();
7458 const int* conn_ptr=conn->begin();
7460 //creating graph arcs (cell to cell relations)
7461 //arcs are stored in terms of (index,value) notation
7464 // means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7465 // in present version arcs are not doubled but reflexive (1,1) arcs are present for each cell
7467 //warning here one node have less than or equal effective number of cell with it
7468 //but cell could have more than effective nodes
7469 //because other equals nodes in other domain (with other global inode)
7470 std::vector <int> cell2cell_index(nbCells+1,0);
7471 std::vector <int> cell2cell;
7472 cell2cell.reserve(3*nbCells);
7474 for (int icell=0; icell<nbCells;icell++)
7476 std::map<int,int > counter;
7477 for (int iconn=index_ptr[icell]+1; iconn<index_ptr[icell+1];iconn++)
7479 int inode=conn_ptr[iconn];
7480 for (int iconnr=indexr_ptr[inode]; iconnr<indexr_ptr[inode+1];iconnr++)
7482 int icell2=revConn_ptr[iconnr];
7483 std::map<int,int>::iterator iter=counter.find(icell2);
7484 if (iter!=counter.end()) (iter->second)++;
7485 else counter.insert(std::make_pair(icell2,1));
7488 for (std::map<int,int>::const_iterator iter=counter.begin();
7489 iter!=counter.end(); iter++)
7490 if (iter->second >= meshDim)
7492 cell2cell_index[icell+1]++;
7493 cell2cell.push_back(iter->first);
7498 cell2cell_index[0]=0;
7499 for (int icell=0; icell<nbCells;icell++)
7500 cell2cell_index[icell+1]=cell2cell_index[icell]+cell2cell_index[icell+1];
7502 //filling up index and value to create skylinearray structure
7503 MEDCouplingSkyLineArray * array(MEDCouplingSkyLineArray::New(cell2cell_index,cell2cell));
7508 void MEDCouplingUMesh::writeVTKLL(std::ostream& ofs, const std::string& cellData, const std::string& pointData, DataArrayByte *byteData) const
7510 int nbOfCells=getNumberOfCells();
7512 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::writeVTK : the unstructured mesh has no cells !");
7513 ofs << " <" << getVTKDataSetType() << ">\n";
7514 ofs << " <Piece NumberOfPoints=\"" << getNumberOfNodes() << "\" NumberOfCells=\"" << nbOfCells << "\">\n";
7515 ofs << " <PointData>\n" << pointData << std::endl;
7516 ofs << " </PointData>\n";
7517 ofs << " <CellData>\n" << cellData << std::endl;
7518 ofs << " </CellData>\n";
7519 ofs << " <Points>\n";
7520 if(getSpaceDimension()==3)
7521 _coords->writeVTK(ofs,8,"Points",byteData);
7524 MCAuto<DataArrayDouble> coo=_coords->changeNbOfComponents(3,0.);
7525 coo->writeVTK(ofs,8,"Points",byteData);
7527 ofs << " </Points>\n";
7528 ofs << " <Cells>\n";
7529 const int *cPtr=_nodal_connec->begin();
7530 const int *cIPtr=_nodal_connec_index->begin();
7531 MCAuto<DataArrayInt> faceoffsets=DataArrayInt::New(); faceoffsets->alloc(nbOfCells,1);
7532 MCAuto<DataArrayInt> types=DataArrayInt::New(); types->alloc(nbOfCells,1);
7533 MCAuto<DataArrayInt> offsets=DataArrayInt::New(); offsets->alloc(nbOfCells,1);
7534 MCAuto<DataArrayInt> connectivity=DataArrayInt::New(); connectivity->alloc(_nodal_connec->getNumberOfTuples()-nbOfCells,1);
7535 int *w1=faceoffsets->getPointer(),*w2=types->getPointer(),*w3=offsets->getPointer(),*w4=connectivity->getPointer();
7536 int szFaceOffsets=0,szConn=0;
7537 for(int i=0;i<nbOfCells;i++,w1++,w2++,w3++)
7540 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]!=INTERP_KERNEL::NORM_POLYHED)
7543 *w3=szConn+cIPtr[i+1]-cIPtr[i]-1; szConn+=cIPtr[i+1]-cIPtr[i]-1;
7544 w4=std::copy(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],w4);
7548 int deltaFaceOffset=cIPtr[i+1]-cIPtr[i]+1;
7549 *w1=szFaceOffsets+deltaFaceOffset; szFaceOffsets+=deltaFaceOffset;
7550 std::set<int> c(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1]); c.erase(-1);
7551 *w3=szConn+(int)c.size(); szConn+=(int)c.size();
7552 w4=std::copy(c.begin(),c.end(),w4);
7555 types->transformWithIndArr(MEDCOUPLING2VTKTYPETRADUCER,MEDCOUPLING2VTKTYPETRADUCER+INTERP_KERNEL::NORM_MAXTYPE+1);
7556 types->writeVTK(ofs,8,"UInt8","types",byteData);
7557 offsets->writeVTK(ofs,8,"Int32","offsets",byteData);
7558 if(szFaceOffsets!=0)
7559 {//presence of Polyhedra
7560 connectivity->reAlloc(szConn);
7561 faceoffsets->writeVTK(ofs,8,"Int32","faceoffsets",byteData);
7562 MCAuto<DataArrayInt> faces=DataArrayInt::New(); faces->alloc(szFaceOffsets,1);
7563 w1=faces->getPointer();
7564 for(int i=0;i<nbOfCells;i++)
7565 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]==INTERP_KERNEL::NORM_POLYHED)
7567 int nbFaces=std::count(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],-1)+1;
7569 const int *w6=cPtr+cIPtr[i]+1,*w5=0;
7570 for(int j=0;j<nbFaces;j++)
7572 w5=std::find(w6,cPtr+cIPtr[i+1],-1);
7573 *w1++=(int)std::distance(w6,w5);
7574 w1=std::copy(w6,w5,w1);
7578 faces->writeVTK(ofs,8,"Int32","faces",byteData);
7580 connectivity->writeVTK(ofs,8,"Int32","connectivity",byteData);
7581 ofs << " </Cells>\n";
7582 ofs << " </Piece>\n";
7583 ofs << " </" << getVTKDataSetType() << ">\n";
7586 void MEDCouplingUMesh::reprQuickOverview(std::ostream& stream) const
7588 stream << "MEDCouplingUMesh C++ instance at " << this << ". Name : \"" << getName() << "\".";
7590 { stream << " Not set !"; return ; }
7591 stream << " Mesh dimension : " << _mesh_dim << ".";
7595 { stream << " No coordinates set !"; return ; }
7596 if(!_coords->isAllocated())
7597 { stream << " Coordinates set but not allocated !"; return ; }
7598 stream << " Space dimension : " << _coords->getNumberOfComponents() << "." << std::endl;
7599 stream << "Number of nodes : " << _coords->getNumberOfTuples() << ".";
7600 if(!_nodal_connec_index)
7601 { stream << std::endl << "Nodal connectivity NOT set !"; return ; }
7602 if(!_nodal_connec_index->isAllocated())
7603 { stream << std::endl << "Nodal connectivity set but not allocated !"; return ; }
7604 int lgth=_nodal_connec_index->getNumberOfTuples();
7605 int cpt=_nodal_connec_index->getNumberOfComponents();
7606 if(cpt!=1 || lgth<1)
7608 stream << std::endl << "Number of cells : " << lgth-1 << ".";
7611 std::string MEDCouplingUMesh::getVTKDataSetType() const
7613 return std::string("UnstructuredGrid");
7616 std::string MEDCouplingUMesh::getVTKFileExtension() const
7618 return std::string("vtu");
7624 * Provides a renumbering of the cells of this (which has to be a piecewise connected 1D line), so that
7625 * the segments of the line are indexed in consecutive order (i.e. cells \a i and \a i+1 are neighbors).
7626 * This doesn't modify the mesh. This method only works using nodal connectivity consideration. Coordinates of nodes are ignored here.
7627 * The caller is to deal with the resulting DataArrayInt.
7628 * \throw If the coordinate array is not set.
7629 * \throw If the nodal connectivity of the cells is not defined.
7630 * \throw If m1 is not a mesh of dimension 2, or m1 is not a mesh of dimension 1
7631 * \throw If m2 is not a (piecewise) line (i.e. if a point has more than 2 adjacent segments)
7633 * \sa DataArrayInt::sortEachPairToMakeALinkedList
7635 DataArrayInt *MEDCouplingUMesh::orderConsecutiveCells1D() const
7637 checkFullyDefined();
7638 if(getMeshDimension()!=1)
7639 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D works on unstructured mesh with meshdim = 1 !");
7641 // Check that this is a line (and not a more complex 1D mesh) - each point is used at most by 2 segments:
7642 MCAuto<DataArrayInt> _d(DataArrayInt::New()),_dI(DataArrayInt::New());
7643 MCAuto<DataArrayInt> _rD(DataArrayInt::New()),_rDI(DataArrayInt::New());
7644 MCAuto<MEDCouplingUMesh> m_points(buildDescendingConnectivity(_d, _dI, _rD, _rDI));
7645 const int *d(_d->begin()), *dI(_dI->begin());
7646 const int *rD(_rD->begin()), *rDI(_rDI->begin());
7647 MCAuto<DataArrayInt> _dsi(_rDI->deltaShiftIndex());
7648 const int * dsi(_dsi->begin());
7649 MCAuto<DataArrayInt> dsii = _dsi->findIdsNotInRange(0,3);
7651 if (dsii->getNumberOfTuples())
7652 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D only work with a mesh being a (piecewise) connected line!");
7654 int nc(getNumberOfCells());
7655 MCAuto<DataArrayInt> result(DataArrayInt::New());
7656 result->alloc(nc,1);
7658 // set of edges not used so far
7659 std::set<int> edgeSet;
7660 for (int i=0; i<nc; edgeSet.insert(i), i++);
7664 // while we have points with only one neighbor segments
7667 std::list<int> linePiece;
7668 // fills a list of consecutive segment linked to startSeg. This can go forward or backward.
7669 for (int direction=0;direction<2;direction++) // direction=0 --> forward, direction=1 --> backward
7671 // Fill the list forward (resp. backward) from the start segment:
7672 int activeSeg = startSeg;
7673 int prevPointId = -20;
7675 while (!edgeSet.empty())
7677 if (!(direction == 1 && prevPointId==-20)) // prevent adding twice startSeg
7680 linePiece.push_back(activeSeg);
7682 linePiece.push_front(activeSeg);
7683 edgeSet.erase(activeSeg);
7686 int ptId1 = d[dI[activeSeg]], ptId2 = d[dI[activeSeg]+1];
7687 ptId = direction ? (ptId1 == prevPointId ? ptId2 : ptId1) : (ptId2 == prevPointId ? ptId1 : ptId2);
7688 if (dsi[ptId] == 1) // hitting the end of the line
7691 int seg1 = rD[rDI[ptId]], seg2 = rD[rDI[ptId]+1];
7692 activeSeg = (seg1 == activeSeg) ? seg2 : seg1;
7695 // Done, save final piece into DA:
7696 std::copy(linePiece.begin(), linePiece.end(), result->getPointer()+newIdx);
7697 newIdx += linePiece.size();
7699 // identify next valid start segment (one which is not consumed)
7700 if(!edgeSet.empty())
7701 startSeg = *(edgeSet.begin());
7703 while (!edgeSet.empty());
7704 return result.retn();
7708 * This method split some of edges of 2D cells in \a this. The edges to be split are specified in \a subNodesInSeg
7709 * and in \a subNodesInSegI using \ref numbering-indirect storage mode.
7710 * To do the work this method can optionally needs information about middle of subedges for quadratic cases if
7711 * a minimal creation of new nodes is wanted.
7712 * So this method try to reduce at most the number of new nodes. The only case that can lead this method to add
7713 * nodes if a SEG3 is split without information of middle.
7714 * \b WARNING : is returned value is different from 0 a call to MEDCouplingUMesh::mergeNodes is necessary to
7715 * avoid to have a non conform mesh.
7717 * \return int - the number of new nodes created (in most of cases 0).
7719 * \throw If \a this is not coherent.
7720 * \throw If \a this has not spaceDim equal to 2.
7721 * \throw If \a this has not meshDim equal to 2.
7722 * \throw If some subcells needed to be split are orphan.
7723 * \sa MEDCouplingUMesh::conformize2D
7725 int MEDCouplingUMesh::split2DCells(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI, const DataArrayInt *midOpt, const DataArrayInt *midOptI)
7727 if(!desc || !descI || !subNodesInSeg || !subNodesInSegI)
7728 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : the 4 first arrays must be not null !");
7729 desc->checkAllocated(); descI->checkAllocated(); subNodesInSeg->checkAllocated(); subNodesInSegI->checkAllocated();
7730 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
7731 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : This method only works for meshes with spaceDim=2 and meshDim=2 !");
7732 if(midOpt==0 && midOptI==0)
7734 split2DCellsLinear(desc,descI,subNodesInSeg,subNodesInSegI);
7737 else if(midOpt!=0 && midOptI!=0)
7738 return split2DCellsQuadratic(desc,descI,subNodesInSeg,subNodesInSegI,midOpt,midOptI);
7740 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : middle parameters must be set to null for all or not null for all.");
7744 * 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
7745 * 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
7746 * the geometric cell type set to INTERP_KERNEL::NORM_POLYGON.
7747 * 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
7748 * 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.
7750 * \return false if the input connectivity represents already the convex hull, true if the input cell needs to be reordered.
7752 bool MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis(const double *coords, const int *nodalConnBg, const int *nodalConnEnd, DataArrayInt *nodalConnecOut)
7754 std::size_t sz=std::distance(nodalConnBg,nodalConnEnd);
7757 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)*nodalConnBg);
7758 if(cm.getDimension()==2)
7760 const int *node=nodalConnBg+1;
7761 int startNode=*node++;
7762 double refX=coords[2*startNode];
7763 for(;node!=nodalConnEnd;node++)
7765 if(coords[2*(*node)]<refX)
7768 refX=coords[2*startNode];
7771 std::vector<int> tmpOut; tmpOut.reserve(sz); tmpOut.push_back(startNode);
7775 double angle0=-M_PI/2;
7780 double angleNext=0.;
7781 while(nextNode!=startNode)
7785 for(node=nodalConnBg+1;node!=nodalConnEnd;node++)
7787 if(*node!=tmpOut.back() && *node!=prevNode)
7789 tmp2[0]=coords[2*(*node)]-coords[2*tmpOut.back()]; tmp2[1]=coords[2*(*node)+1]-coords[2*tmpOut.back()+1];
7790 double angleM=INTERP_KERNEL::EdgeArcCircle::GetAbsoluteAngle(tmp2,tmp1);
7795 res=angle0-angleM+2.*M_PI;
7804 if(nextNode!=startNode)
7806 angle0=angleNext-M_PI;
7809 prevNode=tmpOut.back();
7810 tmpOut.push_back(nextNode);
7813 std::vector<int> tmp3(2*(sz-1));
7814 std::vector<int>::iterator it=std::copy(nodalConnBg+1,nodalConnEnd,tmp3.begin());
7815 std::copy(nodalConnBg+1,nodalConnEnd,it);
7816 if(std::search(tmp3.begin(),tmp3.end(),tmpOut.begin(),tmpOut.end())!=tmp3.end())
7818 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
7821 if(std::search(tmp3.rbegin(),tmp3.rend(),tmpOut.begin(),tmpOut.end())!=tmp3.rend())
7823 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
7828 nodalConnecOut->pushBackSilent((int)INTERP_KERNEL::NORM_POLYGON);
7829 nodalConnecOut->insertAtTheEnd(tmpOut.begin(),tmpOut.end());
7834 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
7837 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
7841 * This method works on an input pair (\b arr, \b arrIndx) where \b arr indexes is in \b arrIndx.
7842 * 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.
7844 * \param [in] idsToRemoveBg begin of set of ids to remove in \b arr (included)
7845 * \param [in] idsToRemoveEnd end of set of ids to remove in \b arr (excluded)
7846 * \param [in,out] arr array in which the remove operation will be done.
7847 * \param [in,out] arrIndx array in the remove operation will modify
7848 * \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])
7849 * \return true if \b arr and \b arrIndx have been modified, false if not.
7851 bool MEDCouplingUMesh::RemoveIdsFromIndexedArrays(const int *idsToRemoveBg, const int *idsToRemoveEnd, DataArrayInt *arr, DataArrayInt *arrIndx, int offsetForRemoval)
7853 if(!arrIndx || !arr)
7854 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::RemoveIdsFromIndexedArrays : some input arrays are empty !");
7855 if(offsetForRemoval<0)
7856 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::RemoveIdsFromIndexedArrays : offsetForRemoval should be >=0 !");
7857 std::set<int> s(idsToRemoveBg,idsToRemoveEnd);
7858 int nbOfGrps=arrIndx->getNumberOfTuples()-1;
7859 int *arrIPtr=arrIndx->getPointer();
7862 const int *arrPtr=arr->begin();
7863 std::vector<int> arrOut;//no utility to switch to DataArrayInt because copy always needed
7864 for(int i=0;i<nbOfGrps;i++,arrIPtr++)
7866 if(*arrIPtr-previousArrI>offsetForRemoval)
7868 for(const int *work=arrPtr+previousArrI+offsetForRemoval;work!=arrPtr+*arrIPtr;work++)
7870 if(s.find(*work)==s.end())
7871 arrOut.push_back(*work);
7874 previousArrI=*arrIPtr;
7875 *arrIPtr=(int)arrOut.size();
7877 if(arr->getNumberOfTuples()==arrOut.size())
7879 arr->alloc((int)arrOut.size(),1);
7880 std::copy(arrOut.begin(),arrOut.end(),arr->getPointer());
7885 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn
7886 * (\ref numbering-indirect).
7887 * This method returns the result of the extraction ( specified by a set of ids in [\b idsOfSelectBg , \b idsOfSelectEnd ) ).
7888 * The selection of extraction is done standardly in new2old format.
7889 * This method returns indexed arrays (\ref numbering-indirect) using 2 arrays (arrOut,arrIndexOut).
7891 * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
7892 * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
7893 * \param [in] arrIn arr origin array from which the extraction will be done.
7894 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7895 * \param [out] arrOut the resulting array
7896 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
7897 * \sa MEDCouplingUMesh::ExtractFromIndexedArraysSlice
7899 void MEDCouplingUMesh::ExtractFromIndexedArrays(const int *idsOfSelectBg, const int *idsOfSelectEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
7900 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
7902 if(!arrIn || !arrIndxIn)
7903 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : input pointer is NULL !");
7904 arrIn->checkAllocated(); arrIndxIn->checkAllocated();
7905 if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1)
7906 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : input arrays must have exactly one component !");
7907 std::size_t sz=std::distance(idsOfSelectBg,idsOfSelectEnd);
7908 const int *arrInPtr=arrIn->begin();
7909 const int *arrIndxPtr=arrIndxIn->begin();
7910 int nbOfGrps=arrIndxIn->getNumberOfTuples()-1;
7912 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : The format of \"arrIndxIn\" is invalid ! Its nb of tuples should be >=1 !");
7913 int maxSizeOfArr=arrIn->getNumberOfTuples();
7914 MCAuto<DataArrayInt> arro=DataArrayInt::New();
7915 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
7916 arrIo->alloc((int)(sz+1),1);
7917 const int *idsIt=idsOfSelectBg;
7918 int *work=arrIo->getPointer();
7921 for(std::size_t i=0;i<sz;i++,work++,idsIt++)
7923 if(*idsIt>=0 && *idsIt<nbOfGrps)
7924 lgth+=arrIndxPtr[*idsIt+1]-arrIndxPtr[*idsIt];
7927 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " ! Must be in [0," << nbOfGrps << ") !";
7928 throw INTERP_KERNEL::Exception(oss.str());
7934 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " and at this pos arrIndxIn[" << *idsIt;
7935 oss << "+1]-arrIndxIn[" << *idsIt << "] < 0 ! The input index array is bugged !";
7936 throw INTERP_KERNEL::Exception(oss.str());
7939 arro->alloc(lgth,1);
7940 work=arro->getPointer();
7941 idsIt=idsOfSelectBg;
7942 for(std::size_t i=0;i<sz;i++,idsIt++)
7944 if(arrIndxPtr[*idsIt]>=0 && arrIndxPtr[*idsIt+1]<=maxSizeOfArr)
7945 work=std::copy(arrInPtr+arrIndxPtr[*idsIt],arrInPtr+arrIndxPtr[*idsIt+1],work);
7948 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " arrIndx[" << *idsIt << "] must be >= 0 and arrIndx[";
7949 oss << *idsIt << "+1] <= " << maxSizeOfArr << " (the size of arrIn)!";
7950 throw INTERP_KERNEL::Exception(oss.str());
7954 arrIndexOut=arrIo.retn();
7958 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn
7959 * (\ref numbering-indirect).
7960 * 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 ).
7961 * The selection of extraction is done standardly in new2old format.
7962 * This method returns indexed arrays (\ref numbering-indirect) using 2 arrays (arrOut,arrIndexOut).
7964 * \param [in] idsOfSelectStart begin of set of ids of the input extraction (included)
7965 * \param [in] idsOfSelectStop end of set of ids of the input extraction (excluded)
7966 * \param [in] idsOfSelectStep
7967 * \param [in] arrIn arr origin array from which the extraction will be done.
7968 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7969 * \param [out] arrOut the resulting array
7970 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
7971 * \sa MEDCouplingUMesh::ExtractFromIndexedArrays
7973 void MEDCouplingUMesh::ExtractFromIndexedArraysSlice(int idsOfSelectStart, int idsOfSelectStop, int idsOfSelectStep, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
7974 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
7976 if(!arrIn || !arrIndxIn)
7977 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : input pointer is NULL !");
7978 arrIn->checkAllocated(); arrIndxIn->checkAllocated();
7979 if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1)
7980 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : input arrays must have exactly one component !");
7981 int sz=DataArrayInt::GetNumberOfItemGivenBESRelative(idsOfSelectStart,idsOfSelectStop,idsOfSelectStep,"MEDCouplingUMesh::ExtractFromIndexedArraysSlice : Input slice ");
7982 const int *arrInPtr=arrIn->begin();
7983 const int *arrIndxPtr=arrIndxIn->begin();
7984 int nbOfGrps=arrIndxIn->getNumberOfTuples()-1;
7986 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : The format of \"arrIndxIn\" is invalid ! Its nb of tuples should be >=1 !");
7987 int maxSizeOfArr=arrIn->getNumberOfTuples();
7988 MCAuto<DataArrayInt> arro=DataArrayInt::New();
7989 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
7990 arrIo->alloc((int)(sz+1),1);
7991 int idsIt=idsOfSelectStart;
7992 int *work=arrIo->getPointer();
7995 for(int i=0;i<sz;i++,work++,idsIt+=idsOfSelectStep)
7997 if(idsIt>=0 && idsIt<nbOfGrps)
7998 lgth+=arrIndxPtr[idsIt+1]-arrIndxPtr[idsIt];
8001 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " ! Must be in [0," << nbOfGrps << ") !";
8002 throw INTERP_KERNEL::Exception(oss.str());
8008 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " and at this pos arrIndxIn[" << idsIt;
8009 oss << "+1]-arrIndxIn[" << idsIt << "] < 0 ! The input index array is bugged !";
8010 throw INTERP_KERNEL::Exception(oss.str());
8013 arro->alloc(lgth,1);
8014 work=arro->getPointer();
8015 idsIt=idsOfSelectStart;
8016 for(int i=0;i<sz;i++,idsIt+=idsOfSelectStep)
8018 if(arrIndxPtr[idsIt]>=0 && arrIndxPtr[idsIt+1]<=maxSizeOfArr)
8019 work=std::copy(arrInPtr+arrIndxPtr[idsIt],arrInPtr+arrIndxPtr[idsIt+1],work);
8022 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " arrIndx[" << idsIt << "] must be >= 0 and arrIndx[";
8023 oss << idsIt << "+1] <= " << maxSizeOfArr << " (the size of arrIn)!";
8024 throw INTERP_KERNEL::Exception(oss.str());
8028 arrIndexOut=arrIo.retn();
8032 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
8033 * 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
8034 * cellIds \b in [ \b idsOfSelectBg , \b idsOfSelectEnd ) a copy coming from the corresponding values in input pair (\b srcArr, \b srcArrIndex).
8035 * This method is an generalization of MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx that performs the same thing but by without building explicitly a result output arrays.
8037 * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
8038 * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
8039 * \param [in] arrIn arr origin array from which the extraction will be done.
8040 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
8041 * \param [in] srcArr input array that will be used as source of copy for ids in [ \b idsOfSelectBg, \b idsOfSelectEnd )
8042 * \param [in] srcArrIndex index array of \b srcArr
8043 * \param [out] arrOut the resulting array
8044 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
8046 * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx
8048 void MEDCouplingUMesh::SetPartOfIndexedArrays(const int *idsOfSelectBg, const int *idsOfSelectEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
8049 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex,
8050 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
8052 if(arrIn==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
8053 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArrays : presence of null pointer in input parameter !");
8054 MCAuto<DataArrayInt> arro=DataArrayInt::New();
8055 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
8056 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
8057 std::vector<bool> v(nbOfTuples,true);
8059 const int *arrIndxInPtr=arrIndxIn->begin();
8060 const int *srcArrIndexPtr=srcArrIndex->begin();
8061 for(const int *it=idsOfSelectBg;it!=idsOfSelectEnd;it++,srcArrIndexPtr++)
8063 if(*it>=0 && *it<nbOfTuples)
8066 offset+=(srcArrIndexPtr[1]-srcArrIndexPtr[0])-(arrIndxInPtr[*it+1]-arrIndxInPtr[*it]);
8070 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArrays : On pos #" << std::distance(idsOfSelectBg,it) << " value is " << *it << " not in [0," << nbOfTuples << ") !";
8071 throw INTERP_KERNEL::Exception(oss.str());
8074 srcArrIndexPtr=srcArrIndex->begin();
8075 arrIo->alloc(nbOfTuples+1,1);
8076 arro->alloc(arrIn->getNumberOfTuples()+offset,1);
8077 const int *arrInPtr=arrIn->begin();
8078 const int *srcArrPtr=srcArr->begin();
8079 int *arrIoPtr=arrIo->getPointer(); *arrIoPtr++=0;
8080 int *arroPtr=arro->getPointer();
8081 for(int ii=0;ii<nbOfTuples;ii++,arrIoPtr++)
8085 arroPtr=std::copy(arrInPtr+arrIndxInPtr[ii],arrInPtr+arrIndxInPtr[ii+1],arroPtr);
8086 *arrIoPtr=arrIoPtr[-1]+(arrIndxInPtr[ii+1]-arrIndxInPtr[ii]);
8090 std::size_t pos=std::distance(idsOfSelectBg,std::find(idsOfSelectBg,idsOfSelectEnd,ii));
8091 arroPtr=std::copy(srcArrPtr+srcArrIndexPtr[pos],srcArrPtr+srcArrIndexPtr[pos+1],arroPtr);
8092 *arrIoPtr=arrIoPtr[-1]+(srcArrIndexPtr[pos+1]-srcArrIndexPtr[pos]);
8096 arrIndexOut=arrIo.retn();
8100 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
8101 * This method is an specialization of MEDCouplingUMesh::SetPartOfIndexedArrays in the case of assignment do not modify the index in \b arrIndxIn.
8103 * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
8104 * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
8105 * \param [in,out] arrInOut arr origin array from which the extraction will be done.
8106 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
8107 * \param [in] srcArr input array that will be used as source of copy for ids in [ \b idsOfSelectBg , \b idsOfSelectEnd )
8108 * \param [in] srcArrIndex index array of \b srcArr
8110 * \sa MEDCouplingUMesh::SetPartOfIndexedArrays
8112 void MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx(const int *idsOfSelectBg, const int *idsOfSelectEnd, DataArrayInt *arrInOut, const DataArrayInt *arrIndxIn,
8113 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex)
8115 if(arrInOut==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
8116 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx : presence of null pointer in input parameter !");
8117 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
8118 const int *arrIndxInPtr=arrIndxIn->begin();
8119 const int *srcArrIndexPtr=srcArrIndex->begin();
8120 int *arrInOutPtr=arrInOut->getPointer();
8121 const int *srcArrPtr=srcArr->begin();
8122 for(const int *it=idsOfSelectBg;it!=idsOfSelectEnd;it++,srcArrIndexPtr++)
8124 if(*it>=0 && *it<nbOfTuples)
8126 if(srcArrIndexPtr[1]-srcArrIndexPtr[0]==arrIndxInPtr[*it+1]-arrIndxInPtr[*it])
8127 std::copy(srcArrPtr+srcArrIndexPtr[0],srcArrPtr+srcArrIndexPtr[1],arrInOutPtr+arrIndxInPtr[*it]);
8130 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] !";
8131 throw INTERP_KERNEL::Exception(oss.str());
8136 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx : On pos #" << std::distance(idsOfSelectBg,it) << " value is " << *it << " not in [0," << nbOfTuples << ") !";
8137 throw INTERP_KERNEL::Exception(oss.str());
8143 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
8144 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
8145 * 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]].
8146 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
8147 * A negative value in \b arrIn means that it is ignored.
8148 * 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.
8150 * \param [in] arrIn arr origin array from which the extraction will be done.
8151 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
8152 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
8153 * \sa MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed, MEDCouplingUMesh::partitionBySpreadZone
8155 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGradually(const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn)
8157 int seed=0,nbOfDepthPeelingPerformed=0;
8158 return ComputeSpreadZoneGraduallyFromSeed(&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfDepthPeelingPerformed);
8162 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
8163 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
8164 * 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]].
8165 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
8166 * A negative value in \b arrIn means that it is ignored.
8167 * 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.
8168 * \param [in] seedBg the begin pointer (included) of an array containing the seed of the search zone
8169 * \param [in] seedEnd the end pointer (not included) of an array containing the seed of the search zone
8170 * \param [in] arrIn arr origin array from which the extraction will be done.
8171 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
8172 * \param [in] nbOfDepthPeeling the max number of peels requested in search. By default -1, that is to say, no limit.
8173 * \param [out] nbOfDepthPeelingPerformed the number of peels effectively performed. May be different from \a nbOfDepthPeeling
8174 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
8175 * \sa MEDCouplingUMesh::partitionBySpreadZone
8177 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(const int *seedBg, const int *seedEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn, int nbOfDepthPeeling, int& nbOfDepthPeelingPerformed)
8179 nbOfDepthPeelingPerformed=0;
8181 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed : arrIndxIn input pointer is NULL !");
8182 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
8185 DataArrayInt *ret=DataArrayInt::New(); ret->alloc(0,1);
8189 std::vector<bool> fetched(nbOfTuples,false);
8190 return ComputeSpreadZoneGraduallyFromSeedAlg(fetched,seedBg,seedEnd,arrIn,arrIndxIn,nbOfDepthPeeling,nbOfDepthPeelingPerformed);
8195 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
8196 * 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
8197 * cellIds \b in [\b idsOfSelectBg, \b idsOfSelectEnd) a copy coming from the corresponding values in input pair (\b srcArr, \b srcArrIndex).
8198 * This method is an generalization of MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx that performs the same thing but by without building explicitly a result output arrays.
8200 * \param [in] start begin of set of ids of the input extraction (included)
8201 * \param [in] end end of set of ids of the input extraction (excluded)
8202 * \param [in] step step of the set of ids in range mode.
8203 * \param [in] arrIn arr origin array from which the extraction will be done.
8204 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
8205 * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd)
8206 * \param [in] srcArrIndex index array of \b srcArr
8207 * \param [out] arrOut the resulting array
8208 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
8210 * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx MEDCouplingUMesh::SetPartOfIndexedArrays
8212 void MEDCouplingUMesh::SetPartOfIndexedArraysSlice(int start, int end, int step, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
8213 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex,
8214 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
8216 if(arrIn==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
8217 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSlice : presence of null pointer in input parameter !");
8218 MCAuto<DataArrayInt> arro=DataArrayInt::New();
8219 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
8220 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
8222 const int *arrIndxInPtr=arrIndxIn->begin();
8223 const int *srcArrIndexPtr=srcArrIndex->begin();
8224 int nbOfElemsToSet=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::SetPartOfIndexedArraysSlice : ");
8226 for(int i=0;i<nbOfElemsToSet;i++,srcArrIndexPtr++,it+=step)
8228 if(it>=0 && it<nbOfTuples)
8229 offset+=(srcArrIndexPtr[1]-srcArrIndexPtr[0])-(arrIndxInPtr[it+1]-arrIndxInPtr[it]);
8232 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSlice : On pos #" << i << " value is " << it << " not in [0," << nbOfTuples << ") !";
8233 throw INTERP_KERNEL::Exception(oss.str());
8236 srcArrIndexPtr=srcArrIndex->begin();
8237 arrIo->alloc(nbOfTuples+1,1);
8238 arro->alloc(arrIn->getNumberOfTuples()+offset,1);
8239 const int *arrInPtr=arrIn->begin();
8240 const int *srcArrPtr=srcArr->begin();
8241 int *arrIoPtr=arrIo->getPointer(); *arrIoPtr++=0;
8242 int *arroPtr=arro->getPointer();
8243 for(int ii=0;ii<nbOfTuples;ii++,arrIoPtr++)
8245 int pos=DataArray::GetPosOfItemGivenBESRelativeNoThrow(ii,start,end,step);
8248 arroPtr=std::copy(arrInPtr+arrIndxInPtr[ii],arrInPtr+arrIndxInPtr[ii+1],arroPtr);
8249 *arrIoPtr=arrIoPtr[-1]+(arrIndxInPtr[ii+1]-arrIndxInPtr[ii]);
8253 arroPtr=std::copy(srcArrPtr+srcArrIndexPtr[pos],srcArrPtr+srcArrIndexPtr[pos+1],arroPtr);
8254 *arrIoPtr=arrIoPtr[-1]+(srcArrIndexPtr[pos+1]-srcArrIndexPtr[pos]);
8258 arrIndexOut=arrIo.retn();
8262 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
8263 * This method is an specialization of MEDCouplingUMesh::SetPartOfIndexedArrays in the case of assignment do not modify the index in \b arrIndxIn.
8265 * \param [in] start begin of set of ids of the input extraction (included)
8266 * \param [in] end end of set of ids of the input extraction (excluded)
8267 * \param [in] step step of the set of ids in range mode.
8268 * \param [in,out] arrInOut arr origin array from which the extraction will be done.
8269 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
8270 * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd)
8271 * \param [in] srcArrIndex index array of \b srcArr
8273 * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSlice MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx
8275 void MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice(int start, int end, int step, DataArrayInt *arrInOut, const DataArrayInt *arrIndxIn,
8276 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex)
8278 if(arrInOut==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
8279 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : presence of null pointer in input parameter !");
8280 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
8281 const int *arrIndxInPtr=arrIndxIn->begin();
8282 const int *srcArrIndexPtr=srcArrIndex->begin();
8283 int *arrInOutPtr=arrInOut->getPointer();
8284 const int *srcArrPtr=srcArr->begin();
8285 int nbOfElemsToSet=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : ");
8287 for(int i=0;i<nbOfElemsToSet;i++,srcArrIndexPtr++,it+=step)
8289 if(it>=0 && it<nbOfTuples)
8291 if(srcArrIndexPtr[1]-srcArrIndexPtr[0]==arrIndxInPtr[it+1]-arrIndxInPtr[it])
8292 std::copy(srcArrPtr+srcArrIndexPtr[0],srcArrPtr+srcArrIndexPtr[1],arrInOutPtr+arrIndxInPtr[it]);
8295 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : On pos #" << i << " id (idsOfSelectBg[" << i << "]) is " << it << " arrIndxIn[id+1]-arrIndxIn[id]!=srcArrIndex[pos+1]-srcArrIndex[pos] !";
8296 throw INTERP_KERNEL::Exception(oss.str());
8301 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : On pos #" << i << " value is " << it << " not in [0," << nbOfTuples << ") !";
8302 throw INTERP_KERNEL::Exception(oss.str());
8308 * \b this is expected to be a mesh fully defined whose spaceDim==meshDim.
8309 * It returns a new allocated mesh having the same mesh dimension and lying on same coordinates.
8310 * The returned mesh contains as poly cells as number of contiguous zone (regarding connectivity).
8311 * A spread contiguous zone is built using poly cells (polyhedra in 3D, polygons in 2D and polyline in 1D).
8312 * The sum of measure field of returned mesh is equal to the sum of measure field of this.
8314 * \return a newly allocated mesh lying on the same coords than \b this with same meshdimension than \b this.
8316 MEDCouplingUMesh *MEDCouplingUMesh::buildSpreadZonesWithPoly() const
8318 checkFullyDefined();
8319 int mdim=getMeshDimension();
8320 int spaceDim=getSpaceDimension();
8322 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension and spacedimension do not match !");
8323 std::vector<DataArrayInt *> partition=partitionBySpreadZone();
8324 std::vector< MCAuto<DataArrayInt> > partitionAuto; partitionAuto.reserve(partition.size());
8325 std::copy(partition.begin(),partition.end(),std::back_insert_iterator<std::vector< MCAuto<DataArrayInt> > >(partitionAuto));
8326 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
8327 ret->setCoords(getCoords());
8328 ret->allocateCells((int)partition.size());
8330 for(std::vector<DataArrayInt *>::const_iterator it=partition.begin();it!=partition.end();it++)
8332 MCAuto<MEDCouplingUMesh> tmp=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf((*it)->begin(),(*it)->end(),true));
8333 MCAuto<DataArrayInt> cell;
8337 cell=tmp->buildUnionOf2DMesh();
8340 cell=tmp->buildUnionOf3DMesh();
8343 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension supported are [2,3] ! Not implemented yet for others !");
8346 ret->insertNextCell((INTERP_KERNEL::NormalizedCellType)cell->getIJSafe(0,0),cell->getNumberOfTuples()-1,cell->begin()+1);
8349 ret->finishInsertingCells();
8354 * This method partitions \b this into contiguous zone.
8355 * This method only needs a well defined connectivity. Coordinates are not considered here.
8356 * This method returns a vector of \b newly allocated arrays that the caller has to deal with.
8358 std::vector<DataArrayInt *> MEDCouplingUMesh::partitionBySpreadZone() const
8360 DataArrayInt *neigh=0,*neighI=0;
8361 computeNeighborsOfCells(neigh,neighI);
8362 MCAuto<DataArrayInt> neighAuto(neigh),neighIAuto(neighI);
8363 return PartitionBySpreadZone(neighAuto,neighIAuto);
8366 std::vector<DataArrayInt *> MEDCouplingUMesh::PartitionBySpreadZone(const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn)
8368 if(!arrIn || !arrIndxIn)
8369 throw INTERP_KERNEL::Exception("PartitionBySpreadZone : null input pointers !");
8370 arrIn->checkAllocated(); arrIndxIn->checkAllocated();
8371 int nbOfTuples(arrIndxIn->getNumberOfTuples());
8372 if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1 || nbOfTuples<1)
8373 throw INTERP_KERNEL::Exception("PartitionBySpreadZone : invalid arrays in input !");
8374 int nbOfCellsCur(nbOfTuples-1);
8375 std::vector<DataArrayInt *> ret;
8378 std::vector<bool> fetchedCells(nbOfCellsCur,false);
8379 std::vector< MCAuto<DataArrayInt> > ret2;
8381 while(seed<nbOfCellsCur)
8383 int nbOfPeelPerformed=0;
8384 ret2.push_back(ComputeSpreadZoneGraduallyFromSeedAlg(fetchedCells,&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfPeelPerformed));
8385 seed=(int)std::distance(fetchedCells.begin(),std::find(fetchedCells.begin()+seed,fetchedCells.end(),false));
8387 for(std::vector< MCAuto<DataArrayInt> >::iterator it=ret2.begin();it!=ret2.end();it++)
8388 ret.push_back((*it).retn());
8393 * This method returns given a distribution of cell type (returned for example by MEDCouplingUMesh::getDistributionOfTypes method and customized after) a
8394 * newly allocated DataArrayInt instance with 2 components ready to be interpreted as input of DataArrayInt::findRangeIdForEachTuple method.
8396 * \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.
8397 * \return a newly allocated DataArrayInt to be managed by the caller.
8398 * \throw In case of \a code has not the right format (typically of size 3*n)
8400 DataArrayInt *MEDCouplingUMesh::ComputeRangesFromTypeDistribution(const std::vector<int>& code)
8402 MCAuto<DataArrayInt> ret=DataArrayInt::New();
8403 std::size_t nb=code.size()/3;
8404 if(code.size()%3!=0)
8405 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeRangesFromTypeDistribution : invalid input code !");
8406 ret->alloc((int)nb,2);
8407 int *retPtr=ret->getPointer();
8408 for(std::size_t i=0;i<nb;i++,retPtr+=2)
8410 retPtr[0]=code[3*i+2];
8411 retPtr[1]=code[3*i+2]+code[3*i+1];
8417 * This method expects that \a this a 3D mesh (spaceDim=3 and meshDim=3) with all coordinates and connectivities set.
8418 * All cells in \a this are expected to be linear 3D cells.
8419 * This method will split **all** 3D cells in \a this into INTERP_KERNEL::NORM_TETRA4 cells and put them in the returned mesh.
8420 * It leads to an increase to number of cells.
8421 * This method contrary to MEDCouplingUMesh::simplexize can append coordinates in \a this to perform its work.
8422 * The \a nbOfAdditionalPoints returned value informs about it. If > 0, the coordinates array in returned mesh will have \a nbOfAdditionalPoints
8423 * more tuples (nodes) than in \a this. Anyway, all the nodes in \a this (with the same order) will be in the returned mesh.
8425 * \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.
8426 * For all other cells, the splitting policy will be ignored. See INTERP_KERNEL::SplittingPolicy for the images.
8427 * \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.
8428 * \param [out] n2oCells - A new instance of DataArrayInt holding, for each new cell,
8429 * an id of old cell producing it. The caller is to delete this array using
8430 * decrRef() as it is no more needed.
8431 * \return MEDCoupling1SGTUMesh * - the mesh containing only INTERP_KERNEL::NORM_TETRA4 cells.
8433 * \warning This method operates on each cells in this independently ! So it can leads to non conform mesh in returned value ! If you expect to have a conform mesh in output
8434 * the policy PLANAR_FACE_6 should be used on a mesh sorted with MEDCoupling1SGTUMesh::sortHexa8EachOther.
8436 * \throw If \a this is not a 3D mesh (spaceDim==3 and meshDim==3).
8437 * \throw If \a this is not fully constituted with linear 3D cells.
8438 * \sa MEDCouplingUMesh::simplexize, MEDCoupling1SGTUMesh::sortHexa8EachOther
8440 MEDCoupling1SGTUMesh *MEDCouplingUMesh::tetrahedrize(int policy, DataArrayInt *& n2oCells, int& nbOfAdditionalPoints) const
8442 INTERP_KERNEL::SplittingPolicy pol((INTERP_KERNEL::SplittingPolicy)policy);
8443 checkConnectivityFullyDefined();
8444 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
8445 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tetrahedrize : only available for mesh with meshdim == 3 and spacedim == 3 !");
8446 int nbOfCells(getNumberOfCells()),nbNodes(getNumberOfNodes());
8447 MCAuto<MEDCoupling1SGTUMesh> ret0(MEDCoupling1SGTUMesh::New(getName(),INTERP_KERNEL::NORM_TETRA4));
8448 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(nbOfCells,1);
8449 int *retPt(ret->getPointer());
8450 MCAuto<DataArrayInt> newConn(DataArrayInt::New()); newConn->alloc(0,1);
8451 MCAuto<DataArrayDouble> addPts(DataArrayDouble::New()); addPts->alloc(0,1);
8452 const int *oldc(_nodal_connec->begin());
8453 const int *oldci(_nodal_connec_index->begin());
8454 const double *coords(_coords->begin());
8455 for(int i=0;i<nbOfCells;i++,oldci++,retPt++)
8457 std::vector<int> a; std::vector<double> b;
8458 INTERP_KERNEL::SplitIntoTetras(pol,(INTERP_KERNEL::NormalizedCellType)oldc[oldci[0]],oldc+oldci[0]+1,oldc+oldci[1],coords,a,b);
8459 std::size_t nbOfTet(a.size()/4); *retPt=(int)nbOfTet;
8460 const int *aa(&a[0]);
8463 for(std::vector<int>::iterator it=a.begin();it!=a.end();it++)
8465 *it=(-(*(it))-1+nbNodes);
8466 addPts->insertAtTheEnd(b.begin(),b.end());
8467 nbNodes+=(int)b.size()/3;
8469 for(std::size_t j=0;j<nbOfTet;j++,aa+=4)
8470 newConn->insertAtTheEnd(aa,aa+4);
8472 if(!addPts->empty())
8474 addPts->rearrange(3);
8475 nbOfAdditionalPoints=addPts->getNumberOfTuples();
8476 addPts=DataArrayDouble::Aggregate(getCoords(),addPts);
8477 ret0->setCoords(addPts);
8481 nbOfAdditionalPoints=0;
8482 ret0->setCoords(getCoords());
8484 ret0->setNodalConnectivity(newConn);
8486 ret->computeOffsetsFull();
8487 n2oCells=ret->buildExplicitArrOfSliceOnScaledArr(0,nbOfCells,1);
8491 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),
8492 _own_cell(true),_cell_id(-1),_nb_cell(0)
8497 _nb_cell=mesh->getNumberOfCells();
8501 MEDCouplingUMeshCellIterator::~MEDCouplingUMeshCellIterator()
8509 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh, MEDCouplingUMeshCell *itc, int bg, int end):_mesh(mesh),_cell(itc),
8510 _own_cell(false),_cell_id(bg-1),
8517 MEDCouplingUMeshCell *MEDCouplingUMeshCellIterator::nextt()
8520 if(_cell_id<_nb_cell)
8529 MEDCouplingUMeshCellByTypeEntry::MEDCouplingUMeshCellByTypeEntry(MEDCouplingUMesh *mesh):_mesh(mesh)
8535 MEDCouplingUMeshCellByTypeIterator *MEDCouplingUMeshCellByTypeEntry::iterator()
8537 return new MEDCouplingUMeshCellByTypeIterator(_mesh);
8540 MEDCouplingUMeshCellByTypeEntry::~MEDCouplingUMeshCellByTypeEntry()
8546 MEDCouplingUMeshCellEntry::MEDCouplingUMeshCellEntry(MEDCouplingUMesh *mesh, INTERP_KERNEL::NormalizedCellType type, MEDCouplingUMeshCell *itc, int bg, int end):_mesh(mesh),_type(type),
8554 MEDCouplingUMeshCellEntry::~MEDCouplingUMeshCellEntry()
8560 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCellEntry::getType() const
8565 int MEDCouplingUMeshCellEntry::getNumberOfElems() const
8570 MEDCouplingUMeshCellIterator *MEDCouplingUMeshCellEntry::iterator()
8572 return new MEDCouplingUMeshCellIterator(_mesh,_itc,_bg,_end);
8575 MEDCouplingUMeshCellByTypeIterator::MEDCouplingUMeshCellByTypeIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),_cell_id(0),_nb_cell(0)
8580 _nb_cell=mesh->getNumberOfCells();
8584 MEDCouplingUMeshCellByTypeIterator::~MEDCouplingUMeshCellByTypeIterator()
8591 MEDCouplingUMeshCellEntry *MEDCouplingUMeshCellByTypeIterator::nextt()
8593 const int *c=_mesh->getNodalConnectivity()->begin();
8594 const int *ci=_mesh->getNodalConnectivityIndex()->begin();
8595 if(_cell_id<_nb_cell)
8597 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[_cell_id]];
8598 int nbOfElems=(int)std::distance(ci+_cell_id,std::find_if(ci+_cell_id,ci+_nb_cell,MEDCouplingImpl::ConnReader(c,type)));
8599 int startId=_cell_id;
8600 _cell_id+=nbOfElems;
8601 return new MEDCouplingUMeshCellEntry(_mesh,type,_cell,startId,_cell_id);
8607 MEDCouplingUMeshCell::MEDCouplingUMeshCell(MEDCouplingUMesh *mesh):_conn(0),_conn_indx(0),_conn_lgth(NOTICABLE_FIRST_VAL)
8611 _conn=mesh->getNodalConnectivity()->getPointer();
8612 _conn_indx=mesh->getNodalConnectivityIndex()->getPointer();
8616 void MEDCouplingUMeshCell::next()
8618 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8623 _conn_lgth=_conn_indx[1]-_conn_indx[0];
8626 std::string MEDCouplingUMeshCell::repr() const
8628 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8630 std::ostringstream oss; oss << "Cell Type " << INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)_conn[0]).getRepr();
8632 std::copy(_conn+1,_conn+_conn_lgth,std::ostream_iterator<int>(oss," "));
8636 return std::string("MEDCouplingUMeshCell::repr : Invalid pos");
8639 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCell::getType() const
8641 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8642 return (INTERP_KERNEL::NormalizedCellType)_conn[0];
8644 return INTERP_KERNEL::NORM_ERROR;
8647 const int *MEDCouplingUMeshCell::getAllConn(int& lgth) const
8650 if(_conn_lgth!=NOTICABLE_FIRST_VAL)