1 // Copyright (C) 2007-2016 CEA/DEN, EDF R&D
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 // Author : Anthony Geay (CEA/DEN)
21 #include "MEDCouplingUMesh.hxx"
22 #include "MEDCouplingCMesh.hxx"
23 #include "MEDCoupling1GTUMesh.hxx"
24 #include "MEDCouplingFieldDouble.hxx"
25 #include "MEDCouplingSkyLineArray.hxx"
26 #include "CellModel.hxx"
27 #include "VolSurfUser.txx"
28 #include "InterpolationUtils.hxx"
29 #include "PointLocatorAlgos.txx"
31 #include "BBTreeDst.txx"
32 #include "SplitterTetra.hxx"
33 #include "DiameterCalculator.hxx"
34 #include "DirectedBoundingBox.hxx"
35 #include "InterpKernelMatrixTools.hxx"
36 #include "InterpKernelMeshQuality.hxx"
37 #include "InterpKernelCellSimplify.hxx"
38 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
39 #include "InterpKernelAutoPtr.hxx"
40 #include "InterpKernelGeo2DNode.hxx"
41 #include "InterpKernelGeo2DEdgeLin.hxx"
42 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
43 #include "InterpKernelGeo2DQuadraticPolygon.hxx"
44 #include "MEDCouplingUMesh_internal.hxx"
53 using namespace MEDCoupling;
55 double MEDCouplingUMesh::EPS_FOR_POLYH_ORIENTATION=1.e-14;
58 const INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::MEDMEM_ORDER[N_MEDMEM_ORDER] = { INTERP_KERNEL::NORM_POINT1, INTERP_KERNEL::NORM_SEG2, INTERP_KERNEL::NORM_SEG3, INTERP_KERNEL::NORM_SEG4, INTERP_KERNEL::NORM_POLYL, INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4, INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_TRI7, INTERP_KERNEL::NORM_QUAD8, INTERP_KERNEL::NORM_QUAD9, INTERP_KERNEL::NORM_POLYGON, INTERP_KERNEL::NORM_QPOLYG, INTERP_KERNEL::NORM_TETRA4, INTERP_KERNEL::NORM_PYRA5, INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXA8, INTERP_KERNEL::NORM_HEXGP12, INTERP_KERNEL::NORM_TETRA10, INTERP_KERNEL::NORM_PYRA13, INTERP_KERNEL::NORM_PENTA15, INTERP_KERNEL::NORM_HEXA20, INTERP_KERNEL::NORM_HEXA27, INTERP_KERNEL::NORM_POLYHED };
59 const int MEDCouplingUMesh::MEDCOUPLING2VTKTYPETRADUCER[INTERP_KERNEL::NORM_MAXTYPE+1]={1,3,21,5,9,7,22,34,23,28,-1,-1,-1,-1,10,14,13,-1,12,-1,24,-1,16,27,-1,26,-1,29,-1,-1,25,42,36,4};
62 MEDCouplingUMesh *MEDCouplingUMesh::New()
64 return new MEDCouplingUMesh;
67 MEDCouplingUMesh *MEDCouplingUMesh::New(const std::string& meshName, int meshDim)
69 MEDCouplingUMesh *ret=new MEDCouplingUMesh;
70 ret->setName(meshName);
71 ret->setMeshDimension(meshDim);
76 * Returns a new MEDCouplingUMesh which is a full copy of \a this one. No data is shared
77 * between \a this and the new mesh.
78 * \return MEDCouplingUMesh * - a new instance of MEDCouplingMesh. The caller is to
79 * delete this mesh using decrRef() as it is no more needed.
81 MEDCouplingUMesh *MEDCouplingUMesh::deepCopy() const
88 * Returns a new MEDCouplingUMesh which is a copy of \a this one.
89 * \param [in] recDeepCpy - if \a true, the copy is deep, else all data arrays of \a
90 * this mesh are shared by the new mesh.
91 * \return MEDCouplingUMesh * - a new instance of MEDCouplingMesh. The caller is to
92 * delete this mesh using decrRef() as it is no more needed.
94 MEDCouplingUMesh *MEDCouplingUMesh::clone(bool recDeepCpy) const
96 return new MEDCouplingUMesh(*this,recDeepCpy);
100 * This method behaves mostly like MEDCouplingUMesh::deepCopy method, except that only nodal connectivity arrays are deeply copied.
101 * The coordinates are shared between \a this and the returned instance.
103 * \return MEDCouplingUMesh * - A new object instance holding the copy of \a this (deep for connectivity, shallow for coordiantes)
104 * \sa MEDCouplingUMesh::deepCopy
106 MEDCouplingUMesh *MEDCouplingUMesh::deepCopyConnectivityOnly() const
108 checkConnectivityFullyDefined();
109 MCAuto<MEDCouplingUMesh> ret=clone(false);
110 MCAuto<DataArrayInt> c(getNodalConnectivity()->deepCopy()),ci(getNodalConnectivityIndex()->deepCopy());
111 ret->setConnectivity(c,ci);
115 void MEDCouplingUMesh::shallowCopyConnectivityFrom(const MEDCouplingPointSet *other)
118 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is null !");
119 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
121 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is not an MEDCouplingUMesh instance !");
122 MEDCouplingUMesh *otherC2=const_cast<MEDCouplingUMesh *>(otherC);//sorry :(
123 setConnectivity(otherC2->getNodalConnectivity(),otherC2->getNodalConnectivityIndex(),true);
126 std::size_t MEDCouplingUMesh::getHeapMemorySizeWithoutChildren() const
128 std::size_t ret(MEDCouplingPointSet::getHeapMemorySizeWithoutChildren());
132 std::vector<const BigMemoryObject *> MEDCouplingUMesh::getDirectChildrenWithNull() const
134 std::vector<const BigMemoryObject *> ret(MEDCouplingPointSet::getDirectChildrenWithNull());
135 ret.push_back(_nodal_connec);
136 ret.push_back(_nodal_connec_index);
140 void MEDCouplingUMesh::updateTime() const
142 MEDCouplingPointSet::updateTime();
145 updateTimeWith(*_nodal_connec);
147 if(_nodal_connec_index)
149 updateTimeWith(*_nodal_connec_index);
153 MEDCouplingUMesh::MEDCouplingUMesh():_mesh_dim(-2),_nodal_connec(0),_nodal_connec_index(0)
158 * Checks if \a this mesh is well defined. If no exception is thrown by this method,
159 * then \a this mesh is most probably is writable, exchangeable and available for most
160 * of algorithms. When a mesh is constructed from scratch, it is a good habit to call
161 * this method to check that all is in order with \a this mesh.
162 * \throw If the mesh dimension is not set.
163 * \throw If the coordinates array is not set (if mesh dimension != -1 ).
164 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
165 * \throw If the connectivity data array has more than one component.
166 * \throw If the connectivity data array has a named component.
167 * \throw If the connectivity index data array has more than one component.
168 * \throw If the connectivity index data array has a named component.
170 void MEDCouplingUMesh::checkConsistencyLight() const
173 throw INTERP_KERNEL::Exception("No mesh dimension specified !");
175 MEDCouplingPointSet::checkConsistencyLight();
176 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
178 if((int)INTERP_KERNEL::CellModel::GetCellModel(*iter).getDimension()!=_mesh_dim)
180 std::ostringstream message;
181 message << "Mesh invalid because dimension is " << _mesh_dim << " and there is presence of cell(s) with type " << (*iter);
182 throw INTERP_KERNEL::Exception(message.str().c_str());
187 if(_nodal_connec->getNumberOfComponents()!=1)
188 throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to be with number of components set to one !");
189 if(_nodal_connec->getInfoOnComponent(0)!="")
190 throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to have no info on its single component !");
194 throw INTERP_KERNEL::Exception("Nodal connectivity array is not defined !");
195 if(_nodal_connec_index)
197 if(_nodal_connec_index->getNumberOfComponents()!=1)
198 throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to be with number of components set to one !");
199 if(_nodal_connec_index->getInfoOnComponent(0)!="")
200 throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to have no info on its single component !");
204 throw INTERP_KERNEL::Exception("Nodal connectivity index array is not defined !");
208 * Checks if \a this mesh is well defined. If no exception is thrown by this method,
209 * then \a this mesh is most probably is writable, exchangeable and available for all
210 * algorithms. <br> In addition to the checks performed by checkConsistencyLight(), this
211 * method thoroughly checks the nodal connectivity.
212 * \param [in] eps - a not used parameter.
213 * \throw If the mesh dimension is not set.
214 * \throw If the coordinates array is not set (if mesh dimension != -1 ).
215 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
216 * \throw If the connectivity data array has more than one component.
217 * \throw If the connectivity data array has a named component.
218 * \throw If the connectivity index data array has more than one component.
219 * \throw If the connectivity index data array has a named component.
220 * \throw If number of nodes defining an element does not correspond to the type of element.
221 * \throw If the nodal connectivity includes an invalid node id.
223 void MEDCouplingUMesh::checkConsistency(double eps) const
225 checkConsistencyLight();
228 int meshDim=getMeshDimension();
229 int nbOfNodes=getNumberOfNodes();
230 int nbOfCells=getNumberOfCells();
231 const int *ptr=_nodal_connec->getConstPointer();
232 const int *ptrI=_nodal_connec_index->getConstPointer();
233 for(int i=0;i<nbOfCells;i++)
235 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)ptr[ptrI[i]]);
236 if((int)cm.getDimension()!=meshDim)
238 std::ostringstream oss;
239 oss << "MEDCouplingUMesh::checkConsistency : cell << #" << i<< " with type Type " << cm.getRepr() << " in 'this' whereas meshdim == " << meshDim << " !";
240 throw INTERP_KERNEL::Exception(oss.str());
242 int nbOfNodesInCell=ptrI[i+1]-ptrI[i]-1;
244 if(nbOfNodesInCell!=(int)cm.getNumberOfNodes())
246 std::ostringstream oss;
247 oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with static Type '" << cm.getRepr() << "' has " << cm.getNumberOfNodes();
248 oss << " nodes whereas in connectivity there is " << nbOfNodesInCell << " nodes ! Looks very bad !";
249 throw INTERP_KERNEL::Exception(oss.str());
251 if(cm.isQuadratic() && cm.isDynamic() && meshDim == 2)
252 if (nbOfNodesInCell % 2 || nbOfNodesInCell < 4)
254 std::ostringstream oss;
255 oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with quadratic type '" << cm.getRepr() << "' has " << nbOfNodesInCell;
256 oss << " nodes. This should be even, and greater or equal than 4!! Looks very bad!";
257 throw INTERP_KERNEL::Exception(oss.str());
259 for(const int *w=ptr+ptrI[i]+1;w!=ptr+ptrI[i+1];w++)
264 if(nodeId>=nbOfNodes)
266 std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " whereas there are only " << nbOfNodes << " nodes in the mesh !";
267 throw INTERP_KERNEL::Exception(oss.str());
272 std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " in connectivity ! sounds bad !";
273 throw INTERP_KERNEL::Exception(oss.str());
277 if((INTERP_KERNEL::NormalizedCellType)(ptr[ptrI[i]])!=INTERP_KERNEL::NORM_POLYHED)
279 std::ostringstream oss; oss << "Cell #" << i << " is built with node #-1 in connectivity ! sounds bad !";
280 throw INTERP_KERNEL::Exception(oss.str());
288 * Sets dimension of \a this mesh. The mesh dimension in general depends on types of
289 * elements contained in the mesh. For more info on the mesh dimension see
290 * \ref MEDCouplingUMeshPage.
291 * \param [in] meshDim - a new mesh dimension.
292 * \throw If \a meshDim is invalid. A valid range is <em> -1 <= meshDim <= 3</em>.
294 void MEDCouplingUMesh::setMeshDimension(int meshDim)
296 if(meshDim<-1 || meshDim>3)
297 throw INTERP_KERNEL::Exception("Invalid meshDim specified ! Must be greater or equal to -1 and lower or equal to 3 !");
303 * Allocates memory to store an estimation of the given number of cells. The closer is the estimation to the number of cells effectively inserted,
304 * the less will the library need to reallocate memory. If the number of cells to be inserted is not known simply put 0 to this parameter.
305 * If a nodal connectivity previouly existed before the call of this method, it will be reset.
307 * \param [in] nbOfCells - estimation of the number of cell \a this mesh will contain.
309 * \if ENABLE_EXAMPLES
310 * \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
311 * \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
314 void MEDCouplingUMesh::allocateCells(int nbOfCells)
317 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::allocateCells : the input number of cells should be >= 0 !");
318 if(_nodal_connec_index)
320 _nodal_connec_index->decrRef();
324 _nodal_connec->decrRef();
326 _nodal_connec_index=DataArrayInt::New();
327 _nodal_connec_index->reserve(nbOfCells+1);
328 _nodal_connec_index->pushBackSilent(0);
329 _nodal_connec=DataArrayInt::New();
330 _nodal_connec->reserve(2*nbOfCells);
336 * Appends a cell to the connectivity array. For deeper understanding what is
337 * happening see \ref MEDCouplingUMeshNodalConnectivity.
338 * \param [in] type - type of cell to add.
339 * \param [in] size - number of nodes constituting this cell.
340 * \param [in] nodalConnOfCell - the connectivity of the cell to add.
342 * \if ENABLE_EXAMPLES
343 * \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
344 * \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
347 void MEDCouplingUMesh::insertNextCell(INTERP_KERNEL::NormalizedCellType type, int size, const int *nodalConnOfCell)
349 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
350 if(_nodal_connec_index==0)
351 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::insertNextCell : nodal connectivity not set ! invoke allocateCells before calling insertNextCell !");
352 if((int)cm.getDimension()==_mesh_dim)
355 if(size!=(int)cm.getNumberOfNodes())
357 std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : Trying to push a " << cm.getRepr() << " cell with a size of " << size;
358 oss << " ! Expecting " << cm.getNumberOfNodes() << " !";
359 throw INTERP_KERNEL::Exception(oss.str());
361 int idx=_nodal_connec_index->back();
363 _nodal_connec_index->pushBackSilent(val);
364 _nodal_connec->writeOnPlace(idx,type,nodalConnOfCell,size);
369 std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : cell type " << cm.getRepr() << " has a dimension " << cm.getDimension();
370 oss << " whereas Mesh Dimension of current UMesh instance is set to " << _mesh_dim << " ! Please invoke \"setMeshDimension\" method before or invoke ";
371 oss << "\"MEDCouplingUMesh::New\" static method with 2 parameters name and meshDimension !";
372 throw INTERP_KERNEL::Exception(oss.str());
377 * Compacts data arrays to release unused memory. This method is to be called after
378 * finishing cell insertion using \a this->insertNextCell().
380 * \if ENABLE_EXAMPLES
381 * \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
382 * \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
385 void MEDCouplingUMesh::finishInsertingCells()
387 _nodal_connec->pack();
388 _nodal_connec_index->pack();
389 _nodal_connec->declareAsNew();
390 _nodal_connec_index->declareAsNew();
395 * Entry point for iteration over cells of this. Warning the returned cell iterator should be deallocated.
396 * Useful for python users.
398 MEDCouplingUMeshCellIterator *MEDCouplingUMesh::cellIterator()
400 return new MEDCouplingUMeshCellIterator(this);
404 * Entry point for iteration over cells groups geo types per geotypes. Warning the returned cell iterator should be deallocated.
405 * If \a this is not so that that cells are grouped by geo types this method will throw an exception.
406 * In this case MEDCouplingUMesh::sortCellsInMEDFileFrmt or MEDCouplingUMesh::rearrange2ConsecutiveCellTypes methods for example can be called before invoking this method.
407 * Useful for python users.
409 MEDCouplingUMeshCellByTypeEntry *MEDCouplingUMesh::cellsByType()
411 if(!checkConsecutiveCellTypes())
412 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::cellsByType : this mesh is not sorted by type !");
413 return new MEDCouplingUMeshCellByTypeEntry(this);
417 * Returns a set of all cell types available in \a this mesh.
418 * \return std::set<INTERP_KERNEL::NormalizedCellType> - the set of cell types.
419 * \warning this method does not throw any exception even if \a this is not defined.
420 * \sa MEDCouplingUMesh::getAllGeoTypesSorted
422 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypes() const
428 * This method returns the sorted list of geometric types in \a this.
429 * 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
430 * having the same geometric type. So a same geometric type can appear more than once if the cells are not sorted per geometric type.
432 * \throw if connectivity in \a this is not correctly defined.
434 * \sa MEDCouplingMesh::getAllGeoTypes
436 std::vector<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypesSorted() const
438 std::vector<INTERP_KERNEL::NormalizedCellType> ret;
439 checkConnectivityFullyDefined();
440 int nbOfCells(getNumberOfCells());
443 if(getNodalConnectivityArrayLen()<1)
444 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAllGeoTypesSorted : the connectivity in this seems invalid !");
445 const int *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin());
446 ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci++]);
447 for(int i=1;i<nbOfCells;i++,ci++)
448 if(ret.back()!=((INTERP_KERNEL::NormalizedCellType)c[*ci]))
449 ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci]);
454 * This method is a method that compares \a this and \a other.
455 * This method compares \b all attributes, even names and component names.
457 bool MEDCouplingUMesh::isEqualIfNotWhy(const MEDCouplingMesh *other, double prec, std::string& reason) const
460 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isEqualIfNotWhy : input other pointer is null !");
461 std::ostringstream oss; oss.precision(15);
462 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
465 reason="mesh given in input is not castable in MEDCouplingUMesh !";
468 if(!MEDCouplingPointSet::isEqualIfNotWhy(other,prec,reason))
470 if(_mesh_dim!=otherC->_mesh_dim)
472 oss << "umesh dimension mismatch : this mesh dimension=" << _mesh_dim << " other mesh dimension=" << otherC->_mesh_dim;
476 if(_types!=otherC->_types)
478 oss << "umesh geometric type mismatch :\nThis geometric types are :";
479 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
480 { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
481 oss << "\nOther geometric types are :";
482 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=otherC->_types.begin();iter!=otherC->_types.end();iter++)
483 { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
487 if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
488 if(_nodal_connec==0 || otherC->_nodal_connec==0)
490 reason="Only one UMesh between the two this and other has its nodal connectivity DataArrayInt defined !";
493 if(_nodal_connec!=otherC->_nodal_connec)
494 if(!_nodal_connec->isEqualIfNotWhy(*otherC->_nodal_connec,reason))
496 reason.insert(0,"Nodal connectivity DataArrayInt differ : ");
499 if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
500 if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
502 reason="Only one UMesh between the two this and other has its nodal connectivity index DataArrayInt defined !";
505 if(_nodal_connec_index!=otherC->_nodal_connec_index)
506 if(!_nodal_connec_index->isEqualIfNotWhy(*otherC->_nodal_connec_index,reason))
508 reason.insert(0,"Nodal connectivity index DataArrayInt differ : ");
515 * Checks if data arrays of this mesh (node coordinates, nodal
516 * connectivity of cells, etc) of two meshes are same. Textual data like name etc. are
518 * \param [in] other - the mesh to compare with.
519 * \param [in] prec - precision value used to compare node coordinates.
520 * \return bool - \a true if the two meshes are same.
522 bool MEDCouplingUMesh::isEqualWithoutConsideringStr(const MEDCouplingMesh *other, double prec) const
524 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
527 if(!MEDCouplingPointSet::isEqualWithoutConsideringStr(other,prec))
529 if(_mesh_dim!=otherC->_mesh_dim)
531 if(_types!=otherC->_types)
533 if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
534 if(_nodal_connec==0 || otherC->_nodal_connec==0)
536 if(_nodal_connec!=otherC->_nodal_connec)
537 if(!_nodal_connec->isEqualWithoutConsideringStr(*otherC->_nodal_connec))
539 if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
540 if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
542 if(_nodal_connec_index!=otherC->_nodal_connec_index)
543 if(!_nodal_connec_index->isEqualWithoutConsideringStr(*otherC->_nodal_connec_index))
549 * Checks if \a this and \a other meshes are geometrically equivalent with high
550 * probability, else an exception is thrown. The meshes are considered equivalent if
551 * (1) meshes contain the same number of nodes and the same number of elements of the
552 * same types (2) three cells of the two meshes (first, last and middle) are based
553 * on coincident nodes (with a specified precision).
554 * \param [in] other - the mesh to compare with.
555 * \param [in] prec - the precision used to compare nodes of the two meshes.
556 * \throw If the two meshes do not match.
558 void MEDCouplingUMesh::checkFastEquivalWith(const MEDCouplingMesh *other, double prec) const
560 MEDCouplingPointSet::checkFastEquivalWith(other,prec);
561 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
563 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkFastEquivalWith : Two meshes are not not unstructured !");
567 * Returns the reverse nodal connectivity. The reverse nodal connectivity enumerates
568 * cells each node belongs to.
569 * \warning For speed reasons, this method does not check if node ids in the nodal
570 * connectivity correspond to the size of node coordinates array.
571 * \param [in,out] revNodal - an array holding ids of cells sharing each node.
572 * \param [in,out] revNodalIndx - an array, of length \a this->getNumberOfNodes() + 1,
573 * dividing cell ids in \a revNodal into groups each referring to one
574 * node. Its every element (except the last one) is an index pointing to the
575 * first id of a group of cells. For example cells sharing the node #1 are
576 * described by following range of indices:
577 * [ \a revNodalIndx[1], \a revNodalIndx[2] ) and the cell ids are
578 * \a revNodal[ \a revNodalIndx[1] ], \a revNodal[ \a revNodalIndx[1] + 1], ...
579 * Number of cells sharing the *i*-th node is
580 * \a revNodalIndx[ *i*+1 ] - \a revNodalIndx[ *i* ].
581 * \throw If the coordinates array is not set.
582 * \throw If the nodal connectivity of cells is not defined.
584 * \if ENABLE_EXAMPLES
585 * \ref cpp_mcumesh_getReverseNodalConnectivity "Here is a C++ example".<br>
586 * \ref py_mcumesh_getReverseNodalConnectivity "Here is a Python example".
589 void MEDCouplingUMesh::getReverseNodalConnectivity(DataArrayInt *revNodal, DataArrayInt *revNodalIndx) const
592 int nbOfNodes(getNumberOfNodes());
593 int *revNodalIndxPtr=(int *)malloc((nbOfNodes+1)*sizeof(int));
594 revNodalIndx->useArray(revNodalIndxPtr,true,C_DEALLOC,nbOfNodes+1,1);
595 std::fill(revNodalIndxPtr,revNodalIndxPtr+nbOfNodes+1,0);
596 const int *conn(_nodal_connec->begin()),*connIndex(_nodal_connec_index->begin());
597 int nbOfCells(getNumberOfCells()),nbOfEltsInRevNodal(0);
598 for(int eltId=0;eltId<nbOfCells;eltId++)
600 const int *strtNdlConnOfCurCell(conn+connIndex[eltId]+1),*endNdlConnOfCurCell(conn+connIndex[eltId+1]);
601 for(const int *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
602 if(*iter>=0)//for polyhedrons
604 nbOfEltsInRevNodal++;
605 revNodalIndxPtr[(*iter)+1]++;
608 std::transform(revNodalIndxPtr+1,revNodalIndxPtr+nbOfNodes+1,revNodalIndxPtr,revNodalIndxPtr+1,std::plus<int>());
609 int *revNodalPtr=(int *)malloc((nbOfEltsInRevNodal)*sizeof(int));
610 revNodal->useArray(revNodalPtr,true,C_DEALLOC,nbOfEltsInRevNodal,1);
611 std::fill(revNodalPtr,revNodalPtr+nbOfEltsInRevNodal,-1);
612 for(int eltId=0;eltId<nbOfCells;eltId++)
614 const int *strtNdlConnOfCurCell=conn+connIndex[eltId]+1;
615 const int *endNdlConnOfCurCell=conn+connIndex[eltId+1];
616 for(const int *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
617 if(*iter>=0)//for polyhedrons
618 *std::find_if(revNodalPtr+revNodalIndxPtr[*iter],revNodalPtr+revNodalIndxPtr[*iter+1],std::bind2nd(std::equal_to<int>(),-1))=eltId;
623 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
624 * this->getMeshDimension(), that bound cells of \a this mesh. In addition arrays
625 * describing correspondence between cells of \a this and the result meshes are
626 * returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending connectivity,
627 * i.e. enumerate cells of the result mesh bounding each cell of \a this mesh. The
628 * arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
629 * i.e. enumerate cells of \a this mesh bounded by each cell of the result mesh.
630 * \warning For speed reasons, this method does not check if node ids in the nodal
631 * connectivity correspond to the size of node coordinates array.
632 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
633 * to write this mesh to the MED file, its cells must be sorted using
634 * sortCellsInMEDFileFrmt().
635 * \param [in,out] desc - the array containing cell ids of the result mesh bounding
636 * each cell of \a this mesh.
637 * \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
638 * dividing cell ids in \a desc into groups each referring to one
639 * cell of \a this mesh. Its every element (except the last one) is an index
640 * pointing to the first id of a group of cells. For example cells of the
641 * result mesh bounding the cell #1 of \a this mesh are described by following
643 * [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
644 * \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
645 * Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
646 * \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
647 * \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
648 * by each cell of the result mesh.
649 * \param [in,out] revDescIndx - the array, of length one more than number of cells
650 * in the result mesh,
651 * dividing cell ids in \a revDesc into groups each referring to one
652 * cell of the result mesh the same way as \a descIndx divides \a desc.
653 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is to
654 * delete this mesh using decrRef() as it is no more needed.
655 * \throw If the coordinates array is not set.
656 * \throw If the nodal connectivity of cells is node defined.
657 * \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
658 * revDescIndx == NULL.
660 * \if ENABLE_EXAMPLES
661 * \ref cpp_mcumesh_buildDescendingConnectivity "Here is a C++ example".<br>
662 * \ref py_mcumesh_buildDescendingConnectivity "Here is a Python example".
664 * \sa buildDescendingConnectivity2()
666 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
668 return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
672 * \a this has to have a mesh dimension equal to 3. If it is not the case an INTERP_KERNEL::Exception will be thrown.
673 * This behaves exactly as MEDCouplingUMesh::buildDescendingConnectivity does except that this method compute directly the transition from mesh dimension 3 to sub edges (dimension 1)
674 * in one shot. That is to say that this method is equivalent to 2 successive calls to MEDCouplingUMesh::buildDescendingConnectivity.
675 * This method returns 4 arrays and a mesh as MEDCouplingUMesh::buildDescendingConnectivity does.
676 * \sa MEDCouplingUMesh::buildDescendingConnectivity
678 MEDCouplingUMesh *MEDCouplingUMesh::explode3DMeshTo1D(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
681 if(getMeshDimension()!=3)
682 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explode3DMeshTo1D : This has to have a mesh dimension to 3 !");
683 return buildDescendingConnectivityGen<MinusTwoSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
687 * 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.
688 * This method works for both meshes with mesh dimenstion equal to 2 or 3. Dynamical cells are not supported (polygons, polyhedrons...)
690 * \sa explode3DMeshTo1D, buildDescendingConnectiviy
692 MEDCouplingUMesh *MEDCouplingUMesh::explodeMeshIntoMicroEdges(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
695 switch(getMeshDimension())
698 return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
700 return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
702 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explodeMeshIntoMicroEdges : Only 2D and 3D supported !");
707 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
708 * this->getMeshDimension(), that bound cells of \a this mesh. In
709 * addition arrays describing correspondence between cells of \a this and the result
710 * meshes are returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending
711 * connectivity, i.e. enumerate cells of the result mesh bounding each cell of \a this
712 * mesh. This method differs from buildDescendingConnectivity() in that apart
713 * from cell ids, \a desc returns mutual orientation of cells in \a this and the
714 * result meshes. So a positive id means that order of nodes in corresponding cells
715 * of two meshes is same, and a negative id means a reverse order of nodes. Since a
716 * cell with id #0 can't be negative, the array \a desc returns ids in FORTRAN mode,
717 * i.e. cell ids are one-based.
718 * Arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
719 * i.e. enumerate cells of \a this mesh bounded by each cell of the result mesh.
720 * \warning For speed reasons, this method does not check if node ids in the nodal
721 * connectivity correspond to the size of node coordinates array.
722 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
723 * to write this mesh to the MED file, its cells must be sorted using
724 * sortCellsInMEDFileFrmt().
725 * \param [in,out] desc - the array containing cell ids of the result mesh bounding
726 * each cell of \a this mesh.
727 * \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
728 * dividing cell ids in \a desc into groups each referring to one
729 * cell of \a this mesh. Its every element (except the last one) is an index
730 * pointing to the first id of a group of cells. For example cells of the
731 * result mesh bounding the cell #1 of \a this mesh are described by following
733 * [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
734 * \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
735 * Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
736 * \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
737 * \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
738 * by each cell of the result mesh.
739 * \param [in,out] revDescIndx - the array, of length one more than number of cells
740 * in the result mesh,
741 * dividing cell ids in \a revDesc into groups each referring to one
742 * cell of the result mesh the same way as \a descIndx divides \a desc.
743 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This result mesh
744 * shares the node coordinates array with \a this mesh. The caller is to
745 * delete this mesh using decrRef() as it is no more needed.
746 * \throw If the coordinates array is not set.
747 * \throw If the nodal connectivity of cells is node defined.
748 * \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
749 * revDescIndx == NULL.
751 * \if ENABLE_EXAMPLES
752 * \ref cpp_mcumesh_buildDescendingConnectivity2 "Here is a C++ example".<br>
753 * \ref py_mcumesh_buildDescendingConnectivity2 "Here is a Python example".
755 * \sa buildDescendingConnectivity()
757 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity2(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
759 return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingOrientationSensitiveNbrer);
763 * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
764 * For speed reasons no check of this will be done. This method calls
765 * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
766 * This method lists cell by cell in \b this which are its neighbors. To compute the result
767 * only connectivities are considered.
768 * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
769 * The format of return is hence \ref numbering-indirect.
771 * \param [out] neighbors is an array storing all the neighbors of all cells in \b this. This array is newly
772 * allocated and should be dealt by the caller. \b neighborsIndx 2nd output
773 * parameter allows to select the right part in this array (\ref numbering-indirect). The number of tuples
774 * is equal to the last values in \b neighborsIndx.
775 * \param [out] neighborsIndx is an array of size this->getNumberOfCells()+1 newly allocated and should be
776 * dealt by the caller. This arrays allow to use the first output parameter \b neighbors (\ref numbering-indirect).
778 void MEDCouplingUMesh::computeNeighborsOfCells(DataArrayInt *&neighbors, DataArrayInt *&neighborsIndx) const
780 MCAuto<DataArrayInt> desc=DataArrayInt::New();
781 MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
782 MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
783 MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
784 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
786 ComputeNeighborsOfCellsAdv(desc,descIndx,revDesc,revDescIndx,neighbors,neighborsIndx);
789 void MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne(const DataArrayInt *nodeNeigh, const DataArrayInt *nodeNeighI, MCAuto<DataArrayInt>& cellNeigh, MCAuto<DataArrayInt>& cellNeighIndex) const
791 if(!nodeNeigh || !nodeNeighI)
792 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : null pointer !");
793 checkConsistencyLight();
794 nodeNeigh->checkAllocated(); nodeNeighI->checkAllocated();
795 nodeNeigh->checkNbOfComps(1,"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : node neigh");
796 nodeNeighI->checkNbOfComps(1,"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : node neigh index");
797 nodeNeighI->checkNbOfTuples(1+getNumberOfNodes(),"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : invalid length");
798 int nbCells(getNumberOfCells());
799 const int *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin()),*ne(nodeNeigh->begin()),*nei(nodeNeighI->begin());
800 cellNeigh=DataArrayInt::New(); cellNeigh->alloc(0,1); cellNeighIndex=DataArrayInt::New(); cellNeighIndex->alloc(1,1); cellNeighIndex->setIJ(0,0,0);
801 for(int i=0;i<nbCells;i++)
804 for(const int *it=c+ci[i]+1;it!=c+ci[i+1];it++)
806 s.insert(ne+nei[*it],ne+nei[*it+1]);
808 cellNeigh->insertAtTheEnd(s.begin(),s.end());
809 cellNeighIndex->pushBackSilent(cellNeigh->getNumberOfTuples());
814 * This method is called by MEDCouplingUMesh::computeNeighborsOfCells. This methods performs the algorithm
815 * of MEDCouplingUMesh::computeNeighborsOfCells.
816 * This method is useful for users that want to reduce along a criterion the set of neighbours cell. This is
817 * typically the case to extract a set a neighbours,
818 * excluding a set of meshdim-1 cells in input descending connectivity.
819 * Typically \b desc, \b descIndx, \b revDesc and \b revDescIndx (\ref numbering-indirect) input params are
820 * the result of MEDCouplingUMesh::buildDescendingConnectivity.
821 * This method lists cell by cell in \b this which are its neighbors. To compute the result only connectivities
823 * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
825 * \param [in] desc descending connectivity array.
826 * \param [in] descIndx descending connectivity index array used to walk through \b desc (\ref numbering-indirect).
827 * \param [in] revDesc reverse descending connectivity array.
828 * \param [in] revDescIndx reverse descending connectivity index array used to walk through \b revDesc (\ref numbering-indirect).
829 * \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
830 * parameter allows to select the right part in this array. The number of tuples is equal to the last values in \b neighborsIndx.
831 * \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.
833 void MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(const DataArrayInt *desc, const DataArrayInt *descIndx, const DataArrayInt *revDesc, const DataArrayInt *revDescIndx,
834 DataArrayInt *&neighbors, DataArrayInt *&neighborsIndx)
836 if(!desc || !descIndx || !revDesc || !revDescIndx)
837 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeNeighborsOfCellsAdv some input array is empty !");
838 const int *descPtr=desc->begin();
839 const int *descIPtr=descIndx->begin();
840 const int *revDescPtr=revDesc->begin();
841 const int *revDescIPtr=revDescIndx->begin();
843 int nbCells=descIndx->getNumberOfTuples()-1;
844 MCAuto<DataArrayInt> out0=DataArrayInt::New();
845 MCAuto<DataArrayInt> out1=DataArrayInt::New(); out1->alloc(nbCells+1,1);
846 int *out1Ptr=out1->getPointer();
848 out0->reserve(desc->getNumberOfTuples());
849 for(int i=0;i<nbCells;i++,descIPtr++,out1Ptr++)
851 for(const int *w1=descPtr+descIPtr[0];w1!=descPtr+descIPtr[1];w1++)
853 std::set<int> s(revDescPtr+revDescIPtr[*w1],revDescPtr+revDescIPtr[(*w1)+1]);
855 out0->insertAtTheEnd(s.begin(),s.end());
857 *out1Ptr=out0->getNumberOfTuples();
859 neighbors=out0.retn();
860 neighborsIndx=out1.retn();
864 * Explodes \a this into edges whatever its dimension.
866 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::explodeIntoEdges(MCAuto<DataArrayInt>& desc, MCAuto<DataArrayInt>& descIndex, MCAuto<DataArrayInt>& revDesc, MCAuto<DataArrayInt>& revDescIndx) const
869 int mdim(getMeshDimension());
870 desc=DataArrayInt::New(); descIndex=DataArrayInt::New(); revDesc=DataArrayInt::New(); revDescIndx=DataArrayInt::New();
871 MCAuto<MEDCouplingUMesh> mesh1D;
876 mesh1D=explode3DMeshTo1D(desc,descIndex,revDesc,revDescIndx);
881 mesh1D=buildDescendingConnectivity(desc,descIndex,revDesc,revDescIndx);
886 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2] !");
893 * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
894 * For speed reasons no check of this will be done. This method calls
895 * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
896 * This method lists node by node in \b this which are its neighbors. To compute the result
897 * only connectivities are considered.
898 * The neighbor nodes of node having id 'nodeId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
900 * \param [out] neighbors is an array storing all the neighbors of all nodes in \b this. This array
901 * is newly allocated and should be dealt by the caller. \b neighborsIndx 2nd output
902 * parameter allows to select the right part in this array (\ref numbering-indirect).
903 * The number of tuples is equal to the last values in \b neighborsIndx.
904 * \param [out] neighborsIdx is an array of size this->getNumberOfCells()+1 newly allocated and should
905 * be dealt by the caller. This arrays allow to use the first output parameter \b neighbors.
907 * \sa MEDCouplingUMesh::computeEnlargedNeighborsOfNodes
909 void MEDCouplingUMesh::computeNeighborsOfNodes(DataArrayInt *&neighbors, DataArrayInt *&neighborsIdx) const
912 int mdim(getMeshDimension()),nbNodes(getNumberOfNodes());
913 MCAuto<DataArrayInt> desc(DataArrayInt::New()),descIndx(DataArrayInt::New()),revDesc(DataArrayInt::New()),revDescIndx(DataArrayInt::New());
914 MCConstAuto<MEDCouplingUMesh> mesh1D;
919 mesh1D=explode3DMeshTo1D(desc,descIndx,revDesc,revDescIndx);
924 mesh1D=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
929 mesh1D.takeRef(this);
934 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2,1] !");
937 desc=DataArrayInt::New(); descIndx=DataArrayInt::New(); revDesc=0; revDescIndx=0;
938 mesh1D->getReverseNodalConnectivity(desc,descIndx);
939 MCAuto<DataArrayInt> ret0(DataArrayInt::New());
940 ret0->alloc(desc->getNumberOfTuples(),1);
941 int *r0Pt(ret0->getPointer());
942 const int *c1DPtr(mesh1D->getNodalConnectivity()->begin()),*rn(desc->begin()),*rni(descIndx->begin());
943 for(int i=0;i<nbNodes;i++,rni++)
945 for(const int *oneDCellIt=rn+rni[0];oneDCellIt!=rn+rni[1];oneDCellIt++)
946 *r0Pt++=c1DPtr[3*(*oneDCellIt)+1]==i?c1DPtr[3*(*oneDCellIt)+2]:c1DPtr[3*(*oneDCellIt)+1];
948 neighbors=ret0.retn();
949 neighborsIdx=descIndx.retn();
953 * 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.
954 * 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.
955 * This method is useful to find ghost cells of a part of a mesh with a code based on fields on nodes.
957 * \sa MEDCouplingUMesh::computeNeighborsOfNodes
959 void MEDCouplingUMesh::computeEnlargedNeighborsOfNodes(MCAuto<DataArrayInt> &neighbors, MCAuto<DataArrayInt>& neighborsIdx) const
962 int nbOfNodes(getNumberOfNodes());
963 const int *conn(_nodal_connec->begin()),*connIndex(_nodal_connec_index->begin());
964 int nbOfCells(getNumberOfCells());
965 std::vector< std::set<int> > st0(nbOfNodes);
966 for(int eltId=0;eltId<nbOfCells;eltId++)
968 const int *strtNdlConnOfCurCell(conn+connIndex[eltId]+1),*endNdlConnOfCurCell(conn+connIndex[eltId+1]);
969 std::set<int> s(strtNdlConnOfCurCell,endNdlConnOfCurCell); s.erase(-1); //for polyhedrons
970 for(std::set<int>::const_iterator iter2=s.begin();iter2!=s.end();iter2++)
971 st0[*iter2].insert(s.begin(),s.end());
973 neighborsIdx=DataArrayInt::New(); neighborsIdx->alloc(nbOfNodes+1,1); neighborsIdx->setIJ(0,0,0);
975 int *neighIdx(neighborsIdx->getPointer());
976 for(std::vector< std::set<int> >::const_iterator it=st0.begin();it!=st0.end();it++,neighIdx++)
977 neighIdx[1]=neighIdx[0]+(*it).size()-1;
979 neighbors=DataArrayInt::New(); neighbors->alloc(neighborsIdx->back(),1);
981 const int *neighIdx(neighborsIdx->begin());
982 int *neigh(neighbors->getPointer()),nodeId(0);
983 for(std::vector< std::set<int> >::const_iterator it=st0.begin();it!=st0.end();it++,neighIdx++,nodeId++)
985 std::set<int> s(*it); s.erase(nodeId);
986 std::copy(s.begin(),s.end(),neigh+*neighIdx);
992 * Converts specified cells to either polygons (if \a this is a 2D mesh) or
993 * polyhedrons (if \a this is a 3D mesh). The cells to convert are specified by an
994 * array of cell ids. Pay attention that after conversion all algorithms work slower
995 * with \a this mesh than before conversion. <br> If an exception is thrown during the
996 * conversion due presence of invalid ids in the array of cells to convert, as a
997 * result \a this mesh contains some already converted elements. In this case the 2D
998 * mesh remains valid but 3D mesh becomes \b inconsistent!
999 * \warning This method can significantly modify the order of geometric types in \a this,
1000 * hence, to write this mesh to the MED file, its cells must be sorted using
1001 * sortCellsInMEDFileFrmt().
1002 * \param [in] cellIdsToConvertBg - the array holding ids of cells to convert.
1003 * \param [in] cellIdsToConvertEnd - a pointer to the last-plus-one-th element of \a
1004 * cellIdsToConvertBg.
1005 * \throw If the coordinates array is not set.
1006 * \throw If the nodal connectivity of cells is node defined.
1007 * \throw If dimension of \a this mesh is not either 2 or 3.
1009 * \if ENABLE_EXAMPLES
1010 * \ref cpp_mcumesh_convertToPolyTypes "Here is a C++ example".<br>
1011 * \ref py_mcumesh_convertToPolyTypes "Here is a Python example".
1014 void MEDCouplingUMesh::convertToPolyTypes(const int *cellIdsToConvertBg, const int *cellIdsToConvertEnd)
1016 checkFullyDefined();
1017 int dim=getMeshDimension();
1019 throw INTERP_KERNEL::Exception("Invalid mesh dimension : must be 2 or 3 !");
1020 int nbOfCells(getNumberOfCells());
1023 const int *connIndex=_nodal_connec_index->begin();
1024 int *conn=_nodal_connec->getPointer();
1025 for(const int *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1027 if(*iter>=0 && *iter<nbOfCells)
1029 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*iter]]);
1030 if(!cm.isQuadratic())
1031 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_POLYGON;
1033 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_QPOLYG;
1037 std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1038 oss << " in range [0," << nbOfCells << ") !";
1039 throw INTERP_KERNEL::Exception(oss.str());
1045 int *connIndex(_nodal_connec_index->getPointer());
1046 const int *connOld(_nodal_connec->getConstPointer());
1047 MCAuto<DataArrayInt> connNew(DataArrayInt::New()),connNewI(DataArrayInt::New()); connNew->alloc(0,1); connNewI->alloc(1,1); connNewI->setIJ(0,0,0);
1048 std::vector<bool> toBeDone(nbOfCells,false);
1049 for(const int *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1051 if(*iter>=0 && *iter<nbOfCells)
1052 toBeDone[*iter]=true;
1055 std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1056 oss << " in range [0," << nbOfCells << ") !";
1057 throw INTERP_KERNEL::Exception(oss.str());
1060 for(int cellId=0;cellId<nbOfCells;cellId++)
1062 int pos(connIndex[cellId]),posP1(connIndex[cellId+1]);
1063 int lgthOld(posP1-pos-1);
1064 if(toBeDone[cellId])
1066 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connOld[pos]);
1067 unsigned nbOfFaces(cm.getNumberOfSons2(connOld+pos+1,lgthOld));
1068 int *tmp(new int[nbOfFaces*lgthOld+1]);
1069 int *work=tmp; *work++=INTERP_KERNEL::NORM_POLYHED;
1070 for(unsigned j=0;j<nbOfFaces;j++)
1072 INTERP_KERNEL::NormalizedCellType type;
1073 unsigned offset=cm.fillSonCellNodalConnectivity2(j,connOld+pos+1,lgthOld,work,type);
1077 std::size_t newLgth(std::distance(tmp,work)-1);//-1 for last -1
1078 connNew->pushBackValsSilent(tmp,tmp+newLgth);
1079 connNewI->pushBackSilent(connNewI->back()+(int)newLgth);
1084 connNew->pushBackValsSilent(connOld+pos,connOld+posP1);
1085 connNewI->pushBackSilent(connNewI->back()+posP1-pos);
1088 setConnectivity(connNew,connNewI,false);//false because computeTypes called just behind.
1094 * Converts all cells to either polygons (if \a this is a 2D mesh) or
1095 * polyhedrons (if \a this is a 3D mesh).
1096 * \warning As this method is purely for user-friendliness and no optimization is
1097 * done to avoid construction of a useless vector, this method can be costly
1099 * \throw If the coordinates array is not set.
1100 * \throw If the nodal connectivity of cells is node defined.
1101 * \throw If dimension of \a this mesh is not either 2 or 3.
1103 void MEDCouplingUMesh::convertAllToPoly()
1105 int nbOfCells=getNumberOfCells();
1106 std::vector<int> cellIds(nbOfCells);
1107 for(int i=0;i<nbOfCells;i++)
1109 convertToPolyTypes(&cellIds[0],&cellIds[0]+cellIds.size());
1113 * Fixes nodal connectivity of invalid cells of type NORM_POLYHED. This method
1114 * expects that all NORM_POLYHED cells have connectivity similar to that of prismatic
1115 * volumes like NORM_HEXA8, NORM_PENTA6 etc., i.e. the first half of nodes describes a
1116 * base facet of the volume and the second half of nodes describes an opposite facet
1117 * having the same number of nodes as the base one. This method converts such
1118 * connectivity to a valid polyhedral format where connectivity of each facet is
1119 * explicitly described and connectivity of facets are separated by -1. If \a this mesh
1120 * contains a NORM_POLYHED cell with a valid connectivity, or an invalid connectivity is
1121 * not as expected, an exception is thrown and the mesh remains unchanged. Care of
1122 * a correct orientation of the first facet of a polyhedron, else orientation of a
1123 * corrected cell is reverse.<br>
1124 * This method is useful to build an extruded unstructured mesh with polyhedrons as
1125 * it releases the user from boring description of polyhedra connectivity in the valid
1127 * \throw If \a this->getMeshDimension() != 3.
1128 * \throw If \a this->getSpaceDimension() != 3.
1129 * \throw If the nodal connectivity of cells is not defined.
1130 * \throw If the coordinates array is not set.
1131 * \throw If \a this mesh contains polyhedrons with the valid connectivity.
1132 * \throw If \a this mesh contains polyhedrons with odd number of nodes.
1134 * \if ENABLE_EXAMPLES
1135 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
1136 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
1139 void MEDCouplingUMesh::convertExtrudedPolyhedra()
1141 checkFullyDefined();
1142 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1143 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertExtrudedPolyhedra works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
1144 int nbOfCells=getNumberOfCells();
1145 MCAuto<DataArrayInt> newCi=DataArrayInt::New();
1146 newCi->alloc(nbOfCells+1,1);
1147 int *newci=newCi->getPointer();
1148 const int *ci=_nodal_connec_index->getConstPointer();
1149 const int *c=_nodal_connec->getConstPointer();
1151 for(int i=0;i<nbOfCells;i++)
1153 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1154 if(type==INTERP_KERNEL::NORM_POLYHED)
1156 if(std::count(c+ci[i]+1,c+ci[i+1],-1)!=0)
1158 std::ostringstream oss; oss << "MEDCouplingUMesh::convertExtrudedPolyhedra : cell # " << i << " is a polhedron BUT it has NOT exactly 1 face !";
1159 throw INTERP_KERNEL::Exception(oss.str());
1161 std::size_t n2=std::distance(c+ci[i]+1,c+ci[i+1]);
1164 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 !";
1165 throw INTERP_KERNEL::Exception(oss.str());
1168 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)
1171 newci[i+1]=(ci[i+1]-ci[i])+newci[i];
1173 MCAuto<DataArrayInt> newC=DataArrayInt::New();
1174 newC->alloc(newci[nbOfCells],1);
1175 int *newc=newC->getPointer();
1176 for(int i=0;i<nbOfCells;i++)
1178 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1179 if(type==INTERP_KERNEL::NORM_POLYHED)
1181 std::size_t n1=std::distance(c+ci[i]+1,c+ci[i+1])/2;
1182 newc=std::copy(c+ci[i],c+ci[i]+n1+1,newc);
1184 for(std::size_t j=0;j<n1;j++)
1186 newc[j]=c[ci[i]+1+n1+(n1-j)%n1];
1188 newc[n1+5*j+1]=c[ci[i]+1+j];
1189 newc[n1+5*j+2]=c[ci[i]+1+j+n1];
1190 newc[n1+5*j+3]=c[ci[i]+1+(j+1)%n1+n1];
1191 newc[n1+5*j+4]=c[ci[i]+1+(j+1)%n1];
1196 newc=std::copy(c+ci[i],c+ci[i+1],newc);
1198 _nodal_connec_index->decrRef(); _nodal_connec_index=newCi.retn();
1199 _nodal_connec->decrRef(); _nodal_connec=newC.retn();
1204 * Converts all polygons (if \a this is a 2D mesh) or polyhedrons (if \a this is a 3D
1205 * mesh) to cells of classical types. This method is opposite to convertToPolyTypes().
1206 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
1207 * to write this mesh to the MED file, its cells must be sorted using
1208 * sortCellsInMEDFileFrmt().
1209 * \warning Cells (and most notably polyhedrons) must be correctly oriented for this to work
1210 * properly. See orientCorrectlyPolyhedrons() and arePolyhedronsNotCorrectlyOriented().
1211 * \return \c true if at least one cell has been converted, \c false else. In the
1212 * last case the nodal connectivity remains unchanged.
1213 * \throw If the coordinates array is not set.
1214 * \throw If the nodal connectivity of cells is not defined.
1215 * \throw If \a this->getMeshDimension() < 0.
1217 bool MEDCouplingUMesh::unPolyze()
1219 checkFullyDefined();
1220 int mdim=getMeshDimension();
1222 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::unPolyze works on umeshes with meshdim equals to 0, 1 2 or 3 !");
1225 int nbOfCells=getNumberOfCells();
1228 int initMeshLgth=getNodalConnectivityArrayLen();
1229 int *conn=_nodal_connec->getPointer();
1230 int *index=_nodal_connec_index->getPointer();
1235 for(int i=0;i<nbOfCells;i++)
1237 lgthOfCurCell=index[i+1]-posOfCurCell;
1238 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
1239 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
1240 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::NORM_ERROR;
1244 switch(cm.getDimension())
1248 INTERP_KERNEL::AutoPtr<int> tmp=new int[lgthOfCurCell-1];
1249 std::copy(conn+posOfCurCell+1,conn+posOfCurCell+lgthOfCurCell,(int *)tmp);
1250 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly2D(cm.isQuadratic(),tmp,lgthOfCurCell-1,conn+newPos+1,newLgth);
1255 int nbOfFaces,lgthOfPolyhConn;
1256 INTERP_KERNEL::AutoPtr<int> zipFullReprOfPolyh=INTERP_KERNEL::CellSimplify::getFullPolyh3DCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,nbOfFaces,lgthOfPolyhConn);
1257 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly3D(zipFullReprOfPolyh,nbOfFaces,lgthOfPolyhConn,conn+newPos+1,newLgth);
1262 newType=(lgthOfCurCell==3)?INTERP_KERNEL::NORM_SEG2:INTERP_KERNEL::NORM_POLYL;
1266 ret=ret || (newType!=type);
1267 conn[newPos]=newType;
1269 posOfCurCell=index[i+1];
1274 std::copy(conn+posOfCurCell,conn+posOfCurCell+lgthOfCurCell,conn+newPos);
1275 newPos+=lgthOfCurCell;
1276 posOfCurCell+=lgthOfCurCell;
1280 if(newPos!=initMeshLgth)
1281 _nodal_connec->reAlloc(newPos);
1288 * This method expects that spaceDimension is equal to 3 and meshDimension equal to 3.
1289 * This method performs operation only on polyhedrons in \b this. If no polyhedrons exists in \b this, \b this remains unchanged.
1290 * This method allows to merge if any coplanar 3DSurf cells that may appear in some polyhedrons cells.
1292 * \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
1295 void MEDCouplingUMesh::simplifyPolyhedra(double eps)
1297 checkFullyDefined();
1298 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1299 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplifyPolyhedra : works on meshdimension 3 and spaceDimension 3 !");
1300 MCAuto<DataArrayDouble> coords=getCoords()->deepCopy();
1301 coords->recenterForMaxPrecision(eps);
1303 int nbOfCells=getNumberOfCells();
1304 const int *conn=_nodal_connec->getConstPointer();
1305 const int *index=_nodal_connec_index->getConstPointer();
1306 MCAuto<DataArrayInt> connINew=DataArrayInt::New();
1307 connINew->alloc(nbOfCells+1,1);
1308 int *connINewPtr=connINew->getPointer(); *connINewPtr++=0;
1309 MCAuto<DataArrayInt> connNew=DataArrayInt::New(); connNew->alloc(0,1);
1311 for(int i=0;i<nbOfCells;i++,connINewPtr++)
1313 if(conn[index[i]]==(int)INTERP_KERNEL::NORM_POLYHED)
1315 SimplifyPolyhedronCell(eps,coords,conn+index[i],conn+index[i+1],connNew);
1319 connNew->insertAtTheEnd(conn+index[i],conn+index[i+1]);
1320 *connINewPtr=connNew->getNumberOfTuples();
1323 setConnectivity(connNew,connINew,false);
1327 * This method returns all node ids used in the connectivity of \b this. The data array returned has to be dealt by the caller.
1328 * The returned node ids are sorted ascendingly. This method is close to MEDCouplingUMesh::getNodeIdsInUse except
1329 * the format of the returned DataArrayInt instance.
1331 * \return a newly allocated DataArrayInt sorted ascendingly of fetched node ids.
1332 * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1334 DataArrayInt *MEDCouplingUMesh::computeFetchedNodeIds() const
1336 checkConnectivityFullyDefined();
1337 const int *maxEltPt(std::max_element(_nodal_connec->begin(),_nodal_connec->end()));
1338 int maxElt(maxEltPt==_nodal_connec->end()?0:std::abs(*maxEltPt)+1);
1339 std::vector<bool> retS(maxElt,false);
1340 computeNodeIdsAlg(retS);
1341 return DataArrayInt::BuildListOfSwitchedOn(retS);
1345 * \param [in,out] nodeIdsInUse an array of size typically equal to nbOfNodes.
1346 * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1348 void MEDCouplingUMesh::computeNodeIdsAlg(std::vector<bool>& nodeIdsInUse) const
1350 int nbOfNodes((int)nodeIdsInUse.size()),nbOfCells(getNumberOfCells());
1351 const int *connIndex(_nodal_connec_index->getConstPointer()),*conn(_nodal_connec->getConstPointer());
1352 for(int i=0;i<nbOfCells;i++)
1353 for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1356 if(conn[j]<nbOfNodes)
1357 nodeIdsInUse[conn[j]]=true;
1360 std::ostringstream oss; oss << "MEDCouplingUMesh::computeNodeIdsAlg : In cell #" << i << " presence of node id " << conn[j] << " not in [0," << nbOfNodes << ") !";
1361 throw INTERP_KERNEL::Exception(oss.str());
1368 struct MEDCouplingAccVisit
1370 MEDCouplingAccVisit():_new_nb_of_nodes(0) { }
1371 int operator()(int val) { if(val!=-1) return _new_nb_of_nodes++; else return -1; }
1372 int _new_nb_of_nodes;
1378 * Finds nodes not used in any cell and returns an array giving a new id to every node
1379 * by excluding the unused nodes, for which the array holds -1. The result array is
1380 * a mapping in "Old to New" mode.
1381 * \param [out] nbrOfNodesInUse - number of node ids present in the nodal connectivity.
1382 * \return DataArrayInt * - a new instance of DataArrayInt. Its length is \a
1383 * this->getNumberOfNodes(). It holds for each node of \a this mesh either -1
1384 * if the node is unused or a new id else. The caller is to delete this
1385 * array using decrRef() as it is no more needed.
1386 * \throw If the coordinates array is not set.
1387 * \throw If the nodal connectivity of cells is not defined.
1388 * \throw If the nodal connectivity includes an invalid id.
1390 * \if ENABLE_EXAMPLES
1391 * \ref cpp_mcumesh_getNodeIdsInUse "Here is a C++ example".<br>
1392 * \ref py_mcumesh_getNodeIdsInUse "Here is a Python example".
1394 * \sa computeFetchedNodeIds, computeNodeIdsAlg()
1396 DataArrayInt *MEDCouplingUMesh::getNodeIdsInUse(int& nbrOfNodesInUse) const
1399 int nbOfNodes(getNumberOfNodes());
1400 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1401 ret->alloc(nbOfNodes,1);
1402 int *traducer=ret->getPointer();
1403 std::fill(traducer,traducer+nbOfNodes,-1);
1404 int nbOfCells=getNumberOfCells();
1405 const int *connIndex=_nodal_connec_index->getConstPointer();
1406 const int *conn=_nodal_connec->getConstPointer();
1407 for(int i=0;i<nbOfCells;i++)
1408 for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1411 if(conn[j]<nbOfNodes)
1412 traducer[conn[j]]=1;
1415 std::ostringstream oss; oss << "MEDCouplingUMesh::getNodeIdsInUse : In cell #" << i << " presence of node id " << conn[j] << " not in [0," << nbOfNodes << ") !";
1416 throw INTERP_KERNEL::Exception(oss.str());
1419 nbrOfNodesInUse=(int)std::count(traducer,traducer+nbOfNodes,1);
1420 std::transform(traducer,traducer+nbOfNodes,traducer,MEDCouplingAccVisit());
1425 * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1426 * For each cell in \b this the number of nodes constituting cell is computed.
1427 * For each polyhedron cell, the sum of the number of nodes of each face constituting polyhedron cell is returned.
1428 * So for pohyhedrons some nodes can be counted several times in the returned result.
1430 * \return a newly allocated array
1431 * \sa MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell
1433 DataArrayInt *MEDCouplingUMesh::computeNbOfNodesPerCell() const
1435 checkConnectivityFullyDefined();
1436 int nbOfCells=getNumberOfCells();
1437 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1438 ret->alloc(nbOfCells,1);
1439 int *retPtr=ret->getPointer();
1440 const int *conn=getNodalConnectivity()->getConstPointer();
1441 const int *connI=getNodalConnectivityIndex()->getConstPointer();
1442 for(int i=0;i<nbOfCells;i++,retPtr++)
1444 if(conn[connI[i]]!=(int)INTERP_KERNEL::NORM_POLYHED)
1445 *retPtr=connI[i+1]-connI[i]-1;
1447 *retPtr=connI[i+1]-connI[i]-1-std::count(conn+connI[i]+1,conn+connI[i+1],-1);
1453 * This method computes effective number of nodes per cell. That is to say nodes appearing several times in nodal connectivity of a cell,
1454 * will be counted only once here whereas it will be counted several times in MEDCouplingUMesh::computeNbOfNodesPerCell method.
1456 * \return DataArrayInt * - new object to be deallocated by the caller.
1457 * \sa MEDCouplingUMesh::computeNbOfNodesPerCell
1459 DataArrayInt *MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell() const
1461 checkConnectivityFullyDefined();
1462 int nbOfCells=getNumberOfCells();
1463 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1464 ret->alloc(nbOfCells,1);
1465 int *retPtr=ret->getPointer();
1466 const int *conn=getNodalConnectivity()->getConstPointer();
1467 const int *connI=getNodalConnectivityIndex()->getConstPointer();
1468 for(int i=0;i<nbOfCells;i++,retPtr++)
1470 std::set<int> s(conn+connI[i]+1,conn+connI[i+1]);
1471 if(conn[connI[i]]!=(int)INTERP_KERNEL::NORM_POLYHED)
1472 *retPtr=(int)s.size();
1476 *retPtr=(int)s.size();
1483 * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1484 * For each cell in \b this the number of faces constituting (entity of dimension this->getMeshDimension()-1) cell is computed.
1486 * \return a newly allocated array
1488 DataArrayInt *MEDCouplingUMesh::computeNbOfFacesPerCell() const
1490 checkConnectivityFullyDefined();
1491 int nbOfCells=getNumberOfCells();
1492 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1493 ret->alloc(nbOfCells,1);
1494 int *retPtr=ret->getPointer();
1495 const int *conn=getNodalConnectivity()->getConstPointer();
1496 const int *connI=getNodalConnectivityIndex()->getConstPointer();
1497 for(int i=0;i<nbOfCells;i++,retPtr++,connI++)
1499 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]);
1500 *retPtr=cm.getNumberOfSons2(conn+connI[0]+1,connI[1]-connI[0]-1);
1506 * Removes unused nodes (the node coordinates array is shorten) and returns an array
1507 * mapping between new and old node ids in "Old to New" mode. -1 values in the returned
1508 * array mean that the corresponding old node is no more used.
1509 * \return DataArrayInt * - a new instance of DataArrayInt of length \a
1510 * this->getNumberOfNodes() before call of this method. The caller is to
1511 * delete this array using decrRef() as it is no more needed.
1512 * \throw If the coordinates array is not set.
1513 * \throw If the nodal connectivity of cells is not defined.
1514 * \throw If the nodal connectivity includes an invalid id.
1515 * \sa areAllNodesFetched
1517 * \if ENABLE_EXAMPLES
1518 * \ref cpp_mcumesh_zipCoordsTraducer "Here is a C++ example".<br>
1519 * \ref py_mcumesh_zipCoordsTraducer "Here is a Python example".
1522 DataArrayInt *MEDCouplingUMesh::zipCoordsTraducer()
1524 return MEDCouplingPointSet::zipCoordsTraducer();
1528 * This method stands if 'cell1' and 'cell2' are equals regarding 'compType' policy.
1529 * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1531 int MEDCouplingUMesh::AreCellsEqual(const int *conn, const int *connI, int cell1, int cell2, int compType)
1536 return AreCellsEqualPolicy0(conn,connI,cell1,cell2);
1538 return AreCellsEqualPolicy1(conn,connI,cell1,cell2);
1540 return AreCellsEqualPolicy2(conn,connI,cell1,cell2);
1542 return AreCellsEqualPolicy2NoType(conn,connI,cell1,cell2);
1544 return AreCellsEqualPolicy7(conn,connI,cell1,cell2);
1546 throw INTERP_KERNEL::Exception("Unknown comparison asked ! Must be in 0,1,2,3 or 7.");
1550 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 0.
1552 int MEDCouplingUMesh::AreCellsEqualPolicy0(const int *conn, const int *connI, int cell1, int cell2)
1554 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1555 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;
1560 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 1.
1562 int MEDCouplingUMesh::AreCellsEqualPolicy1(const int *conn, const int *connI, int cell1, int cell2)
1564 int sz=connI[cell1+1]-connI[cell1];
1565 if(sz==connI[cell2+1]-connI[cell2])
1567 if(conn[connI[cell1]]==conn[connI[cell2]])
1569 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1570 unsigned dim=cm.getDimension();
1576 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz1];
1577 int *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(int *)tmp);
1578 std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1579 work=std::search((int *)tmp,(int *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1580 return work!=tmp+sz1?1:0;
1583 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;//case of SEG2 and SEG3
1586 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy1 : not implemented yet for meshdim == 3 !");
1593 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 2.
1595 int MEDCouplingUMesh::AreCellsEqualPolicy2(const int *conn, const int *connI, int cell1, int cell2)
1597 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1599 if(conn[connI[cell1]]==conn[connI[cell2]])
1601 std::set<int> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1602 std::set<int> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1610 * This method is less restrictive than AreCellsEqualPolicy2. Here the geometric type is absolutely not taken into account !
1612 int MEDCouplingUMesh::AreCellsEqualPolicy2NoType(const int *conn, const int *connI, int cell1, int cell2)
1614 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1616 std::set<int> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1617 std::set<int> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1624 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 7.
1626 int MEDCouplingUMesh::AreCellsEqualPolicy7(const int *conn, const int *connI, int cell1, int cell2)
1628 int sz=connI[cell1+1]-connI[cell1];
1629 if(sz==connI[cell2+1]-connI[cell2])
1631 if(conn[connI[cell1]]==conn[connI[cell2]])
1633 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1634 unsigned dim=cm.getDimension();
1640 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz1];
1641 int *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(int *)tmp);
1642 std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1643 work=std::search((int *)tmp,(int *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1648 std::reverse_iterator<int *> it1((int *)tmp+sz1);
1649 std::reverse_iterator<int *> it2((int *)tmp);
1650 if(std::search(it1,it2,conn+connI[cell2]+1,conn+connI[cell2+1])!=it2)
1656 return work!=tmp+sz1?1:0;
1659 {//case of SEG2 and SEG3
1660 if(std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1))
1662 if(!cm.isQuadratic())
1664 std::reverse_iterator<const int *> it1(conn+connI[cell1+1]);
1665 std::reverse_iterator<const int *> it2(conn+connI[cell1]+1);
1666 if(std::equal(it1,it2,conn+connI[cell2]+1))
1672 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])
1679 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy7 : not implemented yet for meshdim == 3 !");
1687 * This method find cells that are equal (regarding \a compType) in \a this. The comparison is specified
1689 * This method keeps the coordiantes of \a this. This method is time consuming.
1691 * \param [in] compType input specifying the technique used to compare cells each other.
1692 * - 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.
1693 * - 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)
1694 * and their type equal. For 1D mesh the policy 1 is equivalent to 0.
1695 * - 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
1696 * can be used for users not sensitive to orientation of cell
1697 * \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.
1698 * \param [out] commonCellsArr common cells ids (\ref numbering-indirect)
1699 * \param [out] commonCellsIArr common cells ids (\ref numbering-indirect)
1700 * \return the correspondance array old to new in a newly allocated array.
1703 void MEDCouplingUMesh::findCommonCells(int compType, int startCellId, DataArrayInt *& commonCellsArr, DataArrayInt *& commonCellsIArr) const
1705 MCAuto<DataArrayInt> revNodal=DataArrayInt::New(),revNodalI=DataArrayInt::New();
1706 getReverseNodalConnectivity(revNodal,revNodalI);
1707 FindCommonCellsAlg(compType,startCellId,_nodal_connec,_nodal_connec_index,revNodal,revNodalI,commonCellsArr,commonCellsIArr);
1710 void MEDCouplingUMesh::FindCommonCellsAlg(int compType, int startCellId, const DataArrayInt *nodal, const DataArrayInt *nodalI, const DataArrayInt *revNodal, const DataArrayInt *revNodalI,
1711 DataArrayInt *& commonCellsArr, DataArrayInt *& commonCellsIArr)
1713 MCAuto<DataArrayInt> commonCells=DataArrayInt::New(),commonCellsI=DataArrayInt::New(); commonCells->alloc(0,1);
1714 int nbOfCells=nodalI->getNumberOfTuples()-1;
1715 commonCellsI->reserve(1); commonCellsI->pushBackSilent(0);
1716 const int *revNodalPtr=revNodal->getConstPointer(),*revNodalIPtr=revNodalI->getConstPointer();
1717 const int *connPtr=nodal->getConstPointer(),*connIPtr=nodalI->getConstPointer();
1718 std::vector<bool> isFetched(nbOfCells,false);
1721 for(int i=0;i<nbOfCells;i++)
1725 const int *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind2nd(std::not_equal_to<int>(),-1));
1726 std::vector<int> v,v2;
1727 if(connOfNode!=connPtr+connIPtr[i+1])
1729 const int *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1730 v2.insert(v2.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1]);
1733 for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1737 const int *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1738 std::vector<int>::iterator it=std::set_intersection(v.begin(),v.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1739 v2.resize(std::distance(v2.begin(),it));
1743 if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1745 int pos=commonCellsI->back();
1746 commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1747 for(const int *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1748 isFetched[*it]=true;
1756 for(int i=startCellId;i<nbOfCells;i++)
1760 const int *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind2nd(std::not_equal_to<int>(),-1));
1761 std::vector<int> v,v2;
1762 if(connOfNode!=connPtr+connIPtr[i+1])
1764 v2.insert(v2.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1]);
1767 for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1771 std::vector<int>::iterator it=std::set_intersection(v.begin(),v.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1772 v2.resize(std::distance(v2.begin(),it));
1776 if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1778 int pos=commonCellsI->back();
1779 commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1780 for(const int *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1781 isFetched[*it]=true;
1787 commonCellsArr=commonCells.retn();
1788 commonCellsIArr=commonCellsI.retn();
1792 * Checks if \a this mesh includes all cells of an \a other mesh, and returns an array
1793 * giving for each cell of the \a other an id of a cell in \a this mesh. A value larger
1794 * than \a this->getNumberOfCells() in the returned array means that there is no
1795 * corresponding cell in \a this mesh.
1796 * It is expected that \a this and \a other meshes share the same node coordinates
1797 * array, if it is not so an exception is thrown.
1798 * \param [in] other - the mesh to compare with.
1799 * \param [in] compType - specifies a cell comparison technique. For meaning of its
1800 * valid values [0,1,2], see zipConnectivityTraducer().
1801 * \param [out] arr - a new instance of DataArrayInt returning correspondence
1802 * between cells of the two meshes. It contains \a other->getNumberOfCells()
1803 * values. The caller is to delete this array using
1804 * decrRef() as it is no more needed.
1805 * \return bool - \c true if all cells of \a other mesh are present in the \a this
1808 * \if ENABLE_EXAMPLES
1809 * \ref cpp_mcumesh_areCellsIncludedIn "Here is a C++ example".<br>
1810 * \ref py_mcumesh_areCellsIncludedIn "Here is a Python example".
1812 * \sa checkDeepEquivalOnSameNodesWith()
1813 * \sa checkGeoEquivalWith()
1815 bool MEDCouplingUMesh::areCellsIncludedIn(const MEDCouplingUMesh *other, int compType, DataArrayInt *& arr) const
1817 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1818 int nbOfCells=getNumberOfCells();
1819 static const int possibleCompType[]={0,1,2};
1820 if(std::find(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),compType)==possibleCompType+sizeof(possibleCompType)/sizeof(int))
1822 std::ostringstream oss; oss << "MEDCouplingUMesh::areCellsIncludedIn : only following policies are possible : ";
1823 std::copy(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),std::ostream_iterator<int>(oss," "));
1825 throw INTERP_KERNEL::Exception(oss.str());
1827 MCAuto<DataArrayInt> o2n=mesh->zipConnectivityTraducer(compType,nbOfCells);
1828 arr=o2n->subArray(nbOfCells);
1829 arr->setName(other->getName());
1831 if(other->getNumberOfCells()==0)
1833 return arr->getMaxValue(tmp)<nbOfCells;
1837 * This method makes the assumption that \a this and \a other share the same coords. If not an exception will be thrown !
1838 * This method tries to determine if \b other is fully included in \b this.
1839 * The main difference is that this method is not expected to throw exception.
1840 * This method has two outputs :
1842 * \param other other mesh
1843 * \param arr is an output parameter that returns a \b newly created instance. This array is of size 'other->getNumberOfCells()'.
1844 * \return If \a other is fully included in 'this 'true is returned. If not false is returned.
1846 bool MEDCouplingUMesh::areCellsIncludedInPolicy7(const MEDCouplingUMesh *other, DataArrayInt *& arr) const
1848 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1849 DataArrayInt *commonCells=0,*commonCellsI=0;
1850 int thisNbCells=getNumberOfCells();
1851 mesh->findCommonCells(7,thisNbCells,commonCells,commonCellsI);
1852 MCAuto<DataArrayInt> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1853 const int *commonCellsPtr=commonCells->getConstPointer(),*commonCellsIPtr=commonCellsI->getConstPointer();
1854 int otherNbCells=other->getNumberOfCells();
1855 MCAuto<DataArrayInt> arr2=DataArrayInt::New();
1856 arr2->alloc(otherNbCells,1);
1857 arr2->fillWithZero();
1858 int *arr2Ptr=arr2->getPointer();
1859 int nbOfCommon=commonCellsI->getNumberOfTuples()-1;
1860 for(int i=0;i<nbOfCommon;i++)
1862 int start=commonCellsPtr[commonCellsIPtr[i]];
1863 if(start<thisNbCells)
1865 for(int j=commonCellsIPtr[i]+1;j!=commonCellsIPtr[i+1];j++)
1867 int sig=commonCellsPtr[j]>0?1:-1;
1868 int val=std::abs(commonCellsPtr[j])-1;
1869 if(val>=thisNbCells)
1870 arr2Ptr[val-thisNbCells]=sig*(start+1);
1874 arr2->setName(other->getName());
1875 if(arr2->presenceOfValue(0))
1881 MEDCouplingUMesh *MEDCouplingUMesh::mergeMyselfWithOnSameCoords(const MEDCouplingPointSet *other) const
1884 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : input other is null !");
1885 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
1887 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : the input other mesh is not of type unstructured !");
1888 std::vector<const MEDCouplingUMesh *> ms(2);
1891 return MergeUMeshesOnSameCoords(ms);
1895 * Build a sub part of \b this lying or not on the same coordinates than \b this (regarding value of \b keepCoords).
1896 * By default coordinates are kept. This method is close to MEDCouplingUMesh::buildPartOfMySelf except that here input
1897 * cellIds is not given explicitely but by a range python like.
1902 * \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.
1903 * \return a newly allocated
1905 * \warning This method modifies can generate an unstructured mesh whose cells are not sorted by geometric type order.
1906 * In view of the MED file writing, a renumbering of cells of returned unstructured mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
1908 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfSlice(int start, int end, int step, bool keepCoords) const
1910 if(getMeshDimension()!=-1)
1911 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelfSlice(start,end,step,keepCoords));
1914 int newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfSlice for -1 dimension mesh ");
1916 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
1918 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
1920 return const_cast<MEDCouplingUMesh *>(this);
1925 * Creates a new MEDCouplingUMesh containing specified cells of \a this mesh.
1926 * The result mesh shares or not the node coordinates array with \a this mesh depending
1927 * on \a keepCoords parameter.
1928 * \warning Cells of the result mesh can be \b not sorted by geometric type, hence,
1929 * to write this mesh to the MED file, its cells must be sorted using
1930 * sortCellsInMEDFileFrmt().
1931 * \param [in] begin - an array of cell ids to include to the new mesh.
1932 * \param [in] end - a pointer to last-plus-one-th element of \a begin.
1933 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
1934 * array of \a this mesh, else "free" nodes are removed from the result mesh
1935 * by calling zipCoords().
1936 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
1937 * to delete this mesh using decrRef() as it is no more needed.
1938 * \throw If the coordinates array is not set.
1939 * \throw If the nodal connectivity of cells is not defined.
1940 * \throw If any cell id in the array \a begin is not valid.
1942 * \if ENABLE_EXAMPLES
1943 * \ref cpp_mcumesh_buildPartOfMySelf "Here is a C++ example".<br>
1944 * \ref py_mcumesh_buildPartOfMySelf "Here is a Python example".
1947 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelf(const int *begin, const int *end, bool keepCoords) const
1949 if(getMeshDimension()!=-1)
1950 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelf(begin,end,keepCoords));
1954 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
1956 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
1958 return const_cast<MEDCouplingUMesh *>(this);
1963 * This method operates only on nodal connectivity on \b this. Coordinates of \b this is completely ignored here.
1965 * 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.
1966 * Size of [ \b cellIdsBg, \b cellIdsEnd ) ) must be equal to the number of cells of otherOnSameCoordsThanThis.
1967 * The number of cells of \b this will remain the same with this method.
1969 * \param [in] cellIdsBg begin of cell ids (included) of cells in this to assign
1970 * \param [in] cellIdsEnd end of cell ids (excluded) of cells in this to assign
1971 * \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 ).
1972 * Coordinate pointer of \b this and those of \b otherOnSameCoordsThanThis must be the same
1974 void MEDCouplingUMesh::setPartOfMySelf(const int *cellIdsBg, const int *cellIdsEnd, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
1976 checkConnectivityFullyDefined();
1977 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
1978 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
1979 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelf : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
1980 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
1982 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
1983 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
1984 throw INTERP_KERNEL::Exception(oss.str());
1986 int nbOfCellsToModify=(int)std::distance(cellIdsBg,cellIdsEnd);
1987 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
1989 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
1990 throw INTERP_KERNEL::Exception(oss.str());
1992 int nbOfCells=getNumberOfCells();
1993 bool easyAssign=true;
1994 const int *connI=_nodal_connec_index->getConstPointer();
1995 const int *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
1996 for(const int *it=cellIdsBg;it!=cellIdsEnd && easyAssign;it++,connIOther++)
1998 if(*it>=0 && *it<nbOfCells)
2000 easyAssign=(connIOther[1]-connIOther[0])==(connI[*it+1]-connI[*it]);
2004 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : On pos #" << std::distance(cellIdsBg,it) << " id is equal to " << *it << " which is not in [0," << nbOfCells << ") !";
2005 throw INTERP_KERNEL::Exception(oss.str());
2010 MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2015 DataArrayInt *arrOut=0,*arrIOut=0;
2016 MEDCouplingUMesh::SetPartOfIndexedArrays(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2018 MCAuto<DataArrayInt> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2019 setConnectivity(arrOut,arrIOut,true);
2023 void MEDCouplingUMesh::setPartOfMySelfSlice(int start, int end, int step, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2025 checkConnectivityFullyDefined();
2026 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2027 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2028 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelfSlice : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2029 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2031 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2032 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2033 throw INTERP_KERNEL::Exception(oss.str());
2035 int nbOfCellsToModify=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::setPartOfMySelfSlice : ");
2036 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2038 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2039 throw INTERP_KERNEL::Exception(oss.str());
2041 int nbOfCells=getNumberOfCells();
2042 bool easyAssign=true;
2043 const int *connI=_nodal_connec_index->getConstPointer();
2044 const int *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2046 for(int i=0;i<nbOfCellsToModify && easyAssign;i++,it+=step,connIOther++)
2048 if(it>=0 && it<nbOfCells)
2050 easyAssign=(connIOther[1]-connIOther[0])==(connI[it+1]-connI[it]);
2054 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : On pos #" << i << " id is equal to " << it << " which is not in [0," << nbOfCells << ") !";
2055 throw INTERP_KERNEL::Exception(oss.str());
2060 MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2065 DataArrayInt *arrOut=0,*arrIOut=0;
2066 MEDCouplingUMesh::SetPartOfIndexedArraysSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2068 MCAuto<DataArrayInt> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2069 setConnectivity(arrOut,arrIOut,true);
2075 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2076 * this->getMeshDimension(), that bound some cells of \a this mesh.
2077 * The cells of lower dimension to include to the result mesh are selected basing on
2078 * specified node ids and the value of \a fullyIn parameter. If \a fullyIn ==\c true, a
2079 * cell is copied if its all nodes are in the array \a begin of node ids. If \a fullyIn
2080 * ==\c false, a cell is copied if any its node is in the array of node ids. The
2081 * created mesh shares the node coordinates array with \a this mesh.
2082 * \param [in] begin - the array of node ids.
2083 * \param [in] end - a pointer to the (last+1)-th element of \a begin.
2084 * \param [in] fullyIn - if \c true, then cells whose all nodes are in the
2085 * array \a begin are added, else cells whose any node is in the
2086 * array \a begin are added.
2087 * \return MEDCouplingUMesh * - new instance of MEDCouplingUMesh. The caller is
2088 * to delete this mesh using decrRef() as it is no more needed.
2089 * \throw If the coordinates array is not set.
2090 * \throw If the nodal connectivity of cells is not defined.
2091 * \throw If any node id in \a begin is not valid.
2093 * \if ENABLE_EXAMPLES
2094 * \ref cpp_mcumesh_buildFacePartOfMySelfNode "Here is a C++ example".<br>
2095 * \ref py_mcumesh_buildFacePartOfMySelfNode "Here is a Python example".
2098 MEDCouplingUMesh *MEDCouplingUMesh::buildFacePartOfMySelfNode(const int *begin, const int *end, bool fullyIn) const
2100 MCAuto<DataArrayInt> desc,descIndx,revDesc,revDescIndx;
2101 desc=DataArrayInt::New(); descIndx=DataArrayInt::New(); revDesc=DataArrayInt::New(); revDescIndx=DataArrayInt::New();
2102 MCAuto<MEDCouplingUMesh> subMesh=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2103 desc=0; descIndx=0; revDesc=0; revDescIndx=0;
2104 return static_cast<MEDCouplingUMesh*>(subMesh->buildPartOfMySelfNode(begin,end,fullyIn));
2108 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2109 * this->getMeshDimension(), which bound only one cell of \a this mesh.
2110 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2111 * array of \a this mesh, else "free" nodes are removed from the result mesh
2112 * by calling zipCoords().
2113 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2114 * to delete this mesh using decrRef() as it is no more needed.
2115 * \throw If the coordinates array is not set.
2116 * \throw If the nodal connectivity of cells is not defined.
2118 * \if ENABLE_EXAMPLES
2119 * \ref cpp_mcumesh_buildBoundaryMesh "Here is a C++ example".<br>
2120 * \ref py_mcumesh_buildBoundaryMesh "Here is a Python example".
2123 MEDCouplingUMesh *MEDCouplingUMesh::buildBoundaryMesh(bool keepCoords) const
2125 DataArrayInt *desc=DataArrayInt::New();
2126 DataArrayInt *descIndx=DataArrayInt::New();
2127 DataArrayInt *revDesc=DataArrayInt::New();
2128 DataArrayInt *revDescIndx=DataArrayInt::New();
2130 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2133 descIndx->decrRef();
2134 int nbOfCells=meshDM1->getNumberOfCells();
2135 const int *revDescIndxC=revDescIndx->getConstPointer();
2136 std::vector<int> boundaryCells;
2137 for(int i=0;i<nbOfCells;i++)
2138 if(revDescIndxC[i+1]-revDescIndxC[i]==1)
2139 boundaryCells.push_back(i);
2140 revDescIndx->decrRef();
2141 MEDCouplingUMesh *ret=meshDM1->buildPartOfMySelf(&boundaryCells[0],&boundaryCells[0]+boundaryCells.size(),keepCoords);
2146 * This method returns a newly created DataArrayInt instance containing ids of cells located in boundary.
2147 * A cell is detected to be on boundary if it contains one or more than one face having only one father.
2148 * This method makes the assumption that \a this is fully defined (coords,connectivity). If not an exception will be thrown.
2150 DataArrayInt *MEDCouplingUMesh::findCellIdsOnBoundary() const
2152 checkFullyDefined();
2153 MCAuto<DataArrayInt> desc=DataArrayInt::New();
2154 MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
2155 MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
2156 MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
2158 buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx)->decrRef();
2159 desc=(DataArrayInt*)0; descIndx=(DataArrayInt*)0;
2161 MCAuto<DataArrayInt> tmp=revDescIndx->deltaShiftIndex();
2162 MCAuto<DataArrayInt> faceIds=tmp->findIdsEqual(1); tmp=(DataArrayInt*)0;
2163 const int *revDescPtr=revDesc->getConstPointer();
2164 const int *revDescIndxPtr=revDescIndx->getConstPointer();
2165 int nbOfCells=getNumberOfCells();
2166 std::vector<bool> ret1(nbOfCells,false);
2168 for(const int *pt=faceIds->begin();pt!=faceIds->end();pt++)
2169 if(!ret1[revDescPtr[revDescIndxPtr[*pt]]])
2170 { ret1[revDescPtr[revDescIndxPtr[*pt]]]=true; sz++; }
2172 DataArrayInt *ret2=DataArrayInt::New();
2174 int *ret2Ptr=ret2->getPointer();
2176 for(std::vector<bool>::const_iterator it=ret1.begin();it!=ret1.end();it++,sz++)
2179 ret2->setName("BoundaryCells");
2184 * This method finds in \b this the cell ids that lie on mesh \b otherDimM1OnSameCoords.
2185 * \b this and \b otherDimM1OnSameCoords have to lie on the same coordinate array pointer. The coherency of that coords array with connectivity
2186 * of \b this and \b otherDimM1OnSameCoords is not important here because this method works only on connectivity.
2187 * this->getMeshDimension() - 1 must be equal to otherDimM1OnSameCoords.getMeshDimension()
2189 * s0 is the cell ids set in \b this lying on at least one node in the fetched nodes in \b otherDimM1OnSameCoords.
2190 * 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
2191 * equals a cell in \b otherDimM1OnSameCoords.
2193 * \throw if \b otherDimM1OnSameCoords is not part of constituent of \b this, or if coordinate pointer of \b this and \b otherDimM1OnSameCoords
2194 * are not same, or if this->getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension()
2196 * \param [in] otherDimM1OnSameCoords
2197 * \param [out] cellIdsRk0 a newly allocated array containing the cell ids of s0 (which are cell ids of \b this) in the above algorithm.
2198 * \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
2199 * cellIdsRk1->transformWithIndArr(cellIdsRk0->begin(),cellIdsRk0->end());
2201 void MEDCouplingUMesh::findCellIdsLyingOn(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayInt *&cellIdsRk0, DataArrayInt *&cellIdsRk1) const
2203 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2204 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : coordinates pointer are not the same ! Use tryToShareSameCoords method !");
2205 checkConnectivityFullyDefined();
2206 otherDimM1OnSameCoords.checkConnectivityFullyDefined();
2207 if(getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension())
2208 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : invalid mesh dimension of input mesh regarding meshdimesion of this !");
2209 MCAuto<DataArrayInt> fetchedNodeIds1=otherDimM1OnSameCoords.computeFetchedNodeIds();
2210 MCAuto<DataArrayInt> s0arr=getCellIdsLyingOnNodes(fetchedNodeIds1->begin(),fetchedNodeIds1->end(),false);
2211 MCAuto<MEDCouplingUMesh> thisPart=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(s0arr->begin(),s0arr->end(),true));
2212 MCAuto<DataArrayInt> descThisPart=DataArrayInt::New(),descIThisPart=DataArrayInt::New(),revDescThisPart=DataArrayInt::New(),revDescIThisPart=DataArrayInt::New();
2213 MCAuto<MEDCouplingUMesh> thisPartConsti=thisPart->buildDescendingConnectivity(descThisPart,descIThisPart,revDescThisPart,revDescIThisPart);
2214 const int *revDescThisPartPtr=revDescThisPart->getConstPointer(),*revDescIThisPartPtr=revDescIThisPart->getConstPointer();
2215 DataArrayInt *idsOtherInConsti=0;
2216 bool b=thisPartConsti->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsOtherInConsti);
2217 MCAuto<DataArrayInt> idsOtherInConstiAuto(idsOtherInConsti);
2219 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : the given mdim-1 mesh in other is not a constituent of this !");
2221 for(const int *idOther=idsOtherInConsti->begin();idOther!=idsOtherInConsti->end();idOther++)
2222 s1.insert(revDescThisPartPtr+revDescIThisPartPtr[*idOther],revDescThisPartPtr+revDescIThisPartPtr[*idOther+1]);
2223 MCAuto<DataArrayInt> s1arr_renum1=DataArrayInt::New(); s1arr_renum1->alloc((int)s1.size(),1); std::copy(s1.begin(),s1.end(),s1arr_renum1->getPointer());
2224 s1arr_renum1->sort();
2225 cellIdsRk0=s0arr.retn();
2226 //cellIdsRk1=s_renum1.retn();
2227 cellIdsRk1=s1arr_renum1.retn();
2231 * 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
2232 * returned. This subpart of meshdim-1 mesh is built using meshdim-1 cells in it shared only one cell in \b this.
2234 * \return a newly allocated mesh lying on the same coordinates than \b this. The caller has to deal with returned mesh.
2236 MEDCouplingUMesh *MEDCouplingUMesh::computeSkin() const
2238 MCAuto<DataArrayInt> desc=DataArrayInt::New();
2239 MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
2240 MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
2241 MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
2243 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2244 revDesc=0; desc=0; descIndx=0;
2245 MCAuto<DataArrayInt> revDescIndx2=revDescIndx->deltaShiftIndex();
2246 MCAuto<DataArrayInt> part=revDescIndx2->findIdsEqual(1);
2247 return static_cast<MEDCouplingUMesh *>(meshDM1->buildPartOfMySelf(part->begin(),part->end(),true));
2251 * Finds nodes lying on the boundary of \a this mesh.
2252 * \return DataArrayInt * - a new instance of DataArrayInt holding ids of found
2253 * nodes. The caller is to delete this array using decrRef() as it is no
2255 * \throw If the coordinates array is not set.
2256 * \throw If the nodal connectivity of cells is node defined.
2258 * \if ENABLE_EXAMPLES
2259 * \ref cpp_mcumesh_findBoundaryNodes "Here is a C++ example".<br>
2260 * \ref py_mcumesh_findBoundaryNodes "Here is a Python example".
2263 DataArrayInt *MEDCouplingUMesh::findBoundaryNodes() const
2265 MCAuto<MEDCouplingUMesh> skin=computeSkin();
2266 return skin->computeFetchedNodeIds();
2269 MEDCouplingUMesh *MEDCouplingUMesh::buildUnstructured() const
2272 return const_cast<MEDCouplingUMesh *>(this);
2276 * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2277 * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2278 * 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.
2279 * If a node is in the boundary of \b this \b and in the boundary of \b otherDimM1OnSameCoords this node is considerd as needed to be duplicated.
2280 * 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.
2282 * \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
2283 * parameter is altered during the call.
2284 * \param [out] nodeIdsToDuplicate node ids needed to be duplicated following the algorithm explain above.
2285 * \param [out] cellIdsNeededToBeRenum cell ids in \b this in which the renumber of nodes should be performed.
2286 * \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.
2288 * \warning This method modifies param \b otherDimM1OnSameCoords (for speed reasons).
2290 void MEDCouplingUMesh::findNodesToDuplicate(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayInt *& nodeIdsToDuplicate,
2291 DataArrayInt *& cellIdsNeededToBeRenum, DataArrayInt *& cellIdsNotModified) const
2293 typedef MCAuto<DataArrayInt> DAInt;
2294 typedef MCAuto<MEDCouplingUMesh> MCUMesh;
2296 checkFullyDefined();
2297 otherDimM1OnSameCoords.checkFullyDefined();
2298 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2299 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : meshes do not share the same coords array !");
2300 if(otherDimM1OnSameCoords.getMeshDimension()!=getMeshDimension()-1)
2301 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the mesh given in other parameter must have this->getMeshDimension()-1 !");
2303 // Checking star-shaped M1 group:
2304 DAInt dt0=DataArrayInt::New(),dit0=DataArrayInt::New(),rdt0=DataArrayInt::New(),rdit0=DataArrayInt::New();
2305 MCUMesh meshM2 = otherDimM1OnSameCoords.buildDescendingConnectivity(dt0, dit0, rdt0, rdit0);
2306 DAInt dsi = rdit0->deltaShiftIndex();
2307 DAInt idsTmp0 = dsi->findIdsNotInRange(-1, 3);
2308 if(idsTmp0->getNumberOfTuples())
2309 throw INTERP_KERNEL::Exception("MEDFileUMesh::buildInnerBoundaryAlongM1Group: group is too complex: some points (or edges) have more than two connected segments (or faces)!");
2310 dt0=0; dit0=0; rdt0=0; rdit0=0; idsTmp0=0;
2312 // Get extreme nodes from the group (they won't be duplicated), ie nodes belonging to boundary cells of M1
2313 DAInt xtremIdsM2 = dsi->findIdsEqual(1); dsi = 0;
2314 MCUMesh meshM2Part = static_cast<MEDCouplingUMesh *>(meshM2->buildPartOfMySelf(xtremIdsM2->begin(), xtremIdsM2->end(),true));
2315 DAInt xtrem = meshM2Part->computeFetchedNodeIds();
2316 // Remove from the list points on the boundary of the M0 mesh (those need duplication!)
2317 dt0=DataArrayInt::New(),dit0=DataArrayInt::New(),rdt0=DataArrayInt::New(),rdit0=DataArrayInt::New();
2318 MCUMesh m0desc = buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); dt0=0; dit0=0; rdt0=0;
2319 dsi = rdit0->deltaShiftIndex();
2320 DAInt boundSegs = dsi->findIdsEqual(1); // boundary segs/faces of the M0 mesh
2321 MCUMesh m0descSkin = static_cast<MEDCouplingUMesh *>(m0desc->buildPartOfMySelf(boundSegs->begin(),boundSegs->end(), true));
2322 DAInt fNodes = m0descSkin->computeFetchedNodeIds();
2323 // In 3D, some points on the boundary of M0 still need duplication:
2325 if (getMeshDimension() == 3)
2327 DAInt dnu1=DataArrayInt::New(), dnu2=DataArrayInt::New(), dnu3=DataArrayInt::New(), dnu4=DataArrayInt::New();
2328 MCUMesh m0descSkinDesc = m0descSkin->buildDescendingConnectivity(dnu1, dnu2, dnu3, dnu4);
2329 dnu1=0;dnu2=0;dnu3=0;dnu4=0;
2330 DataArrayInt * corresp=0;
2331 meshM2->areCellsIncludedIn(m0descSkinDesc,2,corresp);
2332 DAInt validIds = corresp->findIdsInRange(0, meshM2->getNumberOfCells());
2334 if (validIds->getNumberOfTuples())
2336 MCUMesh m1IntersecSkin = static_cast<MEDCouplingUMesh *>(m0descSkinDesc->buildPartOfMySelf(validIds->begin(), validIds->end(), true));
2337 DAInt notDuplSkin = m1IntersecSkin->findBoundaryNodes();
2338 DAInt fNodes1 = fNodes->buildSubstraction(notDuplSkin);
2339 notDup = xtrem->buildSubstraction(fNodes1);
2342 notDup = xtrem->buildSubstraction(fNodes);
2345 notDup = xtrem->buildSubstraction(fNodes);
2347 // Now compute cells around group (i.e. cells where we will do the propagation to identify the two sub-sets delimited by the group)
2348 DAInt m1Nodes = otherDimM1OnSameCoords.computeFetchedNodeIds();
2349 DAInt dupl = m1Nodes->buildSubstraction(notDup);
2350 DAInt cellsAroundGroup = getCellIdsLyingOnNodes(dupl->begin(), dupl->end(), false); // false= take cell in, even if not all nodes are in notDup
2353 MCUMesh m0Part2=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(cellsAroundGroup->begin(),cellsAroundGroup->end(),true));
2354 int nCells2 = m0Part2->getNumberOfCells();
2355 DAInt desc00=DataArrayInt::New(),descI00=DataArrayInt::New(),revDesc00=DataArrayInt::New(),revDescI00=DataArrayInt::New();
2356 MCUMesh m01=m0Part2->buildDescendingConnectivity(desc00,descI00,revDesc00,revDescI00);
2358 // Neighbor information of the mesh without considering the crack (serves to count how many connex pieces it is made of)
2359 DataArrayInt *tmp00=0,*tmp11=0;
2360 MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00, tmp00, tmp11);
2361 DAInt neighInit00(tmp00);
2362 DAInt neighIInit00(tmp11);
2363 // Neighbor information of the mesh WITH the crack (some neighbors are removed):
2364 DataArrayInt *idsTmp=0;
2365 bool b=m01->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsTmp);
2367 // In the neighbor information remove the connection between high dimension cells and its low level constituents which are part
2368 // of the frontier given in parameter (i.e. the cells of low dimension from the group delimiting the crack):
2369 MEDCouplingUMesh::RemoveIdsFromIndexedArrays(ids->begin(),ids->end(),desc00,descI00);
2370 DataArrayInt *tmp0=0,*tmp1=0;
2371 // Compute the neighbor of each cell in m0Part2, taking into account the broken link above. Two
2372 // cells on either side of the crack (defined by the mesh of low dimension) are not neighbor anymore.
2373 ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00,tmp0,tmp1);
2374 DAInt neigh00(tmp0);
2375 DAInt neighI00(tmp1);
2377 // For each initial connex part of the sub-mesh (or said differently for each independent crack):
2378 int seed = 0, nIter = 0;
2379 int nIterMax = nCells2+1; // Safety net for the loop
2380 DAInt hitCells = DataArrayInt::New(); hitCells->alloc(nCells2);
2381 hitCells->fillWithValue(-1);
2382 DAInt cellsToModifyConn0_torenum = DataArrayInt::New();
2383 cellsToModifyConn0_torenum->alloc(0,1);
2384 while (nIter < nIterMax)
2386 DAInt t = hitCells->findIdsEqual(-1);
2387 if (!t->getNumberOfTuples())
2389 // Connex zone without the crack (to compute the next seed really)
2391 DAInt connexCheck = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neighInit00,neighIInit00, -1, dnu);
2393 for (int * ptr = connexCheck->getPointer(); cnt < connexCheck->getNumberOfTuples(); ptr++, cnt++)
2394 hitCells->setIJ(*ptr,0,1);
2395 // Connex zone WITH the crack (to identify cells lying on either part of the crack)
2396 DAInt spreadZone = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neigh00,neighI00, -1, dnu);
2397 cellsToModifyConn0_torenum = DataArrayInt::Aggregate(cellsToModifyConn0_torenum, spreadZone, 0);
2398 // Compute next seed, i.e. a cell in another connex part, which was not covered by the previous iterations
2399 DAInt comple = cellsToModifyConn0_torenum->buildComplement(nCells2);
2400 DAInt nonHitCells = hitCells->findIdsEqual(-1);
2401 DAInt intersec = nonHitCells->buildIntersection(comple);
2402 if (intersec->getNumberOfTuples())
2403 { seed = intersec->getIJ(0,0); }
2408 if (nIter >= nIterMax)
2409 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate(): internal error - too many iterations.");
2411 DAInt cellsToModifyConn1_torenum=cellsToModifyConn0_torenum->buildComplement(neighI00->getNumberOfTuples()-1);
2412 cellsToModifyConn0_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2413 cellsToModifyConn1_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2415 cellIdsNeededToBeRenum=cellsToModifyConn0_torenum.retn();
2416 cellIdsNotModified=cellsToModifyConn1_torenum.retn();
2417 nodeIdsToDuplicate=dupl.retn();
2421 * This method operates a modification of the connectivity and coords in \b this.
2422 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2423 * its ids will be modified to id this->getNumberOfNodes()+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2424 * More explicitely the renumber array in nodes is not explicitely given in old2new to avoid to build a big array of renumbering whereas typically few node ids needs to be
2425 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id this->getNumberOfNodes()+0, node id nodeIdsToDuplicateBg[1] will have id this->getNumberOfNodes()+1,
2426 * node id nodeIdsToDuplicateBg[2] will have id this->getNumberOfNodes()+2...
2428 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2430 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2431 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2433 void MEDCouplingUMesh::duplicateNodes(const int *nodeIdsToDuplicateBg, const int *nodeIdsToDuplicateEnd)
2435 int nbOfNodes=getNumberOfNodes();
2436 duplicateNodesInCoords(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd);
2437 duplicateNodesInConn(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,nbOfNodes);
2441 * This method renumbers only nodal connectivity in \a this. The renumbering is only an offset applied. So this method is a specialization of
2442 * \a renumberNodesInConn. \b WARNING, this method does not check that the resulting node ids in the nodal connectivity is in a valid range !
2444 * \param [in] offset - specifies the offset to be applied on each element of connectivity.
2446 * \sa renumberNodesInConn
2448 void MEDCouplingUMesh::renumberNodesWithOffsetInConn(int offset)
2450 checkConnectivityFullyDefined();
2451 int *conn(getNodalConnectivity()->getPointer());
2452 const int *connIndex(getNodalConnectivityIndex()->getConstPointer());
2453 int nbOfCells(getNumberOfCells());
2454 for(int i=0;i<nbOfCells;i++)
2455 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2457 int& node=conn[iconn];
2458 if(node>=0)//avoid polyhedron separator
2463 _nodal_connec->declareAsNew();
2468 * Same than renumberNodesInConn(const int *) except that here the format of old-to-new traducer is using map instead
2469 * 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
2472 void MEDCouplingUMesh::renumberNodesInConn(const INTERP_KERNEL::HashMap<int,int>& newNodeNumbersO2N)
2474 checkConnectivityFullyDefined();
2475 int *conn(getNodalConnectivity()->getPointer());
2476 const int *connIndex(getNodalConnectivityIndex()->getConstPointer());
2477 int nbOfCells(getNumberOfCells());
2478 for(int i=0;i<nbOfCells;i++)
2479 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2481 int& node=conn[iconn];
2482 if(node>=0)//avoid polyhedron separator
2484 INTERP_KERNEL::HashMap<int,int>::const_iterator it(newNodeNumbersO2N.find(node));
2485 if(it!=newNodeNumbersO2N.end())
2491 std::ostringstream oss; oss << "MEDCouplingUMesh::renumberNodesInConn(map) : presence in connectivity for cell #" << i << " of node #" << node << " : Not in map !";
2492 throw INTERP_KERNEL::Exception(oss.str());
2496 _nodal_connec->declareAsNew();
2501 * Changes ids of nodes within the nodal connectivity arrays according to a permutation
2502 * array in "Old to New" mode. The node coordinates array is \b not changed by this method.
2503 * This method is a generalization of shiftNodeNumbersInConn().
2504 * \warning This method performs no check of validity of new ids. **Use it with care !**
2505 * \param [in] newNodeNumbersO2N - a permutation array, of length \a
2506 * this->getNumberOfNodes(), in "Old to New" mode.
2507 * See \ref numbering for more info on renumbering modes.
2508 * \throw If the nodal connectivity of cells is not defined.
2510 * \if ENABLE_EXAMPLES
2511 * \ref cpp_mcumesh_renumberNodesInConn "Here is a C++ example".<br>
2512 * \ref py_mcumesh_renumberNodesInConn "Here is a Python example".
2515 void MEDCouplingUMesh::renumberNodesInConn(const int *newNodeNumbersO2N)
2517 checkConnectivityFullyDefined();
2518 int *conn=getNodalConnectivity()->getPointer();
2519 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2520 int nbOfCells(getNumberOfCells());
2521 for(int i=0;i<nbOfCells;i++)
2522 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2524 int& node=conn[iconn];
2525 if(node>=0)//avoid polyhedron separator
2527 node=newNodeNumbersO2N[node];
2530 _nodal_connec->declareAsNew();
2535 * This method renumbers nodes \b in \b connectivity \b only \b without \b any \b reference \b to \b coords.
2536 * This method performs no check on the fact that new coordinate ids are valid. \b Use \b it \b with \b care !
2537 * This method is an specialization of \ref MEDCoupling::MEDCouplingUMesh::renumberNodesInConn "renumberNodesInConn method".
2539 * \param [in] delta specifies the shift size applied to nodeId in nodal connectivity in \b this.
2541 void MEDCouplingUMesh::shiftNodeNumbersInConn(int delta)
2543 checkConnectivityFullyDefined();
2544 int *conn=getNodalConnectivity()->getPointer();
2545 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2546 int nbOfCells=getNumberOfCells();
2547 for(int i=0;i<nbOfCells;i++)
2548 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2550 int& node=conn[iconn];
2551 if(node>=0)//avoid polyhedron separator
2556 _nodal_connec->declareAsNew();
2561 * This method operates a modification of the connectivity in \b this.
2562 * 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.
2563 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2564 * its ids will be modified to id offset+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2565 * More explicitely the renumber array in nodes is not explicitely given in old2new to avoid to build a big array of renumbering whereas typically few node ids needs to be
2566 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id offset+0, node id nodeIdsToDuplicateBg[1] will have id offset+1,
2567 * node id nodeIdsToDuplicateBg[2] will have id offset+2...
2569 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2570 * As an another consequense after the call of this method \b this can be transiently non cohrent.
2572 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2573 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2574 * \param [in] offset the offset applied to all node ids in connectivity that are in [ \a nodeIdsToDuplicateBg, \a nodeIdsToDuplicateEnd ).
2576 void MEDCouplingUMesh::duplicateNodesInConn(const int *nodeIdsToDuplicateBg, const int *nodeIdsToDuplicateEnd, int offset)
2578 checkConnectivityFullyDefined();
2579 std::map<int,int> m;
2581 for(const int *work=nodeIdsToDuplicateBg;work!=nodeIdsToDuplicateEnd;work++,val++)
2583 int *conn=getNodalConnectivity()->getPointer();
2584 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2585 int nbOfCells=getNumberOfCells();
2586 for(int i=0;i<nbOfCells;i++)
2587 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2589 int& node=conn[iconn];
2590 if(node>=0)//avoid polyhedron separator
2592 std::map<int,int>::iterator it=m.find(node);
2601 * This method renumbers cells of \a this using the array specified by [old2NewBg;old2NewBg+getNumberOfCells())
2603 * Contrary to MEDCouplingPointSet::renumberNodes, this method makes a permutation without any fuse of cell.
2604 * After the call of this method the number of cells remains the same as before.
2606 * If 'check' equals true the method will check that any elements in [ \a old2NewBg; \a old2NewEnd ) is unique ; if not
2607 * an INTERP_KERNEL::Exception will be thrown. When 'check' equals true [ \a old2NewBg ; \a old2NewEnd ) is not expected to
2608 * be strictly in [0;this->getNumberOfCells()).
2610 * If 'check' equals false the method will not check the content of [ \a old2NewBg ; \a old2NewEnd ).
2611 * To avoid any throw of SIGSEGV when 'check' equals false, the elements in [ \a old2NewBg ; \a old2NewEnd ) should be unique and
2612 * should be contained in[0;this->getNumberOfCells()).
2614 * \param [in] old2NewBg is expected to be a dynamically allocated pointer of size at least equal to this->getNumberOfCells()
2617 void MEDCouplingUMesh::renumberCells(const int *old2NewBg, bool check)
2619 checkConnectivityFullyDefined();
2620 int nbCells=getNumberOfCells();
2621 const int *array=old2NewBg;
2623 array=DataArrayInt::CheckAndPreparePermutation(old2NewBg,old2NewBg+nbCells);
2625 const int *conn=_nodal_connec->getConstPointer();
2626 const int *connI=_nodal_connec_index->getConstPointer();
2627 MCAuto<DataArrayInt> o2n=DataArrayInt::New(); o2n->useArray(array,false,C_DEALLOC,nbCells,1);
2628 MCAuto<DataArrayInt> n2o=o2n->invertArrayO2N2N2O(nbCells);
2629 const int *n2oPtr=n2o->begin();
2630 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
2631 newConn->alloc(_nodal_connec->getNumberOfTuples(),_nodal_connec->getNumberOfComponents());
2632 newConn->copyStringInfoFrom(*_nodal_connec);
2633 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
2634 newConnI->alloc(_nodal_connec_index->getNumberOfTuples(),_nodal_connec_index->getNumberOfComponents());
2635 newConnI->copyStringInfoFrom(*_nodal_connec_index);
2637 int *newC=newConn->getPointer();
2638 int *newCI=newConnI->getPointer();
2641 for(int i=0;i<nbCells;i++)
2644 int nbOfElts=connI[pos+1]-connI[pos];
2645 newC=std::copy(conn+connI[pos],conn+connI[pos+1],newC);
2650 setConnectivity(newConn,newConnI);
2652 free(const_cast<int *>(array));
2656 * Finds cells whose bounding boxes intersect a given bounding box.
2657 * \param [in] bbox - an array defining the bounding box via coordinates of its
2658 * extremum points in "no interlace" mode, i.e. xMin, xMax, yMin, yMax, zMin,
2660 * \param [in] eps - a factor used to increase size of the bounding box of cell
2661 * before comparing it with \a bbox. This factor is multiplied by the maximal
2662 * extent of the bounding box of cell to produce an addition to this bounding box.
2663 * \return DataArrayInt * - a new instance of DataArrayInt holding ids for found
2664 * cells. The caller is to delete this array using decrRef() as it is no more
2666 * \throw If the coordinates array is not set.
2667 * \throw If the nodal connectivity of cells is not defined.
2669 * \if ENABLE_EXAMPLES
2670 * \ref cpp_mcumesh_getCellsInBoundingBox "Here is a C++ example".<br>
2671 * \ref py_mcumesh_getCellsInBoundingBox "Here is a Python example".
2674 DataArrayInt *MEDCouplingUMesh::getCellsInBoundingBox(const double *bbox, double eps) const
2676 MCAuto<DataArrayInt> elems=DataArrayInt::New(); elems->alloc(0,1);
2677 if(getMeshDimension()==-1)
2679 elems->pushBackSilent(0);
2680 return elems.retn();
2682 int dim=getSpaceDimension();
2683 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2684 const int* conn = getNodalConnectivity()->getConstPointer();
2685 const int* conn_index= getNodalConnectivityIndex()->getConstPointer();
2686 const double* coords = getCoords()->getConstPointer();
2687 int nbOfCells=getNumberOfCells();
2688 for ( int ielem=0; ielem<nbOfCells;ielem++ )
2690 for (int i=0; i<dim; i++)
2692 elem_bb[i*2]=std::numeric_limits<double>::max();
2693 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2696 for (int inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2698 int node= conn[inode];
2699 if(node>=0)//avoid polyhedron separator
2701 for (int idim=0; idim<dim; idim++)
2703 if ( coords[node*dim+idim] < elem_bb[idim*2] )
2705 elem_bb[idim*2] = coords[node*dim+idim] ;
2707 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2709 elem_bb[idim*2+1] = coords[node*dim+idim] ;
2714 if (intersectsBoundingBox(elem_bb, bbox, dim, eps))
2715 elems->pushBackSilent(ielem);
2717 return elems.retn();
2721 * Given a boundary box 'bbox' returns elements 'elems' contained in this 'bbox' or touching 'bbox' (within 'eps' distance).
2722 * Warning 'elems' is incremented during the call so if elems is not empty before call returned elements will be
2723 * added in 'elems' parameter.
2725 DataArrayInt *MEDCouplingUMesh::getCellsInBoundingBox(const INTERP_KERNEL::DirectedBoundingBox& bbox, double eps)
2727 MCAuto<DataArrayInt> elems=DataArrayInt::New(); elems->alloc(0,1);
2728 if(getMeshDimension()==-1)
2730 elems->pushBackSilent(0);
2731 return elems.retn();
2733 int dim=getSpaceDimension();
2734 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2735 const int* conn = getNodalConnectivity()->getConstPointer();
2736 const int* conn_index= getNodalConnectivityIndex()->getConstPointer();
2737 const double* coords = getCoords()->getConstPointer();
2738 int nbOfCells=getNumberOfCells();
2739 for ( int ielem=0; ielem<nbOfCells;ielem++ )
2741 for (int i=0; i<dim; i++)
2743 elem_bb[i*2]=std::numeric_limits<double>::max();
2744 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2747 for (int inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2749 int node= conn[inode];
2750 if(node>=0)//avoid polyhedron separator
2752 for (int idim=0; idim<dim; idim++)
2754 if ( coords[node*dim+idim] < elem_bb[idim*2] )
2756 elem_bb[idim*2] = coords[node*dim+idim] ;
2758 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2760 elem_bb[idim*2+1] = coords[node*dim+idim] ;
2765 if(intersectsBoundingBox(bbox, elem_bb, dim, eps))
2766 elems->pushBackSilent(ielem);
2768 return elems.retn();
2772 * Returns a type of a cell by its id.
2773 * \param [in] cellId - the id of the cell of interest.
2774 * \return INTERP_KERNEL::NormalizedCellType - enumeration item describing the cell type.
2775 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2777 INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::getTypeOfCell(int cellId) const
2779 const int *ptI=_nodal_connec_index->getConstPointer();
2780 const int *pt=_nodal_connec->getConstPointer();
2781 if(cellId>=0 && cellId<(int)_nodal_connec_index->getNbOfElems()-1)
2782 return (INTERP_KERNEL::NormalizedCellType) pt[ptI[cellId]];
2785 std::ostringstream oss; oss << "MEDCouplingUMesh::getTypeOfCell : Requesting type of cell #" << cellId << " but it should be in [0," << _nodal_connec_index->getNbOfElems()-1 << ") !";
2786 throw INTERP_KERNEL::Exception(oss.str());
2791 * This method returns a newly allocated array containing cell ids (ascendingly sorted) whose geometric type are equal to type.
2792 * This method does not throw exception if geometric type \a type is not in \a this.
2793 * This method throws an INTERP_KERNEL::Exception if meshdimension of \b this is not equal to those of \b type.
2794 * The coordinates array is not considered here.
2796 * \param [in] type the geometric type
2797 * \return cell ids in this having geometric type \a type.
2799 DataArrayInt *MEDCouplingUMesh::giveCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2802 MCAuto<DataArrayInt> ret=DataArrayInt::New();
2804 checkConnectivityFullyDefined();
2805 int nbCells=getNumberOfCells();
2806 int mdim=getMeshDimension();
2807 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
2808 if(mdim!=(int)cm.getDimension())
2809 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::giveCellsWithType : Mismatch between mesh dimension and dimension of the cell !");
2810 const int *ptI=_nodal_connec_index->getConstPointer();
2811 const int *pt=_nodal_connec->getConstPointer();
2812 for(int i=0;i<nbCells;i++)
2814 if((INTERP_KERNEL::NormalizedCellType)pt[ptI[i]]==type)
2815 ret->pushBackSilent(i);
2821 * Returns nb of cells having the geometric type \a type. No throw if no cells in \a this has the geometric type \a type.
2823 int MEDCouplingUMesh::getNumberOfCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2825 const int *ptI=_nodal_connec_index->getConstPointer();
2826 const int *pt=_nodal_connec->getConstPointer();
2827 int nbOfCells=getNumberOfCells();
2829 for(int i=0;i<nbOfCells;i++)
2830 if((INTERP_KERNEL::NormalizedCellType) pt[ptI[i]]==type)
2836 * Returns the nodal connectivity of a given cell.
2837 * The separator of faces within polyhedron connectivity (-1) is not returned, thus
2838 * all returned node ids can be used in getCoordinatesOfNode().
2839 * \param [in] cellId - an id of the cell of interest.
2840 * \param [in,out] conn - a vector where the node ids are appended. It is not
2841 * cleared before the appending.
2842 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2844 void MEDCouplingUMesh::getNodeIdsOfCell(int cellId, std::vector<int>& conn) const
2846 const int *ptI=_nodal_connec_index->getConstPointer();
2847 const int *pt=_nodal_connec->getConstPointer();
2848 for(const int *w=pt+ptI[cellId]+1;w!=pt+ptI[cellId+1];w++)
2853 std::string MEDCouplingUMesh::simpleRepr() const
2855 static const char msg0[]="No coordinates specified !";
2856 std::ostringstream ret;
2857 ret << "Unstructured mesh with name : \"" << getName() << "\"\n";
2858 ret << "Description of mesh : \"" << getDescription() << "\"\n";
2860 double tt=getTime(tmpp1,tmpp2);
2861 ret << "Time attached to the mesh [unit] : " << tt << " [" << getTimeUnit() << "]\n";
2862 ret << "Iteration : " << tmpp1 << " Order : " << tmpp2 << "\n";
2864 { ret << "Mesh dimension : " << _mesh_dim << "\nSpace dimension : "; }
2866 { ret << " Mesh dimension has not been set or is invalid !"; }
2869 const int spaceDim=getSpaceDimension();
2870 ret << spaceDim << "\nInfo attached on space dimension : ";
2871 for(int i=0;i<spaceDim;i++)
2872 ret << "\"" << _coords->getInfoOnComponent(i) << "\" ";
2876 ret << msg0 << "\n";
2877 ret << "Number of nodes : ";
2879 ret << getNumberOfNodes() << "\n";
2881 ret << msg0 << "\n";
2882 ret << "Number of cells : ";
2883 if(_nodal_connec!=0 && _nodal_connec_index!=0)
2884 ret << getNumberOfCells() << "\n";
2886 ret << "No connectivity specified !" << "\n";
2887 ret << "Cell types present : ";
2888 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
2890 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter);
2891 ret << cm.getRepr() << " ";
2897 std::string MEDCouplingUMesh::advancedRepr() const
2899 std::ostringstream ret;
2900 ret << simpleRepr();
2901 ret << "\nCoordinates array : \n___________________\n\n";
2903 _coords->reprWithoutNameStream(ret);
2905 ret << "No array set !\n";
2906 ret << "\n\nConnectivity arrays : \n_____________________\n\n";
2907 reprConnectivityOfThisLL(ret);
2912 * This method returns a C++ code that is a dump of \a this.
2913 * This method will throw if this is not fully defined.
2915 std::string MEDCouplingUMesh::cppRepr() const
2917 static const char coordsName[]="coords";
2918 static const char connName[]="conn";
2919 static const char connIName[]="connI";
2920 checkFullyDefined();
2921 std::ostringstream ret; ret << "// coordinates" << std::endl;
2922 _coords->reprCppStream(coordsName,ret); ret << std::endl << "// connectivity" << std::endl;
2923 _nodal_connec->reprCppStream(connName,ret); ret << std::endl;
2924 _nodal_connec_index->reprCppStream(connIName,ret); ret << std::endl;
2925 ret << "MEDCouplingUMesh *mesh=MEDCouplingUMesh::New(\"" << getName() << "\"," << getMeshDimension() << ");" << std::endl;
2926 ret << "mesh->setCoords(" << coordsName << ");" << std::endl;
2927 ret << "mesh->setConnectivity(" << connName << "," << connIName << ",true);" << std::endl;
2928 ret << coordsName << "->decrRef(); " << connName << "->decrRef(); " << connIName << "->decrRef();" << std::endl;
2932 std::string MEDCouplingUMesh::reprConnectivityOfThis() const
2934 std::ostringstream ret;
2935 reprConnectivityOfThisLL(ret);
2940 * This method builds a newly allocated instance (with the same name than \a this) that the caller has the responsability to deal with.
2941 * This method returns an instance with all arrays allocated (connectivity, connectivity index, coordinates)
2942 * but with length of these arrays set to 0. It allows to define an "empty" mesh (with nor cells nor nodes but compliant with
2945 * This method expects that \a this has a mesh dimension set and higher or equal to 0. If not an exception will be thrown.
2946 * 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
2947 * with number of tuples set to 0, if not the array is taken as this in the returned instance.
2949 MEDCouplingUMesh *MEDCouplingUMesh::buildSetInstanceFromThis(int spaceDim) const
2951 int mdim=getMeshDimension();
2953 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSetInstanceFromThis : invalid mesh dimension ! Should be >= 0 !");
2954 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
2955 MCAuto<DataArrayInt> tmp1,tmp2;
2956 bool needToCpyCT=true;
2959 tmp1=DataArrayInt::New(); tmp1->alloc(0,1);
2967 if(!_nodal_connec_index)
2969 tmp2=DataArrayInt::New(); tmp2->alloc(1,1); tmp2->setIJ(0,0,0);
2974 tmp2=_nodal_connec_index;
2977 ret->setConnectivity(tmp1,tmp2,false);
2982 MCAuto<DataArrayDouble> coords=DataArrayDouble::New(); coords->alloc(0,spaceDim);
2983 ret->setCoords(coords);
2986 ret->setCoords(_coords);
2990 int MEDCouplingUMesh::getNumberOfNodesInCell(int cellId) const
2992 const int *ptI=_nodal_connec_index->getConstPointer();
2993 const int *pt=_nodal_connec->getConstPointer();
2994 if(pt[ptI[cellId]]!=INTERP_KERNEL::NORM_POLYHED)
2995 return ptI[cellId+1]-ptI[cellId]-1;
2997 return (int)std::count_if(pt+ptI[cellId]+1,pt+ptI[cellId+1],std::bind2nd(std::not_equal_to<int>(),-1));
3001 * Returns types of cells of the specified part of \a this mesh.
3002 * This method avoids computing sub-mesh explicitely to get its types.
3003 * \param [in] begin - an array of cell ids of interest.
3004 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3005 * \return std::set<INTERP_KERNEL::NormalizedCellType> - a set of enumeration items
3006 * describing the cell types.
3007 * \throw If the coordinates array is not set.
3008 * \throw If the nodal connectivity of cells is not defined.
3009 * \sa getAllGeoTypes()
3011 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getTypesOfPart(const int *begin, const int *end) const
3013 checkFullyDefined();
3014 std::set<INTERP_KERNEL::NormalizedCellType> ret;
3015 const int *conn=_nodal_connec->getConstPointer();
3016 const int *connIndex=_nodal_connec_index->getConstPointer();
3017 for(const int *w=begin;w!=end;w++)
3018 ret.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]);
3023 * Defines the nodal connectivity using given connectivity arrays in \ref numbering-indirect format.
3024 * Optionally updates
3025 * a set of types of cells constituting \a this mesh.
3026 * This method is for advanced users having prepared their connectivity before. For
3027 * more info on using this method see \ref MEDCouplingUMeshAdvBuild.
3028 * \param [in] conn - the nodal connectivity array.
3029 * \param [in] connIndex - the nodal connectivity index array.
3030 * \param [in] isComputingTypes - if \c true, the set of types constituting \a this
3033 void MEDCouplingUMesh::setConnectivity(DataArrayInt *conn, DataArrayInt *connIndex, bool isComputingTypes)
3035 DataArrayInt::SetArrayIn(conn,_nodal_connec);
3036 DataArrayInt::SetArrayIn(connIndex,_nodal_connec_index);
3037 if(isComputingTypes)
3043 * Copy constructor. If 'deepCopy' is false \a this is a shallow copy of other.
3044 * If 'deeCpy' is true all arrays (coordinates and connectivities) are deeply copied.
3046 MEDCouplingUMesh::MEDCouplingUMesh(const MEDCouplingUMesh& other, bool deepCopy):MEDCouplingPointSet(other,deepCopy),_mesh_dim(other._mesh_dim),
3047 _nodal_connec(0),_nodal_connec_index(0),
3048 _types(other._types)
3050 if(other._nodal_connec)
3051 _nodal_connec=other._nodal_connec->performCopyOrIncrRef(deepCopy);
3052 if(other._nodal_connec_index)
3053 _nodal_connec_index=other._nodal_connec_index->performCopyOrIncrRef(deepCopy);
3056 MEDCouplingUMesh::~MEDCouplingUMesh()
3059 _nodal_connec->decrRef();
3060 if(_nodal_connec_index)
3061 _nodal_connec_index->decrRef();
3065 * Recomputes a set of cell types of \a this mesh. For more info see
3066 * \ref MEDCouplingUMeshNodalConnectivity.
3068 void MEDCouplingUMesh::computeTypes()
3070 ComputeAllTypesInternal(_types,_nodal_connec,_nodal_connec_index);
3075 * Returns a number of cells constituting \a this mesh.
3076 * \return int - the number of cells in \a this mesh.
3077 * \throw If the nodal connectivity of cells is not defined.
3079 int MEDCouplingUMesh::getNumberOfCells() const
3081 if(_nodal_connec_index)
3082 return _nodal_connec_index->getNumberOfTuples()-1;
3087 throw INTERP_KERNEL::Exception("Unable to get number of cells because no connectivity specified !");
3091 * Returns a dimension of \a this mesh, i.e. a dimension of cells constituting \a this
3092 * mesh. For more info see \ref meshes.
3093 * \return int - the dimension of \a this mesh.
3094 * \throw If the mesh dimension is not defined using setMeshDimension().
3096 int MEDCouplingUMesh::getMeshDimension() const
3099 throw INTERP_KERNEL::Exception("No mesh dimension specified !");
3104 * Returns a length of the nodal connectivity array.
3105 * This method is for test reason. Normally the integer returned is not useable by
3106 * user. For more info see \ref MEDCouplingUMeshNodalConnectivity.
3107 * \return int - the length of the nodal connectivity array.
3109 int MEDCouplingUMesh::getNodalConnectivityArrayLen() const
3111 return _nodal_connec->getNbOfElems();
3115 * First step of serialization process. Used by ParaMEDMEM and MEDCouplingCorba to transfert data between process.
3117 void MEDCouplingUMesh::getTinySerializationInformation(std::vector<double>& tinyInfoD, std::vector<int>& tinyInfo, std::vector<std::string>& littleStrings) const
3119 MEDCouplingPointSet::getTinySerializationInformation(tinyInfoD,tinyInfo,littleStrings);
3120 tinyInfo.push_back(getMeshDimension());
3121 tinyInfo.push_back(getNumberOfCells());
3123 tinyInfo.push_back(getNodalConnectivityArrayLen());
3125 tinyInfo.push_back(-1);
3129 * First step of unserialization process.
3131 bool MEDCouplingUMesh::isEmptyMesh(const std::vector<int>& tinyInfo) const
3133 return tinyInfo[6]<=0;
3137 * Second step of serialization process.
3138 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3141 * \param littleStrings
3143 void MEDCouplingUMesh::resizeForUnserialization(const std::vector<int>& tinyInfo, DataArrayInt *a1, DataArrayDouble *a2, std::vector<std::string>& littleStrings) const
3145 MEDCouplingPointSet::resizeForUnserialization(tinyInfo,a1,a2,littleStrings);
3147 a1->alloc(tinyInfo[7]+tinyInfo[6]+1,1);
3151 * Third and final step of serialization process.
3153 void MEDCouplingUMesh::serialize(DataArrayInt *&a1, DataArrayDouble *&a2) const
3155 MEDCouplingPointSet::serialize(a1,a2);
3156 if(getMeshDimension()>-1)
3158 a1=DataArrayInt::New();
3159 a1->alloc(getNodalConnectivityArrayLen()+getNumberOfCells()+1,1);
3160 int *ptA1=a1->getPointer();
3161 const int *conn=getNodalConnectivity()->getConstPointer();
3162 const int *index=getNodalConnectivityIndex()->getConstPointer();
3163 ptA1=std::copy(index,index+getNumberOfCells()+1,ptA1);
3164 std::copy(conn,conn+getNodalConnectivityArrayLen(),ptA1);
3171 * Second and final unserialization process.
3172 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3174 void MEDCouplingUMesh::unserialization(const std::vector<double>& tinyInfoD, const std::vector<int>& tinyInfo, const DataArrayInt *a1, DataArrayDouble *a2, const std::vector<std::string>& littleStrings)
3176 MEDCouplingPointSet::unserialization(tinyInfoD,tinyInfo,a1,a2,littleStrings);
3177 setMeshDimension(tinyInfo[5]);
3181 const int *recvBuffer=a1->getConstPointer();
3182 MCAuto<DataArrayInt> myConnecIndex=DataArrayInt::New();
3183 myConnecIndex->alloc(tinyInfo[6]+1,1);
3184 std::copy(recvBuffer,recvBuffer+tinyInfo[6]+1,myConnecIndex->getPointer());
3185 MCAuto<DataArrayInt> myConnec=DataArrayInt::New();
3186 myConnec->alloc(tinyInfo[7],1);
3187 std::copy(recvBuffer+tinyInfo[6]+1,recvBuffer+tinyInfo[6]+1+tinyInfo[7],myConnec->getPointer());
3188 setConnectivity(myConnec, myConnecIndex);
3195 * Returns a new MEDCouplingFieldDouble containing volumes of cells constituting \a this
3197 * For 1D cells, the returned field contains lengths.<br>
3198 * For 2D cells, the returned field contains areas.<br>
3199 * For 3D cells, the returned field contains volumes.
3200 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3201 * orientation, i.e. the volume is always positive.
3202 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on cells
3203 * and one time . The caller is to delete this field using decrRef() as it is no
3206 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureField(bool isAbs) const
3208 std::string name="MeasureOfMesh_";
3210 int nbelem=getNumberOfCells();
3211 MCAuto<MEDCouplingFieldDouble> field=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3212 field->setName(name);
3213 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3214 array->alloc(nbelem,1);
3215 double *area_vol=array->getPointer();
3216 field->setArray(array) ; array=0;
3217 field->setMesh(const_cast<MEDCouplingUMesh *>(this));
3218 field->synchronizeTimeWithMesh();
3219 if(getMeshDimension()!=-1)
3222 INTERP_KERNEL::NormalizedCellType type;
3223 int dim_space=getSpaceDimension();
3224 const double *coords=getCoords()->getConstPointer();
3225 const int *connec=getNodalConnectivity()->getConstPointer();
3226 const int *connec_index=getNodalConnectivityIndex()->getConstPointer();
3227 for(int iel=0;iel<nbelem;iel++)
3229 ipt=connec_index[iel];
3230 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3231 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);
3234 std::transform(area_vol,area_vol+nbelem,area_vol,std::ptr_fun<double,double>(fabs));
3238 area_vol[0]=std::numeric_limits<double>::max();
3240 return field.retn();
3244 * Returns a new DataArrayDouble containing volumes of specified cells of \a this
3246 * For 1D cells, the returned array contains lengths.<br>
3247 * For 2D cells, the returned array contains areas.<br>
3248 * For 3D cells, the returned array contains volumes.
3249 * This method avoids building explicitly a part of \a this mesh to perform the work.
3250 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3251 * orientation, i.e. the volume is always positive.
3252 * \param [in] begin - an array of cell ids of interest.
3253 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3254 * \return DataArrayDouble * - a new instance of DataArrayDouble. The caller is to
3255 * delete this array using decrRef() as it is no more needed.
3257 * \if ENABLE_EXAMPLES
3258 * \ref cpp_mcumesh_getPartMeasureField "Here is a C++ example".<br>
3259 * \ref py_mcumesh_getPartMeasureField "Here is a Python example".
3261 * \sa getMeasureField()
3263 DataArrayDouble *MEDCouplingUMesh::getPartMeasureField(bool isAbs, const int *begin, const int *end) const
3265 std::string name="PartMeasureOfMesh_";
3267 int nbelem=(int)std::distance(begin,end);
3268 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3269 array->setName(name);
3270 array->alloc(nbelem,1);
3271 double *area_vol=array->getPointer();
3272 if(getMeshDimension()!=-1)
3275 INTERP_KERNEL::NormalizedCellType type;
3276 int dim_space=getSpaceDimension();
3277 const double *coords=getCoords()->getConstPointer();
3278 const int *connec=getNodalConnectivity()->getConstPointer();
3279 const int *connec_index=getNodalConnectivityIndex()->getConstPointer();
3280 for(const int *iel=begin;iel!=end;iel++)
3282 ipt=connec_index[*iel];
3283 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3284 *area_vol++=INTERP_KERNEL::computeVolSurfOfCell2<int,INTERP_KERNEL::ALL_C_MODE>(type,connec+ipt+1,connec_index[*iel+1]-ipt-1,coords,dim_space);
3287 std::transform(array->getPointer(),area_vol,array->getPointer(),std::ptr_fun<double,double>(fabs));
3291 area_vol[0]=std::numeric_limits<double>::max();
3293 return array.retn();
3297 * Returns a new MEDCouplingFieldDouble containing volumes of cells of a dual mesh of
3298 * \a this one. The returned field contains the dual cell volume for each corresponding
3299 * node in \a this mesh. In other words, the field returns the getMeasureField() of
3300 * the dual mesh in P1 sens of \a this.<br>
3301 * For 1D cells, the returned field contains lengths.<br>
3302 * For 2D cells, the returned field contains areas.<br>
3303 * For 3D cells, the returned field contains volumes.
3304 * This method is useful to check "P1*" conservative interpolators.
3305 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3306 * orientation, i.e. the volume is always positive.
3307 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3308 * nodes and one time. The caller is to delete this array using decrRef() as
3309 * it is no more needed.
3311 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureFieldOnNode(bool isAbs) const
3313 MCAuto<MEDCouplingFieldDouble> tmp=getMeasureField(isAbs);
3314 std::string name="MeasureOnNodeOfMesh_";
3316 int nbNodes=getNumberOfNodes();
3317 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_NODES);
3318 double cst=1./((double)getMeshDimension()+1.);
3319 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3320 array->alloc(nbNodes,1);
3321 double *valsToFill=array->getPointer();
3322 std::fill(valsToFill,valsToFill+nbNodes,0.);
3323 const double *values=tmp->getArray()->getConstPointer();
3324 MCAuto<DataArrayInt> da=DataArrayInt::New();
3325 MCAuto<DataArrayInt> daInd=DataArrayInt::New();
3326 getReverseNodalConnectivity(da,daInd);
3327 const int *daPtr=da->getConstPointer();
3328 const int *daIPtr=daInd->getConstPointer();
3329 for(int i=0;i<nbNodes;i++)
3330 for(const int *cell=daPtr+daIPtr[i];cell!=daPtr+daIPtr[i+1];cell++)
3331 valsToFill[i]+=cst*values[*cell];
3333 ret->setArray(array);
3338 * Returns a new MEDCouplingFieldDouble holding normal vectors to cells of \a this
3339 * mesh. The returned normal vectors to each cell have a norm2 equal to 1.
3340 * The computed vectors have <em> this->getMeshDimension()+1 </em> components
3341 * and are normalized.
3342 * <br> \a this can be either
3343 * - a 2D mesh in 2D or 3D space or
3344 * - an 1D mesh in 2D space.
3346 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3347 * cells and one time. The caller is to delete this field using decrRef() as
3348 * it is no more needed.
3349 * \throw If the nodal connectivity of cells is not defined.
3350 * \throw If the coordinates array is not set.
3351 * \throw If the mesh dimension is not set.
3352 * \throw If the mesh and space dimension is not as specified above.
3354 MEDCouplingFieldDouble *MEDCouplingUMesh::buildOrthogonalField() const
3356 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3357 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3358 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3359 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3360 int nbOfCells=getNumberOfCells();
3361 int nbComp=getMeshDimension()+1;
3362 array->alloc(nbOfCells,nbComp);
3363 double *vals=array->getPointer();
3364 const int *connI=_nodal_connec_index->getConstPointer();
3365 const int *conn=_nodal_connec->getConstPointer();
3366 const double *coords=_coords->getConstPointer();
3367 if(getMeshDimension()==2)
3369 if(getSpaceDimension()==3)
3371 MCAuto<DataArrayDouble> loc=computeCellCenterOfMass();
3372 const double *locPtr=loc->getConstPointer();
3373 for(int i=0;i<nbOfCells;i++,vals+=3)
3375 int offset=connI[i];
3376 INTERP_KERNEL::crossprod<3>(locPtr+3*i,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3377 double n=INTERP_KERNEL::norm<3>(vals);
3378 std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3383 MCAuto<MEDCouplingFieldDouble> isAbs=getMeasureField(false);
3384 const double *isAbsPtr=isAbs->getArray()->begin();
3385 for(int i=0;i<nbOfCells;i++,isAbsPtr++)
3386 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=*isAbsPtr>0.?1.:-1.; }
3389 else//meshdimension==1
3392 for(int i=0;i<nbOfCells;i++)
3394 int offset=connI[i];
3395 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3396 double n=INTERP_KERNEL::norm<2>(tmp);
3397 std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3402 ret->setArray(array);
3404 ret->synchronizeTimeWithSupport();
3409 * Returns a new MEDCouplingFieldDouble holding normal vectors to specified cells of
3410 * \a this mesh. The computed vectors have <em> this->getMeshDimension()+1 </em> components
3411 * and are normalized.
3412 * <br> \a this can be either
3413 * - a 2D mesh in 2D or 3D space or
3414 * - an 1D mesh in 2D space.
3416 * This method avoids building explicitly a part of \a this mesh to perform the work.
3417 * \param [in] begin - an array of cell ids of interest.
3418 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3419 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3420 * cells and one time. The caller is to delete this field using decrRef() as
3421 * it is no more needed.
3422 * \throw If the nodal connectivity of cells is not defined.
3423 * \throw If the coordinates array is not set.
3424 * \throw If the mesh dimension is not set.
3425 * \throw If the mesh and space dimension is not as specified above.
3426 * \sa buildOrthogonalField()
3428 * \if ENABLE_EXAMPLES
3429 * \ref cpp_mcumesh_buildPartOrthogonalField "Here is a C++ example".<br>
3430 * \ref py_mcumesh_buildPartOrthogonalField "Here is a Python example".
3433 MEDCouplingFieldDouble *MEDCouplingUMesh::buildPartOrthogonalField(const int *begin, const int *end) const
3435 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3436 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3437 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3438 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3439 std::size_t nbelems=std::distance(begin,end);
3440 int nbComp=getMeshDimension()+1;
3441 array->alloc((int)nbelems,nbComp);
3442 double *vals=array->getPointer();
3443 const int *connI=_nodal_connec_index->getConstPointer();
3444 const int *conn=_nodal_connec->getConstPointer();
3445 const double *coords=_coords->getConstPointer();
3446 if(getMeshDimension()==2)
3448 if(getSpaceDimension()==3)
3450 MCAuto<DataArrayDouble> loc=getPartBarycenterAndOwner(begin,end);
3451 const double *locPtr=loc->getConstPointer();
3452 for(const int *i=begin;i!=end;i++,vals+=3,locPtr+=3)
3454 int offset=connI[*i];
3455 INTERP_KERNEL::crossprod<3>(locPtr,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3456 double n=INTERP_KERNEL::norm<3>(vals);
3457 std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3462 for(std::size_t i=0;i<nbelems;i++)
3463 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=1.; }
3466 else//meshdimension==1
3469 for(const int *i=begin;i!=end;i++)
3471 int offset=connI[*i];
3472 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3473 double n=INTERP_KERNEL::norm<2>(tmp);
3474 std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3479 ret->setArray(array);
3481 ret->synchronizeTimeWithSupport();
3486 * Returns a new MEDCouplingFieldDouble holding a direction vector for each SEG2 in \a
3487 * this 1D mesh. The computed vectors have <em> this->getSpaceDimension() </em> components
3488 * and are \b not normalized.
3489 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3490 * cells and one time. The caller is to delete this field using decrRef() as
3491 * it is no more needed.
3492 * \throw If the nodal connectivity of cells is not defined.
3493 * \throw If the coordinates array is not set.
3494 * \throw If \a this->getMeshDimension() != 1.
3495 * \throw If \a this mesh includes cells of type other than SEG2.
3497 MEDCouplingFieldDouble *MEDCouplingUMesh::buildDirectionVectorField() const
3499 if(getMeshDimension()!=1)
3500 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for buildDirectionVectorField !");
3501 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3502 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for buildDirectionVectorField !");
3503 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3504 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3505 int nbOfCells=getNumberOfCells();
3506 int spaceDim=getSpaceDimension();
3507 array->alloc(nbOfCells,spaceDim);
3508 double *pt=array->getPointer();
3509 const double *coo=getCoords()->getConstPointer();
3510 std::vector<int> conn;
3512 for(int i=0;i<nbOfCells;i++)
3515 getNodeIdsOfCell(i,conn);
3516 pt=std::transform(coo+conn[1]*spaceDim,coo+(conn[1]+1)*spaceDim,coo+conn[0]*spaceDim,pt,std::minus<double>());
3518 ret->setArray(array);
3520 ret->synchronizeTimeWithSupport();
3525 * Creates a 2D mesh by cutting \a this 3D mesh with a plane. In addition to the mesh,
3526 * returns a new DataArrayInt, of length equal to the number of 2D cells in the result
3527 * mesh, holding, for each cell in the result mesh, an id of a 3D cell it comes
3528 * from. If a result face is shared by two 3D cells, then the face in included twice in
3530 * \param [in] origin - 3 components of a point defining location of the plane.
3531 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3532 * must be greater than 1e-6.
3533 * \param [in] eps - half-thickness of the plane.
3534 * \param [out] cellIds - a new instance of DataArrayInt holding ids of 3D cells
3535 * producing correspondent 2D cells. The caller is to delete this array
3536 * using decrRef() as it is no more needed.
3537 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This mesh does
3538 * not share the node coordinates array with \a this mesh. The caller is to
3539 * delete this mesh using decrRef() as it is no more needed.
3540 * \throw If the coordinates array is not set.
3541 * \throw If the nodal connectivity of cells is not defined.
3542 * \throw If \a this->getMeshDimension() != 3 or \a this->getSpaceDimension() != 3.
3543 * \throw If magnitude of \a vec is less than 1e-6.
3544 * \throw If the plane does not intersect any 3D cell of \a this mesh.
3545 * \throw If \a this includes quadratic cells.
3547 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3D(const double *origin, const double *vec, double eps, DataArrayInt *&cellIds) const
3549 checkFullyDefined();
3550 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3551 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3552 MCAuto<DataArrayInt> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3553 if(candidates->empty())
3554 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane considering bounding boxes !");
3555 std::vector<int> nodes;
3556 DataArrayInt *cellIds1D=0;
3557 MCAuto<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3558 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3559 MCAuto<DataArrayInt> desc1=DataArrayInt::New(),desc2=DataArrayInt::New();
3560 MCAuto<DataArrayInt> descIndx1=DataArrayInt::New(),descIndx2=DataArrayInt::New();
3561 MCAuto<DataArrayInt> revDesc1=DataArrayInt::New(),revDesc2=DataArrayInt::New();
3562 MCAuto<DataArrayInt> revDescIndx1=DataArrayInt::New(),revDescIndx2=DataArrayInt::New();
3563 MCAuto<MEDCouplingUMesh> mDesc2=subMesh->buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2);//meshDim==2 spaceDim==3
3564 revDesc2=0; revDescIndx2=0;
3565 MCAuto<MEDCouplingUMesh> mDesc1=mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3566 revDesc1=0; revDescIndx1=0;
3567 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3568 MCAuto<DataArrayInt> cellIds1DTmp(cellIds1D);
3570 std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3571 for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3573 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3574 std::vector< std::pair<int,int> > cut3DSurf(mDesc2->getNumberOfCells());
3575 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->getConstPointer(),mDesc2->getNodalConnectivityIndex()->getConstPointer(),
3576 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3577 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3578 MCAuto<DataArrayInt> conn(DataArrayInt::New()),connI(DataArrayInt::New()),cellIds2(DataArrayInt::New());
3579 connI->pushBackSilent(0); conn->alloc(0,1); cellIds2->alloc(0,1);
3580 subMesh->assemblyForSplitFrom3DSurf(cut3DSurf,desc2->getConstPointer(),descIndx2->getConstPointer(),conn,connI,cellIds2);
3581 if(cellIds2->empty())
3582 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3583 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3D",2);
3584 ret->setCoords(mDesc1->getCoords());
3585 ret->setConnectivity(conn,connI,true);
3586 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3591 * Creates an 1D mesh by cutting \a this 2D mesh in 3D space with a plane. In
3592 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
3593 from. If a result segment is shared by two 2D cells, then the segment in included twice in
3595 * \param [in] origin - 3 components of a point defining location of the plane.
3596 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3597 * must be greater than 1e-6.
3598 * \param [in] eps - half-thickness of the plane.
3599 * \param [out] cellIds - a new instance of DataArrayInt holding ids of faces
3600 * producing correspondent segments. The caller is to delete this array
3601 * using decrRef() as it is no more needed.
3602 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This is an 1D
3603 * mesh in 3D space. This mesh does not share the node coordinates array with
3604 * \a this mesh. The caller is to delete this mesh using decrRef() as it is
3606 * \throw If the coordinates array is not set.
3607 * \throw If the nodal connectivity of cells is not defined.
3608 * \throw If \a this->getMeshDimension() != 2 or \a this->getSpaceDimension() != 3.
3609 * \throw If magnitude of \a vec is less than 1e-6.
3610 * \throw If the plane does not intersect any 2D cell of \a this mesh.
3611 * \throw If \a this includes quadratic cells.
3613 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3DSurf(const double *origin, const double *vec, double eps, DataArrayInt *&cellIds) const
3615 checkFullyDefined();
3616 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
3617 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf works on umeshes with meshdim equal to 2 and spaceDim equal to 3 !");
3618 MCAuto<DataArrayInt> candidates(getCellIdsCrossingPlane(origin,vec,eps));
3619 if(candidates->empty())
3620 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3D surf cells in this intercepts the specified plane considering bounding boxes !");
3621 std::vector<int> nodes;
3622 DataArrayInt *cellIds1D(0);
3623 MCAuto<MEDCouplingUMesh> subMesh(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3624 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3625 MCAuto<DataArrayInt> desc1(DataArrayInt::New()),descIndx1(DataArrayInt::New()),revDesc1(DataArrayInt::New()),revDescIndx1(DataArrayInt::New());
3626 MCAuto<MEDCouplingUMesh> mDesc1(subMesh->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3627 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3628 MCAuto<DataArrayInt> cellIds1DTmp(cellIds1D);
3630 std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3631 for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3633 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3634 int ncellsSub=subMesh->getNumberOfCells();
3635 std::vector< std::pair<int,int> > cut3DSurf(ncellsSub);
3636 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,subMesh->getNodalConnectivity()->getConstPointer(),subMesh->getNodalConnectivityIndex()->getConstPointer(),
3637 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3638 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3639 MCAuto<DataArrayInt> conn(DataArrayInt::New()),connI(DataArrayInt::New()),cellIds2(DataArrayInt::New()); connI->pushBackSilent(0);
3641 const int *nodal=subMesh->getNodalConnectivity()->getConstPointer();
3642 const int *nodalI=subMesh->getNodalConnectivityIndex()->getConstPointer();
3643 for(int i=0;i<ncellsSub;i++)
3645 if(cut3DSurf[i].first!=-1 && cut3DSurf[i].second!=-1)
3647 if(cut3DSurf[i].first!=-2)
3649 conn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG2); conn->pushBackSilent(cut3DSurf[i].first); conn->pushBackSilent(cut3DSurf[i].second);
3650 connI->pushBackSilent(conn->getNumberOfTuples());
3651 cellIds2->pushBackSilent(i);
3655 int cellId3DSurf=cut3DSurf[i].second;
3656 int offset=nodalI[cellId3DSurf]+1;
3657 int nbOfEdges=nodalI[cellId3DSurf+1]-offset;
3658 for(int j=0;j<nbOfEdges;j++)
3660 conn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG2); conn->pushBackSilent(nodal[offset+j]); conn->pushBackSilent(nodal[offset+(j+1)%nbOfEdges]);
3661 connI->pushBackSilent(conn->getNumberOfTuples());
3662 cellIds2->pushBackSilent(cellId3DSurf);
3667 if(cellIds2->empty())
3668 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3DSurf cells in this intercepts the specified plane !");
3669 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3DSurf",1);
3670 ret->setCoords(mDesc1->getCoords());
3671 ret->setConnectivity(conn,connI,true);
3672 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3676 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::clipSingle3DCellByPlane(const double origin[3], const double vec[3], double eps) const
3678 checkFullyDefined();
3679 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3680 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3681 if(getNumberOfCells()!=1)
3682 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works only on mesh containing exactly one cell !");
3684 std::vector<int> nodes;
3685 findNodesOnPlane(origin,vec,eps,nodes);
3686 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());
3687 MCAuto<MEDCouplingUMesh> mDesc2(buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2));//meshDim==2 spaceDim==3
3688 revDesc2=0; revDescIndx2=0;
3689 MCAuto<MEDCouplingUMesh> mDesc1(mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3690 revDesc1=0; revDescIndx1=0;
3691 DataArrayInt *cellIds1D(0);
3692 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3693 MCAuto<DataArrayInt> cellIds1DTmp(cellIds1D);
3694 std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3695 for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3699 int oldNbNodes(mDesc1->getNumberOfNodes());
3700 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3701 sameNbNodes=(mDesc1->getNumberOfNodes()==oldNbNodes);
3703 std::vector< std::pair<int,int> > cut3DSurf(mDesc2->getNumberOfCells());
3704 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->begin(),mDesc2->getNodalConnectivityIndex()->begin(),
3705 mDesc1->getNodalConnectivity()->begin(),mDesc1->getNodalConnectivityIndex()->begin(),
3706 desc1->begin(),descIndx1->begin(),cut3DSurf);
3707 MCAuto<DataArrayInt> conn(DataArrayInt::New()),connI(DataArrayInt::New());
3708 connI->pushBackSilent(0); conn->alloc(0,1);
3710 MCAuto<DataArrayInt> cellIds2(DataArrayInt::New()); cellIds2->alloc(0,1);
3711 assemblyForSplitFrom3DSurf(cut3DSurf,desc2->begin(),descIndx2->begin(),conn,connI,cellIds2);
3712 if(cellIds2->empty())
3713 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3715 std::vector<std::vector<int> > res;
3716 buildSubCellsFromCut(cut3DSurf,desc2->begin(),descIndx2->begin(),mDesc1->getCoords()->begin(),eps,res);
3717 std::size_t sz(res.size());
3718 if(res.size()==mDesc1->getNumberOfCells() && sameNbNodes)
3719 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane : cell is not clipped !");
3720 for(std::size_t i=0;i<sz;i++)
3722 conn->pushBackSilent((int)INTERP_KERNEL::NORM_POLYGON);
3723 conn->insertAtTheEnd(res[i].begin(),res[i].end());
3724 connI->pushBackSilent(conn->getNumberOfTuples());
3726 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
3727 ret->setCoords(mDesc1->getCoords());
3728 ret->setConnectivity(conn,connI,true);
3729 int nbCellsRet(ret->getNumberOfCells());
3731 MCAuto<DataArrayDouble> vec2(DataArrayDouble::New()); vec2->alloc(1,3); std::copy(vec,vec+3,vec2->getPointer());
3732 MCAuto<MEDCouplingFieldDouble> ortho(ret->buildOrthogonalField());
3733 MCAuto<DataArrayDouble> ortho2(ortho->getArray()->selectByTupleIdSafeSlice(0,1,1));
3734 MCAuto<DataArrayDouble> dott(DataArrayDouble::Dot(ortho2,vec2));
3735 MCAuto<DataArrayDouble> ccm(ret->computeCellCenterOfMass());
3736 MCAuto<DataArrayDouble> occm;
3738 MCAuto<DataArrayDouble> pt(DataArrayDouble::New()); pt->alloc(1,3); std::copy(origin,origin+3,pt->getPointer());
3739 occm=DataArrayDouble::Substract(ccm,pt);
3741 vec2=DataArrayDouble::New(); vec2->alloc(nbCellsRet,3);
3742 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);
3743 MCAuto<DataArrayDouble> dott2(DataArrayDouble::Dot(occm,vec2));
3745 const int *cPtr(ret->getNodalConnectivity()->begin()),*ciPtr(ret->getNodalConnectivityIndex()->begin());
3746 MCAuto<MEDCouplingUMesh> ret2(MEDCouplingUMesh::New("Clip3D",3));
3747 ret2->setCoords(mDesc1->getCoords());
3748 MCAuto<DataArrayInt> conn2(DataArrayInt::New()),conn2I(DataArrayInt::New());
3749 conn2I->pushBackSilent(0); conn2->alloc(0,1);
3750 std::vector<int> cell0(1,(int)INTERP_KERNEL::NORM_POLYHED);
3751 std::vector<int> cell1(1,(int)INTERP_KERNEL::NORM_POLYHED);
3752 if(dott->getIJ(0,0)>0)
3754 cell0.insert(cell0.end(),cPtr+1,cPtr+ciPtr[1]);
3755 std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell1,cell1.end()));
3759 cell1.insert(cell1.end(),cPtr+1,cPtr+ciPtr[1]);
3760 std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell0,cell0.end()));
3762 for(int i=1;i<nbCellsRet;i++)
3764 if(dott2->getIJ(i,0)<0)
3766 if(ciPtr[i+1]-ciPtr[i]>=4)
3768 cell0.push_back(-1);
3769 cell0.insert(cell0.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
3774 if(ciPtr[i+1]-ciPtr[i]>=4)
3776 cell1.push_back(-1);
3777 cell1.insert(cell1.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
3781 conn2->insertAtTheEnd(cell0.begin(),cell0.end());
3782 conn2I->pushBackSilent(conn2->getNumberOfTuples());
3783 conn2->insertAtTheEnd(cell1.begin(),cell1.end());
3784 conn2I->pushBackSilent(conn2->getNumberOfTuples());
3785 ret2->setConnectivity(conn2,conn2I,true);
3786 ret2->checkConsistencyLight();
3787 ret2->orientCorrectlyPolyhedrons();
3792 * Finds cells whose bounding boxes intersect a given plane.
3793 * \param [in] origin - 3 components of a point defining location of the plane.
3794 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3795 * must be greater than 1e-6.
3796 * \param [in] eps - half-thickness of the plane.
3797 * \return DataArrayInt * - a new instance of DataArrayInt holding ids of the found
3798 * cells. The caller is to delete this array using decrRef() as it is no more
3800 * \throw If the coordinates array is not set.
3801 * \throw If the nodal connectivity of cells is not defined.
3802 * \throw If \a this->getSpaceDimension() != 3.
3803 * \throw If magnitude of \a vec is less than 1e-6.
3804 * \sa buildSlice3D()
3806 DataArrayInt *MEDCouplingUMesh::getCellIdsCrossingPlane(const double *origin, const double *vec, double eps) const
3808 checkFullyDefined();
3809 if(getSpaceDimension()!=3)
3810 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with spaceDim equal to 3 !");
3811 double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
3813 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellIdsCrossingPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
3815 vec2[0]=vec[1]; vec2[1]=-vec[0]; vec2[2]=0.;//vec2 is the result of cross product of vec with (0,0,1)
3816 double angle=acos(vec[2]/normm);
3817 MCAuto<DataArrayInt> cellIds;
3821 MCAuto<DataArrayDouble> coo=_coords->deepCopy();
3822 double normm2(sqrt(vec2[0]*vec2[0]+vec2[1]*vec2[1]+vec2[2]*vec2[2]));
3823 if(normm2/normm>1e-6)
3824 DataArrayDouble::Rotate3DAlg(origin,vec2,angle,coo->getNumberOfTuples(),coo->getPointer(),coo->getPointer());
3825 MCAuto<MEDCouplingUMesh> mw=clone(false);//false -> shallow copy
3827 mw->getBoundingBox(bbox);
3828 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3829 cellIds=mw->getCellsInBoundingBox(bbox,eps);
3833 getBoundingBox(bbox);
3834 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3835 cellIds=getCellsInBoundingBox(bbox,eps);
3837 return cellIds.retn();
3841 * This method checks that \a this is a contiguous mesh. The user is expected to call this method on a mesh with meshdim==1.
3842 * If not an exception will thrown. If this is an empty mesh with no cell an exception will be thrown too.
3843 * No consideration of coordinate is done by this method.
3844 * 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)
3845 * If not false is returned. In case that false is returned a call to MEDCoupling::MEDCouplingUMesh::mergeNodes could be usefull.
3847 bool MEDCouplingUMesh::isContiguous1D() const
3849 if(getMeshDimension()!=1)
3850 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense only for 1D mesh !");
3851 int nbCells=getNumberOfCells();
3853 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense for non empty mesh !");
3854 const int *connI(_nodal_connec_index->begin()),*conn(_nodal_connec->begin());
3855 int ref=conn[connI[0]+2];
3856 for(int i=1;i<nbCells;i++)
3858 if(conn[connI[i]+1]!=ref)
3860 ref=conn[connI[i]+2];
3866 * This method is only callable on mesh with meshdim == 1 containing only SEG2 and spaceDim==3.
3867 * This method projects this on the 3D line defined by (pt,v). This methods first checks that all SEG2 are along v vector.
3868 * \param pt reference point of the line
3869 * \param v normalized director vector of the line
3870 * \param eps max precision before throwing an exception
3871 * \param res output of size this->getNumberOfCells
3873 void MEDCouplingUMesh::project1D(const double *pt, const double *v, double eps, double *res) const
3875 if(getMeshDimension()!=1)
3876 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for project1D !");
3877 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3878 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for project1D !");
3879 if(getSpaceDimension()!=3)
3880 throw INTERP_KERNEL::Exception("Expected a umesh with spaceDim==3 for project1D !");
3881 MCAuto<MEDCouplingFieldDouble> f=buildDirectionVectorField();
3882 const double *fPtr=f->getArray()->getConstPointer();
3884 for(int i=0;i<getNumberOfCells();i++)
3886 const double *tmp1=fPtr+3*i;
3887 tmp[0]=tmp1[1]*v[2]-tmp1[2]*v[1];
3888 tmp[1]=tmp1[2]*v[0]-tmp1[0]*v[2];
3889 tmp[2]=tmp1[0]*v[1]-tmp1[1]*v[0];
3890 double n1=INTERP_KERNEL::norm<3>(tmp);
3891 n1/=INTERP_KERNEL::norm<3>(tmp1);
3893 throw INTERP_KERNEL::Exception("UMesh::Projection 1D failed !");
3895 const double *coo=getCoords()->getConstPointer();
3896 for(int i=0;i<getNumberOfNodes();i++)
3898 std::transform(coo+i*3,coo+i*3+3,pt,tmp,std::minus<double>());
3899 std::transform(tmp,tmp+3,v,tmp,std::multiplies<double>());
3900 res[i]=std::accumulate(tmp,tmp+3,0.);
3905 * 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.
3906 * \a this is expected to be a mesh so that its space dimension is equal to its
3907 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
3908 * 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).
3910 * 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
3911 * 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).
3912 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
3914 * So this method is more accurate (so, more costly) than simply searching for the closest point in \a this.
3915 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
3917 * \param [in] ptBg the start pointer (included) of the coordinates of the point
3918 * \param [in] ptEnd the end pointer (not included) of the coordinates of the point
3919 * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
3920 * \return the positive value of the distance.
3921 * \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
3923 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoints
3925 double MEDCouplingUMesh::distanceToPoint(const double *ptBg, const double *ptEnd, int& cellId) const
3927 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
3928 if(meshDim!=spaceDim-1)
3929 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint works only for spaceDim=meshDim+1 !");
3930 if(meshDim!=2 && meshDim!=1)
3931 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint : only mesh dimension 2 and 1 are implemented !");
3932 checkFullyDefined();
3933 if((int)std::distance(ptBg,ptEnd)!=spaceDim)
3934 { 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()); }
3935 DataArrayInt *ret1=0;
3936 MCAuto<DataArrayDouble> pts=DataArrayDouble::New(); pts->useArray(ptBg,false,C_DEALLOC,1,spaceDim);
3937 MCAuto<DataArrayDouble> ret0=distanceToPoints(pts,ret1);
3938 MCAuto<DataArrayInt> ret1Safe(ret1);
3939 cellId=*ret1Safe->begin();
3940 return *ret0->begin();
3944 * This method computes the distance from each point of points serie \a pts (stored in a DataArrayDouble in which each tuple represents a point)
3945 * to \a this and the first \a cellId in \a this corresponding to the returned distance.
3946 * 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
3947 * 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).
3948 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
3950 * \a this is expected to be a mesh so that its space dimension is equal to its
3951 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
3952 * 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).
3954 * So this method is more accurate (so, more costly) than simply searching for each point in \a pts the closest point in \a this.
3955 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
3957 * \param [in] pts the list of points in which each tuple represents a point
3958 * \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.
3959 * \return a newly allocated object to be dealed by the caller that tells for each point in \a pts the distance to \a this.
3960 * \throw if number of components of \a pts is not equal to the space dimension.
3961 * \throw if mesh dimension of \a this is not equal to space dimension - 1.
3962 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoint
3964 DataArrayDouble *MEDCouplingUMesh::distanceToPoints(const DataArrayDouble *pts, DataArrayInt *& cellIds) const
3967 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : input points pointer is NULL !");
3968 pts->checkAllocated();
3969 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
3970 if(meshDim!=spaceDim-1)
3971 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints works only for spaceDim=meshDim+1 !");
3972 if(meshDim!=2 && meshDim!=1)
3973 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only mesh dimension 2 and 1 are implemented !");
3974 if(pts->getNumberOfComponents()!=spaceDim)
3976 std::ostringstream oss; oss << "MEDCouplingUMesh::distanceToPoints : input pts DataArrayDouble has " << pts->getNumberOfComponents() << " components whereas it should be equal to " << spaceDim << " (mesh spaceDimension) !";
3977 throw INTERP_KERNEL::Exception(oss.str());
3979 checkFullyDefined();
3980 int nbCells=getNumberOfCells();
3982 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : no cells in this !");
3983 int nbOfPts=pts->getNumberOfTuples();
3984 MCAuto<DataArrayDouble> ret0=DataArrayDouble::New(); ret0->alloc(nbOfPts,1);
3985 MCAuto<DataArrayInt> ret1=DataArrayInt::New(); ret1->alloc(nbOfPts,1);
3986 const int *nc=_nodal_connec->begin(),*ncI=_nodal_connec_index->begin(); const double *coords=_coords->begin();
3987 double *ret0Ptr=ret0->getPointer(); int *ret1Ptr=ret1->getPointer(); const double *ptsPtr=pts->begin();
3988 MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree());
3989 const double *bbox(bboxArr->begin());
3994 BBTreeDst<3> myTree(bbox,0,0,nbCells);
3995 for(int i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=3)
3997 double x=std::numeric_limits<double>::max();
3998 std::vector<int> elems;
3999 myTree.getMinDistanceOfMax(ptsPtr,x);
4000 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4001 DistanceToPoint3DSurfAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4007 BBTreeDst<2> myTree(bbox,0,0,nbCells);
4008 for(int i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=2)
4010 double x=std::numeric_limits<double>::max();
4011 std::vector<int> elems;
4012 myTree.getMinDistanceOfMax(ptsPtr,x);
4013 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4014 DistanceToPoint2DCurveAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4019 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only spacedim 2 and 3 supported !");
4021 cellIds=ret1.retn();
4030 * Finds cells in contact with a ball (i.e. a point with precision).
4031 * 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.
4032 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4034 * \warning This method is suitable if the caller intends to evaluate only one
4035 * point, for more points getCellsContainingPoints() is recommended as it is
4037 * \param [in] pos - array of coordinates of the ball central point.
4038 * \param [in] eps - ball radius.
4039 * \return int - a smallest id of cells being in contact with the ball, -1 in case
4040 * if there are no such cells.
4041 * \throw If the coordinates array is not set.
4042 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4044 int MEDCouplingUMesh::getCellContainingPoint(const double *pos, double eps) const
4046 std::vector<int> elts;
4047 getCellsContainingPoint(pos,eps,elts);
4050 return elts.front();
4054 * Finds cells in contact with a ball (i.e. a point with precision).
4055 * 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.
4056 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4057 * \warning This method is suitable if the caller intends to evaluate only one
4058 * point, for more points getCellsContainingPoints() is recommended as it is
4060 * \param [in] pos - array of coordinates of the ball central point.
4061 * \param [in] eps - ball radius.
4062 * \param [out] elts - vector returning ids of the found cells. It is cleared
4063 * before inserting ids.
4064 * \throw If the coordinates array is not set.
4065 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4067 * \if ENABLE_EXAMPLES
4068 * \ref cpp_mcumesh_getCellsContainingPoint "Here is a C++ example".<br>
4069 * \ref py_mcumesh_getCellsContainingPoint "Here is a Python example".
4072 void MEDCouplingUMesh::getCellsContainingPoint(const double *pos, double eps, std::vector<int>& elts) const
4074 MCAuto<DataArrayInt> eltsUg,eltsIndexUg;
4075 getCellsContainingPoints(pos,1,eps,eltsUg,eltsIndexUg);
4076 elts.clear(); elts.insert(elts.end(),eltsUg->begin(),eltsUg->end());
4080 * Finds cells in contact with several balls (i.e. points with precision).
4081 * This method is an extension of getCellContainingPoint() and
4082 * getCellsContainingPoint() for the case of multiple points.
4083 * 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.
4084 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4085 * \param [in] pos - an array of coordinates of points in full interlace mode :
4086 * X0,Y0,Z0,X1,Y1,Z1,... Size of the array must be \a
4087 * this->getSpaceDimension() * \a nbOfPoints
4088 * \param [in] nbOfPoints - number of points to locate within \a this mesh.
4089 * \param [in] eps - radius of balls (i.e. the precision).
4090 * \param [out] elts - vector returning ids of found cells.
4091 * \param [out] eltsIndex - an array, of length \a nbOfPoints + 1,
4092 * dividing cell ids in \a elts into groups each referring to one
4093 * point. Its every element (except the last one) is an index pointing to the
4094 * first id of a group of cells. For example cells in contact with the *i*-th
4095 * point are described by following range of indices:
4096 * [ \a eltsIndex[ *i* ], \a eltsIndex[ *i*+1 ] ) and the cell ids are
4097 * \a elts[ \a eltsIndex[ *i* ]], \a elts[ \a eltsIndex[ *i* ] + 1 ], ...
4098 * Number of cells in contact with the *i*-th point is
4099 * \a eltsIndex[ *i*+1 ] - \a eltsIndex[ *i* ].
4100 * \throw If the coordinates array is not set.
4101 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4103 * \if ENABLE_EXAMPLES
4104 * \ref cpp_mcumesh_getCellsContainingPoints "Here is a C++ example".<br>
4105 * \ref py_mcumesh_getCellsContainingPoints "Here is a Python example".
4108 void MEDCouplingUMesh::getCellsContainingPoints(const double *pos, int nbOfPoints, double eps,
4109 MCAuto<DataArrayInt>& elts, MCAuto<DataArrayInt>& eltsIndex) const
4111 int spaceDim=getSpaceDimension();
4112 int mDim=getMeshDimension();
4117 const double *coords=_coords->getConstPointer();
4118 getCellsContainingPointsAlg<3>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4125 throw INTERP_KERNEL::Exception("For spaceDim==3 only meshDim==3 implemented for getelementscontainingpoints !");
4127 else if(spaceDim==2)
4131 const double *coords=_coords->getConstPointer();
4132 getCellsContainingPointsAlg<2>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4135 throw INTERP_KERNEL::Exception("For spaceDim==2 only meshDim==2 implemented for getelementscontainingpoints !");
4137 else if(spaceDim==1)
4141 const double *coords=_coords->getConstPointer();
4142 getCellsContainingPointsAlg<1>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4145 throw INTERP_KERNEL::Exception("For spaceDim==1 only meshDim==1 implemented for getelementscontainingpoints !");
4148 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPoints : not managed for mdim not in [1,2,3] !");
4152 * Finds butterfly cells in \a this mesh. A 2D cell is considered to be butterfly if at
4153 * least two its edges intersect each other anywhere except their extremities. An
4154 * INTERP_KERNEL::NORM_NORI3 cell can \b not be butterfly.
4155 * \param [in,out] cells - a vector returning ids of the found cells. It is not
4156 * cleared before filling in.
4157 * \param [in] eps - precision.
4158 * \throw If \a this->getMeshDimension() != 2.
4159 * \throw If \a this->getSpaceDimension() != 2 && \a this->getSpaceDimension() != 3.
4161 void MEDCouplingUMesh::checkButterflyCells(std::vector<int>& cells, double eps) const
4163 const char msg[]="Butterfly detection work only for 2D cells with spaceDim==2 or 3!";
4164 if(getMeshDimension()!=2)
4165 throw INTERP_KERNEL::Exception(msg);
4166 int spaceDim=getSpaceDimension();
4167 if(spaceDim!=2 && spaceDim!=3)
4168 throw INTERP_KERNEL::Exception(msg);
4169 const int *conn=_nodal_connec->getConstPointer();
4170 const int *connI=_nodal_connec_index->getConstPointer();
4171 int nbOfCells=getNumberOfCells();
4172 std::vector<double> cell2DinS2;
4173 for(int i=0;i<nbOfCells;i++)
4175 int offset=connI[i];
4176 int nbOfNodesForCell=connI[i+1]-offset-1;
4177 if(nbOfNodesForCell<=3)
4179 bool isQuad=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[offset]).isQuadratic();
4180 project2DCellOnXY(conn+offset+1,conn+connI[i+1],cell2DinS2);
4181 if(isButterfly2DCell(cell2DinS2,isQuad,eps))
4188 * This method is typically requested to unbutterfly 2D linear cells in \b this.
4190 * 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.
4191 * 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.
4193 * For each 2D linear cell in \b this, this method builds the convex envelop (or the convex hull) of the current cell.
4194 * This convex envelop is computed using Jarvis march algorithm.
4195 * The coordinates and the number of cells of \b this remain unchanged on invocation of this method.
4196 * 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)
4197 * 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.
4199 * \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.
4200 * \sa MEDCouplingUMesh::colinearize2D
4202 DataArrayInt *MEDCouplingUMesh::convexEnvelop2D()
4204 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
4205 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convexEnvelop2D works only for meshDim=2 and spaceDim=2 !");
4206 checkFullyDefined();
4207 const double *coords=getCoords()->getConstPointer();
4208 int nbOfCells=getNumberOfCells();
4209 MCAuto<DataArrayInt> nodalConnecIndexOut=DataArrayInt::New();
4210 nodalConnecIndexOut->alloc(nbOfCells+1,1);
4211 MCAuto<DataArrayInt> nodalConnecOut(DataArrayInt::New());
4212 int *workIndexOut=nodalConnecIndexOut->getPointer();
4214 const int *nodalConnecIn=_nodal_connec->getConstPointer();
4215 const int *nodalConnecIndexIn=_nodal_connec_index->getConstPointer();
4216 std::set<INTERP_KERNEL::NormalizedCellType> types;
4217 MCAuto<DataArrayInt> isChanged(DataArrayInt::New());
4218 isChanged->alloc(0,1);
4219 for(int i=0;i<nbOfCells;i++,workIndexOut++)
4221 int pos=nodalConnecOut->getNumberOfTuples();
4222 if(BuildConvexEnvelopOf2DCellJarvis(coords,nodalConnecIn+nodalConnecIndexIn[i],nodalConnecIn+nodalConnecIndexIn[i+1],nodalConnecOut))
4223 isChanged->pushBackSilent(i);
4224 types.insert((INTERP_KERNEL::NormalizedCellType)nodalConnecOut->getIJ(pos,0));
4225 workIndexOut[1]=nodalConnecOut->getNumberOfTuples();
4227 if(isChanged->empty())
4229 setConnectivity(nodalConnecOut,nodalConnecIndexOut,false);
4231 return isChanged.retn();
4235 * This method is \b NOT const because it can modify \a this.
4236 * \a this is expected to be an unstructured mesh with meshDim==2 and spaceDim==3. If not an exception will be thrown.
4237 * \param mesh1D is an unstructured mesh with MeshDim==1 and spaceDim==3. If not an exception will be thrown.
4238 * \param policy specifies the type of extrusion chosen:
4239 * - \b 0 for translation only (most simple): the cells of the 1D mesh represent the vectors along which the 2D mesh
4240 * will be repeated to build each level
4241 * - \b 1 for translation and rotation: the translation is done as above. For each level, an arc of circle is fitted on
4242 * 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
4243 * 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
4245 * \return an unstructured mesh with meshDim==3 and spaceDim==3. The returned mesh has the same coords than \a this.
4247 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMesh(const MEDCouplingUMesh *mesh1D, int policy)
4249 checkFullyDefined();
4250 mesh1D->checkFullyDefined();
4251 if(!mesh1D->isContiguous1D())
4252 throw INTERP_KERNEL::Exception("buildExtrudedMesh : 1D mesh passed in parameter is not contiguous !");
4253 if(getSpaceDimension()!=mesh1D->getSpaceDimension())
4254 throw INTERP_KERNEL::Exception("Invalid call to buildExtrudedMesh this and mesh1D must have same space dimension !");
4255 if((getMeshDimension()!=2 || getSpaceDimension()!=3) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
4256 throw INTERP_KERNEL::Exception("Invalid 'this' for buildExtrudedMesh method : must be (meshDim==2 and spaceDim==3) or (meshDim==1 and spaceDim==2) !");
4257 if(mesh1D->getMeshDimension()!=1)
4258 throw INTERP_KERNEL::Exception("Invalid 'mesh1D' for buildExtrudedMesh method : must be meshDim==1 !");
4260 if(isPresenceOfQuadratic())
4262 if(mesh1D->isFullyQuadratic())
4265 throw INTERP_KERNEL::Exception("Invalid 2D mesh and 1D mesh because 2D mesh has quadratic cells and 1D is not fully quadratic !");
4267 int oldNbOfNodes(getNumberOfNodes());
4268 MCAuto<DataArrayDouble> newCoords;
4273 newCoords=fillExtCoordsUsingTranslation(mesh1D,isQuad);
4278 newCoords=fillExtCoordsUsingTranslAndAutoRotation(mesh1D,isQuad);
4282 throw INTERP_KERNEL::Exception("Not implemented extrusion policy : must be in (0) !");
4284 setCoords(newCoords);
4285 MCAuto<MEDCouplingUMesh> ret(buildExtrudedMeshFromThisLowLev(oldNbOfNodes,isQuad));
4292 * Checks if \a this mesh is constituted by only quadratic cells.
4293 * \return bool - \c true if there are only quadratic cells in \a this mesh.
4294 * \throw If the coordinates array is not set.
4295 * \throw If the nodal connectivity of cells is not defined.
4297 bool MEDCouplingUMesh::isFullyQuadratic() const
4299 checkFullyDefined();
4301 int nbOfCells=getNumberOfCells();
4302 for(int i=0;i<nbOfCells && ret;i++)
4304 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4305 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4306 ret=cm.isQuadratic();
4312 * Checks if \a this mesh includes any quadratic cell.
4313 * \return bool - \c true if there is at least one quadratic cells in \a this mesh.
4314 * \throw If the coordinates array is not set.
4315 * \throw If the nodal connectivity of cells is not defined.
4317 bool MEDCouplingUMesh::isPresenceOfQuadratic() const
4319 checkFullyDefined();
4321 int nbOfCells=getNumberOfCells();
4322 for(int i=0;i<nbOfCells && !ret;i++)
4324 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4325 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4326 ret=cm.isQuadratic();
4332 * Converts all quadratic cells to linear ones. If there are no quadratic cells in \a
4333 * this mesh, it remains unchanged.
4334 * \throw If the coordinates array is not set.
4335 * \throw If the nodal connectivity of cells is not defined.
4337 void MEDCouplingUMesh::convertQuadraticCellsToLinear()
4339 checkFullyDefined();
4340 int nbOfCells(getNumberOfCells());
4342 const int *iciptr=_nodal_connec_index->begin();
4343 for(int i=0;i<nbOfCells;i++)
4345 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4346 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4347 if(cm.isQuadratic())
4349 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4350 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4351 if(!cml.isDynamic())
4352 delta+=cm.getNumberOfNodes()-cml.getNumberOfNodes();
4354 delta+=(iciptr[i+1]-iciptr[i]-1)/2;
4359 MCAuto<DataArrayInt> newConn(DataArrayInt::New()),newConnI(DataArrayInt::New());
4360 const int *icptr(_nodal_connec->begin());
4361 newConn->alloc(getNodalConnectivityArrayLen()-delta,1);
4362 newConnI->alloc(nbOfCells+1,1);
4363 int *ocptr(newConn->getPointer()),*ociptr(newConnI->getPointer());
4366 for(int i=0;i<nbOfCells;i++,ociptr++)
4368 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)icptr[iciptr[i]];
4369 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4370 if(!cm.isQuadratic())
4372 _types.insert(type);
4373 ocptr=std::copy(icptr+iciptr[i],icptr+iciptr[i+1],ocptr);
4374 ociptr[1]=ociptr[0]+iciptr[i+1]-iciptr[i];
4378 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4379 _types.insert(typel);
4380 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4381 int newNbOfNodes=cml.getNumberOfNodes();
4383 newNbOfNodes=(iciptr[i+1]-iciptr[i]-1)/2;
4384 *ocptr++=(int)typel;
4385 ocptr=std::copy(icptr+iciptr[i]+1,icptr+iciptr[i]+newNbOfNodes+1,ocptr);
4386 ociptr[1]=ociptr[0]+newNbOfNodes+1;
4389 setConnectivity(newConn,newConnI,false);
4393 * This method converts all linear cell in \a this to quadratic one.
4394 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, here it is needed to specify the target
4395 * 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)
4396 * 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.
4397 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, the coordinates in \a this can be become bigger. All created nodes will be put at the
4398 * end of the existing coordinates.
4400 * \param [in] conversionType specifies the type of conversion expected. Only 0 (default) and 1 are supported presently. 0 those that creates the 'most' simple
4401 * corresponding quadratic cells. 1 is those creating the 'most' complex.
4402 * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
4404 * \throw if \a this is not fully defined. It throws too if \a conversionType is not in [0,1].
4406 * \sa MEDCouplingUMesh::convertQuadraticCellsToLinear
4408 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic(int conversionType)
4410 DataArrayInt *conn=0,*connI=0;
4411 DataArrayDouble *coords=0;
4412 std::set<INTERP_KERNEL::NormalizedCellType> types;
4413 checkFullyDefined();
4414 MCAuto<DataArrayInt> ret,connSafe,connISafe;
4415 MCAuto<DataArrayDouble> coordsSafe;
4416 int meshDim=getMeshDimension();
4417 switch(conversionType)
4423 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);
4424 connSafe=conn; connISafe=connI; coordsSafe=coords;
4427 ret=convertLinearCellsToQuadratic2D0(conn,connI,coords,types);
4428 connSafe=conn; connISafe=connI; coordsSafe=coords;
4431 ret=convertLinearCellsToQuadratic3D0(conn,connI,coords,types);
4432 connSafe=conn; connISafe=connI; coordsSafe=coords;
4435 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 0 mesh dimensions available are [1,2,3] !");
4443 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);//it is not a bug. In 1D policy 0 and 1 are equals
4444 connSafe=conn; connISafe=connI; coordsSafe=coords;
4447 ret=convertLinearCellsToQuadratic2D1(conn,connI,coords,types);
4448 connSafe=conn; connISafe=connI; coordsSafe=coords;
4451 ret=convertLinearCellsToQuadratic3D1(conn,connI,coords,types);
4452 connSafe=conn; connISafe=connI; coordsSafe=coords;
4455 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 1 mesh dimensions available are [1,2,3] !");
4460 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion type available are 0 (default, the simplest) and 1 (the most complex) !");
4462 setConnectivity(connSafe,connISafe,false);
4464 setCoords(coordsSafe);
4469 * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
4470 * so that the number of cells remains the same. Quadratic faces are converted to
4471 * polygons. This method works only for 2D meshes in
4472 * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
4473 * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
4474 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
4475 * \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
4476 * a polylinized edge constituting the input polygon.
4477 * \throw If the coordinates array is not set.
4478 * \throw If the nodal connectivity of cells is not defined.
4479 * \throw If \a this->getMeshDimension() != 2.
4480 * \throw If \a this->getSpaceDimension() != 2.
4482 void MEDCouplingUMesh::tessellate2D(double eps)
4484 int meshDim(getMeshDimension()),spaceDim(getSpaceDimension());
4486 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : works only with space dimension equal to 2 !");
4490 return tessellate2DCurveInternal(eps);
4492 return tessellate2DInternal(eps);
4494 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : mesh dimension must be in [1,2] !");
4498 * Tessellates \a this 1D mesh in 2D space by dividing not straight quadratic edges.
4499 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
4500 * \param [in] eps - specifies the maximal angle (in radian) between 2 sub-edges of
4501 * a sub-divided edge.
4502 * \throw If the coordinates array is not set.
4503 * \throw If the nodal connectivity of cells is not defined.
4504 * \throw If \a this->getMeshDimension() != 1.
4505 * \throw If \a this->getSpaceDimension() != 2.
4510 * This method only works if \a this has spaceDimension equal to 2 and meshDimension also equal to 2.
4511 * This method allows to modify connectivity of cells in \a this that shares some edges in \a edgeIdsToBeSplit.
4512 * The nodes to be added in those 2D cells are defined by the pair of \a nodeIdsToAdd and \a nodeIdsIndexToAdd.
4513 * Length of \a nodeIdsIndexToAdd is expected to equal to length of \a edgeIdsToBeSplit + 1.
4514 * The node ids in \a nodeIdsToAdd should be valid. Those nodes have to be sorted exactly following exactly the direction of the edge.
4515 * This method can be seen as the opposite method of colinearize2D.
4516 * 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
4517 * to avoid to modify the numbering of existing nodes.
4519 * \param [in] nodeIdsToAdd - the list of node ids to be added (\a nodeIdsIndexToAdd array allows to walk on this array)
4520 * \param [in] nodeIdsIndexToAdd - the entry point of \a nodeIdsToAdd to point to the corresponding nodes to be added.
4521 * \param [in] mesh1Desc - 1st output of buildDescendingConnectivity2 on \a this.
4522 * \param [in] desc - 2nd output of buildDescendingConnectivity2 on \a this.
4523 * \param [in] descI - 3rd output of buildDescendingConnectivity2 on \a this.
4524 * \param [in] revDesc - 4th output of buildDescendingConnectivity2 on \a this.
4525 * \param [in] revDescI - 5th output of buildDescendingConnectivity2 on \a this.
4527 * \sa buildDescendingConnectivity2
4529 void MEDCouplingUMesh::splitSomeEdgesOf2DMesh(const DataArrayInt *nodeIdsToAdd, const DataArrayInt *nodeIdsIndexToAdd, const DataArrayInt *edgeIdsToBeSplit,
4530 const MEDCouplingUMesh *mesh1Desc, const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *revDesc, const DataArrayInt *revDescI)
4532 if(!nodeIdsToAdd || !nodeIdsIndexToAdd || !edgeIdsToBeSplit || !mesh1Desc || !desc || !descI || !revDesc || !revDescI)
4533 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : input pointers must be not NULL !");
4534 nodeIdsToAdd->checkAllocated(); nodeIdsIndexToAdd->checkAllocated(); edgeIdsToBeSplit->checkAllocated(); desc->checkAllocated(); descI->checkAllocated(); revDesc->checkAllocated(); revDescI->checkAllocated();
4535 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
4536 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : this must have spacedim=meshdim=2 !");
4537 if(mesh1Desc->getSpaceDimension()!=2 || mesh1Desc->getMeshDimension()!=1)
4538 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : mesh1Desc must be the explosion of this with spaceDim=2 and meshDim = 1 !");
4539 //DataArrayInt *out0(0),*outi0(0);
4540 //MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
4541 //MCAuto<DataArrayInt> out0s(out0),outi0s(outi0);
4542 //out0s=out0s->buildUnique(); out0s->sort(true);
4548 * Divides every cell of \a this mesh into simplices (triangles in 2D and tetrahedra in 3D).
4549 * In addition, returns an array mapping new cells to old ones. <br>
4550 * This method typically increases the number of cells in \a this mesh
4551 * but the number of nodes remains \b unchanged.
4552 * That's why the 3D splitting policies
4553 * INTERP_KERNEL::GENERAL_24 and INTERP_KERNEL::GENERAL_48 are not available here.
4554 * \param [in] policy - specifies a pattern used for splitting.
4555 * The semantic of \a policy is:
4556 * - 0 - to split QUAD4 by cutting it along 0-2 diagonal (for 2D mesh only).
4557 * - 1 - to split QUAD4 by cutting it along 1-3 diagonal (for 2D mesh only).
4558 * - INTERP_KERNEL::PLANAR_FACE_5 - to split HEXA8 into 5 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4559 * - INTERP_KERNEL::PLANAR_FACE_6 - to split HEXA8 into 6 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4562 * \return DataArrayInt * - a new instance of DataArrayInt holding, for each new cell,
4563 * an id of old cell producing it. The caller is to delete this array using
4564 * decrRef() as it is no more needed.
4566 * \throw If \a policy is 0 or 1 and \a this->getMeshDimension() != 2.
4567 * \throw If \a policy is INTERP_KERNEL::PLANAR_FACE_5 or INTERP_KERNEL::PLANAR_FACE_6
4568 * and \a this->getMeshDimension() != 3.
4569 * \throw If \a policy is not one of the four discussed above.
4570 * \throw If the nodal connectivity of cells is not defined.
4571 * \sa MEDCouplingUMesh::tetrahedrize, MEDCoupling1SGTUMesh::sortHexa8EachOther
4573 DataArrayInt *MEDCouplingUMesh::simplexize(int policy)
4578 return simplexizePol0();
4580 return simplexizePol1();
4581 case (int) INTERP_KERNEL::PLANAR_FACE_5:
4582 return simplexizePlanarFace5();
4583 case (int) INTERP_KERNEL::PLANAR_FACE_6:
4584 return simplexizePlanarFace6();
4586 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)");
4591 * Checks if \a this mesh is constituted by simplex cells only. Simplex cells are:
4592 * - 1D: INTERP_KERNEL::NORM_SEG2
4593 * - 2D: INTERP_KERNEL::NORM_TRI3
4594 * - 3D: INTERP_KERNEL::NORM_TETRA4.
4596 * This method is useful for users that need to use P1 field services as
4597 * MEDCouplingFieldDouble::getValueOn(), MEDCouplingField::buildMeasureField() etc.
4598 * All these methods need mesh support containing only simplex cells.
4599 * \return bool - \c true if there are only simplex cells in \a this mesh.
4600 * \throw If the coordinates array is not set.
4601 * \throw If the nodal connectivity of cells is not defined.
4602 * \throw If \a this->getMeshDimension() < 1.
4604 bool MEDCouplingUMesh::areOnlySimplexCells() const
4606 checkFullyDefined();
4607 int mdim=getMeshDimension();
4608 if(mdim<1 || mdim>3)
4609 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::areOnlySimplexCells : only available with meshes having a meshdim 1, 2 or 3 !");
4610 int nbCells=getNumberOfCells();
4611 const int *conn=_nodal_connec->begin();
4612 const int *connI=_nodal_connec_index->begin();
4613 for(int i=0;i<nbCells;i++)
4615 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4625 * Converts degenerated 2D or 3D linear cells of \a this mesh into cells of simpler
4626 * type. For example an INTERP_KERNEL::NORM_QUAD4 cell having only three unique nodes in
4627 * its connectivity is transformed into an INTERP_KERNEL::NORM_TRI3 cell. This method
4628 * does \b not perform geometrical checks and checks only nodal connectivity of cells,
4629 * so it can be useful to call mergeNodes() before calling this method.
4630 * \throw If \a this->getMeshDimension() <= 1.
4631 * \throw If the coordinates array is not set.
4632 * \throw If the nodal connectivity of cells is not defined.
4634 void MEDCouplingUMesh::convertDegeneratedCells()
4636 checkFullyDefined();
4637 if(getMeshDimension()<=1)
4638 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4639 int nbOfCells=getNumberOfCells();
4642 int initMeshLgth=getNodalConnectivityArrayLen();
4643 int *conn=_nodal_connec->getPointer();
4644 int *index=_nodal_connec_index->getPointer();
4648 for(int i=0;i<nbOfCells;i++)
4650 lgthOfCurCell=index[i+1]-posOfCurCell;
4651 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4653 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
4654 conn+newPos+1,newLgth);
4655 conn[newPos]=newType;
4657 posOfCurCell=index[i+1];
4660 if(newPos!=initMeshLgth)
4661 _nodal_connec->reAlloc(newPos);
4666 * Finds incorrectly oriented cells of this 2D mesh in 3D space.
4667 * A cell is considered to be oriented correctly if an angle between its
4668 * normal vector and a given vector is less than \c PI / \c 2.
4669 * \param [in] vec - 3 components of the vector specifying the correct orientation of
4671 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
4673 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
4674 * is not cleared before filling in.
4675 * \throw If \a this->getMeshDimension() != 2.
4676 * \throw If \a this->getSpaceDimension() != 3.
4678 * \if ENABLE_EXAMPLES
4679 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
4680 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
4683 void MEDCouplingUMesh::are2DCellsNotCorrectlyOriented(const double *vec, bool polyOnly, std::vector<int>& cells) const
4685 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
4686 throw INTERP_KERNEL::Exception("Invalid mesh to apply are2DCellsNotCorrectlyOriented on it : must be meshDim==2 and spaceDim==3 !");
4687 int nbOfCells=getNumberOfCells();
4688 const int *conn=_nodal_connec->begin();
4689 const int *connI=_nodal_connec_index->begin();
4690 const double *coordsPtr=_coords->begin();
4691 for(int i=0;i<nbOfCells;i++)
4693 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4694 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
4696 bool isQuadratic=INTERP_KERNEL::CellModel::GetCellModel(type).isQuadratic();
4697 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4704 * Reverse connectivity of 2D cells whose orientation is not correct. A cell is
4705 * considered to be oriented correctly if an angle between its normal vector and a
4706 * given vector is less than \c PI / \c 2.
4707 * \param [in] vec - 3 components of the vector specifying the correct orientation of
4709 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
4711 * \throw If \a this->getMeshDimension() != 2.
4712 * \throw If \a this->getSpaceDimension() != 3.
4714 * \if ENABLE_EXAMPLES
4715 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
4716 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
4719 * \sa changeOrientationOfCells
4721 void MEDCouplingUMesh::orientCorrectly2DCells(const double *vec, bool polyOnly)
4723 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
4724 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectly2DCells on it : must be meshDim==2 and spaceDim==3 !");
4725 int nbOfCells(getNumberOfCells()),*conn(_nodal_connec->getPointer());
4726 const int *connI(_nodal_connec_index->begin());
4727 const double *coordsPtr(_coords->begin());
4728 bool isModified(false);
4729 for(int i=0;i<nbOfCells;i++)
4731 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4732 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
4734 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
4735 bool isQuadratic(cm.isQuadratic());
4736 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4739 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
4744 _nodal_connec->declareAsNew();
4749 * This method change the orientation of cells in \a this without any consideration of coordinates. Only connectivity is impacted.
4751 * \sa orientCorrectly2DCells
4753 void MEDCouplingUMesh::changeOrientationOfCells()
4755 int mdim(getMeshDimension());
4756 if(mdim!=2 && mdim!=1)
4757 throw INTERP_KERNEL::Exception("Invalid mesh to apply changeOrientationOfCells on it : must be meshDim==2 or meshDim==1 !");
4758 int nbOfCells(getNumberOfCells()),*conn(_nodal_connec->getPointer());
4759 const int *connI(_nodal_connec_index->begin());
4762 for(int i=0;i<nbOfCells;i++)
4764 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4765 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
4766 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
4771 for(int i=0;i<nbOfCells;i++)
4773 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4774 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
4775 cm.changeOrientationOf1D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
4781 * Finds incorrectly oriented polyhedral cells, i.e. polyhedrons having correctly
4782 * oriented facets. The normal vector of the facet should point out of the cell.
4783 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
4784 * is not cleared before filling in.
4785 * \throw If \a this->getMeshDimension() != 3.
4786 * \throw If \a this->getSpaceDimension() != 3.
4787 * \throw If the coordinates array is not set.
4788 * \throw If the nodal connectivity of cells is not defined.
4790 * \if ENABLE_EXAMPLES
4791 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
4792 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
4795 void MEDCouplingUMesh::arePolyhedronsNotCorrectlyOriented(std::vector<int>& cells) const
4797 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
4798 throw INTERP_KERNEL::Exception("Invalid mesh to apply arePolyhedronsNotCorrectlyOriented on it : must be meshDim==3 and spaceDim==3 !");
4799 int nbOfCells=getNumberOfCells();
4800 const int *conn=_nodal_connec->begin();
4801 const int *connI=_nodal_connec_index->begin();
4802 const double *coordsPtr=_coords->begin();
4803 for(int i=0;i<nbOfCells;i++)
4805 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4806 if(type==INTERP_KERNEL::NORM_POLYHED)
4808 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4815 * Tries to fix connectivity of polyhedra, so that normal vector of all facets to point
4817 * \throw If \a this->getMeshDimension() != 3.
4818 * \throw If \a this->getSpaceDimension() != 3.
4819 * \throw If the coordinates array is not set.
4820 * \throw If the nodal connectivity of cells is not defined.
4821 * \throw If the reparation fails.
4823 * \if ENABLE_EXAMPLES
4824 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
4825 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
4827 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
4829 void MEDCouplingUMesh::orientCorrectlyPolyhedrons()
4831 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
4832 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectlyPolyhedrons on it : must be meshDim==3 and spaceDim==3 !");
4833 int nbOfCells=getNumberOfCells();
4834 int *conn=_nodal_connec->getPointer();
4835 const int *connI=_nodal_connec_index->begin();
4836 const double *coordsPtr=_coords->begin();
4837 for(int i=0;i<nbOfCells;i++)
4839 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4840 if(type==INTERP_KERNEL::NORM_POLYHED)
4844 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4845 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
4847 catch(INTERP_KERNEL::Exception& e)
4849 std::ostringstream oss; oss << "Something wrong in polyhedron #" << i << " : " << e.what();
4850 throw INTERP_KERNEL::Exception(oss.str());
4858 * Finds and fixes incorrectly oriented linear extruded volumes (INTERP_KERNEL::NORM_HEXA8,
4859 * INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXGP12 etc) to respect the MED convention
4860 * according to which the first facet of the cell should be oriented to have the normal vector
4861 * pointing out of cell.
4862 * \return DataArrayInt * - a new instance of DataArrayInt holding ids of fixed
4863 * cells. The caller is to delete this array using decrRef() as it is no more
4865 * \throw If \a this->getMeshDimension() != 3.
4866 * \throw If \a this->getSpaceDimension() != 3.
4867 * \throw If the coordinates array is not set.
4868 * \throw If the nodal connectivity of cells is not defined.
4870 * \if ENABLE_EXAMPLES
4871 * \ref cpp_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a C++ example".<br>
4872 * \ref py_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a Python example".
4874 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
4876 DataArrayInt *MEDCouplingUMesh::findAndCorrectBadOriented3DExtrudedCells()
4878 const char msg[]="check3DCellsWellOriented detection works only for 3D cells !";
4879 if(getMeshDimension()!=3)
4880 throw INTERP_KERNEL::Exception(msg);
4881 int spaceDim=getSpaceDimension();
4883 throw INTERP_KERNEL::Exception(msg);
4885 int nbOfCells=getNumberOfCells();
4886 int *conn=_nodal_connec->getPointer();
4887 const int *connI=_nodal_connec_index->begin();
4888 const double *coo=getCoords()->begin();
4889 MCAuto<DataArrayInt> cells(DataArrayInt::New()); cells->alloc(0,1);
4890 for(int i=0;i<nbOfCells;i++)
4892 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4893 if(cm.isExtruded() && !cm.isDynamic() && !cm.isQuadratic())
4895 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coo))
4897 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
4898 cells->pushBackSilent(i);
4902 return cells.retn();
4906 * This method is a faster method to correct orientation of all 3D cells in \a this.
4907 * 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.
4908 * This method makes the hypothesis that \a this a coherent that is to say MEDCouplingUMesh::checkConsistency should throw no exception.
4910 * \return a newly allocated int array with one components containing cell ids renumbered to fit the convention of MED (MED file and MEDCoupling)
4911 * \sa MEDCouplingUMesh::orientCorrectlyPolyhedrons,
4913 DataArrayInt *MEDCouplingUMesh::findAndCorrectBadOriented3DCells()
4915 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
4916 throw INTERP_KERNEL::Exception("Invalid mesh to apply findAndCorrectBadOriented3DCells on it : must be meshDim==3 and spaceDim==3 !");
4917 int nbOfCells=getNumberOfCells();
4918 int *conn=_nodal_connec->getPointer();
4919 const int *connI=_nodal_connec_index->begin();
4920 const double *coordsPtr=_coords->begin();
4921 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
4922 for(int i=0;i<nbOfCells;i++)
4924 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4927 case INTERP_KERNEL::NORM_TETRA4:
4929 if(!IsTetra4WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4931 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+3));
4932 ret->pushBackSilent(i);
4936 case INTERP_KERNEL::NORM_PYRA5:
4938 if(!IsPyra5WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4940 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+4));
4941 ret->pushBackSilent(i);
4945 case INTERP_KERNEL::NORM_PENTA6:
4946 case INTERP_KERNEL::NORM_HEXA8:
4947 case INTERP_KERNEL::NORM_HEXGP12:
4949 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4951 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
4952 ret->pushBackSilent(i);
4956 case INTERP_KERNEL::NORM_POLYHED:
4958 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4960 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
4961 ret->pushBackSilent(i);
4966 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 !");
4974 * This method has a sense for meshes with spaceDim==3 and meshDim==2.
4975 * If it is not the case an exception will be thrown.
4976 * This method is fast because the first cell of \a this is used to compute the plane.
4977 * \param vec output of size at least 3 used to store the normal vector (with norm equal to Area ) of searched plane.
4978 * \param pos output of size at least 3 used to store a point owned of searched plane.
4980 void MEDCouplingUMesh::getFastAveragePlaneOfThis(double *vec, double *pos) const
4982 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
4983 throw INTERP_KERNEL::Exception("Invalid mesh to apply getFastAveragePlaneOfThis on it : must be meshDim==2 and spaceDim==3 !");
4984 const int *conn=_nodal_connec->begin();
4985 const int *connI=_nodal_connec_index->begin();
4986 const double *coordsPtr=_coords->begin();
4987 INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(conn+1,connI[1]-connI[0]-1,coordsPtr,vec);
4988 std::copy(coordsPtr+3*conn[1],coordsPtr+3*conn[1]+3,pos);
4992 * Creates a new MEDCouplingFieldDouble holding Edge Ratio values of all
4993 * cells. Currently cells of the following types are treated:
4994 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
4995 * For a cell of other type an exception is thrown.
4996 * Space dimension of a 2D mesh can be either 2 or 3.
4997 * The Edge Ratio of a cell \f$t\f$ is:
4998 * \f$\frac{|t|_\infty}{|t|_0}\f$,
4999 * where \f$|t|_\infty\f$ and \f$|t|_0\f$ respectively denote the greatest and
5000 * the smallest edge lengths of \f$t\f$.
5001 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5002 * cells and one time, lying on \a this mesh. The caller is to delete this
5003 * field using decrRef() as it is no more needed.
5004 * \throw If the coordinates array is not set.
5005 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5006 * \throw If the connectivity data array has more than one component.
5007 * \throw If the connectivity data array has a named component.
5008 * \throw If the connectivity index data array has more than one component.
5009 * \throw If the connectivity index data array has a named component.
5010 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
5011 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5012 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5014 MEDCouplingFieldDouble *MEDCouplingUMesh::getEdgeRatioField() const
5016 checkConsistencyLight();
5017 int spaceDim=getSpaceDimension();
5018 int meshDim=getMeshDimension();
5019 if(spaceDim!=2 && spaceDim!=3)
5020 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : SpaceDimension must be equal to 2 or 3 !");
5021 if(meshDim!=2 && meshDim!=3)
5022 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : MeshDimension must be equal to 2 or 3 !");
5023 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5025 int nbOfCells=getNumberOfCells();
5026 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5027 arr->alloc(nbOfCells,1);
5028 double *pt=arr->getPointer();
5029 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5030 const int *conn=_nodal_connec->begin();
5031 const int *connI=_nodal_connec_index->begin();
5032 const double *coo=_coords->begin();
5034 for(int i=0;i<nbOfCells;i++,pt++)
5036 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5039 case INTERP_KERNEL::NORM_TRI3:
5041 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5042 *pt=INTERP_KERNEL::triEdgeRatio(tmp);
5045 case INTERP_KERNEL::NORM_QUAD4:
5047 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5048 *pt=INTERP_KERNEL::quadEdgeRatio(tmp);
5051 case INTERP_KERNEL::NORM_TETRA4:
5053 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5054 *pt=INTERP_KERNEL::tetraEdgeRatio(tmp);
5058 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5060 conn+=connI[i+1]-connI[i];
5062 ret->setName("EdgeRatio");
5063 ret->synchronizeTimeWithSupport();
5068 * Creates a new MEDCouplingFieldDouble holding Aspect Ratio values of all
5069 * cells. Currently cells of the following types are treated:
5070 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5071 * For a cell of other type an exception is thrown.
5072 * Space dimension of a 2D mesh can be either 2 or 3.
5073 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5074 * cells and one time, lying on \a this mesh. The caller is to delete this
5075 * field using decrRef() as it is no more needed.
5076 * \throw If the coordinates array is not set.
5077 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5078 * \throw If the connectivity data array has more than one component.
5079 * \throw If the connectivity data array has a named component.
5080 * \throw If the connectivity index data array has more than one component.
5081 * \throw If the connectivity index data array has a named component.
5082 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
5083 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5084 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5086 MEDCouplingFieldDouble *MEDCouplingUMesh::getAspectRatioField() const
5088 checkConsistencyLight();
5089 int spaceDim=getSpaceDimension();
5090 int meshDim=getMeshDimension();
5091 if(spaceDim!=2 && spaceDim!=3)
5092 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : SpaceDimension must be equal to 2 or 3 !");
5093 if(meshDim!=2 && meshDim!=3)
5094 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : MeshDimension must be equal to 2 or 3 !");
5095 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5097 int nbOfCells=getNumberOfCells();
5098 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5099 arr->alloc(nbOfCells,1);
5100 double *pt=arr->getPointer();
5101 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5102 const int *conn=_nodal_connec->begin();
5103 const int *connI=_nodal_connec_index->begin();
5104 const double *coo=_coords->begin();
5106 for(int i=0;i<nbOfCells;i++,pt++)
5108 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5111 case INTERP_KERNEL::NORM_TRI3:
5113 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5114 *pt=INTERP_KERNEL::triAspectRatio(tmp);
5117 case INTERP_KERNEL::NORM_QUAD4:
5119 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5120 *pt=INTERP_KERNEL::quadAspectRatio(tmp);
5123 case INTERP_KERNEL::NORM_TETRA4:
5125 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5126 *pt=INTERP_KERNEL::tetraAspectRatio(tmp);
5130 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5132 conn+=connI[i+1]-connI[i];
5134 ret->setName("AspectRatio");
5135 ret->synchronizeTimeWithSupport();
5140 * Creates a new MEDCouplingFieldDouble holding Warping factor values of all
5141 * cells of \a this 2D mesh in 3D space. It is a measure of the "planarity" of 2D cell
5142 * in 3D space. Currently only cells of the following types are
5143 * treated: INTERP_KERNEL::NORM_QUAD4.
5144 * For a cell of other type an exception is thrown.
5145 * The warp field is computed as follows: let (a,b,c,d) be the points of the quad.
5147 * \f$t=\vec{da}\times\vec{ab}\f$,
5148 * \f$u=\vec{ab}\times\vec{bc}\f$
5149 * \f$v=\vec{bc}\times\vec{cd}\f$
5150 * \f$w=\vec{cd}\times\vec{da}\f$, the warp is defined as \f$W^3\f$ with
5152 * W=min(\frac{t}{|t|}\cdot\frac{v}{|v|}, \frac{u}{|u|}\cdot\frac{w}{|w|})
5154 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5155 * cells and one time, lying on \a this mesh. The caller is to delete this
5156 * field using decrRef() as it is no more needed.
5157 * \throw If the coordinates array is not set.
5158 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5159 * \throw If the connectivity data array has more than one component.
5160 * \throw If the connectivity data array has a named component.
5161 * \throw If the connectivity index data array has more than one component.
5162 * \throw If the connectivity index data array has a named component.
5163 * \throw If \a this->getMeshDimension() != 2.
5164 * \throw If \a this->getSpaceDimension() != 3.
5165 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5167 MEDCouplingFieldDouble *MEDCouplingUMesh::getWarpField() const
5169 checkConsistencyLight();
5170 int spaceDim=getSpaceDimension();
5171 int meshDim=getMeshDimension();
5173 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : SpaceDimension must be equal to 3 !");
5175 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : MeshDimension must be equal to 2 !");
5176 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5178 int nbOfCells=getNumberOfCells();
5179 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5180 arr->alloc(nbOfCells,1);
5181 double *pt=arr->getPointer();
5182 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5183 const int *conn=_nodal_connec->begin();
5184 const int *connI=_nodal_connec_index->begin();
5185 const double *coo=_coords->begin();
5187 for(int i=0;i<nbOfCells;i++,pt++)
5189 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5192 case INTERP_KERNEL::NORM_QUAD4:
5194 FillInCompact3DMode(3,4,conn+1,coo,tmp);
5195 *pt=INTERP_KERNEL::quadWarp(tmp);
5199 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : A cell with not manged type (NORM_QUAD4) has been detected !");
5201 conn+=connI[i+1]-connI[i];
5203 ret->setName("Warp");
5204 ret->synchronizeTimeWithSupport();
5210 * Creates a new MEDCouplingFieldDouble holding Skew factor values of all
5211 * cells of \a this 2D mesh in 3D space. Currently cells of the following types are
5212 * treated: INTERP_KERNEL::NORM_QUAD4.
5213 * The skew is computed as follow for a quad with points (a,b,c,d): let
5214 * \f$u=\vec{ab}+\vec{dc}\f$ and \f$v=\vec{ac}+\vec{bd}\f$
5215 * then the skew is computed as:
5217 * s=\frac{u}{|u|}\cdot\frac{v}{|v|}
5220 * For a cell of other type an exception is thrown.
5221 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5222 * cells and one time, lying on \a this mesh. The caller is to delete this
5223 * field using decrRef() as it is no more needed.
5224 * \throw If the coordinates array is not set.
5225 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5226 * \throw If the connectivity data array has more than one component.
5227 * \throw If the connectivity data array has a named component.
5228 * \throw If the connectivity index data array has more than one component.
5229 * \throw If the connectivity index data array has a named component.
5230 * \throw If \a this->getMeshDimension() != 2.
5231 * \throw If \a this->getSpaceDimension() != 3.
5232 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5234 MEDCouplingFieldDouble *MEDCouplingUMesh::getSkewField() const
5236 checkConsistencyLight();
5237 int spaceDim=getSpaceDimension();
5238 int meshDim=getMeshDimension();
5240 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : SpaceDimension must be equal to 3 !");
5242 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : MeshDimension must be equal to 2 !");
5243 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5245 int nbOfCells=getNumberOfCells();
5246 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5247 arr->alloc(nbOfCells,1);
5248 double *pt=arr->getPointer();
5249 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5250 const int *conn=_nodal_connec->begin();
5251 const int *connI=_nodal_connec_index->begin();
5252 const double *coo=_coords->begin();
5254 for(int i=0;i<nbOfCells;i++,pt++)
5256 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5259 case INTERP_KERNEL::NORM_QUAD4:
5261 FillInCompact3DMode(3,4,conn+1,coo,tmp);
5262 *pt=INTERP_KERNEL::quadSkew(tmp);
5266 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : A cell with not manged type (NORM_QUAD4) has been detected !");
5268 conn+=connI[i+1]-connI[i];
5270 ret->setName("Skew");
5271 ret->synchronizeTimeWithSupport();
5276 * 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.
5278 * \return a new instance of field containing the result. The returned instance has to be deallocated by the caller.
5280 * \sa getSkewField, getWarpField, getAspectRatioField, getEdgeRatioField
5282 MEDCouplingFieldDouble *MEDCouplingUMesh::computeDiameterField() const
5284 checkConsistencyLight();
5285 MCAuto<MEDCouplingFieldDouble> ret(MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME));
5287 std::set<INTERP_KERNEL::NormalizedCellType> types;
5288 ComputeAllTypesInternal(types,_nodal_connec,_nodal_connec_index);
5289 int spaceDim(getSpaceDimension()),nbCells(getNumberOfCells());
5290 MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
5291 arr->alloc(nbCells,1);
5292 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++)
5294 INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::DiameterCalculator> dc(INTERP_KERNEL::CellModel::GetCellModel(*it).buildInstanceOfDiameterCalulator(spaceDim));
5295 MCAuto<DataArrayInt> cellIds(giveCellsWithType(*it));
5296 dc->computeForListOfCellIdsUMeshFrmt(cellIds->begin(),cellIds->end(),_nodal_connec_index->begin(),_nodal_connec->begin(),getCoords()->begin(),arr->getPointer());
5299 ret->setName("Diameter");
5304 * This method aggregate the bbox of each cell and put it into bbox parameter (xmin,xmax,ymin,ymax,zmin,zmax).
5306 * \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)
5307 * For all other cases this input parameter is ignored.
5308 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5310 * \throw If \a this is not fully set (coordinates and connectivity).
5311 * \throw If a cell in \a this has no valid nodeId.
5312 * \sa MEDCouplingUMesh::getBoundingBoxForBBTreeFast, MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5314 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree(double arcDetEps) const
5316 int mDim(getMeshDimension()),sDim(getSpaceDimension());
5317 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.
5318 return getBoundingBoxForBBTreeFast();
5319 if((mDim==2 && sDim==2) || (mDim==1 && sDim==2))
5321 bool presenceOfQuadratic(false);
5322 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=_types.begin();it!=_types.end();it++)
5324 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(*it));
5325 if(cm.isQuadratic())
5326 presenceOfQuadratic=true;
5328 if(!presenceOfQuadratic)
5329 return getBoundingBoxForBBTreeFast();
5330 if(mDim==2 && sDim==2)
5331 return getBoundingBoxForBBTree2DQuadratic(arcDetEps);
5333 return getBoundingBoxForBBTree1DQuadratic(arcDetEps);
5335 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) !");
5339 * This method aggregate the bbox of each cell only considering the nodes constituting each cell and put it into bbox parameter.
5340 * So meshes having quadratic cells the computed bounding boxes can be invalid !
5342 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5344 * \throw If \a this is not fully set (coordinates and connectivity).
5345 * \throw If a cell in \a this has no valid nodeId.
5347 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTreeFast() const
5349 checkFullyDefined();
5350 int spaceDim(getSpaceDimension()),nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
5351 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5352 double *bbox(ret->getPointer());
5353 for(int i=0;i<nbOfCells*spaceDim;i++)
5355 bbox[2*i]=std::numeric_limits<double>::max();
5356 bbox[2*i+1]=-std::numeric_limits<double>::max();
5358 const double *coordsPtr(_coords->begin());
5359 const int *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5360 for(int i=0;i<nbOfCells;i++)
5362 int offset=connI[i]+1;
5363 int nbOfNodesForCell(connI[i+1]-offset),kk(0);
5364 for(int j=0;j<nbOfNodesForCell;j++)
5366 int nodeId=conn[offset+j];
5367 if(nodeId>=0 && nodeId<nbOfNodes)
5369 for(int k=0;k<spaceDim;k++)
5371 bbox[2*spaceDim*i+2*k]=std::min(bbox[2*spaceDim*i+2*k],coordsPtr[spaceDim*nodeId+k]);
5372 bbox[2*spaceDim*i+2*k+1]=std::max(bbox[2*spaceDim*i+2*k+1],coordsPtr[spaceDim*nodeId+k]);
5379 std::ostringstream oss; oss << "MEDCouplingUMesh::getBoundingBoxForBBTree : cell #" << i << " contains no valid nodeId !";
5380 throw INTERP_KERNEL::Exception(oss.str());
5387 * This method aggregates the bbox of each 2D cell in \a this considering the whole shape. This method is particularly
5388 * useful for 2D meshes having quadratic cells
5389 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5390 * the two extremities of the arc of circle).
5392 * \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)
5393 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5394 * \throw If \a this is not fully defined.
5395 * \throw If \a this is not a mesh with meshDimension equal to 2.
5396 * \throw If \a this is not a mesh with spaceDimension equal to 2.
5397 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic
5399 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic(double arcDetEps) const
5401 checkFullyDefined();
5402 int spaceDim(getSpaceDimension()),mDim(getMeshDimension()),nbOfCells(getNumberOfCells());
5403 if(spaceDim!=2 || mDim!=2)
5404 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!");
5405 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5406 double *bbox(ret->getPointer());
5407 const double *coords(_coords->begin());
5408 const int *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5409 for(int i=0;i<nbOfCells;i++,bbox+=4,connI++)
5411 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5412 int sz(connI[1]-connI[0]-1);
5413 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=arcDetEps;
5414 std::vector<INTERP_KERNEL::Node *> nodes(sz);
5415 INTERP_KERNEL::QuadraticPolygon *pol(0);
5416 for(int j=0;j<sz;j++)
5418 int nodeId(conn[*connI+1+j]);
5419 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5421 if(!cm.isQuadratic())
5422 pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
5424 pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
5425 INTERP_KERNEL::Bounds b; b.prepareForAggregation(); pol->fillBounds(b); delete pol;
5426 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax();
5432 * This method aggregates the bbox of each 1D cell in \a this considering the whole shape. This method is particularly
5433 * useful for 2D meshes having quadratic cells
5434 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5435 * the two extremities of the arc of circle).
5437 * \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)
5438 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5439 * \throw If \a this is not fully defined.
5440 * \throw If \a this is not a mesh with meshDimension equal to 1.
5441 * \throw If \a this is not a mesh with spaceDimension equal to 2.
5442 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5444 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic(double arcDetEps) const
5446 checkFullyDefined();
5447 int spaceDim(getSpaceDimension()),mDim(getMeshDimension()),nbOfCells(getNumberOfCells());
5448 if(spaceDim!=2 || mDim!=1)
5449 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!");
5450 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5451 double *bbox(ret->getPointer());
5452 const double *coords(_coords->begin());
5453 const int *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5454 for(int i=0;i<nbOfCells;i++,bbox+=4,connI++)
5456 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5457 int sz(connI[1]-connI[0]-1);
5458 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=arcDetEps;
5459 std::vector<INTERP_KERNEL::Node *> nodes(sz);
5460 INTERP_KERNEL::Edge *edge(0);
5461 for(int j=0;j<sz;j++)
5463 int nodeId(conn[*connI+1+j]);
5464 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5466 if(!cm.isQuadratic())
5467 edge=INTERP_KERNEL::QuadraticPolygon::BuildLinearEdge(nodes);
5469 edge=INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(nodes);
5470 const INTERP_KERNEL::Bounds& b(edge->getBounds());
5471 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax(); edge->decrRef();
5478 namespace MEDCouplingImpl
5483 ConnReader(const int *c, int val):_conn(c),_val(val) { }
5484 bool operator() (const int& pos) { return _conn[pos]!=_val; }
5493 ConnReader2(const int *c, int val):_conn(c),_val(val) { }
5494 bool operator() (const int& pos) { return _conn[pos]==_val; }
5504 * This method expects that \a this is sorted by types. If not an exception will be thrown.
5505 * This method returns in the same format as code (see MEDCouplingUMesh::checkTypeConsistencyAndContig or MEDCouplingUMesh::splitProfilePerType) how
5506 * \a this is composed in cell types.
5507 * The returned array is of size 3*n where n is the number of different types present in \a this.
5508 * For every k in [0,n] ret[3*k+2]==-1 because it has no sense here.
5509 * This parameter is kept only for compatibility with other methode listed above.
5511 std::vector<int> MEDCouplingUMesh::getDistributionOfTypes() const
5513 checkConnectivityFullyDefined();
5514 const int *conn=_nodal_connec->begin();
5515 const int *connI=_nodal_connec_index->begin();
5516 const int *work=connI;
5517 int nbOfCells=getNumberOfCells();
5518 std::size_t n=getAllGeoTypes().size();
5519 std::vector<int> ret(3*n,-1); //ret[3*k+2]==-1 because it has no sense here
5520 std::set<INTERP_KERNEL::NormalizedCellType> types;
5521 for(std::size_t i=0;work!=connI+nbOfCells;i++)
5523 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn[*work];
5524 if(types.find(typ)!=types.end())
5526 std::ostringstream oss; oss << "MEDCouplingUMesh::getDistributionOfTypes : Type " << INTERP_KERNEL::CellModel::GetCellModel(typ).getRepr();
5527 oss << " is not contiguous !";
5528 throw INTERP_KERNEL::Exception(oss.str());
5532 const int *work2=std::find_if(work+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,typ));
5533 ret[3*i+1]=(int)std::distance(work,work2);
5540 * This method is used to check that this has contiguous cell type in same order than described in \a code.
5541 * only for types cell, type node is not managed.
5542 * Format of \a code is the following. \a code should be of size 3*n and non empty. If not an exception is thrown.
5543 * foreach k in [0,n) on 3*k pos represent the geometric type and 3*k+1 number of elements of type 3*k.
5544 * 3*k+2 refers if different from -1 the pos in 'idsPerType' to get the corresponding array.
5545 * If 2 or more same geometric type is in \a code and exception is thrown too.
5547 * This method firstly checks
5548 * If it exists k so that 3*k geometric type is not in geometric types of this an exception will be thrown.
5549 * If it exists k so that 3*k geometric type exists but the number of consecutive cell types does not match,
5550 * an exception is thrown too.
5552 * If all geometric types in \a code are exactly those in \a this null pointer is returned.
5553 * If it exists a geometric type in \a this \b not in \a code \b no exception is thrown
5554 * and a DataArrayInt instance is returned that the user has the responsability to deallocate.
5556 DataArrayInt *MEDCouplingUMesh::checkTypeConsistencyAndContig(const std::vector<int>& code, const std::vector<const DataArrayInt *>& idsPerType) const
5559 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code is empty, should not !");
5560 std::size_t sz=code.size();
5563 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code size is NOT %3 !");
5564 std::vector<INTERP_KERNEL::NormalizedCellType> types;
5566 bool isNoPflUsed=true;
5567 for(std::size_t i=0;i<n;i++)
5568 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)code[3*i])==types.end())
5570 types.push_back((INTERP_KERNEL::NormalizedCellType)code[3*i]);
5572 if(_types.find((INTERP_KERNEL::NormalizedCellType)code[3*i])==_types.end())
5573 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : expected geo types not in this !");
5574 isNoPflUsed=isNoPflUsed && (code[3*i+2]==-1);
5577 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code contains duplication of types in unstructured mesh !");
5580 if(!checkConsecutiveCellTypesAndOrder(&types[0],&types[0]+types.size()))
5581 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : non contiguous type !");
5582 if(types.size()==_types.size())
5585 MCAuto<DataArrayInt> ret=DataArrayInt::New();
5587 int *retPtr=ret->getPointer();
5588 const int *connI=_nodal_connec_index->begin();
5589 const int *conn=_nodal_connec->begin();
5590 int nbOfCells=getNumberOfCells();
5593 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++,kk++)
5595 i=std::find_if(i,connI+nbOfCells,MEDCouplingImpl::ConnReader2(conn,(int)(*it)));
5596 int offset=(int)std::distance(connI,i);
5597 const int *j=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)(*it)));
5598 int nbOfCellsOfCurType=(int)std::distance(i,j);
5599 if(code[3*kk+2]==-1)
5600 for(int k=0;k<nbOfCellsOfCurType;k++)
5604 int idInIdsPerType=code[3*kk+2];
5605 if(idInIdsPerType>=0 && idInIdsPerType<(int)idsPerType.size())
5607 const DataArrayInt *zePfl=idsPerType[idInIdsPerType];
5610 zePfl->checkAllocated();
5611 if(zePfl->getNumberOfComponents()==1)
5613 for(const int *k=zePfl->begin();k!=zePfl->end();k++,retPtr++)
5615 if(*k>=0 && *k<nbOfCellsOfCurType)
5616 *retPtr=(*k)+offset;
5619 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : the section " << kk << " points to the profile #" << idInIdsPerType;
5620 oss << ", and this profile contains a value " << *k << " should be in [0," << nbOfCellsOfCurType << ") !";
5621 throw INTERP_KERNEL::Exception(oss.str());
5626 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of a profile with nb of compo != 1 !");
5629 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of null profile !");
5633 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : at section " << kk << " of code it points to the array #" << idInIdsPerType;
5634 oss << " should be in [0," << idsPerType.size() << ") !";
5635 throw INTERP_KERNEL::Exception(oss.str());
5644 * This method makes the hypothesis that \a this is sorted by type. If not an exception will be thrown.
5645 * 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.
5646 * 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.
5647 * This method has 1 input \a profile and 3 outputs \a code \a idsInPflPerType and \a idsPerType.
5649 * \param [in] profile
5650 * \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.
5651 * \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,
5652 * \a idsInPflPerType[i] stores the tuple ids in \a profile that correspond to the geometric type code[3*i+0]
5653 * \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.
5654 * This vector can be empty in case of all geometric type cells are fully covered in ascending in the given input \a profile.
5655 * \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
5657 void MEDCouplingUMesh::splitProfilePerType(const DataArrayInt *profile, std::vector<int>& code, std::vector<DataArrayInt *>& idsInPflPerType, std::vector<DataArrayInt *>& idsPerType) const
5660 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile is NULL !");
5661 if(profile->getNumberOfComponents()!=1)
5662 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile should have exactly one component !");
5663 checkConnectivityFullyDefined();
5664 const int *conn=_nodal_connec->begin();
5665 const int *connI=_nodal_connec_index->begin();
5666 int nbOfCells=getNumberOfCells();
5667 std::vector<INTERP_KERNEL::NormalizedCellType> types;
5668 std::vector<int> typeRangeVals(1);
5669 for(const int *i=connI;i!=connI+nbOfCells;)
5671 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5672 if(std::find(types.begin(),types.end(),curType)!=types.end())
5674 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : current mesh is not sorted by type !");
5676 types.push_back(curType);
5677 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
5678 typeRangeVals.push_back((int)std::distance(connI,i));
5681 DataArrayInt *castArr=0,*rankInsideCast=0,*castsPresent=0;
5682 profile->splitByValueRange(&typeRangeVals[0],&typeRangeVals[0]+typeRangeVals.size(),castArr,rankInsideCast,castsPresent);
5683 MCAuto<DataArrayInt> tmp0=castArr;
5684 MCAuto<DataArrayInt> tmp1=rankInsideCast;
5685 MCAuto<DataArrayInt> tmp2=castsPresent;
5687 int nbOfCastsFinal=castsPresent->getNumberOfTuples();
5688 code.resize(3*nbOfCastsFinal);
5689 std::vector< MCAuto<DataArrayInt> > idsInPflPerType2;
5690 std::vector< MCAuto<DataArrayInt> > idsPerType2;
5691 for(int i=0;i<nbOfCastsFinal;i++)
5693 int castId=castsPresent->getIJ(i,0);
5694 MCAuto<DataArrayInt> tmp3=castArr->findIdsEqual(castId);
5695 idsInPflPerType2.push_back(tmp3);
5696 code[3*i]=(int)types[castId];
5697 code[3*i+1]=tmp3->getNumberOfTuples();
5698 MCAuto<DataArrayInt> tmp4=rankInsideCast->selectByTupleId(tmp3->begin(),tmp3->begin()+tmp3->getNumberOfTuples());
5699 if(!tmp4->isIota(typeRangeVals[castId+1]-typeRangeVals[castId]))
5701 tmp4->copyStringInfoFrom(*profile);
5702 idsPerType2.push_back(tmp4);
5703 code[3*i+2]=(int)idsPerType2.size()-1;
5710 std::size_t sz2=idsInPflPerType2.size();
5711 idsInPflPerType.resize(sz2);
5712 for(std::size_t i=0;i<sz2;i++)
5714 DataArrayInt *locDa=idsInPflPerType2[i];
5716 idsInPflPerType[i]=locDa;
5718 std::size_t sz=idsPerType2.size();
5719 idsPerType.resize(sz);
5720 for(std::size_t i=0;i<sz;i++)
5722 DataArrayInt *locDa=idsPerType2[i];
5724 idsPerType[i]=locDa;
5729 * This method is here too emulate the MEDMEM behaviour on BDC (buildDescendingConnectivity). Hoping this method becomes deprecated very soon.
5730 * This method make the assumption that \a this and 'nM1LevMesh' mesh lyies on same coords (same pointer) as MED and MEDMEM does.
5731 * The following equality should be verified 'nM1LevMesh->getMeshDimension()==this->getMeshDimension()-1'
5732 * 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.
5734 MEDCouplingUMesh *MEDCouplingUMesh::emulateMEDMEMBDC(const MEDCouplingUMesh *nM1LevMesh, DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *&revDesc, DataArrayInt *&revDescIndx, DataArrayInt *& nM1LevMeshIds, DataArrayInt *&meshnM1Old2New) const
5736 checkFullyDefined();
5737 nM1LevMesh->checkFullyDefined();
5738 if(getMeshDimension()-1!=nM1LevMesh->getMeshDimension())
5739 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : The mesh passed as first argument should have a meshDim equal to this->getMeshDimension()-1 !" );
5740 if(_coords!=nM1LevMesh->getCoords())
5741 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : 'this' and mesh in first argument should share the same coords : Use tryToShareSameCoords method !");
5742 MCAuto<DataArrayInt> tmp0=DataArrayInt::New();
5743 MCAuto<DataArrayInt> tmp1=DataArrayInt::New();
5744 MCAuto<MEDCouplingUMesh> ret1=buildDescendingConnectivity(desc,descIndx,tmp0,tmp1);
5745 MCAuto<DataArrayInt> ret0=ret1->sortCellsInMEDFileFrmt();
5746 desc->transformWithIndArr(ret0->begin(),ret0->begin()+ret0->getNbOfElems());
5747 MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
5748 tmp->setConnectivity(tmp0,tmp1);
5749 tmp->renumberCells(ret0->begin(),false);
5750 revDesc=tmp->getNodalConnectivity();
5751 revDescIndx=tmp->getNodalConnectivityIndex();
5752 DataArrayInt *ret=0;
5753 if(!ret1->areCellsIncludedIn(nM1LevMesh,2,ret))
5756 ret->getMaxValue(tmp2);
5758 std::ostringstream oss; oss << "MEDCouplingUMesh::emulateMEDMEMBDC : input N-1 mesh present a cell not in descending mesh ... Id of cell is " << tmp2 << " !";
5759 throw INTERP_KERNEL::Exception(oss.str());
5764 revDescIndx->incrRef();
5767 meshnM1Old2New=ret0;
5772 * Permutes the nodal connectivity arrays so that the cells are sorted by type, which is
5773 * necessary for writing the mesh to MED file. Additionally returns a permutation array
5774 * in "Old to New" mode.
5775 * \return DataArrayInt * - a new instance of DataArrayInt. The caller is to delete
5776 * this array using decrRef() as it is no more needed.
5777 * \throw If the nodal connectivity of cells is not defined.
5779 DataArrayInt *MEDCouplingUMesh::sortCellsInMEDFileFrmt()
5781 checkConnectivityFullyDefined();
5782 MCAuto<DataArrayInt> ret=getRenumArrForMEDFileFrmt();
5783 renumberCells(ret->begin(),false);
5788 * This methods checks that cells are sorted by their types.
5789 * This method makes asumption (no check) that connectivity is correctly set before calling.
5791 bool MEDCouplingUMesh::checkConsecutiveCellTypes() const
5793 checkFullyDefined();
5794 const int *conn=_nodal_connec->begin();
5795 const int *connI=_nodal_connec_index->begin();
5796 int nbOfCells=getNumberOfCells();
5797 std::set<INTERP_KERNEL::NormalizedCellType> types;
5798 for(const int *i=connI;i!=connI+nbOfCells;)
5800 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5801 if(types.find(curType)!=types.end())
5803 types.insert(curType);
5804 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
5810 * This method is a specialization of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method that is called here.
5811 * The geometric type order is specified by MED file.
5813 * \sa MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder
5815 bool MEDCouplingUMesh::checkConsecutiveCellTypesForMEDFileFrmt() const
5817 return checkConsecutiveCellTypesAndOrder(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
5821 * This method performs the same job as checkConsecutiveCellTypes except that the order of types sequence is analyzed to check
5822 * that the order is specified in array defined by [ \a orderBg , \a orderEnd ).
5823 * If there is some geo types in \a this \b NOT in [ \a orderBg, \a orderEnd ) it is OK (return true) if contiguous.
5824 * If there is some geo types in [ \a orderBg, \a orderEnd ) \b NOT in \a this it is OK too (return true) if contiguous.
5826 bool MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
5828 checkFullyDefined();
5829 const int *conn=_nodal_connec->begin();
5830 const int *connI=_nodal_connec_index->begin();
5831 int nbOfCells=getNumberOfCells();
5835 std::set<INTERP_KERNEL::NormalizedCellType> sg;
5836 for(const int *i=connI;i!=connI+nbOfCells;)
5838 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5839 const INTERP_KERNEL::NormalizedCellType *isTypeExists=std::find(orderBg,orderEnd,curType);
5840 if(isTypeExists!=orderEnd)
5842 int pos=(int)std::distance(orderBg,isTypeExists);
5846 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
5850 if(sg.find(curType)==sg.end())
5852 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
5863 * This method returns 2 newly allocated DataArrayInt instances. The first is an array of size 'this->getNumberOfCells()' with one component,
5864 * 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
5865 * number of tuples than input type array and with one component. This 2nd output array gives type by type the number of occurence of type in 'this'.
5867 DataArrayInt *MEDCouplingUMesh::getLevArrPerCellTypes(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd, DataArrayInt *&nbPerType) const
5869 checkConnectivityFullyDefined();
5870 int nbOfCells=getNumberOfCells();
5871 const int *conn=_nodal_connec->begin();
5872 const int *connI=_nodal_connec_index->begin();
5873 MCAuto<DataArrayInt> tmpa=DataArrayInt::New();
5874 MCAuto<DataArrayInt> tmpb=DataArrayInt::New();
5875 tmpa->alloc(nbOfCells,1);
5876 tmpb->alloc((int)std::distance(orderBg,orderEnd),1);
5877 tmpb->fillWithZero();
5878 int *tmp=tmpa->getPointer();
5879 int *tmp2=tmpb->getPointer();
5880 for(const int *i=connI;i!=connI+nbOfCells;i++)
5882 const INTERP_KERNEL::NormalizedCellType *where=std::find(orderBg,orderEnd,(INTERP_KERNEL::NormalizedCellType)conn[*i]);
5885 int pos=(int)std::distance(orderBg,where);
5887 tmp[std::distance(connI,i)]=pos;
5891 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*i]);
5892 std::ostringstream oss; oss << "MEDCouplingUMesh::getLevArrPerCellTypes : Cell #" << std::distance(connI,i);
5893 oss << " has a type " << cm.getRepr() << " not in input array of type !";
5894 throw INTERP_KERNEL::Exception(oss.str());
5897 nbPerType=tmpb.retn();
5902 * This method behaves exactly as MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec but the order is those defined in MED file spec.
5904 * \return a new object containing the old to new correspondance.
5906 * \sa MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec, MEDCouplingUMesh::sortCellsInMEDFileFrmt.
5908 DataArrayInt *MEDCouplingUMesh::getRenumArrForMEDFileFrmt() const
5910 return getRenumArrForConsecutiveCellTypesSpec(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
5914 * This method is similar to method MEDCouplingUMesh::rearrange2ConsecutiveCellTypes except that the type order is specfied by [ \a orderBg , \a orderEnd ) (as MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method) and that this method is \b const and performs \b NO permutation in \a this.
5915 * This method returns an array of size getNumberOfCells() that gives a renumber array old2New that can be used as input of MEDCouplingMesh::renumberCells.
5916 * The mesh after this call to MEDCouplingMesh::renumberCells will pass the test of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder with the same inputs.
5917 * The returned array minimizes the permutations that is to say the order of cells inside same geometric type remains the same.
5919 DataArrayInt *MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
5921 DataArrayInt *nbPerType=0;
5922 MCAuto<DataArrayInt> tmpa=getLevArrPerCellTypes(orderBg,orderEnd,nbPerType);
5923 nbPerType->decrRef();
5924 return tmpa->buildPermArrPerLevel();
5928 * This method reorganize the cells of \a this so that the cells with same geometric types are put together.
5929 * The number of cells remains unchanged after the call of this method.
5930 * This method tries to minimizes the number of needed permutations. So, this method behaves not exactly as
5931 * MEDCouplingUMesh::sortCellsInMEDFileFrmt.
5933 * \return the array giving the correspondance old to new.
5935 DataArrayInt *MEDCouplingUMesh::rearrange2ConsecutiveCellTypes()
5937 checkFullyDefined();
5939 const int *conn=_nodal_connec->begin();
5940 const int *connI=_nodal_connec_index->begin();
5941 int nbOfCells=getNumberOfCells();
5942 std::vector<INTERP_KERNEL::NormalizedCellType> types;
5943 for(const int *i=connI;i!=connI+nbOfCells && (types.size()!=_types.size());)
5944 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)conn[*i])==types.end())
5946 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5947 types.push_back(curType);
5948 for(i++;i!=connI+nbOfCells && (INTERP_KERNEL::NormalizedCellType)conn[*i]==curType;i++);
5950 DataArrayInt *ret=DataArrayInt::New();
5951 ret->alloc(nbOfCells,1);
5952 int *retPtr=ret->getPointer();
5953 std::fill(retPtr,retPtr+nbOfCells,-1);
5955 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
5957 for(const int *i=connI;i!=connI+nbOfCells;i++)
5958 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
5959 retPtr[std::distance(connI,i)]=newCellId++;
5961 renumberCells(retPtr,false);
5966 * This method splits \a this into as mush as untructured meshes that consecutive set of same type cells.
5967 * So this method has typically a sense if MEDCouplingUMesh::checkConsecutiveCellTypes has a sense.
5968 * This method makes asumption that connectivity is correctly set before calling.
5970 std::vector<MEDCouplingUMesh *> MEDCouplingUMesh::splitByType() const
5972 checkConnectivityFullyDefined();
5973 const int *conn=_nodal_connec->begin();
5974 const int *connI=_nodal_connec_index->begin();
5975 int nbOfCells=getNumberOfCells();
5976 std::vector<MEDCouplingUMesh *> ret;
5977 for(const int *i=connI;i!=connI+nbOfCells;)
5979 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5980 int beginCellId=(int)std::distance(connI,i);
5981 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
5982 int endCellId=(int)std::distance(connI,i);
5983 int sz=endCellId-beginCellId;
5984 int *cells=new int[sz];
5985 for(int j=0;j<sz;j++)
5986 cells[j]=beginCellId+j;
5987 MEDCouplingUMesh *m=(MEDCouplingUMesh *)buildPartOfMySelf(cells,cells+sz,true);
5995 * This method performs the opposite operation than those in MEDCoupling1SGTUMesh::buildUnstructured.
5996 * If \a this is a single geometric type unstructured mesh, it will be converted into a more compact data structure,
5997 * MEDCoupling1GTUMesh instance. The returned instance will aggregate the same DataArrayDouble instance of coordinates than \a this.
5999 * \return a newly allocated instance, that the caller must manage.
6000 * \throw If \a this contains more than one geometric type.
6001 * \throw If the nodal connectivity of \a this is not fully defined.
6002 * \throw If the internal data is not coherent.
6004 MEDCoupling1GTUMesh *MEDCouplingUMesh::convertIntoSingleGeoTypeMesh() const
6006 checkConnectivityFullyDefined();
6007 if(_types.size()!=1)
6008 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6009 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6010 MCAuto<MEDCoupling1GTUMesh> ret=MEDCoupling1GTUMesh::New(getName(),typ);
6011 ret->setCoords(getCoords());
6012 MEDCoupling1SGTUMesh *retC=dynamic_cast<MEDCoupling1SGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6015 MCAuto<DataArrayInt> c=convertNodalConnectivityToStaticGeoTypeMesh();
6016 retC->setNodalConnectivity(c);
6020 MEDCoupling1DGTUMesh *retD=dynamic_cast<MEDCoupling1DGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6022 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : Internal error !");
6023 DataArrayInt *c=0,*ci=0;
6024 convertNodalConnectivityToDynamicGeoTypeMesh(c,ci);
6025 MCAuto<DataArrayInt> cs(c),cis(ci);
6026 retD->setNodalConnectivity(cs,cis);
6031 DataArrayInt *MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh() const
6033 checkConnectivityFullyDefined();
6034 if(_types.size()!=1)
6035 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6036 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6037 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6040 std::ostringstream oss; oss << "MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : this contains a single geo type (" << cm.getRepr() << ") but ";
6041 oss << "this type is dynamic ! Only static geometric type is possible for that type ! call convertNodalConnectivityToDynamicGeoTypeMesh instead !";
6042 throw INTERP_KERNEL::Exception(oss.str());
6044 int nbCells=getNumberOfCells();
6046 int nbNodesPerCell=(int)cm.getNumberOfNodes();
6047 MCAuto<DataArrayInt> connOut=DataArrayInt::New(); connOut->alloc(nbCells*nbNodesPerCell,1);
6048 int *outPtr=connOut->getPointer();
6049 const int *conn=_nodal_connec->begin();
6050 const int *connI=_nodal_connec_index->begin();
6052 for(int i=0;i<nbCells;i++,connI++)
6054 if(conn[connI[0]]==typi && connI[1]-connI[0]==nbNodesPerCell)
6055 outPtr=std::copy(conn+connI[0]+1,conn+connI[1],outPtr);
6058 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 << ") !";
6059 throw INTERP_KERNEL::Exception(oss.str());
6062 return connOut.retn();
6066 * Convert the nodal connectivity of the mesh so that all the cells are of dynamic types (polygon or quadratic
6067 * polygon). This returns the corresponding new nodal connectivity in \ref numbering-indirect format.
6071 void MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh(DataArrayInt *&nodalConn, DataArrayInt *&nodalConnIndex) const
6073 static const char msg0[]="MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : nodal connectivity in this are invalid ! Call checkConsistency !";
6074 checkConnectivityFullyDefined();
6075 if(_types.size()!=1)
6076 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6077 int nbCells=getNumberOfCells(),lgth=_nodal_connec->getNumberOfTuples();
6079 throw INTERP_KERNEL::Exception(msg0);
6080 MCAuto<DataArrayInt> c(DataArrayInt::New()),ci(DataArrayInt::New());
6081 c->alloc(lgth-nbCells,1); ci->alloc(nbCells+1,1);
6082 int *cp(c->getPointer()),*cip(ci->getPointer());
6083 const int *incp(_nodal_connec->begin()),*incip(_nodal_connec_index->begin());
6085 for(int i=0;i<nbCells;i++,cip++,incip++)
6087 int strt(incip[0]+1),stop(incip[1]);//+1 to skip geo type
6088 int delta(stop-strt);
6091 if((strt>=0 && strt<lgth) && (stop>=0 && stop<=lgth))
6092 cp=std::copy(incp+strt,incp+stop,cp);
6094 throw INTERP_KERNEL::Exception(msg0);
6097 throw INTERP_KERNEL::Exception(msg0);
6098 cip[1]=cip[0]+delta;
6100 nodalConn=c.retn(); nodalConnIndex=ci.retn();
6104 * This method takes in input a vector of MEDCouplingUMesh instances lying on the same coordinates with same mesh dimensions.
6105 * Each mesh in \b ms must be sorted by type with the same order (typically using MEDCouplingUMesh::sortCellsInMEDFileFrmt).
6106 * This method is particulary useful for MED file interaction. It allows to aggregate several meshes and keeping the type sorting
6107 * and the track of the permutation by chunk of same geotype cells to retrieve it. The traditional formats old2new and new2old
6108 * are not used here to avoid the build of big permutation array.
6110 * \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
6111 * those specified in MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6112 * \param [out] szOfCellGrpOfSameType is a newly allocated DataArrayInt instance whose number of tuples is equal to the number of chunks of same geotype
6113 * in all meshes in \b ms. The accumulation of all values of this array is equal to the number of cells of returned mesh.
6114 * \param [out] idInMsOfCellGrpOfSameType is a newly allocated DataArrayInt instance having the same size than \b szOfCellGrpOfSameType. This
6115 * output array gives for each chunck of same type the corresponding mesh id in \b ms.
6116 * \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
6117 * is sorted by type following the geo cell types order of MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6119 MEDCouplingUMesh *MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& ms,
6120 DataArrayInt *&szOfCellGrpOfSameType,
6121 DataArrayInt *&idInMsOfCellGrpOfSameType)
6123 std::vector<const MEDCouplingUMesh *> ms2;
6124 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms.begin();it!=ms.end();it++)
6127 (*it)->checkConnectivityFullyDefined();
6131 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : input vector is empty !");
6132 const DataArrayDouble *refCoo=ms2[0]->getCoords();
6133 int meshDim=ms2[0]->getMeshDimension();
6134 std::vector<const MEDCouplingUMesh *> m1ssm;
6135 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmAuto;
6137 std::vector<const MEDCouplingUMesh *> m1ssmSingle;
6138 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmSingleAuto;
6140 MCAuto<DataArrayInt> ret1(DataArrayInt::New()),ret2(DataArrayInt::New());
6141 ret1->alloc(0,1); ret2->alloc(0,1);
6142 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms2.begin();it!=ms2.end();it++,rk++)
6144 if(meshDim!=(*it)->getMeshDimension())
6145 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshdims mismatch !");
6146 if(refCoo!=(*it)->getCoords())
6147 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshes are not shared by a single coordinates coords !");
6148 std::vector<MEDCouplingUMesh *> sp=(*it)->splitByType();
6149 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<const MEDCouplingUMesh *> >(m1ssm));
6150 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<MCAuto<MEDCouplingUMesh> > >(m1ssmAuto));
6151 for(std::vector<MEDCouplingUMesh *>::const_iterator it2=sp.begin();it2!=sp.end();it2++)
6153 MEDCouplingUMesh *singleCell=static_cast<MEDCouplingUMesh *>((*it2)->buildPartOfMySelf(&fake,&fake+1,true));
6154 m1ssmSingleAuto.push_back(singleCell);
6155 m1ssmSingle.push_back(singleCell);
6156 ret1->pushBackSilent((*it2)->getNumberOfCells()); ret2->pushBackSilent(rk);
6159 MCAuto<MEDCouplingUMesh> m1ssmSingle2=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmSingle);
6160 MCAuto<DataArrayInt> renum=m1ssmSingle2->sortCellsInMEDFileFrmt();
6161 std::vector<const MEDCouplingUMesh *> m1ssmfinal(m1ssm.size());
6162 for(std::size_t i=0;i<m1ssm.size();i++)
6163 m1ssmfinal[renum->getIJ(i,0)]=m1ssm[i];
6164 MCAuto<MEDCouplingUMesh> ret0=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmfinal);
6165 szOfCellGrpOfSameType=ret1->renumber(renum->begin());
6166 idInMsOfCellGrpOfSameType=ret2->renumber(renum->begin());
6171 * This method returns a newly created DataArrayInt instance.
6172 * This method retrieves cell ids in [ \a begin, \a end ) that have the type \a type.
6174 DataArrayInt *MEDCouplingUMesh::keepCellIdsByType(INTERP_KERNEL::NormalizedCellType type, const int *begin, const int *end) const
6176 checkFullyDefined();
6177 const int *conn=_nodal_connec->begin();
6178 const int *connIndex=_nodal_connec_index->begin();
6179 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(0,1);
6180 for(const int *w=begin;w!=end;w++)
6181 if((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]==type)
6182 ret->pushBackSilent(*w);
6187 * This method makes the assumption that da->getNumberOfTuples()<this->getNumberOfCells(). This method makes the assumption that ids contained in 'da'
6188 * are in [0:getNumberOfCells())
6190 DataArrayInt *MEDCouplingUMesh::convertCellArrayPerGeoType(const DataArrayInt *da) const
6192 checkFullyDefined();
6193 const int *conn=_nodal_connec->begin();
6194 const int *connI=_nodal_connec_index->begin();
6195 int nbOfCells=getNumberOfCells();
6196 std::set<INTERP_KERNEL::NormalizedCellType> types(getAllGeoTypes());
6197 int *tmp=new int[nbOfCells];
6198 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
6201 for(const int *i=connI;i!=connI+nbOfCells;i++)
6202 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
6203 tmp[std::distance(connI,i)]=j++;
6205 DataArrayInt *ret=DataArrayInt::New();
6206 ret->alloc(da->getNumberOfTuples(),da->getNumberOfComponents());
6207 ret->copyStringInfoFrom(*da);
6208 int *retPtr=ret->getPointer();
6209 const int *daPtr=da->begin();
6210 int nbOfElems=da->getNbOfElems();
6211 for(int k=0;k<nbOfElems;k++)
6212 retPtr[k]=tmp[daPtr[k]];
6218 * This method reduced number of cells of this by keeping cells whose type is different from 'type' and if type=='type'
6219 * This method \b works \b for mesh sorted by type.
6220 * cells whose ids is in 'idsPerGeoType' array.
6221 * This method conserves coords and name of mesh.
6223 MEDCouplingUMesh *MEDCouplingUMesh::keepSpecifiedCells(INTERP_KERNEL::NormalizedCellType type, const int *idsPerGeoTypeBg, const int *idsPerGeoTypeEnd) const
6225 std::vector<int> code=getDistributionOfTypes();
6226 std::size_t nOfTypesInThis=code.size()/3;
6227 int sz=0,szOfType=0;
6228 for(std::size_t i=0;i<nOfTypesInThis;i++)
6233 szOfType=code[3*i+1];
6235 for(const int *work=idsPerGeoTypeBg;work!=idsPerGeoTypeEnd;work++)
6236 if(*work<0 || *work>=szOfType)
6238 std::ostringstream oss; oss << "MEDCouplingUMesh::keepSpecifiedCells : Request on type " << type << " at place #" << std::distance(idsPerGeoTypeBg,work) << " value " << *work;
6239 oss << ". It should be in [0," << szOfType << ") !";
6240 throw INTERP_KERNEL::Exception(oss.str());
6242 MCAuto<DataArrayInt> idsTokeep=DataArrayInt::New(); idsTokeep->alloc(sz+(int)std::distance(idsPerGeoTypeBg,idsPerGeoTypeEnd),1);
6243 int *idsPtr=idsTokeep->getPointer();
6245 for(std::size_t i=0;i<nOfTypesInThis;i++)
6248 for(int j=0;j<code[3*i+1];j++)
6251 idsPtr=std::transform(idsPerGeoTypeBg,idsPerGeoTypeEnd,idsPtr,std::bind2nd(std::plus<int>(),offset));
6252 offset+=code[3*i+1];
6254 MCAuto<MEDCouplingUMesh> ret=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(idsTokeep->begin(),idsTokeep->end(),true));
6255 ret->copyTinyInfoFrom(this);
6260 * This method returns a vector of size 'this->getNumberOfCells()'.
6261 * This method retrieves for each cell in \a this if it is linear (false) or quadratic(true).
6263 std::vector<bool> MEDCouplingUMesh::getQuadraticStatus() const
6265 int ncell=getNumberOfCells();
6266 std::vector<bool> ret(ncell);
6267 const int *cI=getNodalConnectivityIndex()->begin();
6268 const int *c=getNodalConnectivity()->begin();
6269 for(int i=0;i<ncell;i++)
6271 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[i]];
6272 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6273 ret[i]=cm.isQuadratic();
6279 * Returns a newly created mesh (with ref count ==1) that contains merge of \a this and \a other.
6281 MEDCouplingMesh *MEDCouplingUMesh::mergeMyselfWith(const MEDCouplingMesh *other) const
6283 if(other->getType()!=UNSTRUCTURED)
6284 throw INTERP_KERNEL::Exception("Merge of umesh only available with umesh each other !");
6285 const MEDCouplingUMesh *otherC=static_cast<const MEDCouplingUMesh *>(other);
6286 return MergeUMeshes(this,otherC);
6290 * Returns a new DataArrayDouble holding barycenters of all cells. The barycenter is
6291 * computed by averaging coordinates of cell nodes, so this method is not a right
6292 * choice for degnerated meshes (not well oriented, cells with measure close to zero).
6293 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
6294 * this->getNumberOfCells() tuples per \a this->getSpaceDimension()
6295 * components. The caller is to delete this array using decrRef() as it is
6297 * \throw If the coordinates array is not set.
6298 * \throw If the nodal connectivity of cells is not defined.
6299 * \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
6301 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMass() const
6303 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6304 int spaceDim=getSpaceDimension();
6305 int nbOfCells=getNumberOfCells();
6306 ret->alloc(nbOfCells,spaceDim);
6307 ret->copyStringInfoFrom(*getCoords());
6308 double *ptToFill=ret->getPointer();
6309 const int *nodal=_nodal_connec->begin();
6310 const int *nodalI=_nodal_connec_index->begin();
6311 const double *coor=_coords->begin();
6312 for(int i=0;i<nbOfCells;i++)
6314 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6315 INTERP_KERNEL::computeBarycenter2<int,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[i]+1,nodalI[i+1]-nodalI[i]-1,coor,spaceDim,ptToFill);
6322 * This method computes for each cell in \a this, the location of the iso barycenter of nodes constituting
6323 * the cell. Contrary to badly named MEDCouplingUMesh::computeCellCenterOfMass method that returns the center of inertia of the
6325 * \return a newly allocated DataArrayDouble instance that the caller has to deal with. The returned
6326 * DataArrayDouble instance will have \c this->getNumberOfCells() tuples and \c this->getSpaceDimension() components.
6328 * \sa MEDCouplingUMesh::computeCellCenterOfMass
6329 * \throw If \a this is not fully defined (coordinates and connectivity)
6330 * \throw If there is presence in nodal connectivity in \a this of node ids not in [0, \c this->getNumberOfNodes() )
6332 DataArrayDouble *MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell() const
6334 checkFullyDefined();
6335 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6336 int spaceDim=getSpaceDimension();
6337 int nbOfCells=getNumberOfCells();
6338 int nbOfNodes=getNumberOfNodes();
6339 ret->alloc(nbOfCells,spaceDim);
6340 double *ptToFill=ret->getPointer();
6341 const int *nodal=_nodal_connec->begin();
6342 const int *nodalI=_nodal_connec_index->begin();
6343 const double *coor=_coords->begin();
6344 for(int i=0;i<nbOfCells;i++,ptToFill+=spaceDim)
6346 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6347 std::fill(ptToFill,ptToFill+spaceDim,0.);
6348 if(type!=INTERP_KERNEL::NORM_POLYHED)
6350 for(const int *conn=nodal+nodalI[i]+1;conn!=nodal+nodalI[i+1];conn++)
6352 if(*conn>=0 && *conn<nbOfNodes)
6353 std::transform(coor+spaceDim*conn[0],coor+spaceDim*(conn[0]+1),ptToFill,ptToFill,std::plus<double>());
6356 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of nodeId #" << *conn << " should be in [0," << nbOfNodes << ") !";
6357 throw INTERP_KERNEL::Exception(oss.str());
6360 int nbOfNodesInCell=nodalI[i+1]-nodalI[i]-1;
6361 if(nbOfNodesInCell>0)
6362 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies<double>(),1./(double)nbOfNodesInCell));
6365 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of cell with no nodes !";
6366 throw INTERP_KERNEL::Exception(oss.str());
6371 std::set<int> s(nodal+nodalI[i]+1,nodal+nodalI[i+1]);
6373 for(std::set<int>::const_iterator it=s.begin();it!=s.end();it++)
6375 if(*it>=0 && *it<nbOfNodes)
6376 std::transform(coor+spaceDim*(*it),coor+spaceDim*((*it)+1),ptToFill,ptToFill,std::plus<double>());
6379 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell polyhedron cell #" << i << " presence of nodeId #" << *it << " should be in [0," << nbOfNodes << ") !";
6380 throw INTERP_KERNEL::Exception(oss.str());
6384 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies<double>(),1./(double)s.size()));
6387 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on polyhedron cell #" << i << " there are no nodes !";
6388 throw INTERP_KERNEL::Exception(oss.str());
6396 * Returns a new DataArrayDouble holding barycenters of specified cells. The
6397 * barycenter is computed by averaging coordinates of cell nodes. The cells to treat
6398 * are specified via an array of cell ids.
6399 * \warning Validity of the specified cell ids is not checked!
6400 * Valid range is [ 0, \a this->getNumberOfCells() ).
6401 * \param [in] begin - an array of cell ids of interest.
6402 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
6403 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size ( \a
6404 * end - \a begin ) tuples per \a this->getSpaceDimension() components. The
6405 * caller is to delete this array using decrRef() as it is no more needed.
6406 * \throw If the coordinates array is not set.
6407 * \throw If the nodal connectivity of cells is not defined.
6409 * \if ENABLE_EXAMPLES
6410 * \ref cpp_mcumesh_getPartBarycenterAndOwner "Here is a C++ example".<br>
6411 * \ref py_mcumesh_getPartBarycenterAndOwner "Here is a Python example".
6414 DataArrayDouble *MEDCouplingUMesh::getPartBarycenterAndOwner(const int *begin, const int *end) const
6416 DataArrayDouble *ret=DataArrayDouble::New();
6417 int spaceDim=getSpaceDimension();
6418 int nbOfTuple=(int)std::distance(begin,end);
6419 ret->alloc(nbOfTuple,spaceDim);
6420 double *ptToFill=ret->getPointer();
6421 double *tmp=new double[spaceDim];
6422 const int *nodal=_nodal_connec->begin();
6423 const int *nodalI=_nodal_connec_index->begin();
6424 const double *coor=_coords->begin();
6425 for(const int *w=begin;w!=end;w++)
6427 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[*w]];
6428 INTERP_KERNEL::computeBarycenter2<int,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[*w]+1,nodalI[*w+1]-nodalI[*w]-1,coor,spaceDim,ptToFill);
6436 * 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".
6437 * So the returned instance will have 4 components and \c this->getNumberOfCells() tuples.
6438 * So this method expects that \a this has a spaceDimension equal to 3 and meshDimension equal to 2.
6439 * The computation of the plane equation is done using each time the 3 first nodes of 2D cells.
6440 * This method is useful to detect 2D cells in 3D space that are not coplanar.
6442 * \return DataArrayDouble * - a new instance of DataArrayDouble having 4 components and a number of tuples equal to number of cells in \a this.
6443 * \throw If spaceDim!=3 or meshDim!=2.
6444 * \throw If connectivity of \a this is invalid.
6445 * \throw If connectivity of a cell in \a this points to an invalid node.
6447 DataArrayDouble *MEDCouplingUMesh::computePlaneEquationOf3DFaces() const
6449 MCAuto<DataArrayDouble> ret(DataArrayDouble::New());
6450 int nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
6451 if(getSpaceDimension()!=3 || getMeshDimension()!=2)
6452 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computePlaneEquationOf3DFaces : This method must be applied on a mesh having meshDimension equal 2 and a spaceDimension equal to 3 !");
6453 ret->alloc(nbOfCells,4);
6454 double *retPtr(ret->getPointer());
6455 const int *nodal(_nodal_connec->begin()),*nodalI(_nodal_connec_index->begin());
6456 const double *coor(_coords->begin());
6457 for(int i=0;i<nbOfCells;i++,nodalI++,retPtr+=4)
6459 double matrix[16]={0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,0},matrix2[16];
6460 if(nodalI[1]-nodalI[0]>=3)
6462 for(int j=0;j<3;j++)
6464 int nodeId(nodal[nodalI[0]+1+j]);
6465 if(nodeId>=0 && nodeId<nbOfNodes)
6466 std::copy(coor+nodeId*3,coor+(nodeId+1)*3,matrix+4*j);
6469 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! This cell points to an invalid nodeId : " << nodeId << " !";
6470 throw INTERP_KERNEL::Exception(oss.str());
6476 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! Must be constitued by more than 3 nodes !";
6477 throw INTERP_KERNEL::Exception(oss.str());
6479 INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6480 retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6486 * This method expects as input a DataArrayDouble non nul instance 'da' that should be allocated. If not an exception is thrown.
6489 MEDCouplingUMesh *MEDCouplingUMesh::Build0DMeshFromCoords(DataArrayDouble *da)
6492 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build0DMeshFromCoords : instance of DataArrayDouble must be not null !");
6493 da->checkAllocated();
6494 std::string name(da->getName());
6495 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New(name,0));
6497 ret->setName("Mesh");
6499 int nbOfTuples(da->getNumberOfTuples());
6500 MCAuto<DataArrayInt> c(DataArrayInt::New()),cI(DataArrayInt::New());
6501 c->alloc(2*nbOfTuples,1);
6502 cI->alloc(nbOfTuples+1,1);
6503 int *cp(c->getPointer()),*cip(cI->getPointer());
6505 for(int i=0;i<nbOfTuples;i++)
6507 *cp++=INTERP_KERNEL::NORM_POINT1;
6511 ret->setConnectivity(c,cI,true);
6515 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::Build1DMeshFromCoords(DataArrayDouble *da)
6518 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build01MeshFromCoords : instance of DataArrayDouble must be not null !");
6519 da->checkAllocated();
6520 std::string name(da->getName());
6521 MCAuto<MEDCouplingUMesh> ret;
6523 MCAuto<MEDCouplingCMesh> tmp(MEDCouplingCMesh::New());
6524 MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
6525 arr->alloc(da->getNumberOfTuples());
6526 tmp->setCoordsAt(0,arr);
6527 ret=tmp->buildUnstructured();
6531 ret->setName("Mesh");
6538 * Creates a new MEDCouplingUMesh by concatenating two given meshes of the same dimension.
6539 * Cells and nodes of
6540 * the first mesh precede cells and nodes of the second mesh within the result mesh.
6541 * \param [in] mesh1 - the first mesh.
6542 * \param [in] mesh2 - the second mesh.
6543 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6544 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6545 * is no more needed.
6546 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
6547 * \throw If the coordinates array is not set in none of the meshes.
6548 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
6549 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
6551 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
6553 std::vector<const MEDCouplingUMesh *> tmp(2);
6554 tmp[0]=const_cast<MEDCouplingUMesh *>(mesh1); tmp[1]=const_cast<MEDCouplingUMesh *>(mesh2);
6555 return MergeUMeshes(tmp);
6559 * Creates a new MEDCouplingUMesh by concatenating all given meshes of the same dimension.
6560 * Cells and nodes of
6561 * the *i*-th mesh precede cells and nodes of the (*i*+1)-th mesh within the result mesh.
6562 * \param [in] a - a vector of meshes (MEDCouplingUMesh) to concatenate.
6563 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6564 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6565 * is no more needed.
6566 * \throw If \a a.size() == 0.
6567 * \throw If \a a[ *i* ] == NULL.
6568 * \throw If the coordinates array is not set in none of the meshes.
6569 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
6570 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
6572 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const std::vector<const MEDCouplingUMesh *>& a)
6574 std::size_t sz=a.size();
6576 return MergeUMeshesLL(a);
6577 for(std::size_t ii=0;ii<sz;ii++)
6580 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshes : item #" << ii << " in input array of size "<< sz << " is empty !";
6581 throw INTERP_KERNEL::Exception(oss.str());
6583 std::vector< MCAuto<MEDCouplingUMesh> > bb(sz);
6584 std::vector< const MEDCouplingUMesh * > aa(sz);
6586 for(std::size_t i=0;i<sz && spaceDim==-3;i++)
6588 const MEDCouplingUMesh *cur=a[i];
6589 const DataArrayDouble *coo=cur->getCoords();
6591 spaceDim=coo->getNumberOfComponents();
6594 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : no spaceDim specified ! unable to perform merge !");
6595 for(std::size_t i=0;i<sz;i++)
6597 bb[i]=a[i]->buildSetInstanceFromThis(spaceDim);
6600 return MergeUMeshesLL(aa);
6604 * Creates a new MEDCouplingUMesh by concatenating cells of two given meshes of same
6605 * dimension and sharing the node coordinates array.
6606 * All cells of the first mesh precede all cells of the second mesh
6607 * within the result mesh.
6608 * \param [in] mesh1 - the first mesh.
6609 * \param [in] mesh2 - the second mesh.
6610 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6611 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6612 * is no more needed.
6613 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
6614 * \throw If the meshes do not share the node coordinates array.
6615 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
6616 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
6618 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
6620 std::vector<const MEDCouplingUMesh *> tmp(2);
6621 tmp[0]=mesh1; tmp[1]=mesh2;
6622 return MergeUMeshesOnSameCoords(tmp);
6626 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
6627 * dimension and sharing the node coordinates array.
6628 * All cells of the *i*-th mesh precede all cells of the
6629 * (*i*+1)-th mesh within the result mesh.
6630 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
6631 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6632 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6633 * is no more needed.
6634 * \throw If \a a.size() == 0.
6635 * \throw If \a a[ *i* ] == NULL.
6636 * \throw If the meshes do not share the node coordinates array.
6637 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
6638 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
6640 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes)
6643 throw INTERP_KERNEL::Exception("meshes input parameter is expected to be non empty.");
6644 for(std::size_t ii=0;ii<meshes.size();ii++)
6647 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshesOnSameCoords : item #" << ii << " in input array of size "<< meshes.size() << " is empty !";
6648 throw INTERP_KERNEL::Exception(oss.str());
6650 const DataArrayDouble *coords=meshes.front()->getCoords();
6651 int meshDim=meshes.front()->getMeshDimension();
6652 std::vector<const MEDCouplingUMesh *>::const_iterator iter=meshes.begin();
6654 int meshIndexLgth=0;
6655 for(;iter!=meshes.end();iter++)
6657 if(coords!=(*iter)->getCoords())
6658 throw INTERP_KERNEL::Exception("meshes does not share the same coords ! Try using tryToShareSameCoords method !");
6659 if(meshDim!=(*iter)->getMeshDimension())
6660 throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, FuseUMeshesOnSameCoords impossible !");
6661 meshLgth+=(*iter)->getNodalConnectivityArrayLen();
6662 meshIndexLgth+=(*iter)->getNumberOfCells();
6664 MCAuto<DataArrayInt> nodal=DataArrayInt::New();
6665 nodal->alloc(meshLgth,1);
6666 int *nodalPtr=nodal->getPointer();
6667 MCAuto<DataArrayInt> nodalIndex=DataArrayInt::New();
6668 nodalIndex->alloc(meshIndexLgth+1,1);
6669 int *nodalIndexPtr=nodalIndex->getPointer();
6671 for(iter=meshes.begin();iter!=meshes.end();iter++)
6673 const int *nod=(*iter)->getNodalConnectivity()->begin();
6674 const int *index=(*iter)->getNodalConnectivityIndex()->begin();
6675 int nbOfCells=(*iter)->getNumberOfCells();
6676 int meshLgth2=(*iter)->getNodalConnectivityArrayLen();
6677 nodalPtr=std::copy(nod,nod+meshLgth2,nodalPtr);
6678 if(iter!=meshes.begin())
6679 nodalIndexPtr=std::transform(index+1,index+nbOfCells+1,nodalIndexPtr,std::bind2nd(std::plus<int>(),offset));
6681 nodalIndexPtr=std::copy(index,index+nbOfCells+1,nodalIndexPtr);
6684 MEDCouplingUMesh *ret=MEDCouplingUMesh::New();
6685 ret->setName("merge");
6686 ret->setMeshDimension(meshDim);
6687 ret->setConnectivity(nodal,nodalIndex,true);
6688 ret->setCoords(coords);
6693 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
6694 * dimension and sharing the node coordinates array. Cells of the *i*-th mesh precede
6695 * cells of the (*i*+1)-th mesh within the result mesh. Duplicates of cells are
6696 * removed from \a this mesh and arrays mapping between new and old cell ids in "Old to
6697 * New" mode are returned for each input mesh.
6698 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
6699 * \param [in] compType - specifies a cell comparison technique. For meaning of its
6700 * valid values [0,1,2], see zipConnectivityTraducer().
6701 * \param [in,out] corr - an array of DataArrayInt, of the same size as \a
6702 * meshes. The *i*-th array describes cell ids mapping for \a meshes[ *i* ]
6703 * mesh. The caller is to delete each of the arrays using decrRef() as it is
6705 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6706 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6707 * is no more needed.
6708 * \throw If \a meshes.size() == 0.
6709 * \throw If \a meshes[ *i* ] == NULL.
6710 * \throw If the meshes do not share the node coordinates array.
6711 * \throw If \a meshes[ *i* ]->getMeshDimension() < 0.
6712 * \throw If the \a meshes are of different dimension (getMeshDimension()).
6713 * \throw If the nodal connectivity of cells of any of \a meshes is not defined.
6714 * \throw If the nodal connectivity any of \a meshes includes an invalid id.
6716 MEDCouplingUMesh *MEDCouplingUMesh::FuseUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes, int compType, std::vector<DataArrayInt *>& corr)
6718 //All checks are delegated to MergeUMeshesOnSameCoords
6719 MCAuto<MEDCouplingUMesh> ret=MergeUMeshesOnSameCoords(meshes);
6720 MCAuto<DataArrayInt> o2n=ret->zipConnectivityTraducer(compType);
6721 corr.resize(meshes.size());
6722 std::size_t nbOfMeshes=meshes.size();
6724 const int *o2nPtr=o2n->begin();
6725 for(std::size_t i=0;i<nbOfMeshes;i++)
6727 DataArrayInt *tmp=DataArrayInt::New();
6728 int curNbOfCells=meshes[i]->getNumberOfCells();
6729 tmp->alloc(curNbOfCells,1);
6730 std::copy(o2nPtr+offset,o2nPtr+offset+curNbOfCells,tmp->getPointer());
6731 offset+=curNbOfCells;
6732 tmp->setName(meshes[i]->getName());
6739 * Makes all given meshes share the nodal connectivity array. The common connectivity
6740 * array is created by concatenating the connectivity arrays of all given meshes. All
6741 * the given meshes must be of the same space dimension but dimension of cells **can
6742 * differ**. This method is particulary useful in MEDLoader context to build a \ref
6743 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
6744 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
6745 * \param [in,out] meshes - a vector of meshes to update.
6746 * \throw If any of \a meshes is NULL.
6747 * \throw If the coordinates array is not set in any of \a meshes.
6748 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
6749 * \throw If \a meshes are of different space dimension.
6751 void MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords(const std::vector<MEDCouplingUMesh *>& meshes)
6753 std::size_t sz=meshes.size();
6756 std::vector< const DataArrayDouble * > coords(meshes.size());
6757 std::vector< const DataArrayDouble * >::iterator it2=coords.begin();
6758 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++,it2++)
6762 (*it)->checkConnectivityFullyDefined();
6763 const DataArrayDouble *coo=(*it)->getCoords();
6768 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
6769 oss << " has no coordinate array defined !";
6770 throw INTERP_KERNEL::Exception(oss.str());
6775 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
6776 oss << " is null !";
6777 throw INTERP_KERNEL::Exception(oss.str());
6780 MCAuto<DataArrayDouble> res=DataArrayDouble::Aggregate(coords);
6781 std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();
6782 int offset=(*it)->getNumberOfNodes();
6783 (*it++)->setCoords(res);
6784 for(;it!=meshes.end();it++)
6786 int oldNumberOfNodes=(*it)->getNumberOfNodes();
6787 (*it)->setCoords(res);
6788 (*it)->shiftNodeNumbersInConn(offset);
6789 offset+=oldNumberOfNodes;
6794 * Merges nodes coincident with a given precision within all given meshes that share
6795 * the nodal connectivity array. The given meshes **can be of different** mesh
6796 * dimension. This method is particulary useful in MEDLoader context to build a \ref
6797 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
6798 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
6799 * \param [in,out] meshes - a vector of meshes to update.
6800 * \param [in] eps - the precision used to detect coincident nodes (infinite norm).
6801 * \throw If any of \a meshes is NULL.
6802 * \throw If the \a meshes do not share the same node coordinates array.
6803 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
6805 void MEDCouplingUMesh::MergeNodesOnUMeshesSharingSameCoords(const std::vector<MEDCouplingUMesh *>& meshes, double eps)
6809 std::set<const DataArrayDouble *> s;
6810 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
6813 s.insert((*it)->getCoords());
6816 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 !";
6817 throw INTERP_KERNEL::Exception(oss.str());
6822 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 !";
6823 throw INTERP_KERNEL::Exception(oss.str());
6825 const DataArrayDouble *coo=*(s.begin());
6829 DataArrayInt *comm,*commI;
6830 coo->findCommonTuples(eps,-1,comm,commI);
6831 MCAuto<DataArrayInt> tmp1(comm),tmp2(commI);
6832 int oldNbOfNodes=coo->getNumberOfTuples();
6834 MCAuto<DataArrayInt> o2n=DataArrayInt::ConvertIndexArrayToO2N(oldNbOfNodes,comm->begin(),commI->begin(),commI->end(),newNbOfNodes);
6835 if(oldNbOfNodes==newNbOfNodes)
6837 MCAuto<DataArrayDouble> newCoords=coo->renumberAndReduce(o2n->begin(),newNbOfNodes);
6838 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
6840 (*it)->renumberNodesInConn(o2n->begin());
6841 (*it)->setCoords(newCoords);
6847 * This static operates only for coords in 3D. The polygon is specfied by its connectivity nodes in [ \a begin , \a end ).
6849 bool MEDCouplingUMesh::IsPolygonWellOriented(bool isQuadratic, const double *vec, const int *begin, const int *end, const double *coords)
6852 double v[3]={0.,0.,0.};
6853 std::size_t sz=std::distance(begin,end);
6858 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];
6859 v[1]+=coords[3*begin[i]+2]*coords[3*begin[(i+1)%sz]]-coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+2];
6860 v[2]+=coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+1]-coords[3*begin[i]+1]*coords[3*begin[(i+1)%sz]];
6862 double ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
6864 // Try using quadratic points if standard points are degenerated (for example a QPOLYG with two
6865 // SEG3 forming a circle):
6866 if (fabs(ret) < INTERP_KERNEL::DEFAULT_ABS_TOL && isQuadratic)
6868 v[0] = 0.0; v[1] = 0.0; v[2] = 0.0;
6869 for(std::size_t j=0;j<sz;j++)
6871 if (j%2) // current point i is quadratic, next point i+1 is standard
6874 ip1 = (j+1)%sz; // ip1 = "i+1"
6876 else // current point i is standard, next point i+1 is quadratic
6881 v[0]+=coords[3*begin[i]+1]*coords[3*begin[ip1]+2]-coords[3*begin[i]+2]*coords[3*begin[ip1]+1];
6882 v[1]+=coords[3*begin[i]+2]*coords[3*begin[ip1]]-coords[3*begin[i]]*coords[3*begin[ip1]+2];
6883 v[2]+=coords[3*begin[i]]*coords[3*begin[ip1]+1]-coords[3*begin[i]+1]*coords[3*begin[ip1]];
6885 ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
6891 * The polyhedron is specfied by its connectivity nodes in [ \a begin , \a end ).
6893 bool MEDCouplingUMesh::IsPolyhedronWellOriented(const int *begin, const int *end, const double *coords)
6895 std::vector<std::pair<int,int> > edges;
6896 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
6897 const int *bgFace=begin;
6898 for(std::size_t i=0;i<nbOfFaces;i++)
6900 const int *endFace=std::find(bgFace+1,end,-1);
6901 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
6902 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
6904 std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
6905 if(std::find(edges.begin(),edges.end(),p1)!=edges.end())
6907 edges.push_back(p1);
6911 return INTERP_KERNEL::calculateVolumeForPolyh2<int,INTERP_KERNEL::ALL_C_MODE>(begin,(int)std::distance(begin,end),coords)>-EPS_FOR_POLYH_ORIENTATION;
6915 * The 3D extruded static cell (PENTA6,HEXA8,HEXAGP12...) its connectivity nodes in [ \a begin , \a end ).
6917 bool MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented(const int *begin, const int *end, const double *coords)
6919 double vec0[3],vec1[3];
6920 std::size_t sz=std::distance(begin,end);
6922 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented : the length of nodal connectivity of extruded cell is not even !");
6923 int nbOfNodes=(int)sz/2;
6924 INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(begin,nbOfNodes,coords,vec0);
6925 const double *pt0=coords+3*begin[0];
6926 const double *pt1=coords+3*begin[nbOfNodes];
6927 vec1[0]=pt1[0]-pt0[0]; vec1[1]=pt1[1]-pt0[1]; vec1[2]=pt1[2]-pt0[2];
6928 return (vec0[0]*vec1[0]+vec0[1]*vec1[1]+vec0[2]*vec1[2])<0.;
6931 void MEDCouplingUMesh::CorrectExtrudedStaticCell(int *begin, int *end)
6933 std::size_t sz=std::distance(begin,end);
6934 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz];
6935 std::size_t nbOfNodes(sz/2);
6936 std::copy(begin,end,(int *)tmp);
6937 for(std::size_t j=1;j<nbOfNodes;j++)
6939 begin[j]=tmp[nbOfNodes-j];
6940 begin[j+nbOfNodes]=tmp[nbOfNodes+nbOfNodes-j];
6944 bool MEDCouplingUMesh::IsTetra4WellOriented(const int *begin, const int *end, const double *coords)
6946 std::size_t sz=std::distance(begin,end);
6948 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsTetra4WellOriented : Tetra4 cell with not 4 nodes ! Call checkConsistency !");
6949 double vec0[3],vec1[3];
6950 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[1],*pt2=coords+3*begin[2],*pt3=coords+3*begin[3];
6951 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];
6952 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;
6955 bool MEDCouplingUMesh::IsPyra5WellOriented(const int *begin, const int *end, const double *coords)
6957 std::size_t sz=std::distance(begin,end);
6959 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsPyra5WellOriented : Pyra5 cell with not 5 nodes ! Call checkConsistency !");
6961 INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(begin,4,coords,vec0);
6962 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[4];
6963 return (vec0[0]*(pt1[0]-pt0[0])+vec0[1]*(pt1[1]-pt0[1])+vec0[2]*(pt1[2]-pt0[2]))<0.;
6967 * 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 )
6968 * 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
6971 * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not.
6972 * \param [in] coords the coordinates with nb of components exactly equal to 3
6973 * \param [in] begin begin of the nodal connectivity (geometric type included) of a single polyhedron cell
6974 * \param [in] end end of nodal connectivity of a single polyhedron cell (excluded)
6975 * \param [out] res the result is put at the end of the vector without any alteration of the data.
6977 void MEDCouplingUMesh::SimplifyPolyhedronCell(double eps, const DataArrayDouble *coords, const int *begin, const int *end, DataArrayInt *res)
6979 int nbFaces=std::count(begin+1,end,-1)+1;
6980 MCAuto<DataArrayDouble> v=DataArrayDouble::New(); v->alloc(nbFaces,3);
6981 double *vPtr=v->getPointer();
6982 MCAuto<DataArrayDouble> p=DataArrayDouble::New(); p->alloc(nbFaces,1);
6983 double *pPtr=p->getPointer();
6984 const int *stFaceConn=begin+1;
6985 for(int i=0;i<nbFaces;i++,vPtr+=3,pPtr++)
6987 const int *endFaceConn=std::find(stFaceConn,end,-1);
6988 ComputeVecAndPtOfFace(eps,coords->begin(),stFaceConn,endFaceConn,vPtr,pPtr);
6989 stFaceConn=endFaceConn+1;
6991 pPtr=p->getPointer(); vPtr=v->getPointer();
6992 DataArrayInt *comm1=0,*commI1=0;
6993 v->findCommonTuples(eps,-1,comm1,commI1);
6994 MCAuto<DataArrayInt> comm1Auto(comm1),commI1Auto(commI1);
6995 const int *comm1Ptr=comm1->begin();
6996 const int *commI1Ptr=commI1->begin();
6997 int nbOfGrps1=commI1Auto->getNumberOfTuples()-1;
6998 res->pushBackSilent((int)INTERP_KERNEL::NORM_POLYHED);
7000 MCAuto<MEDCouplingUMesh> mm=MEDCouplingUMesh::New("",3);
7001 mm->setCoords(const_cast<DataArrayDouble *>(coords)); mm->allocateCells(1); mm->insertNextCell(INTERP_KERNEL::NORM_POLYHED,(int)std::distance(begin+1,end),begin+1);
7002 mm->finishInsertingCells();
7004 for(int i=0;i<nbOfGrps1;i++)
7006 int vecId=comm1Ptr[commI1Ptr[i]];
7007 MCAuto<DataArrayDouble> tmpgrp2=p->selectByTupleId(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7008 DataArrayInt *comm2=0,*commI2=0;
7009 tmpgrp2->findCommonTuples(eps,-1,comm2,commI2);
7010 MCAuto<DataArrayInt> comm2Auto(comm2),commI2Auto(commI2);
7011 const int *comm2Ptr=comm2->begin();
7012 const int *commI2Ptr=commI2->begin();
7013 int nbOfGrps2=commI2Auto->getNumberOfTuples()-1;
7014 for(int j=0;j<nbOfGrps2;j++)
7016 if(commI2Ptr[j+1]-commI2Ptr[j]<=1)
7018 res->insertAtTheEnd(begin,end);
7019 res->pushBackSilent(-1);
7023 int pointId=comm1Ptr[commI1Ptr[i]+comm2Ptr[commI2Ptr[j]]];
7024 MCAuto<DataArrayInt> ids2=comm2->selectByTupleIdSafeSlice(commI2Ptr[j],commI2Ptr[j+1],1);
7025 ids2->transformWithIndArr(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7026 DataArrayInt *tmp0=DataArrayInt::New(),*tmp1=DataArrayInt::New(),*tmp2=DataArrayInt::New(),*tmp3=DataArrayInt::New();
7027 MCAuto<MEDCouplingUMesh> mm2=mm->buildDescendingConnectivity(tmp0,tmp1,tmp2,tmp3); tmp0->decrRef(); tmp1->decrRef(); tmp2->decrRef(); tmp3->decrRef();
7028 MCAuto<MEDCouplingUMesh> mm3=static_cast<MEDCouplingUMesh *>(mm2->buildPartOfMySelf(ids2->begin(),ids2->end(),true));
7029 MCAuto<DataArrayInt> idsNodeTmp=mm3->zipCoordsTraducer();
7030 MCAuto<DataArrayInt> idsNode=idsNodeTmp->invertArrayO2N2N2O(mm3->getNumberOfNodes());
7031 const int *idsNodePtr=idsNode->begin();
7032 double center[3]; center[0]=pPtr[pointId]*vPtr[3*vecId]; center[1]=pPtr[pointId]*vPtr[3*vecId+1]; center[2]=pPtr[pointId]*vPtr[3*vecId+2];
7033 double vec[3]; vec[0]=vPtr[3*vecId+1]; vec[1]=-vPtr[3*vecId]; vec[2]=0.;
7034 double norm=vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2];
7035 if(std::abs(norm)>eps)
7037 double angle=INTERP_KERNEL::EdgeArcCircle::SafeAsin(norm);
7038 mm3->rotate(center,vec,angle);
7040 mm3->changeSpaceDimension(2);
7041 MCAuto<MEDCouplingUMesh> mm4=mm3->buildSpreadZonesWithPoly();
7042 const int *conn4=mm4->getNodalConnectivity()->begin();
7043 const int *connI4=mm4->getNodalConnectivityIndex()->begin();
7044 int nbOfCells=mm4->getNumberOfCells();
7045 for(int k=0;k<nbOfCells;k++)
7048 for(const int *work=conn4+connI4[k]+1;work!=conn4+connI4[k+1];work++,l++)
7049 res->pushBackSilent(idsNodePtr[*work]);
7050 res->pushBackSilent(-1);
7055 res->popBackSilent();
7059 * 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
7060 * through origin. The plane is defined by its nodal connectivity [ \b begin, \b end ).
7062 * \param [in] eps below that value the dot product of 2 vectors is considered as colinears
7063 * \param [in] coords coordinates expected to have 3 components.
7064 * \param [in] begin start of the nodal connectivity of the face.
7065 * \param [in] end end of the nodal connectivity (excluded) of the face.
7066 * \param [out] v the normalized vector of size 3
7067 * \param [out] p the pos of plane
7069 void MEDCouplingUMesh::ComputeVecAndPtOfFace(double eps, const double *coords, const int *begin, const int *end, double *v, double *p)
7071 std::size_t nbPoints=std::distance(begin,end);
7073 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeVecAndPtOfFace : < of 3 points in face ! not able to find a plane on that face !");
7074 double vec[3]={0.,0.,0.};
7076 bool refFound=false;
7077 for(;j<nbPoints-1 && !refFound;j++)
7079 vec[0]=coords[3*begin[j+1]]-coords[3*begin[j]];
7080 vec[1]=coords[3*begin[j+1]+1]-coords[3*begin[j]+1];
7081 vec[2]=coords[3*begin[j+1]+2]-coords[3*begin[j]+2];
7082 double norm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
7086 vec[0]/=norm; vec[1]/=norm; vec[2]/=norm;
7089 for(std::size_t i=j;i<nbPoints-1;i++)
7092 curVec[0]=coords[3*begin[i+1]]-coords[3*begin[i]];
7093 curVec[1]=coords[3*begin[i+1]+1]-coords[3*begin[i]+1];
7094 curVec[2]=coords[3*begin[i+1]+2]-coords[3*begin[i]+2];
7095 double norm=sqrt(curVec[0]*curVec[0]+curVec[1]*curVec[1]+curVec[2]*curVec[2]);
7098 curVec[0]/=norm; curVec[1]/=norm; curVec[2]/=norm;
7099 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];
7100 norm=sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
7103 v[0]/=norm; v[1]/=norm; v[2]/=norm;
7104 *p=v[0]*coords[3*begin[i]]+v[1]*coords[3*begin[i]+1]+v[2]*coords[3*begin[i]+2];
7108 throw INTERP_KERNEL::Exception("Not able to find a normal vector of that 3D face !");
7112 * This method tries to obtain a well oriented polyhedron.
7113 * If the algorithm fails, an exception will be thrown.
7115 void MEDCouplingUMesh::TryToCorrectPolyhedronOrientation(int *begin, int *end, const double *coords)
7117 std::list< std::pair<int,int> > edgesOK,edgesFinished;
7118 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
7119 std::vector<bool> isPerm(nbOfFaces,false);//field on faces False: I don't know, True : oriented
7121 int *bgFace=begin,*endFace=std::find(begin+1,end,-1);
7122 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
7123 for(std::size_t l=0;l<nbOfEdgesInFace;l++) { std::pair<int,int> p1(bgFace[l],bgFace[(l+1)%nbOfEdgesInFace]); edgesOK.push_back(p1); }
7125 while(std::find(isPerm.begin(),isPerm.end(),false)!=isPerm.end())
7128 std::size_t smthChanged=0;
7129 for(std::size_t i=0;i<nbOfFaces;i++)
7131 endFace=std::find(bgFace+1,end,-1);
7132 nbOfEdgesInFace=std::distance(bgFace,endFace);
7136 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7138 std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7139 std::pair<int,int> p2(p1.second,p1.first);
7140 bool b1=std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end();
7141 bool b2=std::find(edgesOK.begin(),edgesOK.end(),p2)!=edgesOK.end();
7142 if(b1 || b2) { b=b2; isPerm[i]=true; smthChanged++; break; }
7147 std::reverse(bgFace+1,endFace);
7148 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7150 std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7151 std::pair<int,int> p2(p1.second,p1.first);
7152 if(std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end())
7153 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7154 if(std::find(edgesFinished.begin(),edgesFinished.end(),p1)!=edgesFinished.end() || std::find(edgesFinished.begin(),edgesFinished.end(),p2)!=edgesFinished.end())
7155 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7156 std::list< std::pair<int,int> >::iterator it=std::find(edgesOK.begin(),edgesOK.end(),p2);
7157 if(it!=edgesOK.end())
7160 edgesFinished.push_back(p1);
7163 edgesOK.push_back(p1);
7170 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired !"); }
7172 if(!edgesOK.empty())
7173 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired : Some edges are shared only once !"); }
7174 if(INTERP_KERNEL::calculateVolumeForPolyh2<int,INTERP_KERNEL::ALL_C_MODE>(begin,(int)std::distance(begin,end),coords)<-EPS_FOR_POLYH_ORIENTATION)
7175 {//not lucky ! The first face was not correctly oriented : reorient all faces...
7177 for(std::size_t i=0;i<nbOfFaces;i++)
7179 endFace=std::find(bgFace+1,end,-1);
7180 std::reverse(bgFace+1,endFace);
7188 * This method makes the assumption spacedimension == meshdimension == 2.
7189 * This method works only for linear cells.
7191 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYGON in pos#0)
7193 DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMesh() const
7195 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
7196 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : meshdimension, spacedimension must be equal to 2 !");
7197 MCAuto<MEDCouplingUMesh> skin(computeSkin());
7198 int oldNbOfNodes(skin->getNumberOfNodes());
7199 MCAuto<DataArrayInt> o2n(skin->zipCoordsTraducer());
7200 int nbOfNodesExpected(skin->getNumberOfNodes());
7201 MCAuto<DataArrayInt> n2o(o2n->invertArrayO2N2N2O(oldNbOfNodes));
7202 int nbCells(skin->getNumberOfCells());
7203 if(nbCells==nbOfNodesExpected)
7204 return buildUnionOf2DMeshLinear(skin,n2o);
7205 else if(2*nbCells==nbOfNodesExpected)
7206 return buildUnionOf2DMeshQuadratic(skin,n2o);
7208 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : the mesh 2D in input appears to be not in a single part of a 2D mesh !");
7212 * This method makes the assumption spacedimension == meshdimension == 3.
7213 * This method works only for linear cells.
7215 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYHED in pos#0)
7217 DataArrayInt *MEDCouplingUMesh::buildUnionOf3DMesh() const
7219 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
7220 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf3DMesh : meshdimension, spacedimension must be equal to 2 !");
7221 MCAuto<MEDCouplingUMesh> m=computeSkin();
7222 const int *conn=m->getNodalConnectivity()->begin();
7223 const int *connI=m->getNodalConnectivityIndex()->begin();
7224 int nbOfCells=m->getNumberOfCells();
7225 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(m->getNodalConnectivity()->getNumberOfTuples(),1);
7226 int *work=ret->getPointer(); *work++=INTERP_KERNEL::NORM_POLYHED;
7229 work=std::copy(conn+connI[0]+1,conn+connI[1],work);
7230 for(int i=1;i<nbOfCells;i++)
7233 work=std::copy(conn+connI[i]+1,conn+connI[i+1],work);
7239 * \brief Creates a graph of cell neighbors
7240 * \return MEDCouplingSkyLineArray * - an sky line array the user should delete.
7241 * In the sky line array, graph arcs are stored in terms of (index,value) notation.
7243 * - index: 0 3 5 6 6
7244 * - value: 1 2 3 2 3 3
7245 * means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7246 * Arcs are not doubled but reflexive (1,1) arcs are present for each cell
7248 MEDCouplingSkyLineArray* MEDCouplingUMesh::generateGraph() const
7250 checkConnectivityFullyDefined();
7252 int meshDim = this->getMeshDimension();
7253 MEDCoupling::DataArrayInt* indexr=MEDCoupling::DataArrayInt::New();
7254 MEDCoupling::DataArrayInt* revConn=MEDCoupling::DataArrayInt::New();
7255 this->getReverseNodalConnectivity(revConn,indexr);
7256 const int* indexr_ptr=indexr->begin();
7257 const int* revConn_ptr=revConn->begin();
7259 const MEDCoupling::DataArrayInt* index;
7260 const MEDCoupling::DataArrayInt* conn;
7261 conn=this->getNodalConnectivity(); // it includes a type as the 1st element!!!
7262 index=this->getNodalConnectivityIndex();
7263 int nbCells=this->getNumberOfCells();
7264 const int* index_ptr=index->begin();
7265 const int* conn_ptr=conn->begin();
7267 //creating graph arcs (cell to cell relations)
7268 //arcs are stored in terms of (index,value) notation
7271 // means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7272 // in present version arcs are not doubled but reflexive (1,1) arcs are present for each cell
7274 //warning here one node have less than or equal effective number of cell with it
7275 //but cell could have more than effective nodes
7276 //because other equals nodes in other domain (with other global inode)
7277 std::vector <int> cell2cell_index(nbCells+1,0);
7278 std::vector <int> cell2cell;
7279 cell2cell.reserve(3*nbCells);
7281 for (int icell=0; icell<nbCells;icell++)
7283 std::map<int,int > counter;
7284 for (int iconn=index_ptr[icell]+1; iconn<index_ptr[icell+1];iconn++)
7286 int inode=conn_ptr[iconn];
7287 for (int iconnr=indexr_ptr[inode]; iconnr<indexr_ptr[inode+1];iconnr++)
7289 int icell2=revConn_ptr[iconnr];
7290 std::map<int,int>::iterator iter=counter.find(icell2);
7291 if (iter!=counter.end()) (iter->second)++;
7292 else counter.insert(std::make_pair(icell2,1));
7295 for (std::map<int,int>::const_iterator iter=counter.begin();
7296 iter!=counter.end(); iter++)
7297 if (iter->second >= meshDim)
7299 cell2cell_index[icell+1]++;
7300 cell2cell.push_back(iter->first);
7305 cell2cell_index[0]=0;
7306 for (int icell=0; icell<nbCells;icell++)
7307 cell2cell_index[icell+1]=cell2cell_index[icell]+cell2cell_index[icell+1];
7309 //filling up index and value to create skylinearray structure
7310 MEDCouplingSkyLineArray * array(MEDCouplingSkyLineArray::New(cell2cell_index,cell2cell));
7315 void MEDCouplingUMesh::writeVTKLL(std::ostream& ofs, const std::string& cellData, const std::string& pointData, DataArrayByte *byteData) const
7317 int nbOfCells=getNumberOfCells();
7319 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::writeVTK : the unstructured mesh has no cells !");
7320 ofs << " <" << getVTKDataSetType() << ">\n";
7321 ofs << " <Piece NumberOfPoints=\"" << getNumberOfNodes() << "\" NumberOfCells=\"" << nbOfCells << "\">\n";
7322 ofs << " <PointData>\n" << pointData << std::endl;
7323 ofs << " </PointData>\n";
7324 ofs << " <CellData>\n" << cellData << std::endl;
7325 ofs << " </CellData>\n";
7326 ofs << " <Points>\n";
7327 if(getSpaceDimension()==3)
7328 _coords->writeVTK(ofs,8,"Points",byteData);
7331 MCAuto<DataArrayDouble> coo=_coords->changeNbOfComponents(3,0.);
7332 coo->writeVTK(ofs,8,"Points",byteData);
7334 ofs << " </Points>\n";
7335 ofs << " <Cells>\n";
7336 const int *cPtr=_nodal_connec->begin();
7337 const int *cIPtr=_nodal_connec_index->begin();
7338 MCAuto<DataArrayInt> faceoffsets=DataArrayInt::New(); faceoffsets->alloc(nbOfCells,1);
7339 MCAuto<DataArrayInt> types=DataArrayInt::New(); types->alloc(nbOfCells,1);
7340 MCAuto<DataArrayInt> offsets=DataArrayInt::New(); offsets->alloc(nbOfCells,1);
7341 MCAuto<DataArrayInt> connectivity=DataArrayInt::New(); connectivity->alloc(_nodal_connec->getNumberOfTuples()-nbOfCells,1);
7342 int *w1=faceoffsets->getPointer(),*w2=types->getPointer(),*w3=offsets->getPointer(),*w4=connectivity->getPointer();
7343 int szFaceOffsets=0,szConn=0;
7344 for(int i=0;i<nbOfCells;i++,w1++,w2++,w3++)
7347 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]!=INTERP_KERNEL::NORM_POLYHED)
7350 *w3=szConn+cIPtr[i+1]-cIPtr[i]-1; szConn+=cIPtr[i+1]-cIPtr[i]-1;
7351 w4=std::copy(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],w4);
7355 int deltaFaceOffset=cIPtr[i+1]-cIPtr[i]+1;
7356 *w1=szFaceOffsets+deltaFaceOffset; szFaceOffsets+=deltaFaceOffset;
7357 std::set<int> c(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1]); c.erase(-1);
7358 *w3=szConn+(int)c.size(); szConn+=(int)c.size();
7359 w4=std::copy(c.begin(),c.end(),w4);
7362 types->transformWithIndArr(MEDCOUPLING2VTKTYPETRADUCER,MEDCOUPLING2VTKTYPETRADUCER+INTERP_KERNEL::NORM_MAXTYPE+1);
7363 types->writeVTK(ofs,8,"UInt8","types",byteData);
7364 offsets->writeVTK(ofs,8,"Int32","offsets",byteData);
7365 if(szFaceOffsets!=0)
7366 {//presence of Polyhedra
7367 connectivity->reAlloc(szConn);
7368 faceoffsets->writeVTK(ofs,8,"Int32","faceoffsets",byteData);
7369 MCAuto<DataArrayInt> faces=DataArrayInt::New(); faces->alloc(szFaceOffsets,1);
7370 w1=faces->getPointer();
7371 for(int i=0;i<nbOfCells;i++)
7372 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]==INTERP_KERNEL::NORM_POLYHED)
7374 int nbFaces=std::count(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],-1)+1;
7376 const int *w6=cPtr+cIPtr[i]+1,*w5=0;
7377 for(int j=0;j<nbFaces;j++)
7379 w5=std::find(w6,cPtr+cIPtr[i+1],-1);
7380 *w1++=(int)std::distance(w6,w5);
7381 w1=std::copy(w6,w5,w1);
7385 faces->writeVTK(ofs,8,"Int32","faces",byteData);
7387 connectivity->writeVTK(ofs,8,"Int32","connectivity",byteData);
7388 ofs << " </Cells>\n";
7389 ofs << " </Piece>\n";
7390 ofs << " </" << getVTKDataSetType() << ">\n";
7393 void MEDCouplingUMesh::reprQuickOverview(std::ostream& stream) const
7395 stream << "MEDCouplingUMesh C++ instance at " << this << ". Name : \"" << getName() << "\".";
7397 { stream << " Not set !"; return ; }
7398 stream << " Mesh dimension : " << _mesh_dim << ".";
7402 { stream << " No coordinates set !"; return ; }
7403 if(!_coords->isAllocated())
7404 { stream << " Coordinates set but not allocated !"; return ; }
7405 stream << " Space dimension : " << _coords->getNumberOfComponents() << "." << std::endl;
7406 stream << "Number of nodes : " << _coords->getNumberOfTuples() << ".";
7407 if(!_nodal_connec_index)
7408 { stream << std::endl << "Nodal connectivity NOT set !"; return ; }
7409 if(!_nodal_connec_index->isAllocated())
7410 { stream << std::endl << "Nodal connectivity set but not allocated !"; return ; }
7411 int lgth=_nodal_connec_index->getNumberOfTuples();
7412 int cpt=_nodal_connec_index->getNumberOfComponents();
7413 if(cpt!=1 || lgth<1)
7415 stream << std::endl << "Number of cells : " << lgth-1 << ".";
7418 std::string MEDCouplingUMesh::getVTKDataSetType() const
7420 return std::string("UnstructuredGrid");
7423 std::string MEDCouplingUMesh::getVTKFileExtension() const
7425 return std::string("vtu");
7431 * Provides a renumbering of the cells of this (which has to be a piecewise connected 1D line), so that
7432 * the segments of the line are indexed in consecutive order (i.e. cells \a i and \a i+1 are neighbors).
7433 * This doesn't modify the mesh. This method only works using nodal connectivity consideration. Coordinates of nodes are ignored here.
7434 * The caller is to deal with the resulting DataArrayInt.
7435 * \throw If the coordinate array is not set.
7436 * \throw If the nodal connectivity of the cells is not defined.
7437 * \throw If m1 is not a mesh of dimension 2, or m1 is not a mesh of dimension 1
7438 * \throw If m2 is not a (piecewise) line (i.e. if a point has more than 2 adjacent segments)
7440 * \sa DataArrayInt::sortEachPairToMakeALinkedList
7442 DataArrayInt *MEDCouplingUMesh::orderConsecutiveCells1D() const
7444 checkFullyDefined();
7445 if(getMeshDimension()!=1)
7446 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D works on unstructured mesh with meshdim = 1 !");
7448 // Check that this is a line (and not a more complex 1D mesh) - each point is used at most by 2 segments:
7449 MCAuto<DataArrayInt> _d(DataArrayInt::New()),_dI(DataArrayInt::New());
7450 MCAuto<DataArrayInt> _rD(DataArrayInt::New()),_rDI(DataArrayInt::New());
7451 MCAuto<MEDCouplingUMesh> m_points(buildDescendingConnectivity(_d, _dI, _rD, _rDI));
7452 const int *d(_d->begin()), *dI(_dI->begin());
7453 const int *rD(_rD->begin()), *rDI(_rDI->begin());
7454 MCAuto<DataArrayInt> _dsi(_rDI->deltaShiftIndex());
7455 const int * dsi(_dsi->begin());
7456 MCAuto<DataArrayInt> dsii = _dsi->findIdsNotInRange(0,3);
7458 if (dsii->getNumberOfTuples())
7459 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D only work with a mesh being a (piecewise) connected line!");
7461 int nc(getNumberOfCells());
7462 MCAuto<DataArrayInt> result(DataArrayInt::New());
7463 result->alloc(nc,1);
7465 // set of edges not used so far
7466 std::set<int> edgeSet;
7467 for (int i=0; i<nc; edgeSet.insert(i), i++);
7471 // while we have points with only one neighbor segments
7474 std::list<int> linePiece;
7475 // fills a list of consecutive segment linked to startSeg. This can go forward or backward.
7476 for (int direction=0;direction<2;direction++) // direction=0 --> forward, direction=1 --> backward
7478 // Fill the list forward (resp. backward) from the start segment:
7479 int activeSeg = startSeg;
7480 int prevPointId = -20;
7482 while (!edgeSet.empty())
7484 if (!(direction == 1 && prevPointId==-20)) // prevent adding twice startSeg
7487 linePiece.push_back(activeSeg);
7489 linePiece.push_front(activeSeg);
7490 edgeSet.erase(activeSeg);
7493 int ptId1 = d[dI[activeSeg]], ptId2 = d[dI[activeSeg]+1];
7494 ptId = direction ? (ptId1 == prevPointId ? ptId2 : ptId1) : (ptId2 == prevPointId ? ptId1 : ptId2);
7495 if (dsi[ptId] == 1) // hitting the end of the line
7498 int seg1 = rD[rDI[ptId]], seg2 = rD[rDI[ptId]+1];
7499 activeSeg = (seg1 == activeSeg) ? seg2 : seg1;
7502 // Done, save final piece into DA:
7503 std::copy(linePiece.begin(), linePiece.end(), result->getPointer()+newIdx);
7504 newIdx += linePiece.size();
7506 // identify next valid start segment (one which is not consumed)
7507 if(!edgeSet.empty())
7508 startSeg = *(edgeSet.begin());
7510 while (!edgeSet.empty());
7511 return result.retn();
7515 * This method split some of edges of 2D cells in \a this. The edges to be split are specified in \a subNodesInSeg
7516 * and in \a subNodesInSegI using \ref numbering-indirect storage mode.
7517 * To do the work this method can optionally needs information about middle of subedges for quadratic cases if
7518 * a minimal creation of new nodes is wanted.
7519 * So this method try to reduce at most the number of new nodes. The only case that can lead this method to add
7520 * nodes if a SEG3 is split without information of middle.
7521 * \b WARNING : is returned value is different from 0 a call to MEDCouplingUMesh::mergeNodes is necessary to
7522 * avoid to have a non conform mesh.
7524 * \return int - the number of new nodes created (in most of cases 0).
7526 * \throw If \a this is not coherent.
7527 * \throw If \a this has not spaceDim equal to 2.
7528 * \throw If \a this has not meshDim equal to 2.
7529 * \throw If some subcells needed to be split are orphan.
7530 * \sa MEDCouplingUMesh::conformize2D
7532 int MEDCouplingUMesh::split2DCells(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI, const DataArrayInt *midOpt, const DataArrayInt *midOptI)
7534 if(!desc || !descI || !subNodesInSeg || !subNodesInSegI)
7535 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : the 4 first arrays must be not null !");
7536 desc->checkAllocated(); descI->checkAllocated(); subNodesInSeg->checkAllocated(); subNodesInSegI->checkAllocated();
7537 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
7538 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : This method only works for meshes with spaceDim=2 and meshDim=2 !");
7539 if(midOpt==0 && midOptI==0)
7541 split2DCellsLinear(desc,descI,subNodesInSeg,subNodesInSegI);
7544 else if(midOpt!=0 && midOptI!=0)
7545 return split2DCellsQuadratic(desc,descI,subNodesInSeg,subNodesInSegI,midOpt,midOptI);
7547 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : middle parameters must be set to null for all or not null for all.");
7551 * 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
7552 * 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
7553 * the geometric cell type set to INTERP_KERNEL::NORM_POLYGON.
7554 * 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
7555 * 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.
7557 * \return false if the input connectivity represents already the convex hull, true if the input cell needs to be reordered.
7559 bool MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis(const double *coords, const int *nodalConnBg, const int *nodalConnEnd, DataArrayInt *nodalConnecOut)
7561 std::size_t sz=std::distance(nodalConnBg,nodalConnEnd);
7564 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)*nodalConnBg);
7565 if(cm.getDimension()==2)
7567 const int *node=nodalConnBg+1;
7568 int startNode=*node++;
7569 double refX=coords[2*startNode];
7570 for(;node!=nodalConnEnd;node++)
7572 if(coords[2*(*node)]<refX)
7575 refX=coords[2*startNode];
7578 std::vector<int> tmpOut; tmpOut.reserve(sz); tmpOut.push_back(startNode);
7582 double angle0=-M_PI/2;
7587 double angleNext=0.;
7588 while(nextNode!=startNode)
7592 for(node=nodalConnBg+1;node!=nodalConnEnd;node++)
7594 if(*node!=tmpOut.back() && *node!=prevNode)
7596 tmp2[0]=coords[2*(*node)]-coords[2*tmpOut.back()]; tmp2[1]=coords[2*(*node)+1]-coords[2*tmpOut.back()+1];
7597 double angleM=INTERP_KERNEL::EdgeArcCircle::GetAbsoluteAngle(tmp2,tmp1);
7602 res=angle0-angleM+2.*M_PI;
7611 if(nextNode!=startNode)
7613 angle0=angleNext-M_PI;
7616 prevNode=tmpOut.back();
7617 tmpOut.push_back(nextNode);
7620 std::vector<int> tmp3(2*(sz-1));
7621 std::vector<int>::iterator it=std::copy(nodalConnBg+1,nodalConnEnd,tmp3.begin());
7622 std::copy(nodalConnBg+1,nodalConnEnd,it);
7623 if(std::search(tmp3.begin(),tmp3.end(),tmpOut.begin(),tmpOut.end())!=tmp3.end())
7625 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
7628 if(std::search(tmp3.rbegin(),tmp3.rend(),tmpOut.begin(),tmpOut.end())!=tmp3.rend())
7630 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
7635 nodalConnecOut->pushBackSilent((int)INTERP_KERNEL::NORM_POLYGON);
7636 nodalConnecOut->insertAtTheEnd(tmpOut.begin(),tmpOut.end());
7641 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
7644 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
7648 * This method works on an input pair (\b arr, \b arrIndx) where \b arr indexes is in \b arrIndx.
7649 * 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.
7651 * \param [in] idsToRemoveBg begin of set of ids to remove in \b arr (included)
7652 * \param [in] idsToRemoveEnd end of set of ids to remove in \b arr (excluded)
7653 * \param [in,out] arr array in which the remove operation will be done.
7654 * \param [in,out] arrIndx array in the remove operation will modify
7655 * \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])
7656 * \return true if \b arr and \b arrIndx have been modified, false if not.
7658 bool MEDCouplingUMesh::RemoveIdsFromIndexedArrays(const int *idsToRemoveBg, const int *idsToRemoveEnd, DataArrayInt *arr, DataArrayInt *arrIndx, int offsetForRemoval)
7660 if(!arrIndx || !arr)
7661 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::RemoveIdsFromIndexedArrays : some input arrays are empty !");
7662 if(offsetForRemoval<0)
7663 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::RemoveIdsFromIndexedArrays : offsetForRemoval should be >=0 !");
7664 std::set<int> s(idsToRemoveBg,idsToRemoveEnd);
7665 int nbOfGrps=arrIndx->getNumberOfTuples()-1;
7666 int *arrIPtr=arrIndx->getPointer();
7669 const int *arrPtr=arr->begin();
7670 std::vector<int> arrOut;//no utility to switch to DataArrayInt because copy always needed
7671 for(int i=0;i<nbOfGrps;i++,arrIPtr++)
7673 if(*arrIPtr-previousArrI>offsetForRemoval)
7675 for(const int *work=arrPtr+previousArrI+offsetForRemoval;work!=arrPtr+*arrIPtr;work++)
7677 if(s.find(*work)==s.end())
7678 arrOut.push_back(*work);
7681 previousArrI=*arrIPtr;
7682 *arrIPtr=(int)arrOut.size();
7684 if(arr->getNumberOfTuples()==(int)arrOut.size())
7686 arr->alloc((int)arrOut.size(),1);
7687 std::copy(arrOut.begin(),arrOut.end(),arr->getPointer());
7692 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn
7693 * (\ref numbering-indirect).
7694 * This method returns the result of the extraction ( specified by a set of ids in [\b idsOfSelectBg , \b idsOfSelectEnd ) ).
7695 * The selection of extraction is done standardly in new2old format.
7696 * This method returns indexed arrays (\ref numbering-indirect) using 2 arrays (arrOut,arrIndexOut).
7698 * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
7699 * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
7700 * \param [in] arrIn arr origin array from which the extraction will be done.
7701 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7702 * \param [out] arrOut the resulting array
7703 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
7704 * \sa MEDCouplingUMesh::ExtractFromIndexedArraysSlice
7706 void MEDCouplingUMesh::ExtractFromIndexedArrays(const int *idsOfSelectBg, const int *idsOfSelectEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
7707 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
7709 if(!arrIn || !arrIndxIn)
7710 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : input pointer is NULL !");
7711 arrIn->checkAllocated(); arrIndxIn->checkAllocated();
7712 if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1)
7713 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : input arrays must have exactly one component !");
7714 std::size_t sz=std::distance(idsOfSelectBg,idsOfSelectEnd);
7715 const int *arrInPtr=arrIn->begin();
7716 const int *arrIndxPtr=arrIndxIn->begin();
7717 int nbOfGrps=arrIndxIn->getNumberOfTuples()-1;
7719 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : The format of \"arrIndxIn\" is invalid ! Its nb of tuples should be >=1 !");
7720 int maxSizeOfArr=arrIn->getNumberOfTuples();
7721 MCAuto<DataArrayInt> arro=DataArrayInt::New();
7722 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
7723 arrIo->alloc((int)(sz+1),1);
7724 const int *idsIt=idsOfSelectBg;
7725 int *work=arrIo->getPointer();
7728 for(std::size_t i=0;i<sz;i++,work++,idsIt++)
7730 if(*idsIt>=0 && *idsIt<nbOfGrps)
7731 lgth+=arrIndxPtr[*idsIt+1]-arrIndxPtr[*idsIt];
7734 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " ! Must be in [0," << nbOfGrps << ") !";
7735 throw INTERP_KERNEL::Exception(oss.str());
7741 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " and at this pos arrIndxIn[" << *idsIt;
7742 oss << "+1]-arrIndxIn[" << *idsIt << "] < 0 ! The input index array is bugged !";
7743 throw INTERP_KERNEL::Exception(oss.str());
7746 arro->alloc(lgth,1);
7747 work=arro->getPointer();
7748 idsIt=idsOfSelectBg;
7749 for(std::size_t i=0;i<sz;i++,idsIt++)
7751 if(arrIndxPtr[*idsIt]>=0 && arrIndxPtr[*idsIt+1]<=maxSizeOfArr)
7752 work=std::copy(arrInPtr+arrIndxPtr[*idsIt],arrInPtr+arrIndxPtr[*idsIt+1],work);
7755 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " arrIndx[" << *idsIt << "] must be >= 0 and arrIndx[";
7756 oss << *idsIt << "+1] <= " << maxSizeOfArr << " (the size of arrIn)!";
7757 throw INTERP_KERNEL::Exception(oss.str());
7761 arrIndexOut=arrIo.retn();
7765 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn
7766 * (\ref numbering-indirect).
7767 * 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 ).
7768 * The selection of extraction is done standardly in new2old format.
7769 * This method returns indexed arrays (\ref numbering-indirect) using 2 arrays (arrOut,arrIndexOut).
7771 * \param [in] idsOfSelectStart begin of set of ids of the input extraction (included)
7772 * \param [in] idsOfSelectStop end of set of ids of the input extraction (excluded)
7773 * \param [in] idsOfSelectStep
7774 * \param [in] arrIn arr origin array from which the extraction will be done.
7775 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7776 * \param [out] arrOut the resulting array
7777 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
7778 * \sa MEDCouplingUMesh::ExtractFromIndexedArrays
7780 void MEDCouplingUMesh::ExtractFromIndexedArraysSlice(int idsOfSelectStart, int idsOfSelectStop, int idsOfSelectStep, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
7781 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
7783 if(!arrIn || !arrIndxIn)
7784 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : input pointer is NULL !");
7785 arrIn->checkAllocated(); arrIndxIn->checkAllocated();
7786 if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1)
7787 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : input arrays must have exactly one component !");
7788 int sz=DataArrayInt::GetNumberOfItemGivenBESRelative(idsOfSelectStart,idsOfSelectStop,idsOfSelectStep,"MEDCouplingUMesh::ExtractFromIndexedArraysSlice : Input slice ");
7789 const int *arrInPtr=arrIn->begin();
7790 const int *arrIndxPtr=arrIndxIn->begin();
7791 int nbOfGrps=arrIndxIn->getNumberOfTuples()-1;
7793 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : The format of \"arrIndxIn\" is invalid ! Its nb of tuples should be >=1 !");
7794 int maxSizeOfArr=arrIn->getNumberOfTuples();
7795 MCAuto<DataArrayInt> arro=DataArrayInt::New();
7796 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
7797 arrIo->alloc((int)(sz+1),1);
7798 int idsIt=idsOfSelectStart;
7799 int *work=arrIo->getPointer();
7802 for(int i=0;i<sz;i++,work++,idsIt+=idsOfSelectStep)
7804 if(idsIt>=0 && idsIt<nbOfGrps)
7805 lgth+=arrIndxPtr[idsIt+1]-arrIndxPtr[idsIt];
7808 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " ! Must be in [0," << nbOfGrps << ") !";
7809 throw INTERP_KERNEL::Exception(oss.str());
7815 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " and at this pos arrIndxIn[" << idsIt;
7816 oss << "+1]-arrIndxIn[" << idsIt << "] < 0 ! The input index array is bugged !";
7817 throw INTERP_KERNEL::Exception(oss.str());
7820 arro->alloc(lgth,1);
7821 work=arro->getPointer();
7822 idsIt=idsOfSelectStart;
7823 for(int i=0;i<sz;i++,idsIt+=idsOfSelectStep)
7825 if(arrIndxPtr[idsIt]>=0 && arrIndxPtr[idsIt+1]<=maxSizeOfArr)
7826 work=std::copy(arrInPtr+arrIndxPtr[idsIt],arrInPtr+arrIndxPtr[idsIt+1],work);
7829 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " arrIndx[" << idsIt << "] must be >= 0 and arrIndx[";
7830 oss << idsIt << "+1] <= " << maxSizeOfArr << " (the size of arrIn)!";
7831 throw INTERP_KERNEL::Exception(oss.str());
7835 arrIndexOut=arrIo.retn();
7839 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
7840 * 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
7841 * cellIds \b in [ \b idsOfSelectBg , \b idsOfSelectEnd ) a copy coming from the corresponding values in input pair (\b srcArr, \b srcArrIndex).
7842 * This method is an generalization of MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx that performs the same thing but by without building explicitely a result output arrays.
7844 * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
7845 * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
7846 * \param [in] arrIn arr origin array from which the extraction will be done.
7847 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7848 * \param [in] srcArr input array that will be used as source of copy for ids in [ \b idsOfSelectBg, \b idsOfSelectEnd )
7849 * \param [in] srcArrIndex index array of \b srcArr
7850 * \param [out] arrOut the resulting array
7851 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
7853 * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx
7855 void MEDCouplingUMesh::SetPartOfIndexedArrays(const int *idsOfSelectBg, const int *idsOfSelectEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
7856 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex,
7857 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
7859 if(arrIn==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
7860 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArrays : presence of null pointer in input parameter !");
7861 MCAuto<DataArrayInt> arro=DataArrayInt::New();
7862 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
7863 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
7864 std::vector<bool> v(nbOfTuples,true);
7866 const int *arrIndxInPtr=arrIndxIn->begin();
7867 const int *srcArrIndexPtr=srcArrIndex->begin();
7868 for(const int *it=idsOfSelectBg;it!=idsOfSelectEnd;it++,srcArrIndexPtr++)
7870 if(*it>=0 && *it<nbOfTuples)
7873 offset+=(srcArrIndexPtr[1]-srcArrIndexPtr[0])-(arrIndxInPtr[*it+1]-arrIndxInPtr[*it]);
7877 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArrays : On pos #" << std::distance(idsOfSelectBg,it) << " value is " << *it << " not in [0," << nbOfTuples << ") !";
7878 throw INTERP_KERNEL::Exception(oss.str());
7881 srcArrIndexPtr=srcArrIndex->begin();
7882 arrIo->alloc(nbOfTuples+1,1);
7883 arro->alloc(arrIn->getNumberOfTuples()+offset,1);
7884 const int *arrInPtr=arrIn->begin();
7885 const int *srcArrPtr=srcArr->begin();
7886 int *arrIoPtr=arrIo->getPointer(); *arrIoPtr++=0;
7887 int *arroPtr=arro->getPointer();
7888 for(int ii=0;ii<nbOfTuples;ii++,arrIoPtr++)
7892 arroPtr=std::copy(arrInPtr+arrIndxInPtr[ii],arrInPtr+arrIndxInPtr[ii+1],arroPtr);
7893 *arrIoPtr=arrIoPtr[-1]+(arrIndxInPtr[ii+1]-arrIndxInPtr[ii]);
7897 std::size_t pos=std::distance(idsOfSelectBg,std::find(idsOfSelectBg,idsOfSelectEnd,ii));
7898 arroPtr=std::copy(srcArrPtr+srcArrIndexPtr[pos],srcArrPtr+srcArrIndexPtr[pos+1],arroPtr);
7899 *arrIoPtr=arrIoPtr[-1]+(srcArrIndexPtr[pos+1]-srcArrIndexPtr[pos]);
7903 arrIndexOut=arrIo.retn();
7907 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
7908 * This method is an specialization of MEDCouplingUMesh::SetPartOfIndexedArrays in the case of assignement do not modify the index in \b arrIndxIn.
7910 * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
7911 * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
7912 * \param [in,out] arrInOut arr origin array from which the extraction will be done.
7913 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7914 * \param [in] srcArr input array that will be used as source of copy for ids in [ \b idsOfSelectBg , \b idsOfSelectEnd )
7915 * \param [in] srcArrIndex index array of \b srcArr
7917 * \sa MEDCouplingUMesh::SetPartOfIndexedArrays
7919 void MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx(const int *idsOfSelectBg, const int *idsOfSelectEnd, DataArrayInt *arrInOut, const DataArrayInt *arrIndxIn,
7920 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex)
7922 if(arrInOut==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
7923 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx : presence of null pointer in input parameter !");
7924 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
7925 const int *arrIndxInPtr=arrIndxIn->begin();
7926 const int *srcArrIndexPtr=srcArrIndex->begin();
7927 int *arrInOutPtr=arrInOut->getPointer();
7928 const int *srcArrPtr=srcArr->begin();
7929 for(const int *it=idsOfSelectBg;it!=idsOfSelectEnd;it++,srcArrIndexPtr++)
7931 if(*it>=0 && *it<nbOfTuples)
7933 if(srcArrIndexPtr[1]-srcArrIndexPtr[0]==arrIndxInPtr[*it+1]-arrIndxInPtr[*it])
7934 std::copy(srcArrPtr+srcArrIndexPtr[0],srcArrPtr+srcArrIndexPtr[1],arrInOutPtr+arrIndxInPtr[*it]);
7937 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] !";
7938 throw INTERP_KERNEL::Exception(oss.str());
7943 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx : On pos #" << std::distance(idsOfSelectBg,it) << " value is " << *it << " not in [0," << nbOfTuples << ") !";
7944 throw INTERP_KERNEL::Exception(oss.str());
7950 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
7951 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
7952 * 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]].
7953 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
7954 * A negative value in \b arrIn means that it is ignored.
7955 * 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.
7957 * \param [in] arrIn arr origin array from which the extraction will be done.
7958 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7959 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
7960 * \sa MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed, MEDCouplingUMesh::partitionBySpreadZone
7962 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGradually(const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn)
7964 int seed=0,nbOfDepthPeelingPerformed=0;
7965 return ComputeSpreadZoneGraduallyFromSeed(&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfDepthPeelingPerformed);
7969 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
7970 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
7971 * 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]].
7972 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
7973 * A negative value in \b arrIn means that it is ignored.
7974 * 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.
7975 * \param [in] seedBg the begin pointer (included) of an array containing the seed of the search zone
7976 * \param [in] seedEnd the end pointer (not included) of an array containing the seed of the search zone
7977 * \param [in] arrIn arr origin array from which the extraction will be done.
7978 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7979 * \param [in] nbOfDepthPeeling the max number of peels requested in search. By default -1, that is to say, no limit.
7980 * \param [out] nbOfDepthPeelingPerformed the number of peels effectively performed. May be different from \a nbOfDepthPeeling
7981 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
7982 * \sa MEDCouplingUMesh::partitionBySpreadZone
7984 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(const int *seedBg, const int *seedEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn, int nbOfDepthPeeling, int& nbOfDepthPeelingPerformed)
7986 nbOfDepthPeelingPerformed=0;
7988 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed : arrIndxIn input pointer is NULL !");
7989 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
7992 DataArrayInt *ret=DataArrayInt::New(); ret->alloc(0,1);
7996 std::vector<bool> fetched(nbOfTuples,false);
7997 return ComputeSpreadZoneGraduallyFromSeedAlg(fetched,seedBg,seedEnd,arrIn,arrIndxIn,nbOfDepthPeeling,nbOfDepthPeelingPerformed);
8002 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
8003 * 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
8004 * cellIds \b in [\b idsOfSelectBg, \b idsOfSelectEnd) a copy coming from the corresponding values in input pair (\b srcArr, \b srcArrIndex).
8005 * This method is an generalization of MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx that performs the same thing but by without building explicitely a result output arrays.
8007 * \param [in] start begin of set of ids of the input extraction (included)
8008 * \param [in] end end of set of ids of the input extraction (excluded)
8009 * \param [in] step step of the set of ids in range mode.
8010 * \param [in] arrIn arr origin array from which the extraction will be done.
8011 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
8012 * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd)
8013 * \param [in] srcArrIndex index array of \b srcArr
8014 * \param [out] arrOut the resulting array
8015 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
8017 * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx MEDCouplingUMesh::SetPartOfIndexedArrays
8019 void MEDCouplingUMesh::SetPartOfIndexedArraysSlice(int start, int end, int step, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
8020 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex,
8021 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
8023 if(arrIn==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
8024 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSlice : presence of null pointer in input parameter !");
8025 MCAuto<DataArrayInt> arro=DataArrayInt::New();
8026 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
8027 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
8029 const int *arrIndxInPtr=arrIndxIn->begin();
8030 const int *srcArrIndexPtr=srcArrIndex->begin();
8031 int nbOfElemsToSet=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::SetPartOfIndexedArraysSlice : ");
8033 for(int i=0;i<nbOfElemsToSet;i++,srcArrIndexPtr++,it+=step)
8035 if(it>=0 && it<nbOfTuples)
8036 offset+=(srcArrIndexPtr[1]-srcArrIndexPtr[0])-(arrIndxInPtr[it+1]-arrIndxInPtr[it]);
8039 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSlice : On pos #" << i << " value is " << it << " not in [0," << nbOfTuples << ") !";
8040 throw INTERP_KERNEL::Exception(oss.str());
8043 srcArrIndexPtr=srcArrIndex->begin();
8044 arrIo->alloc(nbOfTuples+1,1);
8045 arro->alloc(arrIn->getNumberOfTuples()+offset,1);
8046 const int *arrInPtr=arrIn->begin();
8047 const int *srcArrPtr=srcArr->begin();
8048 int *arrIoPtr=arrIo->getPointer(); *arrIoPtr++=0;
8049 int *arroPtr=arro->getPointer();
8050 for(int ii=0;ii<nbOfTuples;ii++,arrIoPtr++)
8052 int pos=DataArray::GetPosOfItemGivenBESRelativeNoThrow(ii,start,end,step);
8055 arroPtr=std::copy(arrInPtr+arrIndxInPtr[ii],arrInPtr+arrIndxInPtr[ii+1],arroPtr);
8056 *arrIoPtr=arrIoPtr[-1]+(arrIndxInPtr[ii+1]-arrIndxInPtr[ii]);
8060 arroPtr=std::copy(srcArrPtr+srcArrIndexPtr[pos],srcArrPtr+srcArrIndexPtr[pos+1],arroPtr);
8061 *arrIoPtr=arrIoPtr[-1]+(srcArrIndexPtr[pos+1]-srcArrIndexPtr[pos]);
8065 arrIndexOut=arrIo.retn();
8069 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
8070 * This method is an specialization of MEDCouplingUMesh::SetPartOfIndexedArrays in the case of assignement do not modify the index in \b arrIndxIn.
8072 * \param [in] start begin of set of ids of the input extraction (included)
8073 * \param [in] end end of set of ids of the input extraction (excluded)
8074 * \param [in] step step of the set of ids in range mode.
8075 * \param [in,out] arrInOut arr origin array from which the extraction will be done.
8076 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
8077 * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd)
8078 * \param [in] srcArrIndex index array of \b srcArr
8080 * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSlice MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx
8082 void MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice(int start, int end, int step, DataArrayInt *arrInOut, const DataArrayInt *arrIndxIn,
8083 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex)
8085 if(arrInOut==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
8086 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : presence of null pointer in input parameter !");
8087 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
8088 const int *arrIndxInPtr=arrIndxIn->begin();
8089 const int *srcArrIndexPtr=srcArrIndex->begin();
8090 int *arrInOutPtr=arrInOut->getPointer();
8091 const int *srcArrPtr=srcArr->begin();
8092 int nbOfElemsToSet=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : ");
8094 for(int i=0;i<nbOfElemsToSet;i++,srcArrIndexPtr++,it+=step)
8096 if(it>=0 && it<nbOfTuples)
8098 if(srcArrIndexPtr[1]-srcArrIndexPtr[0]==arrIndxInPtr[it+1]-arrIndxInPtr[it])
8099 std::copy(srcArrPtr+srcArrIndexPtr[0],srcArrPtr+srcArrIndexPtr[1],arrInOutPtr+arrIndxInPtr[it]);
8102 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : On pos #" << i << " id (idsOfSelectBg[" << i << "]) is " << it << " arrIndxIn[id+1]-arrIndxIn[id]!=srcArrIndex[pos+1]-srcArrIndex[pos] !";
8103 throw INTERP_KERNEL::Exception(oss.str());
8108 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : On pos #" << i << " value is " << it << " not in [0," << nbOfTuples << ") !";
8109 throw INTERP_KERNEL::Exception(oss.str());
8115 * \b this is expected to be a mesh fully defined whose spaceDim==meshDim.
8116 * It returns a new allocated mesh having the same mesh dimension and lying on same coordinates.
8117 * The returned mesh contains as poly cells as number of contiguous zone (regarding connectivity).
8118 * A spread contiguous zone is built using poly cells (polyhedra in 3D, polygons in 2D and polyline in 1D).
8119 * The sum of measure field of returned mesh is equal to the sum of measure field of this.
8121 * \return a newly allocated mesh lying on the same coords than \b this with same meshdimension than \b this.
8123 MEDCouplingUMesh *MEDCouplingUMesh::buildSpreadZonesWithPoly() const
8125 checkFullyDefined();
8126 int mdim=getMeshDimension();
8127 int spaceDim=getSpaceDimension();
8129 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension and spacedimension do not match !");
8130 std::vector<DataArrayInt *> partition=partitionBySpreadZone();
8131 std::vector< MCAuto<DataArrayInt> > partitionAuto; partitionAuto.reserve(partition.size());
8132 std::copy(partition.begin(),partition.end(),std::back_insert_iterator<std::vector< MCAuto<DataArrayInt> > >(partitionAuto));
8133 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
8134 ret->setCoords(getCoords());
8135 ret->allocateCells((int)partition.size());
8137 for(std::vector<DataArrayInt *>::const_iterator it=partition.begin();it!=partition.end();it++)
8139 MCAuto<MEDCouplingUMesh> tmp=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf((*it)->begin(),(*it)->end(),true));
8140 MCAuto<DataArrayInt> cell;
8144 cell=tmp->buildUnionOf2DMesh();
8147 cell=tmp->buildUnionOf3DMesh();
8150 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension supported are [2,3] ! Not implemented yet for others !");
8153 ret->insertNextCell((INTERP_KERNEL::NormalizedCellType)cell->getIJSafe(0,0),cell->getNumberOfTuples()-1,cell->begin()+1);
8156 ret->finishInsertingCells();
8161 * This method partitions \b this into contiguous zone.
8162 * This method only needs a well defined connectivity. Coordinates are not considered here.
8163 * This method returns a vector of \b newly allocated arrays that the caller has to deal with.
8165 std::vector<DataArrayInt *> MEDCouplingUMesh::partitionBySpreadZone() const
8167 DataArrayInt *neigh=0,*neighI=0;
8168 computeNeighborsOfCells(neigh,neighI);
8169 MCAuto<DataArrayInt> neighAuto(neigh),neighIAuto(neighI);
8170 return PartitionBySpreadZone(neighAuto,neighIAuto);
8173 std::vector<DataArrayInt *> MEDCouplingUMesh::PartitionBySpreadZone(const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn)
8175 if(!arrIn || !arrIndxIn)
8176 throw INTERP_KERNEL::Exception("PartitionBySpreadZone : null input pointers !");
8177 arrIn->checkAllocated(); arrIndxIn->checkAllocated();
8178 int nbOfTuples(arrIndxIn->getNumberOfTuples());
8179 if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1 || nbOfTuples<1)
8180 throw INTERP_KERNEL::Exception("PartitionBySpreadZone : invalid arrays in input !");
8181 int nbOfCellsCur(nbOfTuples-1);
8182 std::vector<DataArrayInt *> ret;
8185 std::vector<bool> fetchedCells(nbOfCellsCur,false);
8186 std::vector< MCAuto<DataArrayInt> > ret2;
8188 while(seed<nbOfCellsCur)
8190 int nbOfPeelPerformed=0;
8191 ret2.push_back(ComputeSpreadZoneGraduallyFromSeedAlg(fetchedCells,&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfPeelPerformed));
8192 seed=(int)std::distance(fetchedCells.begin(),std::find(fetchedCells.begin()+seed,fetchedCells.end(),false));
8194 for(std::vector< MCAuto<DataArrayInt> >::iterator it=ret2.begin();it!=ret2.end();it++)
8195 ret.push_back((*it).retn());
8200 * This method returns given a distribution of cell type (returned for example by MEDCouplingUMesh::getDistributionOfTypes method and customized after) a
8201 * newly allocated DataArrayInt instance with 2 components ready to be interpreted as input of DataArrayInt::findRangeIdForEachTuple method.
8203 * \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.
8204 * \return a newly allocated DataArrayInt to be managed by the caller.
8205 * \throw In case of \a code has not the right format (typically of size 3*n)
8207 DataArrayInt *MEDCouplingUMesh::ComputeRangesFromTypeDistribution(const std::vector<int>& code)
8209 MCAuto<DataArrayInt> ret=DataArrayInt::New();
8210 std::size_t nb=code.size()/3;
8211 if(code.size()%3!=0)
8212 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeRangesFromTypeDistribution : invalid input code !");
8213 ret->alloc((int)nb,2);
8214 int *retPtr=ret->getPointer();
8215 for(std::size_t i=0;i<nb;i++,retPtr+=2)
8217 retPtr[0]=code[3*i+2];
8218 retPtr[1]=code[3*i+2]+code[3*i+1];
8224 * This method expects that \a this a 3D mesh (spaceDim=3 and meshDim=3) with all coordinates and connectivities set.
8225 * All cells in \a this are expected to be linear 3D cells.
8226 * This method will split **all** 3D cells in \a this into INTERP_KERNEL::NORM_TETRA4 cells and put them in the returned mesh.
8227 * It leads to an increase to number of cells.
8228 * This method contrary to MEDCouplingUMesh::simplexize can append coordinates in \a this to perform its work.
8229 * The \a nbOfAdditionalPoints returned value informs about it. If > 0, the coordinates array in returned mesh will have \a nbOfAdditionalPoints
8230 * more tuples (nodes) than in \a this. Anyway, all the nodes in \a this (with the same order) will be in the returned mesh.
8232 * \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.
8233 * For all other cells, the splitting policy will be ignored. See INTERP_KERNEL::SplittingPolicy for the images.
8234 * \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.
8235 * \param [out] n2oCells - A new instance of DataArrayInt holding, for each new cell,
8236 * an id of old cell producing it. The caller is to delete this array using
8237 * decrRef() as it is no more needed.
8238 * \return MEDCoupling1SGTUMesh * - the mesh containing only INTERP_KERNEL::NORM_TETRA4 cells.
8240 * \warning This method operates on each cells in this independantly ! So it can leads to non conform mesh in returned value ! If you expect to have a conform mesh in output
8241 * the policy PLANAR_FACE_6 should be used on a mesh sorted with MEDCoupling1SGTUMesh::sortHexa8EachOther.
8243 * \throw If \a this is not a 3D mesh (spaceDim==3 and meshDim==3).
8244 * \throw If \a this is not fully constituted with linear 3D cells.
8245 * \sa MEDCouplingUMesh::simplexize, MEDCoupling1SGTUMesh::sortHexa8EachOther
8247 MEDCoupling1SGTUMesh *MEDCouplingUMesh::tetrahedrize(int policy, DataArrayInt *& n2oCells, int& nbOfAdditionalPoints) const
8249 INTERP_KERNEL::SplittingPolicy pol((INTERP_KERNEL::SplittingPolicy)policy);
8250 checkConnectivityFullyDefined();
8251 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
8252 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tetrahedrize : only available for mesh with meshdim == 3 and spacedim == 3 !");
8253 int nbOfCells(getNumberOfCells()),nbNodes(getNumberOfNodes());
8254 MCAuto<MEDCoupling1SGTUMesh> ret0(MEDCoupling1SGTUMesh::New(getName(),INTERP_KERNEL::NORM_TETRA4));
8255 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(nbOfCells,1);
8256 int *retPt(ret->getPointer());
8257 MCAuto<DataArrayInt> newConn(DataArrayInt::New()); newConn->alloc(0,1);
8258 MCAuto<DataArrayDouble> addPts(DataArrayDouble::New()); addPts->alloc(0,1);
8259 const int *oldc(_nodal_connec->begin());
8260 const int *oldci(_nodal_connec_index->begin());
8261 const double *coords(_coords->begin());
8262 for(int i=0;i<nbOfCells;i++,oldci++,retPt++)
8264 std::vector<int> a; std::vector<double> b;
8265 INTERP_KERNEL::SplitIntoTetras(pol,(INTERP_KERNEL::NormalizedCellType)oldc[oldci[0]],oldc+oldci[0]+1,oldc+oldci[1],coords,a,b);
8266 std::size_t nbOfTet(a.size()/4); *retPt=(int)nbOfTet;
8267 const int *aa(&a[0]);
8270 for(std::vector<int>::iterator it=a.begin();it!=a.end();it++)
8272 *it=(-(*(it))-1+nbNodes);
8273 addPts->insertAtTheEnd(b.begin(),b.end());
8274 nbNodes+=(int)b.size()/3;
8276 for(std::size_t j=0;j<nbOfTet;j++,aa+=4)
8277 newConn->insertAtTheEnd(aa,aa+4);
8279 if(!addPts->empty())
8281 addPts->rearrange(3);
8282 nbOfAdditionalPoints=addPts->getNumberOfTuples();
8283 addPts=DataArrayDouble::Aggregate(getCoords(),addPts);
8284 ret0->setCoords(addPts);
8288 nbOfAdditionalPoints=0;
8289 ret0->setCoords(getCoords());
8291 ret0->setNodalConnectivity(newConn);
8293 ret->computeOffsetsFull();
8294 n2oCells=ret->buildExplicitArrOfSliceOnScaledArr(0,nbOfCells,1);
8298 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),
8299 _own_cell(true),_cell_id(-1),_nb_cell(0)
8304 _nb_cell=mesh->getNumberOfCells();
8308 MEDCouplingUMeshCellIterator::~MEDCouplingUMeshCellIterator()
8316 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh, MEDCouplingUMeshCell *itc, int bg, int end):_mesh(mesh),_cell(itc),
8317 _own_cell(false),_cell_id(bg-1),
8324 MEDCouplingUMeshCell *MEDCouplingUMeshCellIterator::nextt()
8327 if(_cell_id<_nb_cell)
8336 MEDCouplingUMeshCellByTypeEntry::MEDCouplingUMeshCellByTypeEntry(MEDCouplingUMesh *mesh):_mesh(mesh)
8342 MEDCouplingUMeshCellByTypeIterator *MEDCouplingUMeshCellByTypeEntry::iterator()
8344 return new MEDCouplingUMeshCellByTypeIterator(_mesh);
8347 MEDCouplingUMeshCellByTypeEntry::~MEDCouplingUMeshCellByTypeEntry()
8353 MEDCouplingUMeshCellEntry::MEDCouplingUMeshCellEntry(MEDCouplingUMesh *mesh, INTERP_KERNEL::NormalizedCellType type, MEDCouplingUMeshCell *itc, int bg, int end):_mesh(mesh),_type(type),
8361 MEDCouplingUMeshCellEntry::~MEDCouplingUMeshCellEntry()
8367 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCellEntry::getType() const
8372 int MEDCouplingUMeshCellEntry::getNumberOfElems() const
8377 MEDCouplingUMeshCellIterator *MEDCouplingUMeshCellEntry::iterator()
8379 return new MEDCouplingUMeshCellIterator(_mesh,_itc,_bg,_end);
8382 MEDCouplingUMeshCellByTypeIterator::MEDCouplingUMeshCellByTypeIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),_cell_id(0),_nb_cell(0)
8387 _nb_cell=mesh->getNumberOfCells();
8391 MEDCouplingUMeshCellByTypeIterator::~MEDCouplingUMeshCellByTypeIterator()
8398 MEDCouplingUMeshCellEntry *MEDCouplingUMeshCellByTypeIterator::nextt()
8400 const int *c=_mesh->getNodalConnectivity()->begin();
8401 const int *ci=_mesh->getNodalConnectivityIndex()->begin();
8402 if(_cell_id<_nb_cell)
8404 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[_cell_id]];
8405 int nbOfElems=(int)std::distance(ci+_cell_id,std::find_if(ci+_cell_id,ci+_nb_cell,MEDCouplingImpl::ConnReader(c,type)));
8406 int startId=_cell_id;
8407 _cell_id+=nbOfElems;
8408 return new MEDCouplingUMeshCellEntry(_mesh,type,_cell,startId,_cell_id);
8414 MEDCouplingUMeshCell::MEDCouplingUMeshCell(MEDCouplingUMesh *mesh):_conn(0),_conn_indx(0),_conn_lgth(NOTICABLE_FIRST_VAL)
8418 _conn=mesh->getNodalConnectivity()->getPointer();
8419 _conn_indx=mesh->getNodalConnectivityIndex()->getPointer();
8423 void MEDCouplingUMeshCell::next()
8425 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8430 _conn_lgth=_conn_indx[1]-_conn_indx[0];
8433 std::string MEDCouplingUMeshCell::repr() const
8435 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8437 std::ostringstream oss; oss << "Cell Type " << INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)_conn[0]).getRepr();
8439 std::copy(_conn+1,_conn+_conn_lgth,std::ostream_iterator<int>(oss," "));
8443 return std::string("MEDCouplingUMeshCell::repr : Invalid pos");
8446 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCell::getType() const
8448 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8449 return (INTERP_KERNEL::NormalizedCellType)_conn[0];
8451 return INTERP_KERNEL::NORM_ERROR;
8454 const int *MEDCouplingUMeshCell::getAllConn(int& lgth) const
8457 if(_conn_lgth!=NOTICABLE_FIRST_VAL)