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->getConstPointer();
597 const int *connIndex=_nodal_connec_index->getConstPointer();
598 int nbOfCells=getNumberOfCells();
599 int nbOfEltsInRevNodal=0;
600 for(int eltId=0;eltId<nbOfCells;eltId++)
602 const int *strtNdlConnOfCurCell=conn+connIndex[eltId]+1;
603 const int *endNdlConnOfCurCell=conn+connIndex[eltId+1];
604 for(const int *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
605 if(*iter>=0)//for polyhedrons
607 nbOfEltsInRevNodal++;
608 revNodalIndxPtr[(*iter)+1]++;
611 std::transform(revNodalIndxPtr+1,revNodalIndxPtr+nbOfNodes+1,revNodalIndxPtr,revNodalIndxPtr+1,std::plus<int>());
612 int *revNodalPtr=(int *)malloc((nbOfEltsInRevNodal)*sizeof(int));
613 revNodal->useArray(revNodalPtr,true,C_DEALLOC,nbOfEltsInRevNodal,1);
614 std::fill(revNodalPtr,revNodalPtr+nbOfEltsInRevNodal,-1);
615 for(int eltId=0;eltId<nbOfCells;eltId++)
617 const int *strtNdlConnOfCurCell=conn+connIndex[eltId]+1;
618 const int *endNdlConnOfCurCell=conn+connIndex[eltId+1];
619 for(const int *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
620 if(*iter>=0)//for polyhedrons
621 *std::find_if(revNodalPtr+revNodalIndxPtr[*iter],revNodalPtr+revNodalIndxPtr[*iter+1],std::bind2nd(std::equal_to<int>(),-1))=eltId;
626 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
627 * this->getMeshDimension(), that bound cells of \a this mesh. In addition arrays
628 * describing correspondence between cells of \a this and the result meshes are
629 * returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending connectivity,
630 * i.e. enumerate cells of the result mesh bounding each cell of \a this mesh. The
631 * arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
632 * i.e. enumerate cells of \a this mesh bounded by each cell of the result mesh.
633 * \warning For speed reasons, this method does not check if node ids in the nodal
634 * connectivity correspond to the size of node coordinates array.
635 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
636 * to write this mesh to the MED file, its cells must be sorted using
637 * sortCellsInMEDFileFrmt().
638 * \param [in,out] desc - the array containing cell ids of the result mesh bounding
639 * each cell of \a this mesh.
640 * \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
641 * dividing cell ids in \a desc into groups each referring to one
642 * cell of \a this mesh. Its every element (except the last one) is an index
643 * pointing to the first id of a group of cells. For example cells of the
644 * result mesh bounding the cell #1 of \a this mesh are described by following
646 * [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
647 * \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
648 * Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
649 * \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
650 * \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
651 * by each cell of the result mesh.
652 * \param [in,out] revDescIndx - the array, of length one more than number of cells
653 * in the result mesh,
654 * dividing cell ids in \a revDesc into groups each referring to one
655 * cell of the result mesh the same way as \a descIndx divides \a desc.
656 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is to
657 * delete this mesh using decrRef() as it is no more needed.
658 * \throw If the coordinates array is not set.
659 * \throw If the nodal connectivity of cells is node defined.
660 * \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
661 * revDescIndx == NULL.
663 * \if ENABLE_EXAMPLES
664 * \ref cpp_mcumesh_buildDescendingConnectivity "Here is a C++ example".<br>
665 * \ref py_mcumesh_buildDescendingConnectivity "Here is a Python example".
667 * \sa buildDescendingConnectivity2()
669 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
671 return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
675 * \a this has to have a mesh dimension equal to 3. If it is not the case an INTERP_KERNEL::Exception will be thrown.
676 * This behaves exactly as MEDCouplingUMesh::buildDescendingConnectivity does except that this method compute directly the transition from mesh dimension 3 to sub edges (dimension 1)
677 * in one shot. That is to say that this method is equivalent to 2 successive calls to MEDCouplingUMesh::buildDescendingConnectivity.
678 * This method returns 4 arrays and a mesh as MEDCouplingUMesh::buildDescendingConnectivity does.
679 * \sa MEDCouplingUMesh::buildDescendingConnectivity
681 MEDCouplingUMesh *MEDCouplingUMesh::explode3DMeshTo1D(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
684 if(getMeshDimension()!=3)
685 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explode3DMeshTo1D : This has to have a mesh dimension to 3 !");
686 return buildDescendingConnectivityGen<MinusTwoSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
690 * 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.
691 * This method works for both meshes with mesh dimenstion equal to 2 or 3. Dynamical cells are not supported (polygons, polyhedrons...)
693 * \sa explode3DMeshTo1D, buildDescendingConnectiviy
695 MEDCouplingUMesh *MEDCouplingUMesh::explodeMeshIntoMicroEdges(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
698 switch(getMeshDimension())
701 return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
703 return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
705 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explodeMeshIntoMicroEdges : Only 2D and 3D supported !");
710 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
711 * this->getMeshDimension(), that bound cells of \a this mesh. In
712 * addition arrays describing correspondence between cells of \a this and the result
713 * meshes are returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending
714 * connectivity, i.e. enumerate cells of the result mesh bounding each cell of \a this
715 * mesh. This method differs from buildDescendingConnectivity() in that apart
716 * from cell ids, \a desc returns mutual orientation of cells in \a this and the
717 * result meshes. So a positive id means that order of nodes in corresponding cells
718 * of two meshes is same, and a negative id means a reverse order of nodes. Since a
719 * cell with id #0 can't be negative, the array \a desc returns ids in FORTRAN mode,
720 * i.e. cell ids are one-based.
721 * Arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
722 * i.e. enumerate cells of \a this mesh bounded by each cell of the result mesh.
723 * \warning For speed reasons, this method does not check if node ids in the nodal
724 * connectivity correspond to the size of node coordinates array.
725 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
726 * to write this mesh to the MED file, its cells must be sorted using
727 * sortCellsInMEDFileFrmt().
728 * \param [in,out] desc - the array containing cell ids of the result mesh bounding
729 * each cell of \a this mesh.
730 * \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
731 * dividing cell ids in \a desc into groups each referring to one
732 * cell of \a this mesh. Its every element (except the last one) is an index
733 * pointing to the first id of a group of cells. For example cells of the
734 * result mesh bounding the cell #1 of \a this mesh are described by following
736 * [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
737 * \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
738 * Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
739 * \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
740 * \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
741 * by each cell of the result mesh.
742 * \param [in,out] revDescIndx - the array, of length one more than number of cells
743 * in the result mesh,
744 * dividing cell ids in \a revDesc into groups each referring to one
745 * cell of the result mesh the same way as \a descIndx divides \a desc.
746 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This result mesh
747 * shares the node coordinates array with \a this mesh. The caller is to
748 * delete this mesh using decrRef() as it is no more needed.
749 * \throw If the coordinates array is not set.
750 * \throw If the nodal connectivity of cells is node defined.
751 * \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
752 * revDescIndx == NULL.
754 * \if ENABLE_EXAMPLES
755 * \ref cpp_mcumesh_buildDescendingConnectivity2 "Here is a C++ example".<br>
756 * \ref py_mcumesh_buildDescendingConnectivity2 "Here is a Python example".
758 * \sa buildDescendingConnectivity()
760 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity2(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
762 return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingOrientationSensitiveNbrer);
766 * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
767 * For speed reasons no check of this will be done. This method calls
768 * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
769 * This method lists cell by cell in \b this which are its neighbors. To compute the result
770 * only connectivities are considered.
771 * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
772 * The format of return is hence \ref numbering-indirect.
774 * \param [out] neighbors is an array storing all the neighbors of all cells in \b this. This array is newly
775 * allocated and should be dealt by the caller. \b neighborsIndx 2nd output
776 * parameter allows to select the right part in this array (\ref numbering-indirect). The number of tuples
777 * is equal to the last values in \b neighborsIndx.
778 * \param [out] neighborsIndx is an array of size this->getNumberOfCells()+1 newly allocated and should be
779 * dealt by the caller. This arrays allow to use the first output parameter \b neighbors (\ref numbering-indirect).
781 void MEDCouplingUMesh::computeNeighborsOfCells(DataArrayInt *&neighbors, DataArrayInt *&neighborsIndx) const
783 MCAuto<DataArrayInt> desc=DataArrayInt::New();
784 MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
785 MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
786 MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
787 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
789 ComputeNeighborsOfCellsAdv(desc,descIndx,revDesc,revDescIndx,neighbors,neighborsIndx);
792 void MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne(const DataArrayInt *nodeNeigh, const DataArrayInt *nodeNeighI, MCAuto<DataArrayInt>& cellNeigh, MCAuto<DataArrayInt>& cellNeighIndex) const
794 if(!nodeNeigh || !nodeNeighI)
795 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : null pointer !");
796 checkConsistencyLight();
797 nodeNeigh->checkAllocated(); nodeNeighI->checkAllocated();
798 nodeNeigh->checkNbOfComps(1,"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : node neigh");
799 nodeNeighI->checkNbOfComps(1,"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : node neigh index");
800 nodeNeighI->checkNbOfTuples(1+getNumberOfNodes(),"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : invalid length");
801 int nbCells(getNumberOfCells());
802 const int *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin()),*ne(nodeNeigh->begin()),*nei(nodeNeighI->begin());
803 cellNeigh=DataArrayInt::New(); cellNeigh->alloc(0,1); cellNeighIndex=DataArrayInt::New(); cellNeighIndex->alloc(1,1); cellNeighIndex->setIJ(0,0,0);
804 for(int i=0;i<nbCells;i++)
807 for(const int *it=c+ci[i]+1;it!=c+ci[i+1];it++)
809 s.insert(ne+nei[*it],ne+nei[*it+1]);
811 cellNeigh->insertAtTheEnd(s.begin(),s.end());
812 cellNeighIndex->pushBackSilent(cellNeigh->getNumberOfTuples());
817 * This method is called by MEDCouplingUMesh::computeNeighborsOfCells. This methods performs the algorithm
818 * of MEDCouplingUMesh::computeNeighborsOfCells.
819 * This method is useful for users that want to reduce along a criterion the set of neighbours cell. This is
820 * typically the case to extract a set a neighbours,
821 * excluding a set of meshdim-1 cells in input descending connectivity.
822 * Typically \b desc, \b descIndx, \b revDesc and \b revDescIndx (\ref numbering-indirect) input params are
823 * the result of MEDCouplingUMesh::buildDescendingConnectivity.
824 * This method lists cell by cell in \b this which are its neighbors. To compute the result only connectivities
826 * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
828 * \param [in] desc descending connectivity array.
829 * \param [in] descIndx descending connectivity index array used to walk through \b desc (\ref numbering-indirect).
830 * \param [in] revDesc reverse descending connectivity array.
831 * \param [in] revDescIndx reverse descending connectivity index array used to walk through \b revDesc (\ref numbering-indirect).
832 * \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
833 * parameter allows to select the right part in this array. The number of tuples is equal to the last values in \b neighborsIndx.
834 * \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.
836 void MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(const DataArrayInt *desc, const DataArrayInt *descIndx, const DataArrayInt *revDesc, const DataArrayInt *revDescIndx,
837 DataArrayInt *&neighbors, DataArrayInt *&neighborsIndx)
839 if(!desc || !descIndx || !revDesc || !revDescIndx)
840 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeNeighborsOfCellsAdv some input array is empty !");
841 const int *descPtr=desc->getConstPointer();
842 const int *descIPtr=descIndx->getConstPointer();
843 const int *revDescPtr=revDesc->getConstPointer();
844 const int *revDescIPtr=revDescIndx->getConstPointer();
846 int nbCells=descIndx->getNumberOfTuples()-1;
847 MCAuto<DataArrayInt> out0=DataArrayInt::New();
848 MCAuto<DataArrayInt> out1=DataArrayInt::New(); out1->alloc(nbCells+1,1);
849 int *out1Ptr=out1->getPointer();
851 out0->reserve(desc->getNumberOfTuples());
852 for(int i=0;i<nbCells;i++,descIPtr++,out1Ptr++)
854 for(const int *w1=descPtr+descIPtr[0];w1!=descPtr+descIPtr[1];w1++)
856 std::set<int> s(revDescPtr+revDescIPtr[*w1],revDescPtr+revDescIPtr[(*w1)+1]);
858 out0->insertAtTheEnd(s.begin(),s.end());
860 *out1Ptr=out0->getNumberOfTuples();
862 neighbors=out0.retn();
863 neighborsIndx=out1.retn();
867 * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
868 * For speed reasons no check of this will be done. This method calls
869 * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
870 * This method lists node by node in \b this which are its neighbors. To compute the result
871 * only connectivities are considered.
872 * The neighbor nodes of node having id 'nodeId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
874 * \param [out] neighbors is an array storing all the neighbors of all nodes in \b this. This array
875 * is newly allocated and should be dealt by the caller. \b neighborsIndx 2nd output
876 * parameter allows to select the right part in this array (\ref numbering-indirect).
877 * The number of tuples is equal to the last values in \b neighborsIndx.
878 * \param [out] neighborsIdx is an array of size this->getNumberOfCells()+1 newly allocated and should
879 * be dealt by the caller. This arrays allow to use the first output parameter \b neighbors.
881 void MEDCouplingUMesh::computeNeighborsOfNodes(DataArrayInt *&neighbors, DataArrayInt *&neighborsIdx) const
884 int mdim(getMeshDimension()),nbNodes(getNumberOfNodes());
885 MCAuto<DataArrayInt> desc(DataArrayInt::New()),descIndx(DataArrayInt::New()),revDesc(DataArrayInt::New()),revDescIndx(DataArrayInt::New());
886 MCAuto<MEDCouplingUMesh> mesh1D;
891 mesh1D=explode3DMeshTo1D(desc,descIndx,revDesc,revDescIndx);
896 mesh1D=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
901 mesh1D=const_cast<MEDCouplingUMesh *>(this);
907 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2,1] !");
910 desc=DataArrayInt::New(); descIndx=DataArrayInt::New(); revDesc=0; revDescIndx=0;
911 mesh1D->getReverseNodalConnectivity(desc,descIndx);
912 MCAuto<DataArrayInt> ret0(DataArrayInt::New());
913 ret0->alloc(desc->getNumberOfTuples(),1);
914 int *r0Pt(ret0->getPointer());
915 const int *c1DPtr(mesh1D->getNodalConnectivity()->begin()),*rn(desc->begin()),*rni(descIndx->begin());
916 for(int i=0;i<nbNodes;i++,rni++)
918 for(const int *oneDCellIt=rn+rni[0];oneDCellIt!=rn+rni[1];oneDCellIt++)
919 *r0Pt++=c1DPtr[3*(*oneDCellIt)+1]==i?c1DPtr[3*(*oneDCellIt)+2]:c1DPtr[3*(*oneDCellIt)+1];
921 neighbors=ret0.retn();
922 neighborsIdx=descIndx.retn();
926 * Converts specified cells to either polygons (if \a this is a 2D mesh) or
927 * polyhedrons (if \a this is a 3D mesh). The cells to convert are specified by an
928 * array of cell ids. Pay attention that after conversion all algorithms work slower
929 * with \a this mesh than before conversion. <br> If an exception is thrown during the
930 * conversion due presence of invalid ids in the array of cells to convert, as a
931 * result \a this mesh contains some already converted elements. In this case the 2D
932 * mesh remains valid but 3D mesh becomes \b inconsistent!
933 * \warning This method can significantly modify the order of geometric types in \a this,
934 * hence, to write this mesh to the MED file, its cells must be sorted using
935 * sortCellsInMEDFileFrmt().
936 * \param [in] cellIdsToConvertBg - the array holding ids of cells to convert.
937 * \param [in] cellIdsToConvertEnd - a pointer to the last-plus-one-th element of \a
938 * cellIdsToConvertBg.
939 * \throw If the coordinates array is not set.
940 * \throw If the nodal connectivity of cells is node defined.
941 * \throw If dimension of \a this mesh is not either 2 or 3.
943 * \if ENABLE_EXAMPLES
944 * \ref cpp_mcumesh_convertToPolyTypes "Here is a C++ example".<br>
945 * \ref py_mcumesh_convertToPolyTypes "Here is a Python example".
948 void MEDCouplingUMesh::convertToPolyTypes(const int *cellIdsToConvertBg, const int *cellIdsToConvertEnd)
951 int dim=getMeshDimension();
953 throw INTERP_KERNEL::Exception("Invalid mesh dimension : must be 2 or 3 !");
954 int nbOfCells(getNumberOfCells());
957 const int *connIndex=_nodal_connec_index->getConstPointer();
958 int *conn=_nodal_connec->getPointer();
959 for(const int *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
961 if(*iter>=0 && *iter<nbOfCells)
963 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*iter]]);
964 if(!cm.isQuadratic())
965 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_POLYGON;
967 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_QPOLYG;
971 std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
972 oss << " in range [0," << nbOfCells << ") !";
973 throw INTERP_KERNEL::Exception(oss.str());
979 int *connIndex(_nodal_connec_index->getPointer());
980 const int *connOld(_nodal_connec->getConstPointer());
981 MCAuto<DataArrayInt> connNew(DataArrayInt::New()),connNewI(DataArrayInt::New()); connNew->alloc(0,1); connNewI->alloc(1,1); connNewI->setIJ(0,0,0);
982 std::vector<bool> toBeDone(nbOfCells,false);
983 for(const int *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
985 if(*iter>=0 && *iter<nbOfCells)
986 toBeDone[*iter]=true;
989 std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
990 oss << " in range [0," << nbOfCells << ") !";
991 throw INTERP_KERNEL::Exception(oss.str());
994 for(int cellId=0;cellId<nbOfCells;cellId++)
996 int pos(connIndex[cellId]),posP1(connIndex[cellId+1]);
997 int lgthOld(posP1-pos-1);
1000 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connOld[pos]);
1001 unsigned nbOfFaces(cm.getNumberOfSons2(connOld+pos+1,lgthOld));
1002 int *tmp(new int[nbOfFaces*lgthOld+1]);
1003 int *work=tmp; *work++=INTERP_KERNEL::NORM_POLYHED;
1004 for(unsigned j=0;j<nbOfFaces;j++)
1006 INTERP_KERNEL::NormalizedCellType type;
1007 unsigned offset=cm.fillSonCellNodalConnectivity2(j,connOld+pos+1,lgthOld,work,type);
1011 std::size_t newLgth(std::distance(tmp,work)-1);//-1 for last -1
1012 connNew->pushBackValsSilent(tmp,tmp+newLgth);
1013 connNewI->pushBackSilent(connNewI->back()+(int)newLgth);
1018 connNew->pushBackValsSilent(connOld+pos,connOld+posP1);
1019 connNewI->pushBackSilent(connNewI->back()+posP1-pos);
1022 setConnectivity(connNew,connNewI,false);//false because computeTypes called just behind.
1028 * Converts all cells to either polygons (if \a this is a 2D mesh) or
1029 * polyhedrons (if \a this is a 3D mesh).
1030 * \warning As this method is purely for user-friendliness and no optimization is
1031 * done to avoid construction of a useless vector, this method can be costly
1033 * \throw If the coordinates array is not set.
1034 * \throw If the nodal connectivity of cells is node defined.
1035 * \throw If dimension of \a this mesh is not either 2 or 3.
1037 void MEDCouplingUMesh::convertAllToPoly()
1039 int nbOfCells=getNumberOfCells();
1040 std::vector<int> cellIds(nbOfCells);
1041 for(int i=0;i<nbOfCells;i++)
1043 convertToPolyTypes(&cellIds[0],&cellIds[0]+cellIds.size());
1047 * Fixes nodal connectivity of invalid cells of type NORM_POLYHED. This method
1048 * expects that all NORM_POLYHED cells have connectivity similar to that of prismatic
1049 * volumes like NORM_HEXA8, NORM_PENTA6 etc., i.e. the first half of nodes describes a
1050 * base facet of the volume and the second half of nodes describes an opposite facet
1051 * having the same number of nodes as the base one. This method converts such
1052 * connectivity to a valid polyhedral format where connectivity of each facet is
1053 * explicitly described and connectivity of facets are separated by -1. If \a this mesh
1054 * contains a NORM_POLYHED cell with a valid connectivity, or an invalid connectivity is
1055 * not as expected, an exception is thrown and the mesh remains unchanged. Care of
1056 * a correct orientation of the first facet of a polyhedron, else orientation of a
1057 * corrected cell is reverse.<br>
1058 * This method is useful to build an extruded unstructured mesh with polyhedrons as
1059 * it releases the user from boring description of polyhedra connectivity in the valid
1061 * \throw If \a this->getMeshDimension() != 3.
1062 * \throw If \a this->getSpaceDimension() != 3.
1063 * \throw If the nodal connectivity of cells is not defined.
1064 * \throw If the coordinates array is not set.
1065 * \throw If \a this mesh contains polyhedrons with the valid connectivity.
1066 * \throw If \a this mesh contains polyhedrons with odd number of nodes.
1068 * \if ENABLE_EXAMPLES
1069 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
1070 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
1073 void MEDCouplingUMesh::convertExtrudedPolyhedra()
1075 checkFullyDefined();
1076 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1077 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertExtrudedPolyhedra works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
1078 int nbOfCells=getNumberOfCells();
1079 MCAuto<DataArrayInt> newCi=DataArrayInt::New();
1080 newCi->alloc(nbOfCells+1,1);
1081 int *newci=newCi->getPointer();
1082 const int *ci=_nodal_connec_index->getConstPointer();
1083 const int *c=_nodal_connec->getConstPointer();
1085 for(int i=0;i<nbOfCells;i++)
1087 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1088 if(type==INTERP_KERNEL::NORM_POLYHED)
1090 if(std::count(c+ci[i]+1,c+ci[i+1],-1)!=0)
1092 std::ostringstream oss; oss << "MEDCouplingUMesh::convertExtrudedPolyhedra : cell # " << i << " is a polhedron BUT it has NOT exactly 1 face !";
1093 throw INTERP_KERNEL::Exception(oss.str());
1095 std::size_t n2=std::distance(c+ci[i]+1,c+ci[i+1]);
1098 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 !";
1099 throw INTERP_KERNEL::Exception(oss.str());
1102 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)
1105 newci[i+1]=(ci[i+1]-ci[i])+newci[i];
1107 MCAuto<DataArrayInt> newC=DataArrayInt::New();
1108 newC->alloc(newci[nbOfCells],1);
1109 int *newc=newC->getPointer();
1110 for(int i=0;i<nbOfCells;i++)
1112 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1113 if(type==INTERP_KERNEL::NORM_POLYHED)
1115 std::size_t n1=std::distance(c+ci[i]+1,c+ci[i+1])/2;
1116 newc=std::copy(c+ci[i],c+ci[i]+n1+1,newc);
1118 for(std::size_t j=0;j<n1;j++)
1120 newc[j]=c[ci[i]+1+n1+(n1-j)%n1];
1122 newc[n1+5*j+1]=c[ci[i]+1+j];
1123 newc[n1+5*j+2]=c[ci[i]+1+j+n1];
1124 newc[n1+5*j+3]=c[ci[i]+1+(j+1)%n1+n1];
1125 newc[n1+5*j+4]=c[ci[i]+1+(j+1)%n1];
1130 newc=std::copy(c+ci[i],c+ci[i+1],newc);
1132 _nodal_connec_index->decrRef(); _nodal_connec_index=newCi.retn();
1133 _nodal_connec->decrRef(); _nodal_connec=newC.retn();
1138 * Converts all polygons (if \a this is a 2D mesh) or polyhedrons (if \a this is a 3D
1139 * mesh) to cells of classical types. This method is opposite to convertToPolyTypes().
1140 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
1141 * to write this mesh to the MED file, its cells must be sorted using
1142 * sortCellsInMEDFileFrmt().
1143 * \warning Cells (and most notably polyhedrons) must be correctly oriented for this to work
1144 * properly. See orientCorrectlyPolyhedrons() and arePolyhedronsNotCorrectlyOriented().
1145 * \return \c true if at least one cell has been converted, \c false else. In the
1146 * last case the nodal connectivity remains unchanged.
1147 * \throw If the coordinates array is not set.
1148 * \throw If the nodal connectivity of cells is not defined.
1149 * \throw If \a this->getMeshDimension() < 0.
1151 bool MEDCouplingUMesh::unPolyze()
1153 checkFullyDefined();
1154 int mdim=getMeshDimension();
1156 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::unPolyze works on umeshes with meshdim equals to 0, 1 2 or 3 !");
1159 int nbOfCells=getNumberOfCells();
1162 int initMeshLgth=getNodalConnectivityArrayLen();
1163 int *conn=_nodal_connec->getPointer();
1164 int *index=_nodal_connec_index->getPointer();
1169 for(int i=0;i<nbOfCells;i++)
1171 lgthOfCurCell=index[i+1]-posOfCurCell;
1172 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
1173 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
1174 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::NORM_ERROR;
1178 switch(cm.getDimension())
1182 INTERP_KERNEL::AutoPtr<int> tmp=new int[lgthOfCurCell-1];
1183 std::copy(conn+posOfCurCell+1,conn+posOfCurCell+lgthOfCurCell,(int *)tmp);
1184 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly2D(cm.isQuadratic(),tmp,lgthOfCurCell-1,conn+newPos+1,newLgth);
1189 int nbOfFaces,lgthOfPolyhConn;
1190 INTERP_KERNEL::AutoPtr<int> zipFullReprOfPolyh=INTERP_KERNEL::CellSimplify::getFullPolyh3DCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,nbOfFaces,lgthOfPolyhConn);
1191 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly3D(zipFullReprOfPolyh,nbOfFaces,lgthOfPolyhConn,conn+newPos+1,newLgth);
1196 newType=(lgthOfCurCell==3)?INTERP_KERNEL::NORM_SEG2:INTERP_KERNEL::NORM_POLYL;
1200 ret=ret || (newType!=type);
1201 conn[newPos]=newType;
1203 posOfCurCell=index[i+1];
1208 std::copy(conn+posOfCurCell,conn+posOfCurCell+lgthOfCurCell,conn+newPos);
1209 newPos+=lgthOfCurCell;
1210 posOfCurCell+=lgthOfCurCell;
1214 if(newPos!=initMeshLgth)
1215 _nodal_connec->reAlloc(newPos);
1222 * This method expects that spaceDimension is equal to 3 and meshDimension equal to 3.
1223 * This method performs operation only on polyhedrons in \b this. If no polyhedrons exists in \b this, \b this remains unchanged.
1224 * This method allows to merge if any coplanar 3DSurf cells that may appear in some polyhedrons cells.
1226 * \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
1229 void MEDCouplingUMesh::simplifyPolyhedra(double eps)
1231 checkFullyDefined();
1232 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1233 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplifyPolyhedra : works on meshdimension 3 and spaceDimension 3 !");
1234 MCAuto<DataArrayDouble> coords=getCoords()->deepCopy();
1235 coords->recenterForMaxPrecision(eps);
1237 int nbOfCells=getNumberOfCells();
1238 const int *conn=_nodal_connec->getConstPointer();
1239 const int *index=_nodal_connec_index->getConstPointer();
1240 MCAuto<DataArrayInt> connINew=DataArrayInt::New();
1241 connINew->alloc(nbOfCells+1,1);
1242 int *connINewPtr=connINew->getPointer(); *connINewPtr++=0;
1243 MCAuto<DataArrayInt> connNew=DataArrayInt::New(); connNew->alloc(0,1);
1245 for(int i=0;i<nbOfCells;i++,connINewPtr++)
1247 if(conn[index[i]]==(int)INTERP_KERNEL::NORM_POLYHED)
1249 SimplifyPolyhedronCell(eps,coords,conn+index[i],conn+index[i+1],connNew);
1253 connNew->insertAtTheEnd(conn+index[i],conn+index[i+1]);
1254 *connINewPtr=connNew->getNumberOfTuples();
1257 setConnectivity(connNew,connINew,false);
1261 * This method returns all node ids used in the connectivity of \b this. The data array returned has to be dealt by the caller.
1262 * The returned node ids are sorted ascendingly. This method is close to MEDCouplingUMesh::getNodeIdsInUse except
1263 * the format of the returned DataArrayInt instance.
1265 * \return a newly allocated DataArrayInt sorted ascendingly of fetched node ids.
1266 * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1268 DataArrayInt *MEDCouplingUMesh::computeFetchedNodeIds() const
1270 checkConnectivityFullyDefined();
1271 const int *maxEltPt(std::max_element(_nodal_connec->begin(),_nodal_connec->end()));
1272 int maxElt(maxEltPt==_nodal_connec->end()?0:std::abs(*maxEltPt)+1);
1273 std::vector<bool> retS(maxElt,false);
1274 computeNodeIdsAlg(retS);
1275 return DataArrayInt::BuildListOfSwitchedOn(retS);
1279 * \param [in,out] nodeIdsInUse an array of size typically equal to nbOfNodes.
1280 * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1282 void MEDCouplingUMesh::computeNodeIdsAlg(std::vector<bool>& nodeIdsInUse) const
1284 int nbOfNodes((int)nodeIdsInUse.size()),nbOfCells(getNumberOfCells());
1285 const int *connIndex(_nodal_connec_index->getConstPointer()),*conn(_nodal_connec->getConstPointer());
1286 for(int i=0;i<nbOfCells;i++)
1287 for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1290 if(conn[j]<nbOfNodes)
1291 nodeIdsInUse[conn[j]]=true;
1294 std::ostringstream oss; oss << "MEDCouplingUMesh::computeNodeIdsAlg : In cell #" << i << " presence of node id " << conn[j] << " not in [0," << nbOfNodes << ") !";
1295 throw INTERP_KERNEL::Exception(oss.str());
1302 struct MEDCouplingAccVisit
1304 MEDCouplingAccVisit():_new_nb_of_nodes(0) { }
1305 int operator()(int val) { if(val!=-1) return _new_nb_of_nodes++; else return -1; }
1306 int _new_nb_of_nodes;
1312 * Finds nodes not used in any cell and returns an array giving a new id to every node
1313 * by excluding the unused nodes, for which the array holds -1. The result array is
1314 * a mapping in "Old to New" mode.
1315 * \param [out] nbrOfNodesInUse - number of node ids present in the nodal connectivity.
1316 * \return DataArrayInt * - a new instance of DataArrayInt. Its length is \a
1317 * this->getNumberOfNodes(). It holds for each node of \a this mesh either -1
1318 * if the node is unused or a new id else. The caller is to delete this
1319 * array using decrRef() as it is no more needed.
1320 * \throw If the coordinates array is not set.
1321 * \throw If the nodal connectivity of cells is not defined.
1322 * \throw If the nodal connectivity includes an invalid id.
1324 * \if ENABLE_EXAMPLES
1325 * \ref cpp_mcumesh_getNodeIdsInUse "Here is a C++ example".<br>
1326 * \ref py_mcumesh_getNodeIdsInUse "Here is a Python example".
1328 * \sa computeFetchedNodeIds, computeNodeIdsAlg()
1330 DataArrayInt *MEDCouplingUMesh::getNodeIdsInUse(int& nbrOfNodesInUse) const
1333 int nbOfNodes(getNumberOfNodes());
1334 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1335 ret->alloc(nbOfNodes,1);
1336 int *traducer=ret->getPointer();
1337 std::fill(traducer,traducer+nbOfNodes,-1);
1338 int nbOfCells=getNumberOfCells();
1339 const int *connIndex=_nodal_connec_index->getConstPointer();
1340 const int *conn=_nodal_connec->getConstPointer();
1341 for(int i=0;i<nbOfCells;i++)
1342 for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1345 if(conn[j]<nbOfNodes)
1346 traducer[conn[j]]=1;
1349 std::ostringstream oss; oss << "MEDCouplingUMesh::getNodeIdsInUse : In cell #" << i << " presence of node id " << conn[j] << " not in [0," << nbOfNodes << ") !";
1350 throw INTERP_KERNEL::Exception(oss.str());
1353 nbrOfNodesInUse=(int)std::count(traducer,traducer+nbOfNodes,1);
1354 std::transform(traducer,traducer+nbOfNodes,traducer,MEDCouplingAccVisit());
1359 * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1360 * For each cell in \b this the number of nodes constituting cell is computed.
1361 * For each polyhedron cell, the sum of the number of nodes of each face constituting polyhedron cell is returned.
1362 * So for pohyhedrons some nodes can be counted several times in the returned result.
1364 * \return a newly allocated array
1365 * \sa MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell
1367 DataArrayInt *MEDCouplingUMesh::computeNbOfNodesPerCell() const
1369 checkConnectivityFullyDefined();
1370 int nbOfCells=getNumberOfCells();
1371 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1372 ret->alloc(nbOfCells,1);
1373 int *retPtr=ret->getPointer();
1374 const int *conn=getNodalConnectivity()->getConstPointer();
1375 const int *connI=getNodalConnectivityIndex()->getConstPointer();
1376 for(int i=0;i<nbOfCells;i++,retPtr++)
1378 if(conn[connI[i]]!=(int)INTERP_KERNEL::NORM_POLYHED)
1379 *retPtr=connI[i+1]-connI[i]-1;
1381 *retPtr=connI[i+1]-connI[i]-1-std::count(conn+connI[i]+1,conn+connI[i+1],-1);
1387 * This method computes effective number of nodes per cell. That is to say nodes appearing several times in nodal connectivity of a cell,
1388 * will be counted only once here whereas it will be counted several times in MEDCouplingUMesh::computeNbOfNodesPerCell method.
1390 * \return DataArrayInt * - new object to be deallocated by the caller.
1391 * \sa MEDCouplingUMesh::computeNbOfNodesPerCell
1393 DataArrayInt *MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell() const
1395 checkConnectivityFullyDefined();
1396 int nbOfCells=getNumberOfCells();
1397 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1398 ret->alloc(nbOfCells,1);
1399 int *retPtr=ret->getPointer();
1400 const int *conn=getNodalConnectivity()->getConstPointer();
1401 const int *connI=getNodalConnectivityIndex()->getConstPointer();
1402 for(int i=0;i<nbOfCells;i++,retPtr++)
1404 std::set<int> s(conn+connI[i]+1,conn+connI[i+1]);
1405 if(conn[connI[i]]!=(int)INTERP_KERNEL::NORM_POLYHED)
1406 *retPtr=(int)s.size();
1410 *retPtr=(int)s.size();
1417 * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1418 * For each cell in \b this the number of faces constituting (entity of dimension this->getMeshDimension()-1) cell is computed.
1420 * \return a newly allocated array
1422 DataArrayInt *MEDCouplingUMesh::computeNbOfFacesPerCell() const
1424 checkConnectivityFullyDefined();
1425 int nbOfCells=getNumberOfCells();
1426 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1427 ret->alloc(nbOfCells,1);
1428 int *retPtr=ret->getPointer();
1429 const int *conn=getNodalConnectivity()->getConstPointer();
1430 const int *connI=getNodalConnectivityIndex()->getConstPointer();
1431 for(int i=0;i<nbOfCells;i++,retPtr++,connI++)
1433 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]);
1434 *retPtr=cm.getNumberOfSons2(conn+connI[0]+1,connI[1]-connI[0]-1);
1440 * Removes unused nodes (the node coordinates array is shorten) and returns an array
1441 * mapping between new and old node ids in "Old to New" mode. -1 values in the returned
1442 * array mean that the corresponding old node is no more used.
1443 * \return DataArrayInt * - a new instance of DataArrayInt of length \a
1444 * this->getNumberOfNodes() before call of this method. The caller is to
1445 * delete this array using decrRef() as it is no more needed.
1446 * \throw If the coordinates array is not set.
1447 * \throw If the nodal connectivity of cells is not defined.
1448 * \throw If the nodal connectivity includes an invalid id.
1449 * \sa areAllNodesFetched
1451 * \if ENABLE_EXAMPLES
1452 * \ref cpp_mcumesh_zipCoordsTraducer "Here is a C++ example".<br>
1453 * \ref py_mcumesh_zipCoordsTraducer "Here is a Python example".
1456 DataArrayInt *MEDCouplingUMesh::zipCoordsTraducer()
1458 return MEDCouplingPointSet::zipCoordsTraducer();
1462 * This method stands if 'cell1' and 'cell2' are equals regarding 'compType' policy.
1463 * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1465 int MEDCouplingUMesh::AreCellsEqual(const int *conn, const int *connI, int cell1, int cell2, int compType)
1470 return AreCellsEqualPolicy0(conn,connI,cell1,cell2);
1472 return AreCellsEqualPolicy1(conn,connI,cell1,cell2);
1474 return AreCellsEqualPolicy2(conn,connI,cell1,cell2);
1476 return AreCellsEqualPolicy2NoType(conn,connI,cell1,cell2);
1478 return AreCellsEqualPolicy7(conn,connI,cell1,cell2);
1480 throw INTERP_KERNEL::Exception("Unknown comparison asked ! Must be in 0,1,2,3 or 7.");
1484 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 0.
1486 int MEDCouplingUMesh::AreCellsEqualPolicy0(const int *conn, const int *connI, int cell1, int cell2)
1488 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1489 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;
1494 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 1.
1496 int MEDCouplingUMesh::AreCellsEqualPolicy1(const int *conn, const int *connI, int cell1, int cell2)
1498 int sz=connI[cell1+1]-connI[cell1];
1499 if(sz==connI[cell2+1]-connI[cell2])
1501 if(conn[connI[cell1]]==conn[connI[cell2]])
1503 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1504 unsigned dim=cm.getDimension();
1510 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz1];
1511 int *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(int *)tmp);
1512 std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1513 work=std::search((int *)tmp,(int *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1514 return work!=tmp+sz1?1:0;
1517 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;//case of SEG2 and SEG3
1520 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy1 : not implemented yet for meshdim == 3 !");
1527 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 2.
1529 int MEDCouplingUMesh::AreCellsEqualPolicy2(const int *conn, const int *connI, int cell1, int cell2)
1531 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1533 if(conn[connI[cell1]]==conn[connI[cell2]])
1535 std::set<int> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1536 std::set<int> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1544 * This method is less restrictive than AreCellsEqualPolicy2. Here the geometric type is absolutely not taken into account !
1546 int MEDCouplingUMesh::AreCellsEqualPolicy2NoType(const int *conn, const int *connI, int cell1, int cell2)
1548 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1550 std::set<int> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1551 std::set<int> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1558 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 7.
1560 int MEDCouplingUMesh::AreCellsEqualPolicy7(const int *conn, const int *connI, int cell1, int cell2)
1562 int sz=connI[cell1+1]-connI[cell1];
1563 if(sz==connI[cell2+1]-connI[cell2])
1565 if(conn[connI[cell1]]==conn[connI[cell2]])
1567 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1568 unsigned dim=cm.getDimension();
1574 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz1];
1575 int *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(int *)tmp);
1576 std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1577 work=std::search((int *)tmp,(int *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1582 std::reverse_iterator<int *> it1((int *)tmp+sz1);
1583 std::reverse_iterator<int *> it2((int *)tmp);
1584 if(std::search(it1,it2,conn+connI[cell2]+1,conn+connI[cell2+1])!=it2)
1590 return work!=tmp+sz1?1:0;
1593 {//case of SEG2 and SEG3
1594 if(std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1))
1596 if(!cm.isQuadratic())
1598 std::reverse_iterator<const int *> it1(conn+connI[cell1+1]);
1599 std::reverse_iterator<const int *> it2(conn+connI[cell1]+1);
1600 if(std::equal(it1,it2,conn+connI[cell2]+1))
1606 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])
1613 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy7 : not implemented yet for meshdim == 3 !");
1621 * This method find cells that are equal (regarding \a compType) in \a this. The comparison is specified
1623 * This method keeps the coordiantes of \a this. This method is time consuming.
1625 * \param [in] compType input specifying the technique used to compare cells each other.
1626 * - 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.
1627 * - 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)
1628 * and their type equal. For 1D mesh the policy 1 is equivalent to 0.
1629 * - 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
1630 * can be used for users not sensitive to orientation of cell
1631 * \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.
1632 * \param [out] commonCellsArr common cells ids (\ref numbering-indirect)
1633 * \param [out] commonCellsIArr common cells ids (\ref numbering-indirect)
1634 * \return the correspondance array old to new in a newly allocated array.
1637 void MEDCouplingUMesh::findCommonCells(int compType, int startCellId, DataArrayInt *& commonCellsArr, DataArrayInt *& commonCellsIArr) const
1639 MCAuto<DataArrayInt> revNodal=DataArrayInt::New(),revNodalI=DataArrayInt::New();
1640 getReverseNodalConnectivity(revNodal,revNodalI);
1641 FindCommonCellsAlg(compType,startCellId,_nodal_connec,_nodal_connec_index,revNodal,revNodalI,commonCellsArr,commonCellsIArr);
1644 void MEDCouplingUMesh::FindCommonCellsAlg(int compType, int startCellId, const DataArrayInt *nodal, const DataArrayInt *nodalI, const DataArrayInt *revNodal, const DataArrayInt *revNodalI,
1645 DataArrayInt *& commonCellsArr, DataArrayInt *& commonCellsIArr)
1647 MCAuto<DataArrayInt> commonCells=DataArrayInt::New(),commonCellsI=DataArrayInt::New(); commonCells->alloc(0,1);
1648 int nbOfCells=nodalI->getNumberOfTuples()-1;
1649 commonCellsI->reserve(1); commonCellsI->pushBackSilent(0);
1650 const int *revNodalPtr=revNodal->getConstPointer(),*revNodalIPtr=revNodalI->getConstPointer();
1651 const int *connPtr=nodal->getConstPointer(),*connIPtr=nodalI->getConstPointer();
1652 std::vector<bool> isFetched(nbOfCells,false);
1655 for(int i=0;i<nbOfCells;i++)
1659 const int *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind2nd(std::not_equal_to<int>(),-1));
1660 std::vector<int> v,v2;
1661 if(connOfNode!=connPtr+connIPtr[i+1])
1663 const int *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1664 v2.insert(v2.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1]);
1667 for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1671 const int *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1672 std::vector<int>::iterator it=std::set_intersection(v.begin(),v.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1673 v2.resize(std::distance(v2.begin(),it));
1677 if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1679 int pos=commonCellsI->back();
1680 commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1681 for(const int *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1682 isFetched[*it]=true;
1690 for(int i=startCellId;i<nbOfCells;i++)
1694 const int *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind2nd(std::not_equal_to<int>(),-1));
1695 std::vector<int> v,v2;
1696 if(connOfNode!=connPtr+connIPtr[i+1])
1698 v2.insert(v2.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1]);
1701 for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1705 std::vector<int>::iterator it=std::set_intersection(v.begin(),v.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1706 v2.resize(std::distance(v2.begin(),it));
1710 if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1712 int pos=commonCellsI->back();
1713 commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1714 for(const int *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1715 isFetched[*it]=true;
1721 commonCellsArr=commonCells.retn();
1722 commonCellsIArr=commonCellsI.retn();
1726 * Checks if \a this mesh includes all cells of an \a other mesh, and returns an array
1727 * giving for each cell of the \a other an id of a cell in \a this mesh. A value larger
1728 * than \a this->getNumberOfCells() in the returned array means that there is no
1729 * corresponding cell in \a this mesh.
1730 * It is expected that \a this and \a other meshes share the same node coordinates
1731 * array, if it is not so an exception is thrown.
1732 * \param [in] other - the mesh to compare with.
1733 * \param [in] compType - specifies a cell comparison technique. For meaning of its
1734 * valid values [0,1,2], see zipConnectivityTraducer().
1735 * \param [out] arr - a new instance of DataArrayInt returning correspondence
1736 * between cells of the two meshes. It contains \a other->getNumberOfCells()
1737 * values. The caller is to delete this array using
1738 * decrRef() as it is no more needed.
1739 * \return bool - \c true if all cells of \a other mesh are present in the \a this
1742 * \if ENABLE_EXAMPLES
1743 * \ref cpp_mcumesh_areCellsIncludedIn "Here is a C++ example".<br>
1744 * \ref py_mcumesh_areCellsIncludedIn "Here is a Python example".
1746 * \sa checkDeepEquivalOnSameNodesWith()
1747 * \sa checkGeoEquivalWith()
1749 bool MEDCouplingUMesh::areCellsIncludedIn(const MEDCouplingUMesh *other, int compType, DataArrayInt *& arr) const
1751 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1752 int nbOfCells=getNumberOfCells();
1753 static const int possibleCompType[]={0,1,2};
1754 if(std::find(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),compType)==possibleCompType+sizeof(possibleCompType)/sizeof(int))
1756 std::ostringstream oss; oss << "MEDCouplingUMesh::areCellsIncludedIn : only following policies are possible : ";
1757 std::copy(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),std::ostream_iterator<int>(oss," "));
1759 throw INTERP_KERNEL::Exception(oss.str());
1761 MCAuto<DataArrayInt> o2n=mesh->zipConnectivityTraducer(compType,nbOfCells);
1762 arr=o2n->subArray(nbOfCells);
1763 arr->setName(other->getName());
1765 if(other->getNumberOfCells()==0)
1767 return arr->getMaxValue(tmp)<nbOfCells;
1771 * This method makes the assumption that \a this and \a other share the same coords. If not an exception will be thrown !
1772 * This method tries to determine if \b other is fully included in \b this.
1773 * The main difference is that this method is not expected to throw exception.
1774 * This method has two outputs :
1776 * \param other other mesh
1777 * \param arr is an output parameter that returns a \b newly created instance. This array is of size 'other->getNumberOfCells()'.
1778 * \return If \a other is fully included in 'this 'true is returned. If not false is returned.
1780 bool MEDCouplingUMesh::areCellsIncludedInPolicy7(const MEDCouplingUMesh *other, DataArrayInt *& arr) const
1782 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1783 DataArrayInt *commonCells=0,*commonCellsI=0;
1784 int thisNbCells=getNumberOfCells();
1785 mesh->findCommonCells(7,thisNbCells,commonCells,commonCellsI);
1786 MCAuto<DataArrayInt> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1787 const int *commonCellsPtr=commonCells->getConstPointer(),*commonCellsIPtr=commonCellsI->getConstPointer();
1788 int otherNbCells=other->getNumberOfCells();
1789 MCAuto<DataArrayInt> arr2=DataArrayInt::New();
1790 arr2->alloc(otherNbCells,1);
1791 arr2->fillWithZero();
1792 int *arr2Ptr=arr2->getPointer();
1793 int nbOfCommon=commonCellsI->getNumberOfTuples()-1;
1794 for(int i=0;i<nbOfCommon;i++)
1796 int start=commonCellsPtr[commonCellsIPtr[i]];
1797 if(start<thisNbCells)
1799 for(int j=commonCellsIPtr[i]+1;j!=commonCellsIPtr[i+1];j++)
1801 int sig=commonCellsPtr[j]>0?1:-1;
1802 int val=std::abs(commonCellsPtr[j])-1;
1803 if(val>=thisNbCells)
1804 arr2Ptr[val-thisNbCells]=sig*(start+1);
1808 arr2->setName(other->getName());
1809 if(arr2->presenceOfValue(0))
1815 MEDCouplingUMesh *MEDCouplingUMesh::mergeMyselfWithOnSameCoords(const MEDCouplingPointSet *other) const
1818 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : input other is null !");
1819 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
1821 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : the input other mesh is not of type unstructured !");
1822 std::vector<const MEDCouplingUMesh *> ms(2);
1825 return MergeUMeshesOnSameCoords(ms);
1829 * Build a sub part of \b this lying or not on the same coordinates than \b this (regarding value of \b keepCoords).
1830 * By default coordinates are kept. This method is close to MEDCouplingUMesh::buildPartOfMySelf except that here input
1831 * cellIds is not given explicitely but by a range python like.
1836 * \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.
1837 * \return a newly allocated
1839 * \warning This method modifies can generate an unstructured mesh whose cells are not sorted by geometric type order.
1840 * In view of the MED file writing, a renumbering of cells of returned unstructured mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
1842 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfSlice(int start, int end, int step, bool keepCoords) const
1844 if(getMeshDimension()!=-1)
1845 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelfSlice(start,end,step,keepCoords));
1848 int newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfSlice for -1 dimension mesh ");
1850 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
1852 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
1854 return const_cast<MEDCouplingUMesh *>(this);
1859 * Creates a new MEDCouplingUMesh containing specified cells of \a this mesh.
1860 * The result mesh shares or not the node coordinates array with \a this mesh depending
1861 * on \a keepCoords parameter.
1862 * \warning Cells of the result mesh can be \b not sorted by geometric type, hence,
1863 * to write this mesh to the MED file, its cells must be sorted using
1864 * sortCellsInMEDFileFrmt().
1865 * \param [in] begin - an array of cell ids to include to the new mesh.
1866 * \param [in] end - a pointer to last-plus-one-th element of \a begin.
1867 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
1868 * array of \a this mesh, else "free" nodes are removed from the result mesh
1869 * by calling zipCoords().
1870 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
1871 * to delete this mesh using decrRef() as it is no more needed.
1872 * \throw If the coordinates array is not set.
1873 * \throw If the nodal connectivity of cells is not defined.
1874 * \throw If any cell id in the array \a begin is not valid.
1876 * \if ENABLE_EXAMPLES
1877 * \ref cpp_mcumesh_buildPartOfMySelf "Here is a C++ example".<br>
1878 * \ref py_mcumesh_buildPartOfMySelf "Here is a Python example".
1881 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelf(const int *begin, const int *end, bool keepCoords) const
1883 if(getMeshDimension()!=-1)
1884 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelf(begin,end,keepCoords));
1888 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
1890 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
1892 return const_cast<MEDCouplingUMesh *>(this);
1897 * This method operates only on nodal connectivity on \b this. Coordinates of \b this is completely ignored here.
1899 * 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.
1900 * Size of [ \b cellIdsBg, \b cellIdsEnd ) ) must be equal to the number of cells of otherOnSameCoordsThanThis.
1901 * The number of cells of \b this will remain the same with this method.
1903 * \param [in] cellIdsBg begin of cell ids (included) of cells in this to assign
1904 * \param [in] cellIdsEnd end of cell ids (excluded) of cells in this to assign
1905 * \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 ).
1906 * Coordinate pointer of \b this and those of \b otherOnSameCoordsThanThis must be the same
1908 void MEDCouplingUMesh::setPartOfMySelf(const int *cellIdsBg, const int *cellIdsEnd, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
1910 checkConnectivityFullyDefined();
1911 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
1912 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
1913 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelf : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
1914 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
1916 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
1917 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
1918 throw INTERP_KERNEL::Exception(oss.str());
1920 int nbOfCellsToModify=(int)std::distance(cellIdsBg,cellIdsEnd);
1921 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
1923 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
1924 throw INTERP_KERNEL::Exception(oss.str());
1926 int nbOfCells=getNumberOfCells();
1927 bool easyAssign=true;
1928 const int *connI=_nodal_connec_index->getConstPointer();
1929 const int *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
1930 for(const int *it=cellIdsBg;it!=cellIdsEnd && easyAssign;it++,connIOther++)
1932 if(*it>=0 && *it<nbOfCells)
1934 easyAssign=(connIOther[1]-connIOther[0])==(connI[*it+1]-connI[*it]);
1938 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : On pos #" << std::distance(cellIdsBg,it) << " id is equal to " << *it << " which is not in [0," << nbOfCells << ") !";
1939 throw INTERP_KERNEL::Exception(oss.str());
1944 MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
1949 DataArrayInt *arrOut=0,*arrIOut=0;
1950 MEDCouplingUMesh::SetPartOfIndexedArrays(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
1952 MCAuto<DataArrayInt> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
1953 setConnectivity(arrOut,arrIOut,true);
1957 void MEDCouplingUMesh::setPartOfMySelfSlice(int start, int end, int step, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
1959 checkConnectivityFullyDefined();
1960 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
1961 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
1962 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelfSlice : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
1963 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
1965 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
1966 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
1967 throw INTERP_KERNEL::Exception(oss.str());
1969 int nbOfCellsToModify=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::setPartOfMySelfSlice : ");
1970 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
1972 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
1973 throw INTERP_KERNEL::Exception(oss.str());
1975 int nbOfCells=getNumberOfCells();
1976 bool easyAssign=true;
1977 const int *connI=_nodal_connec_index->getConstPointer();
1978 const int *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
1980 for(int i=0;i<nbOfCellsToModify && easyAssign;i++,it+=step,connIOther++)
1982 if(it>=0 && it<nbOfCells)
1984 easyAssign=(connIOther[1]-connIOther[0])==(connI[it+1]-connI[it]);
1988 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : On pos #" << i << " id is equal to " << it << " which is not in [0," << nbOfCells << ") !";
1989 throw INTERP_KERNEL::Exception(oss.str());
1994 MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
1999 DataArrayInt *arrOut=0,*arrIOut=0;
2000 MEDCouplingUMesh::SetPartOfIndexedArraysSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2002 MCAuto<DataArrayInt> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2003 setConnectivity(arrOut,arrIOut,true);
2009 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2010 * this->getMeshDimension(), that bound some cells of \a this mesh.
2011 * The cells of lower dimension to include to the result mesh are selected basing on
2012 * specified node ids and the value of \a fullyIn parameter. If \a fullyIn ==\c true, a
2013 * cell is copied if its all nodes are in the array \a begin of node ids. If \a fullyIn
2014 * ==\c false, a cell is copied if any its node is in the array of node ids. The
2015 * created mesh shares the node coordinates array with \a this mesh.
2016 * \param [in] begin - the array of node ids.
2017 * \param [in] end - a pointer to the (last+1)-th element of \a begin.
2018 * \param [in] fullyIn - if \c true, then cells whose all nodes are in the
2019 * array \a begin are added, else cells whose any node is in the
2020 * array \a begin are added.
2021 * \return MEDCouplingUMesh * - new instance of MEDCouplingUMesh. The caller is
2022 * to delete this mesh using decrRef() as it is no more needed.
2023 * \throw If the coordinates array is not set.
2024 * \throw If the nodal connectivity of cells is not defined.
2025 * \throw If any node id in \a begin is not valid.
2027 * \if ENABLE_EXAMPLES
2028 * \ref cpp_mcumesh_buildFacePartOfMySelfNode "Here is a C++ example".<br>
2029 * \ref py_mcumesh_buildFacePartOfMySelfNode "Here is a Python example".
2032 MEDCouplingUMesh *MEDCouplingUMesh::buildFacePartOfMySelfNode(const int *begin, const int *end, bool fullyIn) const
2034 MCAuto<DataArrayInt> desc,descIndx,revDesc,revDescIndx;
2035 desc=DataArrayInt::New(); descIndx=DataArrayInt::New(); revDesc=DataArrayInt::New(); revDescIndx=DataArrayInt::New();
2036 MCAuto<MEDCouplingUMesh> subMesh=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2037 desc=0; descIndx=0; revDesc=0; revDescIndx=0;
2038 return static_cast<MEDCouplingUMesh*>(subMesh->buildPartOfMySelfNode(begin,end,fullyIn));
2042 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2043 * this->getMeshDimension(), which bound only one cell of \a this mesh.
2044 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2045 * array of \a this mesh, else "free" nodes are removed from the result mesh
2046 * by calling zipCoords().
2047 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2048 * to delete this mesh using decrRef() as it is no more needed.
2049 * \throw If the coordinates array is not set.
2050 * \throw If the nodal connectivity of cells is not defined.
2052 * \if ENABLE_EXAMPLES
2053 * \ref cpp_mcumesh_buildBoundaryMesh "Here is a C++ example".<br>
2054 * \ref py_mcumesh_buildBoundaryMesh "Here is a Python example".
2057 MEDCouplingUMesh *MEDCouplingUMesh::buildBoundaryMesh(bool keepCoords) const
2059 DataArrayInt *desc=DataArrayInt::New();
2060 DataArrayInt *descIndx=DataArrayInt::New();
2061 DataArrayInt *revDesc=DataArrayInt::New();
2062 DataArrayInt *revDescIndx=DataArrayInt::New();
2064 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2067 descIndx->decrRef();
2068 int nbOfCells=meshDM1->getNumberOfCells();
2069 const int *revDescIndxC=revDescIndx->getConstPointer();
2070 std::vector<int> boundaryCells;
2071 for(int i=0;i<nbOfCells;i++)
2072 if(revDescIndxC[i+1]-revDescIndxC[i]==1)
2073 boundaryCells.push_back(i);
2074 revDescIndx->decrRef();
2075 MEDCouplingUMesh *ret=meshDM1->buildPartOfMySelf(&boundaryCells[0],&boundaryCells[0]+boundaryCells.size(),keepCoords);
2080 * This method returns a newly created DataArrayInt instance containing ids of cells located in boundary.
2081 * A cell is detected to be on boundary if it contains one or more than one face having only one father.
2082 * This method makes the assumption that \a this is fully defined (coords,connectivity). If not an exception will be thrown.
2084 DataArrayInt *MEDCouplingUMesh::findCellIdsOnBoundary() const
2086 checkFullyDefined();
2087 MCAuto<DataArrayInt> desc=DataArrayInt::New();
2088 MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
2089 MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
2090 MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
2092 buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx)->decrRef();
2093 desc=(DataArrayInt*)0; descIndx=(DataArrayInt*)0;
2095 MCAuto<DataArrayInt> tmp=revDescIndx->deltaShiftIndex();
2096 MCAuto<DataArrayInt> faceIds=tmp->findIdsEqual(1); tmp=(DataArrayInt*)0;
2097 const int *revDescPtr=revDesc->getConstPointer();
2098 const int *revDescIndxPtr=revDescIndx->getConstPointer();
2099 int nbOfCells=getNumberOfCells();
2100 std::vector<bool> ret1(nbOfCells,false);
2102 for(const int *pt=faceIds->begin();pt!=faceIds->end();pt++)
2103 if(!ret1[revDescPtr[revDescIndxPtr[*pt]]])
2104 { ret1[revDescPtr[revDescIndxPtr[*pt]]]=true; sz++; }
2106 DataArrayInt *ret2=DataArrayInt::New();
2108 int *ret2Ptr=ret2->getPointer();
2110 for(std::vector<bool>::const_iterator it=ret1.begin();it!=ret1.end();it++,sz++)
2113 ret2->setName("BoundaryCells");
2118 * This method finds in \b this the cell ids that lie on mesh \b otherDimM1OnSameCoords.
2119 * \b this and \b otherDimM1OnSameCoords have to lie on the same coordinate array pointer. The coherency of that coords array with connectivity
2120 * of \b this and \b otherDimM1OnSameCoords is not important here because this method works only on connectivity.
2121 * this->getMeshDimension() - 1 must be equal to otherDimM1OnSameCoords.getMeshDimension()
2123 * s0 is the cell ids set in \b this lying on at least one node in the fetched nodes in \b otherDimM1OnSameCoords.
2124 * 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
2125 * equals a cell in \b otherDimM1OnSameCoords.
2127 * \throw if \b otherDimM1OnSameCoords is not part of constituent of \b this, or if coordinate pointer of \b this and \b otherDimM1OnSameCoords
2128 * are not same, or if this->getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension()
2130 * \param [in] otherDimM1OnSameCoords
2131 * \param [out] cellIdsRk0 a newly allocated array containing the cell ids of s0 (which are cell ids of \b this) in the above algorithm.
2132 * \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
2133 * cellIdsRk1->transformWithIndArr(cellIdsRk0->begin(),cellIdsRk0->end());
2135 void MEDCouplingUMesh::findCellIdsLyingOn(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayInt *&cellIdsRk0, DataArrayInt *&cellIdsRk1) const
2137 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2138 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : coordinates pointer are not the same ! Use tryToShareSameCoords method !");
2139 checkConnectivityFullyDefined();
2140 otherDimM1OnSameCoords.checkConnectivityFullyDefined();
2141 if(getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension())
2142 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : invalid mesh dimension of input mesh regarding meshdimesion of this !");
2143 MCAuto<DataArrayInt> fetchedNodeIds1=otherDimM1OnSameCoords.computeFetchedNodeIds();
2144 MCAuto<DataArrayInt> s0arr=getCellIdsLyingOnNodes(fetchedNodeIds1->begin(),fetchedNodeIds1->end(),false);
2145 MCAuto<MEDCouplingUMesh> thisPart=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(s0arr->begin(),s0arr->end(),true));
2146 MCAuto<DataArrayInt> descThisPart=DataArrayInt::New(),descIThisPart=DataArrayInt::New(),revDescThisPart=DataArrayInt::New(),revDescIThisPart=DataArrayInt::New();
2147 MCAuto<MEDCouplingUMesh> thisPartConsti=thisPart->buildDescendingConnectivity(descThisPart,descIThisPart,revDescThisPart,revDescIThisPart);
2148 const int *revDescThisPartPtr=revDescThisPart->getConstPointer(),*revDescIThisPartPtr=revDescIThisPart->getConstPointer();
2149 DataArrayInt *idsOtherInConsti=0;
2150 bool b=thisPartConsti->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsOtherInConsti);
2151 MCAuto<DataArrayInt> idsOtherInConstiAuto(idsOtherInConsti);
2153 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : the given mdim-1 mesh in other is not a constituent of this !");
2155 for(const int *idOther=idsOtherInConsti->begin();idOther!=idsOtherInConsti->end();idOther++)
2156 s1.insert(revDescThisPartPtr+revDescIThisPartPtr[*idOther],revDescThisPartPtr+revDescIThisPartPtr[*idOther+1]);
2157 MCAuto<DataArrayInt> s1arr_renum1=DataArrayInt::New(); s1arr_renum1->alloc((int)s1.size(),1); std::copy(s1.begin(),s1.end(),s1arr_renum1->getPointer());
2158 s1arr_renum1->sort();
2159 cellIdsRk0=s0arr.retn();
2160 //cellIdsRk1=s_renum1.retn();
2161 cellIdsRk1=s1arr_renum1.retn();
2165 * 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
2166 * returned. This subpart of meshdim-1 mesh is built using meshdim-1 cells in it shared only one cell in \b this.
2168 * \return a newly allocated mesh lying on the same coordinates than \b this. The caller has to deal with returned mesh.
2170 MEDCouplingUMesh *MEDCouplingUMesh::computeSkin() const
2172 MCAuto<DataArrayInt> desc=DataArrayInt::New();
2173 MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
2174 MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
2175 MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
2177 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2178 revDesc=0; desc=0; descIndx=0;
2179 MCAuto<DataArrayInt> revDescIndx2=revDescIndx->deltaShiftIndex();
2180 MCAuto<DataArrayInt> part=revDescIndx2->findIdsEqual(1);
2181 return static_cast<MEDCouplingUMesh *>(meshDM1->buildPartOfMySelf(part->begin(),part->end(),true));
2185 * Finds nodes lying on the boundary of \a this mesh.
2186 * \return DataArrayInt * - a new instance of DataArrayInt holding ids of found
2187 * nodes. The caller is to delete this array using decrRef() as it is no
2189 * \throw If the coordinates array is not set.
2190 * \throw If the nodal connectivity of cells is node defined.
2192 * \if ENABLE_EXAMPLES
2193 * \ref cpp_mcumesh_findBoundaryNodes "Here is a C++ example".<br>
2194 * \ref py_mcumesh_findBoundaryNodes "Here is a Python example".
2197 DataArrayInt *MEDCouplingUMesh::findBoundaryNodes() const
2199 MCAuto<MEDCouplingUMesh> skin=computeSkin();
2200 return skin->computeFetchedNodeIds();
2203 MEDCouplingUMesh *MEDCouplingUMesh::buildUnstructured() const
2206 return const_cast<MEDCouplingUMesh *>(this);
2210 * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2211 * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2212 * 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.
2213 * 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.
2214 * 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.
2216 * \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
2217 * parameter is altered during the call.
2218 * \param [out] nodeIdsToDuplicate node ids needed to be duplicated following the algorithm explain above.
2219 * \param [out] cellIdsNeededToBeRenum cell ids in \b this in which the renumber of nodes should be performed.
2220 * \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.
2222 * \warning This method modifies param \b otherDimM1OnSameCoords (for speed reasons).
2224 void MEDCouplingUMesh::findNodesToDuplicate(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayInt *& nodeIdsToDuplicate,
2225 DataArrayInt *& cellIdsNeededToBeRenum, DataArrayInt *& cellIdsNotModified) const
2227 typedef MCAuto<DataArrayInt> DAInt;
2228 typedef MCAuto<MEDCouplingUMesh> MCUMesh;
2230 checkFullyDefined();
2231 otherDimM1OnSameCoords.checkFullyDefined();
2232 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2233 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : meshes do not share the same coords array !");
2234 if(otherDimM1OnSameCoords.getMeshDimension()!=getMeshDimension()-1)
2235 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the mesh given in other parameter must have this->getMeshDimension()-1 !");
2237 // Checking star-shaped M1 group:
2238 DAInt dt0=DataArrayInt::New(),dit0=DataArrayInt::New(),rdt0=DataArrayInt::New(),rdit0=DataArrayInt::New();
2239 MCUMesh meshM2 = otherDimM1OnSameCoords.buildDescendingConnectivity(dt0, dit0, rdt0, rdit0);
2240 DAInt dsi = rdit0->deltaShiftIndex();
2241 DAInt idsTmp0 = dsi->findIdsNotInRange(-1, 3);
2242 if(idsTmp0->getNumberOfTuples())
2243 throw INTERP_KERNEL::Exception("MEDFileUMesh::buildInnerBoundaryAlongM1Group: group is too complex: some points (or edges) have more than two connected segments (or faces)!");
2244 dt0=0; dit0=0; rdt0=0; rdit0=0; idsTmp0=0;
2246 // Get extreme nodes from the group (they won't be duplicated), ie nodes belonging to boundary cells of M1
2247 DAInt xtremIdsM2 = dsi->findIdsEqual(1); dsi = 0;
2248 MCUMesh meshM2Part = static_cast<MEDCouplingUMesh *>(meshM2->buildPartOfMySelf(xtremIdsM2->begin(), xtremIdsM2->end(),true));
2249 DAInt xtrem = meshM2Part->computeFetchedNodeIds();
2250 // Remove from the list points on the boundary of the M0 mesh (those need duplication!)
2251 dt0=DataArrayInt::New(),dit0=DataArrayInt::New(),rdt0=DataArrayInt::New(),rdit0=DataArrayInt::New();
2252 MCUMesh m0desc = buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); dt0=0; dit0=0; rdt0=0;
2253 dsi = rdit0->deltaShiftIndex();
2254 DAInt boundSegs = dsi->findIdsEqual(1); // boundary segs/faces of the M0 mesh
2255 MCUMesh m0descSkin = static_cast<MEDCouplingUMesh *>(m0desc->buildPartOfMySelf(boundSegs->begin(),boundSegs->end(), true));
2256 DAInt fNodes = m0descSkin->computeFetchedNodeIds();
2257 // In 3D, some points on the boundary of M0 still need duplication:
2259 if (getMeshDimension() == 3)
2261 DAInt dnu1=DataArrayInt::New(), dnu2=DataArrayInt::New(), dnu3=DataArrayInt::New(), dnu4=DataArrayInt::New();
2262 MCUMesh m0descSkinDesc = m0descSkin->buildDescendingConnectivity(dnu1, dnu2, dnu3, dnu4);
2263 dnu1=0;dnu2=0;dnu3=0;dnu4=0;
2264 DataArrayInt * corresp=0;
2265 meshM2->areCellsIncludedIn(m0descSkinDesc,2,corresp);
2266 DAInt validIds = corresp->findIdsInRange(0, meshM2->getNumberOfCells());
2268 if (validIds->getNumberOfTuples())
2270 MCUMesh m1IntersecSkin = static_cast<MEDCouplingUMesh *>(m0descSkinDesc->buildPartOfMySelf(validIds->begin(), validIds->end(), true));
2271 DAInt notDuplSkin = m1IntersecSkin->findBoundaryNodes();
2272 DAInt fNodes1 = fNodes->buildSubstraction(notDuplSkin);
2273 notDup = xtrem->buildSubstraction(fNodes1);
2276 notDup = xtrem->buildSubstraction(fNodes);
2279 notDup = xtrem->buildSubstraction(fNodes);
2281 // Now compute cells around group (i.e. cells where we will do the propagation to identify the two sub-sets delimited by the group)
2282 DAInt m1Nodes = otherDimM1OnSameCoords.computeFetchedNodeIds();
2283 DAInt dupl = m1Nodes->buildSubstraction(notDup);
2284 DAInt cellsAroundGroup = getCellIdsLyingOnNodes(dupl->begin(), dupl->end(), false); // false= take cell in, even if not all nodes are in notDup
2287 MCUMesh m0Part2=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(cellsAroundGroup->begin(),cellsAroundGroup->end(),true));
2288 int nCells2 = m0Part2->getNumberOfCells();
2289 DAInt desc00=DataArrayInt::New(),descI00=DataArrayInt::New(),revDesc00=DataArrayInt::New(),revDescI00=DataArrayInt::New();
2290 MCUMesh m01=m0Part2->buildDescendingConnectivity(desc00,descI00,revDesc00,revDescI00);
2292 // Neighbor information of the mesh without considering the crack (serves to count how many connex pieces it is made of)
2293 DataArrayInt *tmp00=0,*tmp11=0;
2294 MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00, tmp00, tmp11);
2295 DAInt neighInit00(tmp00);
2296 DAInt neighIInit00(tmp11);
2297 // Neighbor information of the mesh WITH the crack (some neighbors are removed):
2298 DataArrayInt *idsTmp=0;
2299 bool b=m01->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsTmp);
2301 // In the neighbor information remove the connection between high dimension cells and its low level constituents which are part
2302 // of the frontier given in parameter (i.e. the cells of low dimension from the group delimiting the crack):
2303 MEDCouplingUMesh::RemoveIdsFromIndexedArrays(ids->begin(),ids->end(),desc00,descI00);
2304 DataArrayInt *tmp0=0,*tmp1=0;
2305 // Compute the neighbor of each cell in m0Part2, taking into account the broken link above. Two
2306 // cells on either side of the crack (defined by the mesh of low dimension) are not neighbor anymore.
2307 ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00,tmp0,tmp1);
2308 DAInt neigh00(tmp0);
2309 DAInt neighI00(tmp1);
2311 // For each initial connex part of the sub-mesh (or said differently for each independent crack):
2312 int seed = 0, nIter = 0;
2313 int nIterMax = nCells2+1; // Safety net for the loop
2314 DAInt hitCells = DataArrayInt::New(); hitCells->alloc(nCells2);
2315 hitCells->fillWithValue(-1);
2316 DAInt cellsToModifyConn0_torenum = DataArrayInt::New();
2317 cellsToModifyConn0_torenum->alloc(0,1);
2318 while (nIter < nIterMax)
2320 DAInt t = hitCells->findIdsEqual(-1);
2321 if (!t->getNumberOfTuples())
2323 // Connex zone without the crack (to compute the next seed really)
2325 DAInt connexCheck = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neighInit00,neighIInit00, -1, dnu);
2327 for (int * ptr = connexCheck->getPointer(); cnt < connexCheck->getNumberOfTuples(); ptr++, cnt++)
2328 hitCells->setIJ(*ptr,0,1);
2329 // Connex zone WITH the crack (to identify cells lying on either part of the crack)
2330 DAInt spreadZone = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neigh00,neighI00, -1, dnu);
2331 cellsToModifyConn0_torenum = DataArrayInt::Aggregate(cellsToModifyConn0_torenum, spreadZone, 0);
2332 // Compute next seed, i.e. a cell in another connex part, which was not covered by the previous iterations
2333 DAInt comple = cellsToModifyConn0_torenum->buildComplement(nCells2);
2334 DAInt nonHitCells = hitCells->findIdsEqual(-1);
2335 DAInt intersec = nonHitCells->buildIntersection(comple);
2336 if (intersec->getNumberOfTuples())
2337 { seed = intersec->getIJ(0,0); }
2342 if (nIter >= nIterMax)
2343 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate(): internal error - too many iterations.");
2345 DAInt cellsToModifyConn1_torenum=cellsToModifyConn0_torenum->buildComplement(neighI00->getNumberOfTuples()-1);
2346 cellsToModifyConn0_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2347 cellsToModifyConn1_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2349 cellIdsNeededToBeRenum=cellsToModifyConn0_torenum.retn();
2350 cellIdsNotModified=cellsToModifyConn1_torenum.retn();
2351 nodeIdsToDuplicate=dupl.retn();
2355 * This method operates a modification of the connectivity and coords in \b this.
2356 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2357 * its ids will be modified to id this->getNumberOfNodes()+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2358 * 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
2359 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id this->getNumberOfNodes()+0, node id nodeIdsToDuplicateBg[1] will have id this->getNumberOfNodes()+1,
2360 * node id nodeIdsToDuplicateBg[2] will have id this->getNumberOfNodes()+2...
2362 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2364 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2365 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2367 void MEDCouplingUMesh::duplicateNodes(const int *nodeIdsToDuplicateBg, const int *nodeIdsToDuplicateEnd)
2369 int nbOfNodes=getNumberOfNodes();
2370 duplicateNodesInCoords(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd);
2371 duplicateNodesInConn(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,nbOfNodes);
2375 * This method renumbers only nodal connectivity in \a this. The renumbering is only an offset applied. So this method is a specialization of
2376 * \a renumberNodesInConn. \b WARNING, this method does not check that the resulting node ids in the nodal connectivity is in a valid range !
2378 * \param [in] offset - specifies the offset to be applied on each element of connectivity.
2380 * \sa renumberNodesInConn
2382 void MEDCouplingUMesh::renumberNodesWithOffsetInConn(int offset)
2384 checkConnectivityFullyDefined();
2385 int *conn(getNodalConnectivity()->getPointer());
2386 const int *connIndex(getNodalConnectivityIndex()->getConstPointer());
2387 int nbOfCells(getNumberOfCells());
2388 for(int i=0;i<nbOfCells;i++)
2389 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2391 int& node=conn[iconn];
2392 if(node>=0)//avoid polyhedron separator
2397 _nodal_connec->declareAsNew();
2402 * Same than renumberNodesInConn(const int *) except that here the format of old-to-new traducer is using map instead
2403 * 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
2406 void MEDCouplingUMesh::renumberNodesInConn(const INTERP_KERNEL::HashMap<int,int>& newNodeNumbersO2N)
2408 checkConnectivityFullyDefined();
2409 int *conn(getNodalConnectivity()->getPointer());
2410 const int *connIndex(getNodalConnectivityIndex()->getConstPointer());
2411 int nbOfCells(getNumberOfCells());
2412 for(int i=0;i<nbOfCells;i++)
2413 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2415 int& node=conn[iconn];
2416 if(node>=0)//avoid polyhedron separator
2418 INTERP_KERNEL::HashMap<int,int>::const_iterator it(newNodeNumbersO2N.find(node));
2419 if(it!=newNodeNumbersO2N.end())
2425 std::ostringstream oss; oss << "MEDCouplingUMesh::renumberNodesInConn(map) : presence in connectivity for cell #" << i << " of node #" << node << " : Not in map !";
2426 throw INTERP_KERNEL::Exception(oss.str());
2430 _nodal_connec->declareAsNew();
2435 * Changes ids of nodes within the nodal connectivity arrays according to a permutation
2436 * array in "Old to New" mode. The node coordinates array is \b not changed by this method.
2437 * This method is a generalization of shiftNodeNumbersInConn().
2438 * \warning This method performs no check of validity of new ids. **Use it with care !**
2439 * \param [in] newNodeNumbersO2N - a permutation array, of length \a
2440 * this->getNumberOfNodes(), in "Old to New" mode.
2441 * See \ref numbering for more info on renumbering modes.
2442 * \throw If the nodal connectivity of cells is not defined.
2444 * \if ENABLE_EXAMPLES
2445 * \ref cpp_mcumesh_renumberNodesInConn "Here is a C++ example".<br>
2446 * \ref py_mcumesh_renumberNodesInConn "Here is a Python example".
2449 void MEDCouplingUMesh::renumberNodesInConn(const int *newNodeNumbersO2N)
2451 checkConnectivityFullyDefined();
2452 int *conn=getNodalConnectivity()->getPointer();
2453 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2454 int nbOfCells(getNumberOfCells());
2455 for(int i=0;i<nbOfCells;i++)
2456 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2458 int& node=conn[iconn];
2459 if(node>=0)//avoid polyhedron separator
2461 node=newNodeNumbersO2N[node];
2464 _nodal_connec->declareAsNew();
2469 * This method renumbers nodes \b in \b connectivity \b only \b without \b any \b reference \b to \b coords.
2470 * This method performs no check on the fact that new coordinate ids are valid. \b Use \b it \b with \b care !
2471 * This method is an specialization of \ref MEDCoupling::MEDCouplingUMesh::renumberNodesInConn "renumberNodesInConn method".
2473 * \param [in] delta specifies the shift size applied to nodeId in nodal connectivity in \b this.
2475 void MEDCouplingUMesh::shiftNodeNumbersInConn(int delta)
2477 checkConnectivityFullyDefined();
2478 int *conn=getNodalConnectivity()->getPointer();
2479 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2480 int nbOfCells=getNumberOfCells();
2481 for(int i=0;i<nbOfCells;i++)
2482 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2484 int& node=conn[iconn];
2485 if(node>=0)//avoid polyhedron separator
2490 _nodal_connec->declareAsNew();
2495 * This method operates a modification of the connectivity in \b this.
2496 * 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.
2497 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2498 * its ids will be modified to id offset+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2499 * 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
2500 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id offset+0, node id nodeIdsToDuplicateBg[1] will have id offset+1,
2501 * node id nodeIdsToDuplicateBg[2] will have id offset+2...
2503 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2504 * As an another consequense after the call of this method \b this can be transiently non cohrent.
2506 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2507 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2508 * \param [in] offset the offset applied to all node ids in connectivity that are in [ \a nodeIdsToDuplicateBg, \a nodeIdsToDuplicateEnd ).
2510 void MEDCouplingUMesh::duplicateNodesInConn(const int *nodeIdsToDuplicateBg, const int *nodeIdsToDuplicateEnd, int offset)
2512 checkConnectivityFullyDefined();
2513 std::map<int,int> m;
2515 for(const int *work=nodeIdsToDuplicateBg;work!=nodeIdsToDuplicateEnd;work++,val++)
2517 int *conn=getNodalConnectivity()->getPointer();
2518 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2519 int nbOfCells=getNumberOfCells();
2520 for(int i=0;i<nbOfCells;i++)
2521 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2523 int& node=conn[iconn];
2524 if(node>=0)//avoid polyhedron separator
2526 std::map<int,int>::iterator it=m.find(node);
2535 * This method renumbers cells of \a this using the array specified by [old2NewBg;old2NewBg+getNumberOfCells())
2537 * Contrary to MEDCouplingPointSet::renumberNodes, this method makes a permutation without any fuse of cell.
2538 * After the call of this method the number of cells remains the same as before.
2540 * If 'check' equals true the method will check that any elements in [ \a old2NewBg; \a old2NewEnd ) is unique ; if not
2541 * an INTERP_KERNEL::Exception will be thrown. When 'check' equals true [ \a old2NewBg ; \a old2NewEnd ) is not expected to
2542 * be strictly in [0;this->getNumberOfCells()).
2544 * If 'check' equals false the method will not check the content of [ \a old2NewBg ; \a old2NewEnd ).
2545 * To avoid any throw of SIGSEGV when 'check' equals false, the elements in [ \a old2NewBg ; \a old2NewEnd ) should be unique and
2546 * should be contained in[0;this->getNumberOfCells()).
2548 * \param [in] old2NewBg is expected to be a dynamically allocated pointer of size at least equal to this->getNumberOfCells()
2551 void MEDCouplingUMesh::renumberCells(const int *old2NewBg, bool check)
2553 checkConnectivityFullyDefined();
2554 int nbCells=getNumberOfCells();
2555 const int *array=old2NewBg;
2557 array=DataArrayInt::CheckAndPreparePermutation(old2NewBg,old2NewBg+nbCells);
2559 const int *conn=_nodal_connec->getConstPointer();
2560 const int *connI=_nodal_connec_index->getConstPointer();
2561 MCAuto<DataArrayInt> o2n=DataArrayInt::New(); o2n->useArray(array,false,C_DEALLOC,nbCells,1);
2562 MCAuto<DataArrayInt> n2o=o2n->invertArrayO2N2N2O(nbCells);
2563 const int *n2oPtr=n2o->begin();
2564 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
2565 newConn->alloc(_nodal_connec->getNumberOfTuples(),_nodal_connec->getNumberOfComponents());
2566 newConn->copyStringInfoFrom(*_nodal_connec);
2567 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
2568 newConnI->alloc(_nodal_connec_index->getNumberOfTuples(),_nodal_connec_index->getNumberOfComponents());
2569 newConnI->copyStringInfoFrom(*_nodal_connec_index);
2571 int *newC=newConn->getPointer();
2572 int *newCI=newConnI->getPointer();
2575 for(int i=0;i<nbCells;i++)
2578 int nbOfElts=connI[pos+1]-connI[pos];
2579 newC=std::copy(conn+connI[pos],conn+connI[pos+1],newC);
2584 setConnectivity(newConn,newConnI);
2586 free(const_cast<int *>(array));
2590 * Finds cells whose bounding boxes intersect a given bounding box.
2591 * \param [in] bbox - an array defining the bounding box via coordinates of its
2592 * extremum points in "no interlace" mode, i.e. xMin, xMax, yMin, yMax, zMin,
2594 * \param [in] eps - a factor used to increase size of the bounding box of cell
2595 * before comparing it with \a bbox. This factor is multiplied by the maximal
2596 * extent of the bounding box of cell to produce an addition to this bounding box.
2597 * \return DataArrayInt * - a new instance of DataArrayInt holding ids for found
2598 * cells. The caller is to delete this array using decrRef() as it is no more
2600 * \throw If the coordinates array is not set.
2601 * \throw If the nodal connectivity of cells is not defined.
2603 * \if ENABLE_EXAMPLES
2604 * \ref cpp_mcumesh_getCellsInBoundingBox "Here is a C++ example".<br>
2605 * \ref py_mcumesh_getCellsInBoundingBox "Here is a Python example".
2608 DataArrayInt *MEDCouplingUMesh::getCellsInBoundingBox(const double *bbox, double eps) const
2610 MCAuto<DataArrayInt> elems=DataArrayInt::New(); elems->alloc(0,1);
2611 if(getMeshDimension()==-1)
2613 elems->pushBackSilent(0);
2614 return elems.retn();
2616 int dim=getSpaceDimension();
2617 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2618 const int* conn = getNodalConnectivity()->getConstPointer();
2619 const int* conn_index= getNodalConnectivityIndex()->getConstPointer();
2620 const double* coords = getCoords()->getConstPointer();
2621 int nbOfCells=getNumberOfCells();
2622 for ( int ielem=0; ielem<nbOfCells;ielem++ )
2624 for (int i=0; i<dim; i++)
2626 elem_bb[i*2]=std::numeric_limits<double>::max();
2627 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2630 for (int inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2632 int node= conn[inode];
2633 if(node>=0)//avoid polyhedron separator
2635 for (int idim=0; idim<dim; idim++)
2637 if ( coords[node*dim+idim] < elem_bb[idim*2] )
2639 elem_bb[idim*2] = coords[node*dim+idim] ;
2641 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2643 elem_bb[idim*2+1] = coords[node*dim+idim] ;
2648 if (intersectsBoundingBox(elem_bb, bbox, dim, eps))
2649 elems->pushBackSilent(ielem);
2651 return elems.retn();
2655 * Given a boundary box 'bbox' returns elements 'elems' contained in this 'bbox' or touching 'bbox' (within 'eps' distance).
2656 * Warning 'elems' is incremented during the call so if elems is not empty before call returned elements will be
2657 * added in 'elems' parameter.
2659 DataArrayInt *MEDCouplingUMesh::getCellsInBoundingBox(const INTERP_KERNEL::DirectedBoundingBox& bbox, double eps)
2661 MCAuto<DataArrayInt> elems=DataArrayInt::New(); elems->alloc(0,1);
2662 if(getMeshDimension()==-1)
2664 elems->pushBackSilent(0);
2665 return elems.retn();
2667 int dim=getSpaceDimension();
2668 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2669 const int* conn = getNodalConnectivity()->getConstPointer();
2670 const int* conn_index= getNodalConnectivityIndex()->getConstPointer();
2671 const double* coords = getCoords()->getConstPointer();
2672 int nbOfCells=getNumberOfCells();
2673 for ( int ielem=0; ielem<nbOfCells;ielem++ )
2675 for (int i=0; i<dim; i++)
2677 elem_bb[i*2]=std::numeric_limits<double>::max();
2678 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2681 for (int inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2683 int node= conn[inode];
2684 if(node>=0)//avoid polyhedron separator
2686 for (int idim=0; idim<dim; idim++)
2688 if ( coords[node*dim+idim] < elem_bb[idim*2] )
2690 elem_bb[idim*2] = coords[node*dim+idim] ;
2692 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2694 elem_bb[idim*2+1] = coords[node*dim+idim] ;
2699 if(intersectsBoundingBox(bbox, elem_bb, dim, eps))
2700 elems->pushBackSilent(ielem);
2702 return elems.retn();
2706 * Returns a type of a cell by its id.
2707 * \param [in] cellId - the id of the cell of interest.
2708 * \return INTERP_KERNEL::NormalizedCellType - enumeration item describing the cell type.
2709 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2711 INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::getTypeOfCell(int cellId) const
2713 const int *ptI=_nodal_connec_index->getConstPointer();
2714 const int *pt=_nodal_connec->getConstPointer();
2715 if(cellId>=0 && cellId<(int)_nodal_connec_index->getNbOfElems()-1)
2716 return (INTERP_KERNEL::NormalizedCellType) pt[ptI[cellId]];
2719 std::ostringstream oss; oss << "MEDCouplingUMesh::getTypeOfCell : Requesting type of cell #" << cellId << " but it should be in [0," << _nodal_connec_index->getNbOfElems()-1 << ") !";
2720 throw INTERP_KERNEL::Exception(oss.str());
2725 * This method returns a newly allocated array containing cell ids (ascendingly sorted) whose geometric type are equal to type.
2726 * This method does not throw exception if geometric type \a type is not in \a this.
2727 * This method throws an INTERP_KERNEL::Exception if meshdimension of \b this is not equal to those of \b type.
2728 * The coordinates array is not considered here.
2730 * \param [in] type the geometric type
2731 * \return cell ids in this having geometric type \a type.
2733 DataArrayInt *MEDCouplingUMesh::giveCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2736 MCAuto<DataArrayInt> ret=DataArrayInt::New();
2738 checkConnectivityFullyDefined();
2739 int nbCells=getNumberOfCells();
2740 int mdim=getMeshDimension();
2741 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
2742 if(mdim!=(int)cm.getDimension())
2743 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::giveCellsWithType : Mismatch between mesh dimension and dimension of the cell !");
2744 const int *ptI=_nodal_connec_index->getConstPointer();
2745 const int *pt=_nodal_connec->getConstPointer();
2746 for(int i=0;i<nbCells;i++)
2748 if((INTERP_KERNEL::NormalizedCellType)pt[ptI[i]]==type)
2749 ret->pushBackSilent(i);
2755 * Returns nb of cells having the geometric type \a type. No throw if no cells in \a this has the geometric type \a type.
2757 int MEDCouplingUMesh::getNumberOfCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2759 const int *ptI=_nodal_connec_index->getConstPointer();
2760 const int *pt=_nodal_connec->getConstPointer();
2761 int nbOfCells=getNumberOfCells();
2763 for(int i=0;i<nbOfCells;i++)
2764 if((INTERP_KERNEL::NormalizedCellType) pt[ptI[i]]==type)
2770 * Returns the nodal connectivity of a given cell.
2771 * The separator of faces within polyhedron connectivity (-1) is not returned, thus
2772 * all returned node ids can be used in getCoordinatesOfNode().
2773 * \param [in] cellId - an id of the cell of interest.
2774 * \param [in,out] conn - a vector where the node ids are appended. It is not
2775 * cleared before the appending.
2776 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2778 void MEDCouplingUMesh::getNodeIdsOfCell(int cellId, std::vector<int>& conn) const
2780 const int *ptI=_nodal_connec_index->getConstPointer();
2781 const int *pt=_nodal_connec->getConstPointer();
2782 for(const int *w=pt+ptI[cellId]+1;w!=pt+ptI[cellId+1];w++)
2787 std::string MEDCouplingUMesh::simpleRepr() const
2789 static const char msg0[]="No coordinates specified !";
2790 std::ostringstream ret;
2791 ret << "Unstructured mesh with name : \"" << getName() << "\"\n";
2792 ret << "Description of mesh : \"" << getDescription() << "\"\n";
2794 double tt=getTime(tmpp1,tmpp2);
2795 ret << "Time attached to the mesh [unit] : " << tt << " [" << getTimeUnit() << "]\n";
2796 ret << "Iteration : " << tmpp1 << " Order : " << tmpp2 << "\n";
2798 { ret << "Mesh dimension : " << _mesh_dim << "\nSpace dimension : "; }
2800 { ret << " Mesh dimension has not been set or is invalid !"; }
2803 const int spaceDim=getSpaceDimension();
2804 ret << spaceDim << "\nInfo attached on space dimension : ";
2805 for(int i=0;i<spaceDim;i++)
2806 ret << "\"" << _coords->getInfoOnComponent(i) << "\" ";
2810 ret << msg0 << "\n";
2811 ret << "Number of nodes : ";
2813 ret << getNumberOfNodes() << "\n";
2815 ret << msg0 << "\n";
2816 ret << "Number of cells : ";
2817 if(_nodal_connec!=0 && _nodal_connec_index!=0)
2818 ret << getNumberOfCells() << "\n";
2820 ret << "No connectivity specified !" << "\n";
2821 ret << "Cell types present : ";
2822 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
2824 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter);
2825 ret << cm.getRepr() << " ";
2831 std::string MEDCouplingUMesh::advancedRepr() const
2833 std::ostringstream ret;
2834 ret << simpleRepr();
2835 ret << "\nCoordinates array : \n___________________\n\n";
2837 _coords->reprWithoutNameStream(ret);
2839 ret << "No array set !\n";
2840 ret << "\n\nConnectivity arrays : \n_____________________\n\n";
2841 reprConnectivityOfThisLL(ret);
2846 * This method returns a C++ code that is a dump of \a this.
2847 * This method will throw if this is not fully defined.
2849 std::string MEDCouplingUMesh::cppRepr() const
2851 static const char coordsName[]="coords";
2852 static const char connName[]="conn";
2853 static const char connIName[]="connI";
2854 checkFullyDefined();
2855 std::ostringstream ret; ret << "// coordinates" << std::endl;
2856 _coords->reprCppStream(coordsName,ret); ret << std::endl << "// connectivity" << std::endl;
2857 _nodal_connec->reprCppStream(connName,ret); ret << std::endl;
2858 _nodal_connec_index->reprCppStream(connIName,ret); ret << std::endl;
2859 ret << "MEDCouplingUMesh *mesh=MEDCouplingUMesh::New(\"" << getName() << "\"," << getMeshDimension() << ");" << std::endl;
2860 ret << "mesh->setCoords(" << coordsName << ");" << std::endl;
2861 ret << "mesh->setConnectivity(" << connName << "," << connIName << ",true);" << std::endl;
2862 ret << coordsName << "->decrRef(); " << connName << "->decrRef(); " << connIName << "->decrRef();" << std::endl;
2866 std::string MEDCouplingUMesh::reprConnectivityOfThis() const
2868 std::ostringstream ret;
2869 reprConnectivityOfThisLL(ret);
2874 * This method builds a newly allocated instance (with the same name than \a this) that the caller has the responsability to deal with.
2875 * This method returns an instance with all arrays allocated (connectivity, connectivity index, coordinates)
2876 * but with length of these arrays set to 0. It allows to define an "empty" mesh (with nor cells nor nodes but compliant with
2879 * This method expects that \a this has a mesh dimension set and higher or equal to 0. If not an exception will be thrown.
2880 * 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
2881 * with number of tuples set to 0, if not the array is taken as this in the returned instance.
2883 MEDCouplingUMesh *MEDCouplingUMesh::buildSetInstanceFromThis(int spaceDim) const
2885 int mdim=getMeshDimension();
2887 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSetInstanceFromThis : invalid mesh dimension ! Should be >= 0 !");
2888 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
2889 MCAuto<DataArrayInt> tmp1,tmp2;
2890 bool needToCpyCT=true;
2893 tmp1=DataArrayInt::New(); tmp1->alloc(0,1);
2901 if(!_nodal_connec_index)
2903 tmp2=DataArrayInt::New(); tmp2->alloc(1,1); tmp2->setIJ(0,0,0);
2908 tmp2=_nodal_connec_index;
2911 ret->setConnectivity(tmp1,tmp2,false);
2916 MCAuto<DataArrayDouble> coords=DataArrayDouble::New(); coords->alloc(0,spaceDim);
2917 ret->setCoords(coords);
2920 ret->setCoords(_coords);
2924 int MEDCouplingUMesh::getNumberOfNodesInCell(int cellId) const
2926 const int *ptI=_nodal_connec_index->getConstPointer();
2927 const int *pt=_nodal_connec->getConstPointer();
2928 if(pt[ptI[cellId]]!=INTERP_KERNEL::NORM_POLYHED)
2929 return ptI[cellId+1]-ptI[cellId]-1;
2931 return (int)std::count_if(pt+ptI[cellId]+1,pt+ptI[cellId+1],std::bind2nd(std::not_equal_to<int>(),-1));
2935 * Returns types of cells of the specified part of \a this mesh.
2936 * This method avoids computing sub-mesh explicitely to get its types.
2937 * \param [in] begin - an array of cell ids of interest.
2938 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
2939 * \return std::set<INTERP_KERNEL::NormalizedCellType> - a set of enumeration items
2940 * describing the cell types.
2941 * \throw If the coordinates array is not set.
2942 * \throw If the nodal connectivity of cells is not defined.
2943 * \sa getAllGeoTypes()
2945 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getTypesOfPart(const int *begin, const int *end) const
2947 checkFullyDefined();
2948 std::set<INTERP_KERNEL::NormalizedCellType> ret;
2949 const int *conn=_nodal_connec->getConstPointer();
2950 const int *connIndex=_nodal_connec_index->getConstPointer();
2951 for(const int *w=begin;w!=end;w++)
2952 ret.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]);
2957 * Defines the nodal connectivity using given connectivity arrays in \ref numbering-indirect format.
2958 * Optionally updates
2959 * a set of types of cells constituting \a this mesh.
2960 * This method is for advanced users having prepared their connectivity before. For
2961 * more info on using this method see \ref MEDCouplingUMeshAdvBuild.
2962 * \param [in] conn - the nodal connectivity array.
2963 * \param [in] connIndex - the nodal connectivity index array.
2964 * \param [in] isComputingTypes - if \c true, the set of types constituting \a this
2967 void MEDCouplingUMesh::setConnectivity(DataArrayInt *conn, DataArrayInt *connIndex, bool isComputingTypes)
2969 DataArrayInt::SetArrayIn(conn,_nodal_connec);
2970 DataArrayInt::SetArrayIn(connIndex,_nodal_connec_index);
2971 if(isComputingTypes)
2977 * Copy constructor. If 'deepCopy' is false \a this is a shallow copy of other.
2978 * If 'deeCpy' is true all arrays (coordinates and connectivities) are deeply copied.
2980 MEDCouplingUMesh::MEDCouplingUMesh(const MEDCouplingUMesh& other, bool deepCopy):MEDCouplingPointSet(other,deepCopy),_mesh_dim(other._mesh_dim),
2981 _nodal_connec(0),_nodal_connec_index(0),
2982 _types(other._types)
2984 if(other._nodal_connec)
2985 _nodal_connec=other._nodal_connec->performCopyOrIncrRef(deepCopy);
2986 if(other._nodal_connec_index)
2987 _nodal_connec_index=other._nodal_connec_index->performCopyOrIncrRef(deepCopy);
2990 MEDCouplingUMesh::~MEDCouplingUMesh()
2993 _nodal_connec->decrRef();
2994 if(_nodal_connec_index)
2995 _nodal_connec_index->decrRef();
2999 * Recomputes a set of cell types of \a this mesh. For more info see
3000 * \ref MEDCouplingUMeshNodalConnectivity.
3002 void MEDCouplingUMesh::computeTypes()
3004 ComputeAllTypesInternal(_types,_nodal_connec,_nodal_connec_index);
3009 * Returns a number of cells constituting \a this mesh.
3010 * \return int - the number of cells in \a this mesh.
3011 * \throw If the nodal connectivity of cells is not defined.
3013 int MEDCouplingUMesh::getNumberOfCells() const
3015 if(_nodal_connec_index)
3016 return _nodal_connec_index->getNumberOfTuples()-1;
3021 throw INTERP_KERNEL::Exception("Unable to get number of cells because no connectivity specified !");
3025 * Returns a dimension of \a this mesh, i.e. a dimension of cells constituting \a this
3026 * mesh. For more info see \ref meshes.
3027 * \return int - the dimension of \a this mesh.
3028 * \throw If the mesh dimension is not defined using setMeshDimension().
3030 int MEDCouplingUMesh::getMeshDimension() const
3033 throw INTERP_KERNEL::Exception("No mesh dimension specified !");
3038 * Returns a length of the nodal connectivity array.
3039 * This method is for test reason. Normally the integer returned is not useable by
3040 * user. For more info see \ref MEDCouplingUMeshNodalConnectivity.
3041 * \return int - the length of the nodal connectivity array.
3043 int MEDCouplingUMesh::getNodalConnectivityArrayLen() const
3045 return _nodal_connec->getNbOfElems();
3049 * First step of serialization process. Used by ParaMEDMEM and MEDCouplingCorba to transfert data between process.
3051 void MEDCouplingUMesh::getTinySerializationInformation(std::vector<double>& tinyInfoD, std::vector<int>& tinyInfo, std::vector<std::string>& littleStrings) const
3053 MEDCouplingPointSet::getTinySerializationInformation(tinyInfoD,tinyInfo,littleStrings);
3054 tinyInfo.push_back(getMeshDimension());
3055 tinyInfo.push_back(getNumberOfCells());
3057 tinyInfo.push_back(getNodalConnectivityArrayLen());
3059 tinyInfo.push_back(-1);
3063 * First step of unserialization process.
3065 bool MEDCouplingUMesh::isEmptyMesh(const std::vector<int>& tinyInfo) const
3067 return tinyInfo[6]<=0;
3071 * Second step of serialization process.
3072 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3075 * \param littleStrings
3077 void MEDCouplingUMesh::resizeForUnserialization(const std::vector<int>& tinyInfo, DataArrayInt *a1, DataArrayDouble *a2, std::vector<std::string>& littleStrings) const
3079 MEDCouplingPointSet::resizeForUnserialization(tinyInfo,a1,a2,littleStrings);
3081 a1->alloc(tinyInfo[7]+tinyInfo[6]+1,1);
3085 * Third and final step of serialization process.
3087 void MEDCouplingUMesh::serialize(DataArrayInt *&a1, DataArrayDouble *&a2) const
3089 MEDCouplingPointSet::serialize(a1,a2);
3090 if(getMeshDimension()>-1)
3092 a1=DataArrayInt::New();
3093 a1->alloc(getNodalConnectivityArrayLen()+getNumberOfCells()+1,1);
3094 int *ptA1=a1->getPointer();
3095 const int *conn=getNodalConnectivity()->getConstPointer();
3096 const int *index=getNodalConnectivityIndex()->getConstPointer();
3097 ptA1=std::copy(index,index+getNumberOfCells()+1,ptA1);
3098 std::copy(conn,conn+getNodalConnectivityArrayLen(),ptA1);
3105 * Second and final unserialization process.
3106 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3108 void MEDCouplingUMesh::unserialization(const std::vector<double>& tinyInfoD, const std::vector<int>& tinyInfo, const DataArrayInt *a1, DataArrayDouble *a2, const std::vector<std::string>& littleStrings)
3110 MEDCouplingPointSet::unserialization(tinyInfoD,tinyInfo,a1,a2,littleStrings);
3111 setMeshDimension(tinyInfo[5]);
3115 const int *recvBuffer=a1->getConstPointer();
3116 MCAuto<DataArrayInt> myConnecIndex=DataArrayInt::New();
3117 myConnecIndex->alloc(tinyInfo[6]+1,1);
3118 std::copy(recvBuffer,recvBuffer+tinyInfo[6]+1,myConnecIndex->getPointer());
3119 MCAuto<DataArrayInt> myConnec=DataArrayInt::New();
3120 myConnec->alloc(tinyInfo[7],1);
3121 std::copy(recvBuffer+tinyInfo[6]+1,recvBuffer+tinyInfo[6]+1+tinyInfo[7],myConnec->getPointer());
3122 setConnectivity(myConnec, myConnecIndex);
3129 * Returns a new MEDCouplingFieldDouble containing volumes of cells constituting \a this
3131 * For 1D cells, the returned field contains lengths.<br>
3132 * For 2D cells, the returned field contains areas.<br>
3133 * For 3D cells, the returned field contains volumes.
3134 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3135 * orientation, i.e. the volume is always positive.
3136 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on cells
3137 * and one time . The caller is to delete this field using decrRef() as it is no
3140 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureField(bool isAbs) const
3142 std::string name="MeasureOfMesh_";
3144 int nbelem=getNumberOfCells();
3145 MCAuto<MEDCouplingFieldDouble> field=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3146 field->setName(name);
3147 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3148 array->alloc(nbelem,1);
3149 double *area_vol=array->getPointer();
3150 field->setArray(array) ; array=0;
3151 field->setMesh(const_cast<MEDCouplingUMesh *>(this));
3152 field->synchronizeTimeWithMesh();
3153 if(getMeshDimension()!=-1)
3156 INTERP_KERNEL::NormalizedCellType type;
3157 int dim_space=getSpaceDimension();
3158 const double *coords=getCoords()->getConstPointer();
3159 const int *connec=getNodalConnectivity()->getConstPointer();
3160 const int *connec_index=getNodalConnectivityIndex()->getConstPointer();
3161 for(int iel=0;iel<nbelem;iel++)
3163 ipt=connec_index[iel];
3164 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3165 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);
3168 std::transform(area_vol,area_vol+nbelem,area_vol,std::ptr_fun<double,double>(fabs));
3172 area_vol[0]=std::numeric_limits<double>::max();
3174 return field.retn();
3178 * Returns a new DataArrayDouble containing volumes of specified cells of \a this
3180 * For 1D cells, the returned array contains lengths.<br>
3181 * For 2D cells, the returned array contains areas.<br>
3182 * For 3D cells, the returned array contains volumes.
3183 * This method avoids building explicitly a part of \a this mesh to perform the work.
3184 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3185 * orientation, i.e. the volume is always positive.
3186 * \param [in] begin - an array of cell ids of interest.
3187 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3188 * \return DataArrayDouble * - a new instance of DataArrayDouble. The caller is to
3189 * delete this array using decrRef() as it is no more needed.
3191 * \if ENABLE_EXAMPLES
3192 * \ref cpp_mcumesh_getPartMeasureField "Here is a C++ example".<br>
3193 * \ref py_mcumesh_getPartMeasureField "Here is a Python example".
3195 * \sa getMeasureField()
3197 DataArrayDouble *MEDCouplingUMesh::getPartMeasureField(bool isAbs, const int *begin, const int *end) const
3199 std::string name="PartMeasureOfMesh_";
3201 int nbelem=(int)std::distance(begin,end);
3202 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3203 array->setName(name);
3204 array->alloc(nbelem,1);
3205 double *area_vol=array->getPointer();
3206 if(getMeshDimension()!=-1)
3209 INTERP_KERNEL::NormalizedCellType type;
3210 int dim_space=getSpaceDimension();
3211 const double *coords=getCoords()->getConstPointer();
3212 const int *connec=getNodalConnectivity()->getConstPointer();
3213 const int *connec_index=getNodalConnectivityIndex()->getConstPointer();
3214 for(const int *iel=begin;iel!=end;iel++)
3216 ipt=connec_index[*iel];
3217 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3218 *area_vol++=INTERP_KERNEL::computeVolSurfOfCell2<int,INTERP_KERNEL::ALL_C_MODE>(type,connec+ipt+1,connec_index[*iel+1]-ipt-1,coords,dim_space);
3221 std::transform(array->getPointer(),area_vol,array->getPointer(),std::ptr_fun<double,double>(fabs));
3225 area_vol[0]=std::numeric_limits<double>::max();
3227 return array.retn();
3231 * Returns a new MEDCouplingFieldDouble containing volumes of cells of a dual mesh of
3232 * \a this one. The returned field contains the dual cell volume for each corresponding
3233 * node in \a this mesh. In other words, the field returns the getMeasureField() of
3234 * the dual mesh in P1 sens of \a this.<br>
3235 * For 1D cells, the returned field contains lengths.<br>
3236 * For 2D cells, the returned field contains areas.<br>
3237 * For 3D cells, the returned field contains volumes.
3238 * This method is useful to check "P1*" conservative interpolators.
3239 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3240 * orientation, i.e. the volume is always positive.
3241 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3242 * nodes and one time. The caller is to delete this array using decrRef() as
3243 * it is no more needed.
3245 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureFieldOnNode(bool isAbs) const
3247 MCAuto<MEDCouplingFieldDouble> tmp=getMeasureField(isAbs);
3248 std::string name="MeasureOnNodeOfMesh_";
3250 int nbNodes=getNumberOfNodes();
3251 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_NODES);
3252 double cst=1./((double)getMeshDimension()+1.);
3253 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3254 array->alloc(nbNodes,1);
3255 double *valsToFill=array->getPointer();
3256 std::fill(valsToFill,valsToFill+nbNodes,0.);
3257 const double *values=tmp->getArray()->getConstPointer();
3258 MCAuto<DataArrayInt> da=DataArrayInt::New();
3259 MCAuto<DataArrayInt> daInd=DataArrayInt::New();
3260 getReverseNodalConnectivity(da,daInd);
3261 const int *daPtr=da->getConstPointer();
3262 const int *daIPtr=daInd->getConstPointer();
3263 for(int i=0;i<nbNodes;i++)
3264 for(const int *cell=daPtr+daIPtr[i];cell!=daPtr+daIPtr[i+1];cell++)
3265 valsToFill[i]+=cst*values[*cell];
3267 ret->setArray(array);
3272 * Returns a new MEDCouplingFieldDouble holding normal vectors to cells of \a this
3273 * mesh. The returned normal vectors to each cell have a norm2 equal to 1.
3274 * The computed vectors have <em> this->getMeshDimension()+1 </em> components
3275 * and are normalized.
3276 * <br> \a this can be either
3277 * - a 2D mesh in 2D or 3D space or
3278 * - an 1D mesh in 2D space.
3280 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3281 * cells and one time. The caller is to delete this field using decrRef() as
3282 * it is no more needed.
3283 * \throw If the nodal connectivity of cells is not defined.
3284 * \throw If the coordinates array is not set.
3285 * \throw If the mesh dimension is not set.
3286 * \throw If the mesh and space dimension is not as specified above.
3288 MEDCouplingFieldDouble *MEDCouplingUMesh::buildOrthogonalField() const
3290 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3291 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3292 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3293 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3294 int nbOfCells=getNumberOfCells();
3295 int nbComp=getMeshDimension()+1;
3296 array->alloc(nbOfCells,nbComp);
3297 double *vals=array->getPointer();
3298 const int *connI=_nodal_connec_index->getConstPointer();
3299 const int *conn=_nodal_connec->getConstPointer();
3300 const double *coords=_coords->getConstPointer();
3301 if(getMeshDimension()==2)
3303 if(getSpaceDimension()==3)
3305 MCAuto<DataArrayDouble> loc=computeCellCenterOfMass();
3306 const double *locPtr=loc->getConstPointer();
3307 for(int i=0;i<nbOfCells;i++,vals+=3)
3309 int offset=connI[i];
3310 INTERP_KERNEL::crossprod<3>(locPtr+3*i,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3311 double n=INTERP_KERNEL::norm<3>(vals);
3312 std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3317 MCAuto<MEDCouplingFieldDouble> isAbs=getMeasureField(false);
3318 const double *isAbsPtr=isAbs->getArray()->begin();
3319 for(int i=0;i<nbOfCells;i++,isAbsPtr++)
3320 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=*isAbsPtr>0.?1.:-1.; }
3323 else//meshdimension==1
3326 for(int i=0;i<nbOfCells;i++)
3328 int offset=connI[i];
3329 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3330 double n=INTERP_KERNEL::norm<2>(tmp);
3331 std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3336 ret->setArray(array);
3338 ret->synchronizeTimeWithSupport();
3343 * Returns a new MEDCouplingFieldDouble holding normal vectors to specified cells of
3344 * \a this mesh. The computed vectors have <em> this->getMeshDimension()+1 </em> components
3345 * and are normalized.
3346 * <br> \a this can be either
3347 * - a 2D mesh in 2D or 3D space or
3348 * - an 1D mesh in 2D space.
3350 * This method avoids building explicitly a part of \a this mesh to perform the work.
3351 * \param [in] begin - an array of cell ids of interest.
3352 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3353 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3354 * cells and one time. The caller is to delete this field using decrRef() as
3355 * it is no more needed.
3356 * \throw If the nodal connectivity of cells is not defined.
3357 * \throw If the coordinates array is not set.
3358 * \throw If the mesh dimension is not set.
3359 * \throw If the mesh and space dimension is not as specified above.
3360 * \sa buildOrthogonalField()
3362 * \if ENABLE_EXAMPLES
3363 * \ref cpp_mcumesh_buildPartOrthogonalField "Here is a C++ example".<br>
3364 * \ref py_mcumesh_buildPartOrthogonalField "Here is a Python example".
3367 MEDCouplingFieldDouble *MEDCouplingUMesh::buildPartOrthogonalField(const int *begin, const int *end) const
3369 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3370 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3371 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3372 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3373 std::size_t nbelems=std::distance(begin,end);
3374 int nbComp=getMeshDimension()+1;
3375 array->alloc((int)nbelems,nbComp);
3376 double *vals=array->getPointer();
3377 const int *connI=_nodal_connec_index->getConstPointer();
3378 const int *conn=_nodal_connec->getConstPointer();
3379 const double *coords=_coords->getConstPointer();
3380 if(getMeshDimension()==2)
3382 if(getSpaceDimension()==3)
3384 MCAuto<DataArrayDouble> loc=getPartBarycenterAndOwner(begin,end);
3385 const double *locPtr=loc->getConstPointer();
3386 for(const int *i=begin;i!=end;i++,vals+=3,locPtr+=3)
3388 int offset=connI[*i];
3389 INTERP_KERNEL::crossprod<3>(locPtr,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3390 double n=INTERP_KERNEL::norm<3>(vals);
3391 std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3396 for(std::size_t i=0;i<nbelems;i++)
3397 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=1.; }
3400 else//meshdimension==1
3403 for(const int *i=begin;i!=end;i++)
3405 int offset=connI[*i];
3406 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3407 double n=INTERP_KERNEL::norm<2>(tmp);
3408 std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3413 ret->setArray(array);
3415 ret->synchronizeTimeWithSupport();
3420 * Returns a new MEDCouplingFieldDouble holding a direction vector for each SEG2 in \a
3421 * this 1D mesh. The computed vectors have <em> this->getSpaceDimension() </em> components
3422 * and are \b not normalized.
3423 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3424 * cells and one time. The caller is to delete this field using decrRef() as
3425 * it is no more needed.
3426 * \throw If the nodal connectivity of cells is not defined.
3427 * \throw If the coordinates array is not set.
3428 * \throw If \a this->getMeshDimension() != 1.
3429 * \throw If \a this mesh includes cells of type other than SEG2.
3431 MEDCouplingFieldDouble *MEDCouplingUMesh::buildDirectionVectorField() const
3433 if(getMeshDimension()!=1)
3434 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for buildDirectionVectorField !");
3435 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3436 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for buildDirectionVectorField !");
3437 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3438 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3439 int nbOfCells=getNumberOfCells();
3440 int spaceDim=getSpaceDimension();
3441 array->alloc(nbOfCells,spaceDim);
3442 double *pt=array->getPointer();
3443 const double *coo=getCoords()->getConstPointer();
3444 std::vector<int> conn;
3446 for(int i=0;i<nbOfCells;i++)
3449 getNodeIdsOfCell(i,conn);
3450 pt=std::transform(coo+conn[1]*spaceDim,coo+(conn[1]+1)*spaceDim,coo+conn[0]*spaceDim,pt,std::minus<double>());
3452 ret->setArray(array);
3454 ret->synchronizeTimeWithSupport();
3459 * Creates a 2D mesh by cutting \a this 3D mesh with a plane. In addition to the mesh,
3460 * returns a new DataArrayInt, of length equal to the number of 2D cells in the result
3461 * mesh, holding, for each cell in the result mesh, an id of a 3D cell it comes
3462 * from. If a result face is shared by two 3D cells, then the face in included twice in
3464 * \param [in] origin - 3 components of a point defining location of the plane.
3465 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3466 * must be greater than 1e-6.
3467 * \param [in] eps - half-thickness of the plane.
3468 * \param [out] cellIds - a new instance of DataArrayInt holding ids of 3D cells
3469 * producing correspondent 2D cells. The caller is to delete this array
3470 * using decrRef() as it is no more needed.
3471 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This mesh does
3472 * not share the node coordinates array with \a this mesh. The caller is to
3473 * delete this mesh using decrRef() as it is no more needed.
3474 * \throw If the coordinates array is not set.
3475 * \throw If the nodal connectivity of cells is not defined.
3476 * \throw If \a this->getMeshDimension() != 3 or \a this->getSpaceDimension() != 3.
3477 * \throw If magnitude of \a vec is less than 1e-6.
3478 * \throw If the plane does not intersect any 3D cell of \a this mesh.
3479 * \throw If \a this includes quadratic cells.
3481 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3D(const double *origin, const double *vec, double eps, DataArrayInt *&cellIds) const
3483 checkFullyDefined();
3484 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3485 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3486 MCAuto<DataArrayInt> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3487 if(candidates->empty())
3488 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane considering bounding boxes !");
3489 std::vector<int> nodes;
3490 DataArrayInt *cellIds1D=0;
3491 MCAuto<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3492 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3493 MCAuto<DataArrayInt> desc1=DataArrayInt::New(),desc2=DataArrayInt::New();
3494 MCAuto<DataArrayInt> descIndx1=DataArrayInt::New(),descIndx2=DataArrayInt::New();
3495 MCAuto<DataArrayInt> revDesc1=DataArrayInt::New(),revDesc2=DataArrayInt::New();
3496 MCAuto<DataArrayInt> revDescIndx1=DataArrayInt::New(),revDescIndx2=DataArrayInt::New();
3497 MCAuto<MEDCouplingUMesh> mDesc2=subMesh->buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2);//meshDim==2 spaceDim==3
3498 revDesc2=0; revDescIndx2=0;
3499 MCAuto<MEDCouplingUMesh> mDesc1=mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3500 revDesc1=0; revDescIndx1=0;
3501 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3502 MCAuto<DataArrayInt> cellIds1DTmp(cellIds1D);
3504 std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3505 for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3507 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3508 std::vector< std::pair<int,int> > cut3DSurf(mDesc2->getNumberOfCells());
3509 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->getConstPointer(),mDesc2->getNodalConnectivityIndex()->getConstPointer(),
3510 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3511 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3512 MCAuto<DataArrayInt> conn(DataArrayInt::New()),connI(DataArrayInt::New()),cellIds2(DataArrayInt::New());
3513 connI->pushBackSilent(0); conn->alloc(0,1); cellIds2->alloc(0,1);
3514 subMesh->assemblyForSplitFrom3DSurf(cut3DSurf,desc2->getConstPointer(),descIndx2->getConstPointer(),conn,connI,cellIds2);
3515 if(cellIds2->empty())
3516 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3517 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3D",2);
3518 ret->setCoords(mDesc1->getCoords());
3519 ret->setConnectivity(conn,connI,true);
3520 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3525 * Creates an 1D mesh by cutting \a this 2D mesh in 3D space with a plane. In
3526 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
3527 from. If a result segment is shared by two 2D cells, then the segment in included twice in
3529 * \param [in] origin - 3 components of a point defining location of the plane.
3530 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3531 * must be greater than 1e-6.
3532 * \param [in] eps - half-thickness of the plane.
3533 * \param [out] cellIds - a new instance of DataArrayInt holding ids of faces
3534 * producing correspondent segments. The caller is to delete this array
3535 * using decrRef() as it is no more needed.
3536 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This is an 1D
3537 * mesh in 3D space. This mesh does not share the node coordinates array with
3538 * \a this mesh. The caller is to delete this mesh using decrRef() as it is
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() != 2 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 2D cell of \a this mesh.
3545 * \throw If \a this includes quadratic cells.
3547 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3DSurf(const double *origin, const double *vec, double eps, DataArrayInt *&cellIds) const
3549 checkFullyDefined();
3550 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
3551 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf works on umeshes with meshdim equal to 2 and spaceDim equal to 3 !");
3552 MCAuto<DataArrayInt> candidates(getCellIdsCrossingPlane(origin,vec,eps));
3553 if(candidates->empty())
3554 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3D surf cells in this intercepts the specified plane considering bounding boxes !");
3555 std::vector<int> nodes;
3556 DataArrayInt *cellIds1D(0);
3557 MCAuto<MEDCouplingUMesh> subMesh(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3558 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3559 MCAuto<DataArrayInt> desc1(DataArrayInt::New()),descIndx1(DataArrayInt::New()),revDesc1(DataArrayInt::New()),revDescIndx1(DataArrayInt::New());
3560 MCAuto<MEDCouplingUMesh> mDesc1(subMesh->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3561 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3562 MCAuto<DataArrayInt> cellIds1DTmp(cellIds1D);
3564 std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3565 for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3567 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3568 int ncellsSub=subMesh->getNumberOfCells();
3569 std::vector< std::pair<int,int> > cut3DSurf(ncellsSub);
3570 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,subMesh->getNodalConnectivity()->getConstPointer(),subMesh->getNodalConnectivityIndex()->getConstPointer(),
3571 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3572 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3573 MCAuto<DataArrayInt> conn(DataArrayInt::New()),connI(DataArrayInt::New()),cellIds2(DataArrayInt::New()); connI->pushBackSilent(0);
3575 const int *nodal=subMesh->getNodalConnectivity()->getConstPointer();
3576 const int *nodalI=subMesh->getNodalConnectivityIndex()->getConstPointer();
3577 for(int i=0;i<ncellsSub;i++)
3579 if(cut3DSurf[i].first!=-1 && cut3DSurf[i].second!=-1)
3581 if(cut3DSurf[i].first!=-2)
3583 conn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG2); conn->pushBackSilent(cut3DSurf[i].first); conn->pushBackSilent(cut3DSurf[i].second);
3584 connI->pushBackSilent(conn->getNumberOfTuples());
3585 cellIds2->pushBackSilent(i);
3589 int cellId3DSurf=cut3DSurf[i].second;
3590 int offset=nodalI[cellId3DSurf]+1;
3591 int nbOfEdges=nodalI[cellId3DSurf+1]-offset;
3592 for(int j=0;j<nbOfEdges;j++)
3594 conn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG2); conn->pushBackSilent(nodal[offset+j]); conn->pushBackSilent(nodal[offset+(j+1)%nbOfEdges]);
3595 connI->pushBackSilent(conn->getNumberOfTuples());
3596 cellIds2->pushBackSilent(cellId3DSurf);
3601 if(cellIds2->empty())
3602 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3DSurf cells in this intercepts the specified plane !");
3603 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3DSurf",1);
3604 ret->setCoords(mDesc1->getCoords());
3605 ret->setConnectivity(conn,connI,true);
3606 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3610 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::clipSingle3DCellByPlane(const double origin[3], const double vec[3], double eps) const
3612 checkFullyDefined();
3613 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3614 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3615 if(getNumberOfCells()!=1)
3616 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works only on mesh containing exactly one cell !");
3618 std::vector<int> nodes;
3619 findNodesOnPlane(origin,vec,eps,nodes);
3620 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());
3621 MCAuto<MEDCouplingUMesh> mDesc2(buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2));//meshDim==2 spaceDim==3
3622 revDesc2=0; revDescIndx2=0;
3623 MCAuto<MEDCouplingUMesh> mDesc1(mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3624 revDesc1=0; revDescIndx1=0;
3625 DataArrayInt *cellIds1D(0);
3626 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3627 MCAuto<DataArrayInt> cellIds1DTmp(cellIds1D);
3628 std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3629 for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3633 int oldNbNodes(mDesc1->getNumberOfNodes());
3634 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3635 sameNbNodes=(mDesc1->getNumberOfNodes()==oldNbNodes);
3637 std::vector< std::pair<int,int> > cut3DSurf(mDesc2->getNumberOfCells());
3638 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->begin(),mDesc2->getNodalConnectivityIndex()->begin(),
3639 mDesc1->getNodalConnectivity()->begin(),mDesc1->getNodalConnectivityIndex()->begin(),
3640 desc1->begin(),descIndx1->begin(),cut3DSurf);
3641 MCAuto<DataArrayInt> conn(DataArrayInt::New()),connI(DataArrayInt::New());
3642 connI->pushBackSilent(0); conn->alloc(0,1);
3644 MCAuto<DataArrayInt> cellIds2(DataArrayInt::New()); cellIds2->alloc(0,1);
3645 assemblyForSplitFrom3DSurf(cut3DSurf,desc2->begin(),descIndx2->begin(),conn,connI,cellIds2);
3646 if(cellIds2->empty())
3647 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3649 std::vector<std::vector<int> > res;
3650 buildSubCellsFromCut(cut3DSurf,desc2->begin(),descIndx2->begin(),mDesc1->getCoords()->begin(),eps,res);
3651 std::size_t sz(res.size());
3652 if(res.size()==mDesc1->getNumberOfCells() && sameNbNodes)
3653 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane : cell is not clipped !");
3654 for(std::size_t i=0;i<sz;i++)
3656 conn->pushBackSilent((int)INTERP_KERNEL::NORM_POLYGON);
3657 conn->insertAtTheEnd(res[i].begin(),res[i].end());
3658 connI->pushBackSilent(conn->getNumberOfTuples());
3660 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
3661 ret->setCoords(mDesc1->getCoords());
3662 ret->setConnectivity(conn,connI,true);
3663 int nbCellsRet(ret->getNumberOfCells());
3665 MCAuto<DataArrayDouble> vec2(DataArrayDouble::New()); vec2->alloc(1,3); std::copy(vec,vec+3,vec2->getPointer());
3666 MCAuto<MEDCouplingFieldDouble> ortho(ret->buildOrthogonalField());
3667 MCAuto<DataArrayDouble> ortho2(ortho->getArray()->selectByTupleIdSafeSlice(0,1,1));
3668 MCAuto<DataArrayDouble> dott(DataArrayDouble::Dot(ortho2,vec2));
3669 MCAuto<DataArrayDouble> ccm(ret->computeCellCenterOfMass());
3670 MCAuto<DataArrayDouble> occm;
3672 MCAuto<DataArrayDouble> pt(DataArrayDouble::New()); pt->alloc(1,3); std::copy(origin,origin+3,pt->getPointer());
3673 occm=DataArrayDouble::Substract(ccm,pt);
3675 vec2=DataArrayDouble::New(); vec2->alloc(nbCellsRet,3);
3676 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);
3677 MCAuto<DataArrayDouble> dott2(DataArrayDouble::Dot(occm,vec2));
3679 const int *cPtr(ret->getNodalConnectivity()->begin()),*ciPtr(ret->getNodalConnectivityIndex()->begin());
3680 MCAuto<MEDCouplingUMesh> ret2(MEDCouplingUMesh::New("Clip3D",3));
3681 ret2->setCoords(mDesc1->getCoords());
3682 MCAuto<DataArrayInt> conn2(DataArrayInt::New()),conn2I(DataArrayInt::New());
3683 conn2I->pushBackSilent(0); conn2->alloc(0,1);
3684 std::vector<int> cell0(1,(int)INTERP_KERNEL::NORM_POLYHED);
3685 std::vector<int> cell1(1,(int)INTERP_KERNEL::NORM_POLYHED);
3686 if(dott->getIJ(0,0)>0)
3688 cell0.insert(cell0.end(),cPtr+1,cPtr+ciPtr[1]);
3689 std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell1,cell1.end()));
3693 cell1.insert(cell1.end(),cPtr+1,cPtr+ciPtr[1]);
3694 std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell0,cell0.end()));
3696 for(int i=1;i<nbCellsRet;i++)
3698 if(dott2->getIJ(i,0)<0)
3700 if(ciPtr[i+1]-ciPtr[i]>=4)
3702 cell0.push_back(-1);
3703 cell0.insert(cell0.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
3708 if(ciPtr[i+1]-ciPtr[i]>=4)
3710 cell1.push_back(-1);
3711 cell1.insert(cell1.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
3715 conn2->insertAtTheEnd(cell0.begin(),cell0.end());
3716 conn2I->pushBackSilent(conn2->getNumberOfTuples());
3717 conn2->insertAtTheEnd(cell1.begin(),cell1.end());
3718 conn2I->pushBackSilent(conn2->getNumberOfTuples());
3719 ret2->setConnectivity(conn2,conn2I,true);
3720 ret2->checkConsistencyLight();
3721 ret2->orientCorrectlyPolyhedrons();
3726 * Finds cells whose bounding boxes intersect a given plane.
3727 * \param [in] origin - 3 components of a point defining location of the plane.
3728 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3729 * must be greater than 1e-6.
3730 * \param [in] eps - half-thickness of the plane.
3731 * \return DataArrayInt * - a new instance of DataArrayInt holding ids of the found
3732 * cells. The caller is to delete this array using decrRef() as it is no more
3734 * \throw If the coordinates array is not set.
3735 * \throw If the nodal connectivity of cells is not defined.
3736 * \throw If \a this->getSpaceDimension() != 3.
3737 * \throw If magnitude of \a vec is less than 1e-6.
3738 * \sa buildSlice3D()
3740 DataArrayInt *MEDCouplingUMesh::getCellIdsCrossingPlane(const double *origin, const double *vec, double eps) const
3742 checkFullyDefined();
3743 if(getSpaceDimension()!=3)
3744 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with spaceDim equal to 3 !");
3745 double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
3747 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellIdsCrossingPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
3749 vec2[0]=vec[1]; vec2[1]=-vec[0]; vec2[2]=0.;//vec2 is the result of cross product of vec with (0,0,1)
3750 double angle=acos(vec[2]/normm);
3751 MCAuto<DataArrayInt> cellIds;
3755 MCAuto<DataArrayDouble> coo=_coords->deepCopy();
3756 double normm2(sqrt(vec2[0]*vec2[0]+vec2[1]*vec2[1]+vec2[2]*vec2[2]));
3757 if(normm2/normm>1e-6)
3758 DataArrayDouble::Rotate3DAlg(origin,vec2,angle,coo->getNumberOfTuples(),coo->getPointer(),coo->getPointer());
3759 MCAuto<MEDCouplingUMesh> mw=clone(false);//false -> shallow copy
3761 mw->getBoundingBox(bbox);
3762 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3763 cellIds=mw->getCellsInBoundingBox(bbox,eps);
3767 getBoundingBox(bbox);
3768 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3769 cellIds=getCellsInBoundingBox(bbox,eps);
3771 return cellIds.retn();
3775 * This method checks that \a this is a contiguous mesh. The user is expected to call this method on a mesh with meshdim==1.
3776 * If not an exception will thrown. If this is an empty mesh with no cell an exception will be thrown too.
3777 * No consideration of coordinate is done by this method.
3778 * 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)
3779 * If not false is returned. In case that false is returned a call to MEDCoupling::MEDCouplingUMesh::mergeNodes could be usefull.
3781 bool MEDCouplingUMesh::isContiguous1D() const
3783 if(getMeshDimension()!=1)
3784 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense only for 1D mesh !");
3785 int nbCells=getNumberOfCells();
3787 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense for non empty mesh !");
3788 const int *connI(_nodal_connec_index->begin()),*conn(_nodal_connec->begin());
3789 int ref=conn[connI[0]+2];
3790 for(int i=1;i<nbCells;i++)
3792 if(conn[connI[i]+1]!=ref)
3794 ref=conn[connI[i]+2];
3800 * This method is only callable on mesh with meshdim == 1 containing only SEG2 and spaceDim==3.
3801 * This method projects this on the 3D line defined by (pt,v). This methods first checks that all SEG2 are along v vector.
3802 * \param pt reference point of the line
3803 * \param v normalized director vector of the line
3804 * \param eps max precision before throwing an exception
3805 * \param res output of size this->getNumberOfCells
3807 void MEDCouplingUMesh::project1D(const double *pt, const double *v, double eps, double *res) const
3809 if(getMeshDimension()!=1)
3810 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for project1D !");
3811 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3812 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for project1D !");
3813 if(getSpaceDimension()!=3)
3814 throw INTERP_KERNEL::Exception("Expected a umesh with spaceDim==3 for project1D !");
3815 MCAuto<MEDCouplingFieldDouble> f=buildDirectionVectorField();
3816 const double *fPtr=f->getArray()->getConstPointer();
3818 for(int i=0;i<getNumberOfCells();i++)
3820 const double *tmp1=fPtr+3*i;
3821 tmp[0]=tmp1[1]*v[2]-tmp1[2]*v[1];
3822 tmp[1]=tmp1[2]*v[0]-tmp1[0]*v[2];
3823 tmp[2]=tmp1[0]*v[1]-tmp1[1]*v[0];
3824 double n1=INTERP_KERNEL::norm<3>(tmp);
3825 n1/=INTERP_KERNEL::norm<3>(tmp1);
3827 throw INTERP_KERNEL::Exception("UMesh::Projection 1D failed !");
3829 const double *coo=getCoords()->getConstPointer();
3830 for(int i=0;i<getNumberOfNodes();i++)
3832 std::transform(coo+i*3,coo+i*3+3,pt,tmp,std::minus<double>());
3833 std::transform(tmp,tmp+3,v,tmp,std::multiplies<double>());
3834 res[i]=std::accumulate(tmp,tmp+3,0.);
3839 * 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.
3840 * \a this is expected to be a mesh so that its space dimension is equal to its
3841 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
3842 * 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).
3844 * 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
3845 * 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).
3846 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
3848 * So this method is more accurate (so, more costly) than simply searching for the closest point in \a this.
3849 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
3851 * \param [in] ptBg the start pointer (included) of the coordinates of the point
3852 * \param [in] ptEnd the end pointer (not included) of the coordinates of the point
3853 * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
3854 * \return the positive value of the distance.
3855 * \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
3857 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoints
3859 double MEDCouplingUMesh::distanceToPoint(const double *ptBg, const double *ptEnd, int& cellId) const
3861 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
3862 if(meshDim!=spaceDim-1)
3863 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint works only for spaceDim=meshDim+1 !");
3864 if(meshDim!=2 && meshDim!=1)
3865 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint : only mesh dimension 2 and 1 are implemented !");
3866 checkFullyDefined();
3867 if((int)std::distance(ptBg,ptEnd)!=spaceDim)
3868 { 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()); }
3869 DataArrayInt *ret1=0;
3870 MCAuto<DataArrayDouble> pts=DataArrayDouble::New(); pts->useArray(ptBg,false,C_DEALLOC,1,spaceDim);
3871 MCAuto<DataArrayDouble> ret0=distanceToPoints(pts,ret1);
3872 MCAuto<DataArrayInt> ret1Safe(ret1);
3873 cellId=*ret1Safe->begin();
3874 return *ret0->begin();
3878 * This method computes the distance from each point of points serie \a pts (stored in a DataArrayDouble in which each tuple represents a point)
3879 * to \a this and the first \a cellId in \a this corresponding to the returned distance.
3880 * 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
3881 * 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).
3882 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
3884 * \a this is expected to be a mesh so that its space dimension is equal to its
3885 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
3886 * 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).
3888 * So this method is more accurate (so, more costly) than simply searching for each point in \a pts the closest point in \a this.
3889 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
3891 * \param [in] pts the list of points in which each tuple represents a point
3892 * \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.
3893 * \return a newly allocated object to be dealed by the caller that tells for each point in \a pts the distance to \a this.
3894 * \throw if number of components of \a pts is not equal to the space dimension.
3895 * \throw if mesh dimension of \a this is not equal to space dimension - 1.
3896 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoint
3898 DataArrayDouble *MEDCouplingUMesh::distanceToPoints(const DataArrayDouble *pts, DataArrayInt *& cellIds) const
3901 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : input points pointer is NULL !");
3902 pts->checkAllocated();
3903 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
3904 if(meshDim!=spaceDim-1)
3905 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints works only for spaceDim=meshDim+1 !");
3906 if(meshDim!=2 && meshDim!=1)
3907 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only mesh dimension 2 and 1 are implemented !");
3908 if(pts->getNumberOfComponents()!=spaceDim)
3910 std::ostringstream oss; oss << "MEDCouplingUMesh::distanceToPoints : input pts DataArrayDouble has " << pts->getNumberOfComponents() << " components whereas it should be equal to " << spaceDim << " (mesh spaceDimension) !";
3911 throw INTERP_KERNEL::Exception(oss.str());
3913 checkFullyDefined();
3914 int nbCells=getNumberOfCells();
3916 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : no cells in this !");
3917 int nbOfPts=pts->getNumberOfTuples();
3918 MCAuto<DataArrayDouble> ret0=DataArrayDouble::New(); ret0->alloc(nbOfPts,1);
3919 MCAuto<DataArrayInt> ret1=DataArrayInt::New(); ret1->alloc(nbOfPts,1);
3920 const int *nc=_nodal_connec->begin(),*ncI=_nodal_connec_index->begin(); const double *coords=_coords->begin();
3921 double *ret0Ptr=ret0->getPointer(); int *ret1Ptr=ret1->getPointer(); const double *ptsPtr=pts->begin();
3922 MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree());
3923 const double *bbox(bboxArr->begin());
3928 BBTreeDst<3> myTree(bbox,0,0,nbCells);
3929 for(int i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=3)
3931 double x=std::numeric_limits<double>::max();
3932 std::vector<int> elems;
3933 myTree.getMinDistanceOfMax(ptsPtr,x);
3934 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
3935 DistanceToPoint3DSurfAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
3941 BBTreeDst<2> myTree(bbox,0,0,nbCells);
3942 for(int i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=2)
3944 double x=std::numeric_limits<double>::max();
3945 std::vector<int> elems;
3946 myTree.getMinDistanceOfMax(ptsPtr,x);
3947 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
3948 DistanceToPoint2DCurveAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
3953 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only spacedim 2 and 3 supported !");
3955 cellIds=ret1.retn();
3964 * Finds cells in contact with a ball (i.e. a point with precision).
3965 * 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.
3966 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
3968 * \warning This method is suitable if the caller intends to evaluate only one
3969 * point, for more points getCellsContainingPoints() is recommended as it is
3971 * \param [in] pos - array of coordinates of the ball central point.
3972 * \param [in] eps - ball radius.
3973 * \return int - a smallest id of cells being in contact with the ball, -1 in case
3974 * if there are no such cells.
3975 * \throw If the coordinates array is not set.
3976 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
3978 int MEDCouplingUMesh::getCellContainingPoint(const double *pos, double eps) const
3980 std::vector<int> elts;
3981 getCellsContainingPoint(pos,eps,elts);
3984 return elts.front();
3988 * Finds cells in contact with a ball (i.e. a point with precision).
3989 * 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.
3990 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
3991 * \warning This method is suitable if the caller intends to evaluate only one
3992 * point, for more points getCellsContainingPoints() is recommended as it is
3994 * \param [in] pos - array of coordinates of the ball central point.
3995 * \param [in] eps - ball radius.
3996 * \param [out] elts - vector returning ids of the found cells. It is cleared
3997 * before inserting ids.
3998 * \throw If the coordinates array is not set.
3999 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4001 * \if ENABLE_EXAMPLES
4002 * \ref cpp_mcumesh_getCellsContainingPoint "Here is a C++ example".<br>
4003 * \ref py_mcumesh_getCellsContainingPoint "Here is a Python example".
4006 void MEDCouplingUMesh::getCellsContainingPoint(const double *pos, double eps, std::vector<int>& elts) const
4008 MCAuto<DataArrayInt> eltsUg,eltsIndexUg;
4009 getCellsContainingPoints(pos,1,eps,eltsUg,eltsIndexUg);
4010 elts.clear(); elts.insert(elts.end(),eltsUg->begin(),eltsUg->end());
4014 * Finds cells in contact with several balls (i.e. points with precision).
4015 * This method is an extension of getCellContainingPoint() and
4016 * getCellsContainingPoint() for the case of multiple points.
4017 * 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.
4018 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4019 * \param [in] pos - an array of coordinates of points in full interlace mode :
4020 * X0,Y0,Z0,X1,Y1,Z1,... Size of the array must be \a
4021 * this->getSpaceDimension() * \a nbOfPoints
4022 * \param [in] nbOfPoints - number of points to locate within \a this mesh.
4023 * \param [in] eps - radius of balls (i.e. the precision).
4024 * \param [out] elts - vector returning ids of found cells.
4025 * \param [out] eltsIndex - an array, of length \a nbOfPoints + 1,
4026 * dividing cell ids in \a elts into groups each referring to one
4027 * point. Its every element (except the last one) is an index pointing to the
4028 * first id of a group of cells. For example cells in contact with the *i*-th
4029 * point are described by following range of indices:
4030 * [ \a eltsIndex[ *i* ], \a eltsIndex[ *i*+1 ] ) and the cell ids are
4031 * \a elts[ \a eltsIndex[ *i* ]], \a elts[ \a eltsIndex[ *i* ] + 1 ], ...
4032 * Number of cells in contact with the *i*-th point is
4033 * \a eltsIndex[ *i*+1 ] - \a eltsIndex[ *i* ].
4034 * \throw If the coordinates array is not set.
4035 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4037 * \if ENABLE_EXAMPLES
4038 * \ref cpp_mcumesh_getCellsContainingPoints "Here is a C++ example".<br>
4039 * \ref py_mcumesh_getCellsContainingPoints "Here is a Python example".
4042 void MEDCouplingUMesh::getCellsContainingPoints(const double *pos, int nbOfPoints, double eps,
4043 MCAuto<DataArrayInt>& elts, MCAuto<DataArrayInt>& eltsIndex) const
4045 int spaceDim=getSpaceDimension();
4046 int mDim=getMeshDimension();
4051 const double *coords=_coords->getConstPointer();
4052 getCellsContainingPointsAlg<3>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4059 throw INTERP_KERNEL::Exception("For spaceDim==3 only meshDim==3 implemented for getelementscontainingpoints !");
4061 else if(spaceDim==2)
4065 const double *coords=_coords->getConstPointer();
4066 getCellsContainingPointsAlg<2>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4069 throw INTERP_KERNEL::Exception("For spaceDim==2 only meshDim==2 implemented for getelementscontainingpoints !");
4071 else if(spaceDim==1)
4075 const double *coords=_coords->getConstPointer();
4076 getCellsContainingPointsAlg<1>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4079 throw INTERP_KERNEL::Exception("For spaceDim==1 only meshDim==1 implemented for getelementscontainingpoints !");
4082 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPoints : not managed for mdim not in [1,2,3] !");
4086 * Finds butterfly cells in \a this mesh. A 2D cell is considered to be butterfly if at
4087 * least two its edges intersect each other anywhere except their extremities. An
4088 * INTERP_KERNEL::NORM_NORI3 cell can \b not be butterfly.
4089 * \param [in,out] cells - a vector returning ids of the found cells. It is not
4090 * cleared before filling in.
4091 * \param [in] eps - precision.
4092 * \throw If \a this->getMeshDimension() != 2.
4093 * \throw If \a this->getSpaceDimension() != 2 && \a this->getSpaceDimension() != 3.
4095 void MEDCouplingUMesh::checkButterflyCells(std::vector<int>& cells, double eps) const
4097 const char msg[]="Butterfly detection work only for 2D cells with spaceDim==2 or 3!";
4098 if(getMeshDimension()!=2)
4099 throw INTERP_KERNEL::Exception(msg);
4100 int spaceDim=getSpaceDimension();
4101 if(spaceDim!=2 && spaceDim!=3)
4102 throw INTERP_KERNEL::Exception(msg);
4103 const int *conn=_nodal_connec->getConstPointer();
4104 const int *connI=_nodal_connec_index->getConstPointer();
4105 int nbOfCells=getNumberOfCells();
4106 std::vector<double> cell2DinS2;
4107 for(int i=0;i<nbOfCells;i++)
4109 int offset=connI[i];
4110 int nbOfNodesForCell=connI[i+1]-offset-1;
4111 if(nbOfNodesForCell<=3)
4113 bool isQuad=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[offset]).isQuadratic();
4114 project2DCellOnXY(conn+offset+1,conn+connI[i+1],cell2DinS2);
4115 if(isButterfly2DCell(cell2DinS2,isQuad,eps))
4122 * This method is typically requested to unbutterfly 2D linear cells in \b this.
4124 * 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.
4125 * 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.
4127 * For each 2D linear cell in \b this, this method builds the convex envelop (or the convex hull) of the current cell.
4128 * This convex envelop is computed using Jarvis march algorithm.
4129 * The coordinates and the number of cells of \b this remain unchanged on invocation of this method.
4130 * 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)
4131 * 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.
4133 * \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.
4134 * \sa MEDCouplingUMesh::colinearize2D
4136 DataArrayInt *MEDCouplingUMesh::convexEnvelop2D()
4138 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
4139 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convexEnvelop2D works only for meshDim=2 and spaceDim=2 !");
4140 checkFullyDefined();
4141 const double *coords=getCoords()->getConstPointer();
4142 int nbOfCells=getNumberOfCells();
4143 MCAuto<DataArrayInt> nodalConnecIndexOut=DataArrayInt::New();
4144 nodalConnecIndexOut->alloc(nbOfCells+1,1);
4145 MCAuto<DataArrayInt> nodalConnecOut(DataArrayInt::New());
4146 int *workIndexOut=nodalConnecIndexOut->getPointer();
4148 const int *nodalConnecIn=_nodal_connec->getConstPointer();
4149 const int *nodalConnecIndexIn=_nodal_connec_index->getConstPointer();
4150 std::set<INTERP_KERNEL::NormalizedCellType> types;
4151 MCAuto<DataArrayInt> isChanged(DataArrayInt::New());
4152 isChanged->alloc(0,1);
4153 for(int i=0;i<nbOfCells;i++,workIndexOut++)
4155 int pos=nodalConnecOut->getNumberOfTuples();
4156 if(BuildConvexEnvelopOf2DCellJarvis(coords,nodalConnecIn+nodalConnecIndexIn[i],nodalConnecIn+nodalConnecIndexIn[i+1],nodalConnecOut))
4157 isChanged->pushBackSilent(i);
4158 types.insert((INTERP_KERNEL::NormalizedCellType)nodalConnecOut->getIJ(pos,0));
4159 workIndexOut[1]=nodalConnecOut->getNumberOfTuples();
4161 if(isChanged->empty())
4163 setConnectivity(nodalConnecOut,nodalConnecIndexOut,false);
4165 return isChanged.retn();
4169 * This method is \b NOT const because it can modify \a this.
4170 * \a this is expected to be an unstructured mesh with meshDim==2 and spaceDim==3. If not an exception will be thrown.
4171 * \param mesh1D is an unstructured mesh with MeshDim==1 and spaceDim==3. If not an exception will be thrown.
4172 * \param policy specifies the type of extrusion chosen:
4173 * - \b 0 for translation only (most simple): the cells of the 1D mesh represent the vectors along which the 2D mesh
4174 * will be repeated to build each level
4175 * - \b 1 for translation and rotation: the translation is done as above. For each level, an arc of circle is fitted on
4176 * 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
4177 * 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
4179 * \return an unstructured mesh with meshDim==3 and spaceDim==3. The returned mesh has the same coords than \a this.
4181 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMesh(const MEDCouplingUMesh *mesh1D, int policy)
4183 checkFullyDefined();
4184 mesh1D->checkFullyDefined();
4185 if(!mesh1D->isContiguous1D())
4186 throw INTERP_KERNEL::Exception("buildExtrudedMesh : 1D mesh passed in parameter is not contiguous !");
4187 if(getSpaceDimension()!=mesh1D->getSpaceDimension())
4188 throw INTERP_KERNEL::Exception("Invalid call to buildExtrudedMesh this and mesh1D must have same space dimension !");
4189 if((getMeshDimension()!=2 || getSpaceDimension()!=3) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
4190 throw INTERP_KERNEL::Exception("Invalid 'this' for buildExtrudedMesh method : must be (meshDim==2 and spaceDim==3) or (meshDim==1 and spaceDim==2) !");
4191 if(mesh1D->getMeshDimension()!=1)
4192 throw INTERP_KERNEL::Exception("Invalid 'mesh1D' for buildExtrudedMesh method : must be meshDim==1 !");
4194 if(isPresenceOfQuadratic())
4196 if(mesh1D->isFullyQuadratic())
4199 throw INTERP_KERNEL::Exception("Invalid 2D mesh and 1D mesh because 2D mesh has quadratic cells and 1D is not fully quadratic !");
4201 int oldNbOfNodes(getNumberOfNodes());
4202 MCAuto<DataArrayDouble> newCoords;
4207 newCoords=fillExtCoordsUsingTranslation(mesh1D,isQuad);
4212 newCoords=fillExtCoordsUsingTranslAndAutoRotation(mesh1D,isQuad);
4216 throw INTERP_KERNEL::Exception("Not implemented extrusion policy : must be in (0) !");
4218 setCoords(newCoords);
4219 MCAuto<MEDCouplingUMesh> ret(buildExtrudedMeshFromThisLowLev(oldNbOfNodes,isQuad));
4226 * Checks if \a this mesh is constituted by only quadratic cells.
4227 * \return bool - \c true if there are only quadratic cells in \a this mesh.
4228 * \throw If the coordinates array is not set.
4229 * \throw If the nodal connectivity of cells is not defined.
4231 bool MEDCouplingUMesh::isFullyQuadratic() const
4233 checkFullyDefined();
4235 int nbOfCells=getNumberOfCells();
4236 for(int i=0;i<nbOfCells && ret;i++)
4238 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4239 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4240 ret=cm.isQuadratic();
4246 * Checks if \a this mesh includes any quadratic cell.
4247 * \return bool - \c true if there is at least one quadratic cells in \a this mesh.
4248 * \throw If the coordinates array is not set.
4249 * \throw If the nodal connectivity of cells is not defined.
4251 bool MEDCouplingUMesh::isPresenceOfQuadratic() const
4253 checkFullyDefined();
4255 int nbOfCells=getNumberOfCells();
4256 for(int i=0;i<nbOfCells && !ret;i++)
4258 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4259 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4260 ret=cm.isQuadratic();
4266 * Converts all quadratic cells to linear ones. If there are no quadratic cells in \a
4267 * this mesh, it remains unchanged.
4268 * \throw If the coordinates array is not set.
4269 * \throw If the nodal connectivity of cells is not defined.
4271 void MEDCouplingUMesh::convertQuadraticCellsToLinear()
4273 checkFullyDefined();
4274 int nbOfCells(getNumberOfCells());
4276 const int *iciptr=_nodal_connec_index->begin();
4277 for(int i=0;i<nbOfCells;i++)
4279 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4280 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4281 if(cm.isQuadratic())
4283 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4284 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4285 if(!cml.isDynamic())
4286 delta+=cm.getNumberOfNodes()-cml.getNumberOfNodes();
4288 delta+=(iciptr[i+1]-iciptr[i]-1)/2;
4293 MCAuto<DataArrayInt> newConn(DataArrayInt::New()),newConnI(DataArrayInt::New());
4294 const int *icptr(_nodal_connec->begin());
4295 newConn->alloc(getNodalConnectivityArrayLen()-delta,1);
4296 newConnI->alloc(nbOfCells+1,1);
4297 int *ocptr(newConn->getPointer()),*ociptr(newConnI->getPointer());
4300 for(int i=0;i<nbOfCells;i++,ociptr++)
4302 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)icptr[iciptr[i]];
4303 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4304 if(!cm.isQuadratic())
4306 _types.insert(type);
4307 ocptr=std::copy(icptr+iciptr[i],icptr+iciptr[i+1],ocptr);
4308 ociptr[1]=ociptr[0]+iciptr[i+1]-iciptr[i];
4312 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4313 _types.insert(typel);
4314 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4315 int newNbOfNodes=cml.getNumberOfNodes();
4317 newNbOfNodes=(iciptr[i+1]-iciptr[i]-1)/2;
4318 *ocptr++=(int)typel;
4319 ocptr=std::copy(icptr+iciptr[i]+1,icptr+iciptr[i]+newNbOfNodes+1,ocptr);
4320 ociptr[1]=ociptr[0]+newNbOfNodes+1;
4323 setConnectivity(newConn,newConnI,false);
4327 * This method converts all linear cell in \a this to quadratic one.
4328 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, here it is needed to specify the target
4329 * 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)
4330 * 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.
4331 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, the coordinates in \a this can be become bigger. All created nodes will be put at the
4332 * end of the existing coordinates.
4334 * \param [in] conversionType specifies the type of conversion expected. Only 0 (default) and 1 are supported presently. 0 those that creates the 'most' simple
4335 * corresponding quadratic cells. 1 is those creating the 'most' complex.
4336 * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
4338 * \throw if \a this is not fully defined. It throws too if \a conversionType is not in [0,1].
4340 * \sa MEDCouplingUMesh::convertQuadraticCellsToLinear
4342 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic(int conversionType)
4344 DataArrayInt *conn=0,*connI=0;
4345 DataArrayDouble *coords=0;
4346 std::set<INTERP_KERNEL::NormalizedCellType> types;
4347 checkFullyDefined();
4348 MCAuto<DataArrayInt> ret,connSafe,connISafe;
4349 MCAuto<DataArrayDouble> coordsSafe;
4350 int meshDim=getMeshDimension();
4351 switch(conversionType)
4357 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);
4358 connSafe=conn; connISafe=connI; coordsSafe=coords;
4361 ret=convertLinearCellsToQuadratic2D0(conn,connI,coords,types);
4362 connSafe=conn; connISafe=connI; coordsSafe=coords;
4365 ret=convertLinearCellsToQuadratic3D0(conn,connI,coords,types);
4366 connSafe=conn; connISafe=connI; coordsSafe=coords;
4369 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 0 mesh dimensions available are [1,2,3] !");
4377 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);//it is not a bug. In 1D policy 0 and 1 are equals
4378 connSafe=conn; connISafe=connI; coordsSafe=coords;
4381 ret=convertLinearCellsToQuadratic2D1(conn,connI,coords,types);
4382 connSafe=conn; connISafe=connI; coordsSafe=coords;
4385 ret=convertLinearCellsToQuadratic3D1(conn,connI,coords,types);
4386 connSafe=conn; connISafe=connI; coordsSafe=coords;
4389 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 1 mesh dimensions available are [1,2,3] !");
4394 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion type available are 0 (default, the simplest) and 1 (the most complex) !");
4396 setConnectivity(connSafe,connISafe,false);
4398 setCoords(coordsSafe);
4403 * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
4404 * so that the number of cells remains the same. Quadratic faces are converted to
4405 * polygons. This method works only for 2D meshes in
4406 * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
4407 * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
4408 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
4409 * \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
4410 * a polylinized edge constituting the input polygon.
4411 * \throw If the coordinates array is not set.
4412 * \throw If the nodal connectivity of cells is not defined.
4413 * \throw If \a this->getMeshDimension() != 2.
4414 * \throw If \a this->getSpaceDimension() != 2.
4416 void MEDCouplingUMesh::tessellate2D(double eps)
4418 int meshDim(getMeshDimension()),spaceDim(getSpaceDimension());
4420 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : works only with space dimension equal to 2 !");
4424 return tessellate2DCurveInternal(eps);
4426 return tessellate2DInternal(eps);
4428 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : mesh dimension must be in [1,2] !");
4432 * Tessellates \a this 1D mesh in 2D space by dividing not straight quadratic edges.
4433 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
4434 * \param [in] eps - specifies the maximal angle (in radian) between 2 sub-edges of
4435 * a sub-divided edge.
4436 * \throw If the coordinates array is not set.
4437 * \throw If the nodal connectivity of cells is not defined.
4438 * \throw If \a this->getMeshDimension() != 1.
4439 * \throw If \a this->getSpaceDimension() != 2.
4444 * This method only works if \a this has spaceDimension equal to 2 and meshDimension also equal to 2.
4445 * This method allows to modify connectivity of cells in \a this that shares some edges in \a edgeIdsToBeSplit.
4446 * The nodes to be added in those 2D cells are defined by the pair of \a nodeIdsToAdd and \a nodeIdsIndexToAdd.
4447 * Length of \a nodeIdsIndexToAdd is expected to equal to length of \a edgeIdsToBeSplit + 1.
4448 * The node ids in \a nodeIdsToAdd should be valid. Those nodes have to be sorted exactly following exactly the direction of the edge.
4449 * This method can be seen as the opposite method of colinearize2D.
4450 * 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
4451 * to avoid to modify the numbering of existing nodes.
4453 * \param [in] nodeIdsToAdd - the list of node ids to be added (\a nodeIdsIndexToAdd array allows to walk on this array)
4454 * \param [in] nodeIdsIndexToAdd - the entry point of \a nodeIdsToAdd to point to the corresponding nodes to be added.
4455 * \param [in] mesh1Desc - 1st output of buildDescendingConnectivity2 on \a this.
4456 * \param [in] desc - 2nd output of buildDescendingConnectivity2 on \a this.
4457 * \param [in] descI - 3rd output of buildDescendingConnectivity2 on \a this.
4458 * \param [in] revDesc - 4th output of buildDescendingConnectivity2 on \a this.
4459 * \param [in] revDescI - 5th output of buildDescendingConnectivity2 on \a this.
4461 * \sa buildDescendingConnectivity2
4463 void MEDCouplingUMesh::splitSomeEdgesOf2DMesh(const DataArrayInt *nodeIdsToAdd, const DataArrayInt *nodeIdsIndexToAdd, const DataArrayInt *edgeIdsToBeSplit,
4464 const MEDCouplingUMesh *mesh1Desc, const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *revDesc, const DataArrayInt *revDescI)
4466 if(!nodeIdsToAdd || !nodeIdsIndexToAdd || !edgeIdsToBeSplit || !mesh1Desc || !desc || !descI || !revDesc || !revDescI)
4467 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : input pointers must be not NULL !");
4468 nodeIdsToAdd->checkAllocated(); nodeIdsIndexToAdd->checkAllocated(); edgeIdsToBeSplit->checkAllocated(); desc->checkAllocated(); descI->checkAllocated(); revDesc->checkAllocated(); revDescI->checkAllocated();
4469 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
4470 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : this must have spacedim=meshdim=2 !");
4471 if(mesh1Desc->getSpaceDimension()!=2 || mesh1Desc->getMeshDimension()!=1)
4472 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : mesh1Desc must be the explosion of this with spaceDim=2 and meshDim = 1 !");
4473 //DataArrayInt *out0(0),*outi0(0);
4474 //MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
4475 //MCAuto<DataArrayInt> out0s(out0),outi0s(outi0);
4476 //out0s=out0s->buildUnique(); out0s->sort(true);
4482 * Divides every cell of \a this mesh into simplices (triangles in 2D and tetrahedra in 3D).
4483 * In addition, returns an array mapping new cells to old ones. <br>
4484 * This method typically increases the number of cells in \a this mesh
4485 * but the number of nodes remains \b unchanged.
4486 * That's why the 3D splitting policies
4487 * INTERP_KERNEL::GENERAL_24 and INTERP_KERNEL::GENERAL_48 are not available here.
4488 * \param [in] policy - specifies a pattern used for splitting.
4489 * The semantic of \a policy is:
4490 * - 0 - to split QUAD4 by cutting it along 0-2 diagonal (for 2D mesh only).
4491 * - 1 - to split QUAD4 by cutting it along 1-3 diagonal (for 2D mesh only).
4492 * - INTERP_KERNEL::PLANAR_FACE_5 - to split HEXA8 into 5 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4493 * - INTERP_KERNEL::PLANAR_FACE_6 - to split HEXA8 into 6 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4496 * \return DataArrayInt * - a new instance of DataArrayInt holding, for each new cell,
4497 * an id of old cell producing it. The caller is to delete this array using
4498 * decrRef() as it is no more needed.
4500 * \throw If \a policy is 0 or 1 and \a this->getMeshDimension() != 2.
4501 * \throw If \a policy is INTERP_KERNEL::PLANAR_FACE_5 or INTERP_KERNEL::PLANAR_FACE_6
4502 * and \a this->getMeshDimension() != 3.
4503 * \throw If \a policy is not one of the four discussed above.
4504 * \throw If the nodal connectivity of cells is not defined.
4505 * \sa MEDCouplingUMesh::tetrahedrize, MEDCoupling1SGTUMesh::sortHexa8EachOther
4507 DataArrayInt *MEDCouplingUMesh::simplexize(int policy)
4512 return simplexizePol0();
4514 return simplexizePol1();
4515 case (int) INTERP_KERNEL::PLANAR_FACE_5:
4516 return simplexizePlanarFace5();
4517 case (int) INTERP_KERNEL::PLANAR_FACE_6:
4518 return simplexizePlanarFace6();
4520 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)");
4525 * Checks if \a this mesh is constituted by simplex cells only. Simplex cells are:
4526 * - 1D: INTERP_KERNEL::NORM_SEG2
4527 * - 2D: INTERP_KERNEL::NORM_TRI3
4528 * - 3D: INTERP_KERNEL::NORM_TETRA4.
4530 * This method is useful for users that need to use P1 field services as
4531 * MEDCouplingFieldDouble::getValueOn(), MEDCouplingField::buildMeasureField() etc.
4532 * All these methods need mesh support containing only simplex cells.
4533 * \return bool - \c true if there are only simplex cells in \a this mesh.
4534 * \throw If the coordinates array is not set.
4535 * \throw If the nodal connectivity of cells is not defined.
4536 * \throw If \a this->getMeshDimension() < 1.
4538 bool MEDCouplingUMesh::areOnlySimplexCells() const
4540 checkFullyDefined();
4541 int mdim=getMeshDimension();
4542 if(mdim<1 || mdim>3)
4543 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::areOnlySimplexCells : only available with meshes having a meshdim 1, 2 or 3 !");
4544 int nbCells=getNumberOfCells();
4545 const int *conn=_nodal_connec->begin();
4546 const int *connI=_nodal_connec_index->begin();
4547 for(int i=0;i<nbCells;i++)
4549 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4559 * Converts degenerated 2D or 3D linear cells of \a this mesh into cells of simpler
4560 * type. For example an INTERP_KERNEL::NORM_QUAD4 cell having only three unique nodes in
4561 * its connectivity is transformed into an INTERP_KERNEL::NORM_TRI3 cell. This method
4562 * does \b not perform geometrical checks and checks only nodal connectivity of cells,
4563 * so it can be useful to call mergeNodes() before calling this method.
4564 * \throw If \a this->getMeshDimension() <= 1.
4565 * \throw If the coordinates array is not set.
4566 * \throw If the nodal connectivity of cells is not defined.
4568 void MEDCouplingUMesh::convertDegeneratedCells()
4570 checkFullyDefined();
4571 if(getMeshDimension()<=1)
4572 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4573 int nbOfCells=getNumberOfCells();
4576 int initMeshLgth=getNodalConnectivityArrayLen();
4577 int *conn=_nodal_connec->getPointer();
4578 int *index=_nodal_connec_index->getPointer();
4582 for(int i=0;i<nbOfCells;i++)
4584 lgthOfCurCell=index[i+1]-posOfCurCell;
4585 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4587 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
4588 conn+newPos+1,newLgth);
4589 conn[newPos]=newType;
4591 posOfCurCell=index[i+1];
4594 if(newPos!=initMeshLgth)
4595 _nodal_connec->reAlloc(newPos);
4600 * Finds incorrectly oriented cells of this 2D mesh in 3D space.
4601 * A cell is considered to be oriented correctly if an angle between its
4602 * normal vector and a given vector is less than \c PI / \c 2.
4603 * \param [in] vec - 3 components of the vector specifying the correct orientation of
4605 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
4607 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
4608 * is not cleared before filling in.
4609 * \throw If \a this->getMeshDimension() != 2.
4610 * \throw If \a this->getSpaceDimension() != 3.
4612 * \if ENABLE_EXAMPLES
4613 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
4614 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
4617 void MEDCouplingUMesh::are2DCellsNotCorrectlyOriented(const double *vec, bool polyOnly, std::vector<int>& cells) const
4619 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
4620 throw INTERP_KERNEL::Exception("Invalid mesh to apply are2DCellsNotCorrectlyOriented on it : must be meshDim==2 and spaceDim==3 !");
4621 int nbOfCells=getNumberOfCells();
4622 const int *conn=_nodal_connec->begin();
4623 const int *connI=_nodal_connec_index->begin();
4624 const double *coordsPtr=_coords->begin();
4625 for(int i=0;i<nbOfCells;i++)
4627 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4628 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
4630 bool isQuadratic=INTERP_KERNEL::CellModel::GetCellModel(type).isQuadratic();
4631 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4638 * Reverse connectivity of 2D cells whose orientation is not correct. A cell is
4639 * considered to be oriented correctly if an angle between its normal vector and a
4640 * given vector is less than \c PI / \c 2.
4641 * \param [in] vec - 3 components of the vector specifying the correct orientation of
4643 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
4645 * \throw If \a this->getMeshDimension() != 2.
4646 * \throw If \a this->getSpaceDimension() != 3.
4648 * \if ENABLE_EXAMPLES
4649 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
4650 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
4653 * \sa changeOrientationOfCells
4655 void MEDCouplingUMesh::orientCorrectly2DCells(const double *vec, bool polyOnly)
4657 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
4658 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectly2DCells on it : must be meshDim==2 and spaceDim==3 !");
4659 int nbOfCells(getNumberOfCells()),*conn(_nodal_connec->getPointer());
4660 const int *connI(_nodal_connec_index->begin());
4661 const double *coordsPtr(_coords->begin());
4662 bool isModified(false);
4663 for(int i=0;i<nbOfCells;i++)
4665 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4666 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
4668 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
4669 bool isQuadratic(cm.isQuadratic());
4670 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4673 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
4678 _nodal_connec->declareAsNew();
4683 * This method change the orientation of cells in \a this without any consideration of coordinates. Only connectivity is impacted.
4685 * \sa orientCorrectly2DCells
4687 void MEDCouplingUMesh::changeOrientationOfCells()
4689 int mdim(getMeshDimension());
4690 if(mdim!=2 && mdim!=1)
4691 throw INTERP_KERNEL::Exception("Invalid mesh to apply changeOrientationOfCells on it : must be meshDim==2 or meshDim==1 !");
4692 int nbOfCells(getNumberOfCells()),*conn(_nodal_connec->getPointer());
4693 const int *connI(_nodal_connec_index->begin());
4696 for(int i=0;i<nbOfCells;i++)
4698 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4699 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
4700 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
4705 for(int i=0;i<nbOfCells;i++)
4707 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4708 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
4709 cm.changeOrientationOf1D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
4715 * Finds incorrectly oriented polyhedral cells, i.e. polyhedrons having correctly
4716 * oriented facets. The normal vector of the facet should point out of the cell.
4717 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
4718 * is not cleared before filling in.
4719 * \throw If \a this->getMeshDimension() != 3.
4720 * \throw If \a this->getSpaceDimension() != 3.
4721 * \throw If the coordinates array is not set.
4722 * \throw If the nodal connectivity of cells is not defined.
4724 * \if ENABLE_EXAMPLES
4725 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
4726 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
4729 void MEDCouplingUMesh::arePolyhedronsNotCorrectlyOriented(std::vector<int>& cells) const
4731 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
4732 throw INTERP_KERNEL::Exception("Invalid mesh to apply arePolyhedronsNotCorrectlyOriented on it : must be meshDim==3 and spaceDim==3 !");
4733 int nbOfCells=getNumberOfCells();
4734 const int *conn=_nodal_connec->begin();
4735 const int *connI=_nodal_connec_index->begin();
4736 const double *coordsPtr=_coords->begin();
4737 for(int i=0;i<nbOfCells;i++)
4739 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4740 if(type==INTERP_KERNEL::NORM_POLYHED)
4742 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4749 * Tries to fix connectivity of polyhedra, so that normal vector of all facets to point
4751 * \throw If \a this->getMeshDimension() != 3.
4752 * \throw If \a this->getSpaceDimension() != 3.
4753 * \throw If the coordinates array is not set.
4754 * \throw If the nodal connectivity of cells is not defined.
4755 * \throw If the reparation fails.
4757 * \if ENABLE_EXAMPLES
4758 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
4759 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
4761 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
4763 void MEDCouplingUMesh::orientCorrectlyPolyhedrons()
4765 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
4766 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectlyPolyhedrons on it : must be meshDim==3 and spaceDim==3 !");
4767 int nbOfCells=getNumberOfCells();
4768 int *conn=_nodal_connec->getPointer();
4769 const int *connI=_nodal_connec_index->begin();
4770 const double *coordsPtr=_coords->begin();
4771 for(int i=0;i<nbOfCells;i++)
4773 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4774 if(type==INTERP_KERNEL::NORM_POLYHED)
4778 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4779 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
4781 catch(INTERP_KERNEL::Exception& e)
4783 std::ostringstream oss; oss << "Something wrong in polyhedron #" << i << " : " << e.what();
4784 throw INTERP_KERNEL::Exception(oss.str());
4792 * Finds and fixes incorrectly oriented linear extruded volumes (INTERP_KERNEL::NORM_HEXA8,
4793 * INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXGP12 etc) to respect the MED convention
4794 * according to which the first facet of the cell should be oriented to have the normal vector
4795 * pointing out of cell.
4796 * \return DataArrayInt * - a new instance of DataArrayInt holding ids of fixed
4797 * cells. The caller is to delete this array using decrRef() as it is no more
4799 * \throw If \a this->getMeshDimension() != 3.
4800 * \throw If \a this->getSpaceDimension() != 3.
4801 * \throw If the coordinates array is not set.
4802 * \throw If the nodal connectivity of cells is not defined.
4804 * \if ENABLE_EXAMPLES
4805 * \ref cpp_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a C++ example".<br>
4806 * \ref py_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a Python example".
4808 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
4810 DataArrayInt *MEDCouplingUMesh::findAndCorrectBadOriented3DExtrudedCells()
4812 const char msg[]="check3DCellsWellOriented detection works only for 3D cells !";
4813 if(getMeshDimension()!=3)
4814 throw INTERP_KERNEL::Exception(msg);
4815 int spaceDim=getSpaceDimension();
4817 throw INTERP_KERNEL::Exception(msg);
4819 int nbOfCells=getNumberOfCells();
4820 int *conn=_nodal_connec->getPointer();
4821 const int *connI=_nodal_connec_index->begin();
4822 const double *coo=getCoords()->begin();
4823 MCAuto<DataArrayInt> cells(DataArrayInt::New()); cells->alloc(0,1);
4824 for(int i=0;i<nbOfCells;i++)
4826 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4827 if(cm.isExtruded() && !cm.isDynamic() && !cm.isQuadratic())
4829 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coo))
4831 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
4832 cells->pushBackSilent(i);
4836 return cells.retn();
4840 * This method is a faster method to correct orientation of all 3D cells in \a this.
4841 * 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.
4842 * This method makes the hypothesis that \a this a coherent that is to say MEDCouplingUMesh::checkConsistency should throw no exception.
4844 * \return a newly allocated int array with one components containing cell ids renumbered to fit the convention of MED (MED file and MEDCoupling)
4845 * \sa MEDCouplingUMesh::orientCorrectlyPolyhedrons,
4847 DataArrayInt *MEDCouplingUMesh::findAndCorrectBadOriented3DCells()
4849 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
4850 throw INTERP_KERNEL::Exception("Invalid mesh to apply findAndCorrectBadOriented3DCells on it : must be meshDim==3 and spaceDim==3 !");
4851 int nbOfCells=getNumberOfCells();
4852 int *conn=_nodal_connec->getPointer();
4853 const int *connI=_nodal_connec_index->begin();
4854 const double *coordsPtr=_coords->begin();
4855 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
4856 for(int i=0;i<nbOfCells;i++)
4858 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4861 case INTERP_KERNEL::NORM_TETRA4:
4863 if(!IsTetra4WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4865 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+3));
4866 ret->pushBackSilent(i);
4870 case INTERP_KERNEL::NORM_PYRA5:
4872 if(!IsPyra5WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4874 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+4));
4875 ret->pushBackSilent(i);
4879 case INTERP_KERNEL::NORM_PENTA6:
4880 case INTERP_KERNEL::NORM_HEXA8:
4881 case INTERP_KERNEL::NORM_HEXGP12:
4883 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4885 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
4886 ret->pushBackSilent(i);
4890 case INTERP_KERNEL::NORM_POLYHED:
4892 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4894 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
4895 ret->pushBackSilent(i);
4900 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 !");
4908 * This method has a sense for meshes with spaceDim==3 and meshDim==2.
4909 * If it is not the case an exception will be thrown.
4910 * This method is fast because the first cell of \a this is used to compute the plane.
4911 * \param vec output of size at least 3 used to store the normal vector (with norm equal to Area ) of searched plane.
4912 * \param pos output of size at least 3 used to store a point owned of searched plane.
4914 void MEDCouplingUMesh::getFastAveragePlaneOfThis(double *vec, double *pos) const
4916 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
4917 throw INTERP_KERNEL::Exception("Invalid mesh to apply getFastAveragePlaneOfThis on it : must be meshDim==2 and spaceDim==3 !");
4918 const int *conn=_nodal_connec->begin();
4919 const int *connI=_nodal_connec_index->begin();
4920 const double *coordsPtr=_coords->begin();
4921 INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(conn+1,connI[1]-connI[0]-1,coordsPtr,vec);
4922 std::copy(coordsPtr+3*conn[1],coordsPtr+3*conn[1]+3,pos);
4926 * Creates a new MEDCouplingFieldDouble holding Edge Ratio values of all
4927 * cells. Currently cells of the following types are treated:
4928 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
4929 * For a cell of other type an exception is thrown.
4930 * Space dimension of a 2D mesh can be either 2 or 3.
4931 * The Edge Ratio of a cell \f$t\f$ is:
4932 * \f$\frac{|t|_\infty}{|t|_0}\f$,
4933 * where \f$|t|_\infty\f$ and \f$|t|_0\f$ respectively denote the greatest and
4934 * the smallest edge lengths of \f$t\f$.
4935 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
4936 * cells and one time, lying on \a this mesh. The caller is to delete this
4937 * field using decrRef() as it is no more needed.
4938 * \throw If the coordinates array is not set.
4939 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
4940 * \throw If the connectivity data array has more than one component.
4941 * \throw If the connectivity data array has a named component.
4942 * \throw If the connectivity index data array has more than one component.
4943 * \throw If the connectivity index data array has a named component.
4944 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
4945 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
4946 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
4948 MEDCouplingFieldDouble *MEDCouplingUMesh::getEdgeRatioField() const
4950 checkConsistencyLight();
4951 int spaceDim=getSpaceDimension();
4952 int meshDim=getMeshDimension();
4953 if(spaceDim!=2 && spaceDim!=3)
4954 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : SpaceDimension must be equal to 2 or 3 !");
4955 if(meshDim!=2 && meshDim!=3)
4956 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : MeshDimension must be equal to 2 or 3 !");
4957 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
4959 int nbOfCells=getNumberOfCells();
4960 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
4961 arr->alloc(nbOfCells,1);
4962 double *pt=arr->getPointer();
4963 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
4964 const int *conn=_nodal_connec->begin();
4965 const int *connI=_nodal_connec_index->begin();
4966 const double *coo=_coords->begin();
4968 for(int i=0;i<nbOfCells;i++,pt++)
4970 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
4973 case INTERP_KERNEL::NORM_TRI3:
4975 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
4976 *pt=INTERP_KERNEL::triEdgeRatio(tmp);
4979 case INTERP_KERNEL::NORM_QUAD4:
4981 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
4982 *pt=INTERP_KERNEL::quadEdgeRatio(tmp);
4985 case INTERP_KERNEL::NORM_TETRA4:
4987 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
4988 *pt=INTERP_KERNEL::tetraEdgeRatio(tmp);
4992 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
4994 conn+=connI[i+1]-connI[i];
4996 ret->setName("EdgeRatio");
4997 ret->synchronizeTimeWithSupport();
5002 * Creates a new MEDCouplingFieldDouble holding Aspect Ratio values of all
5003 * cells. Currently cells of the following types are treated:
5004 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5005 * For a cell of other type an exception is thrown.
5006 * Space dimension of a 2D mesh can be either 2 or 3.
5007 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5008 * cells and one time, lying on \a this mesh. The caller is to delete this
5009 * field using decrRef() as it is no more needed.
5010 * \throw If the coordinates array is not set.
5011 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5012 * \throw If the connectivity data array has more than one component.
5013 * \throw If the connectivity data array has a named component.
5014 * \throw If the connectivity index data array has more than one component.
5015 * \throw If the connectivity index data array has a named component.
5016 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
5017 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5018 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5020 MEDCouplingFieldDouble *MEDCouplingUMesh::getAspectRatioField() const
5022 checkConsistencyLight();
5023 int spaceDim=getSpaceDimension();
5024 int meshDim=getMeshDimension();
5025 if(spaceDim!=2 && spaceDim!=3)
5026 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : SpaceDimension must be equal to 2 or 3 !");
5027 if(meshDim!=2 && meshDim!=3)
5028 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : MeshDimension must be equal to 2 or 3 !");
5029 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5031 int nbOfCells=getNumberOfCells();
5032 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5033 arr->alloc(nbOfCells,1);
5034 double *pt=arr->getPointer();
5035 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5036 const int *conn=_nodal_connec->begin();
5037 const int *connI=_nodal_connec_index->begin();
5038 const double *coo=_coords->begin();
5040 for(int i=0;i<nbOfCells;i++,pt++)
5042 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5045 case INTERP_KERNEL::NORM_TRI3:
5047 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5048 *pt=INTERP_KERNEL::triAspectRatio(tmp);
5051 case INTERP_KERNEL::NORM_QUAD4:
5053 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5054 *pt=INTERP_KERNEL::quadAspectRatio(tmp);
5057 case INTERP_KERNEL::NORM_TETRA4:
5059 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5060 *pt=INTERP_KERNEL::tetraAspectRatio(tmp);
5064 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5066 conn+=connI[i+1]-connI[i];
5068 ret->setName("AspectRatio");
5069 ret->synchronizeTimeWithSupport();
5074 * Creates a new MEDCouplingFieldDouble holding Warping factor values of all
5075 * cells of \a this 2D mesh in 3D space. It is a measure of the "planarity" of 2D cell
5076 * in 3D space. Currently only cells of the following types are
5077 * treated: INTERP_KERNEL::NORM_QUAD4.
5078 * For a cell of other type an exception is thrown.
5079 * The warp field is computed as follows: let (a,b,c,d) be the points of the quad.
5081 * \f$t=\vec{da}\times\vec{ab}\f$,
5082 * \f$u=\vec{ab}\times\vec{bc}\f$
5083 * \f$v=\vec{bc}\times\vec{cd}\f$
5084 * \f$w=\vec{cd}\times\vec{da}\f$, the warp is defined as \f$W^3\f$ with
5086 * W=min(\frac{t}{|t|}\cdot\frac{v}{|v|}, \frac{u}{|u|}\cdot\frac{w}{|w|})
5088 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5089 * cells and one time, lying on \a this mesh. The caller is to delete this
5090 * field using decrRef() as it is no more needed.
5091 * \throw If the coordinates array is not set.
5092 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5093 * \throw If the connectivity data array has more than one component.
5094 * \throw If the connectivity data array has a named component.
5095 * \throw If the connectivity index data array has more than one component.
5096 * \throw If the connectivity index data array has a named component.
5097 * \throw If \a this->getMeshDimension() != 2.
5098 * \throw If \a this->getSpaceDimension() != 3.
5099 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5101 MEDCouplingFieldDouble *MEDCouplingUMesh::getWarpField() const
5103 checkConsistencyLight();
5104 int spaceDim=getSpaceDimension();
5105 int meshDim=getMeshDimension();
5107 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : SpaceDimension must be equal to 3 !");
5109 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : MeshDimension must be equal to 2 !");
5110 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5112 int nbOfCells=getNumberOfCells();
5113 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5114 arr->alloc(nbOfCells,1);
5115 double *pt=arr->getPointer();
5116 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5117 const int *conn=_nodal_connec->begin();
5118 const int *connI=_nodal_connec_index->begin();
5119 const double *coo=_coords->begin();
5121 for(int i=0;i<nbOfCells;i++,pt++)
5123 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5126 case INTERP_KERNEL::NORM_QUAD4:
5128 FillInCompact3DMode(3,4,conn+1,coo,tmp);
5129 *pt=INTERP_KERNEL::quadWarp(tmp);
5133 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : A cell with not manged type (NORM_QUAD4) has been detected !");
5135 conn+=connI[i+1]-connI[i];
5137 ret->setName("Warp");
5138 ret->synchronizeTimeWithSupport();
5144 * Creates a new MEDCouplingFieldDouble holding Skew factor values of all
5145 * cells of \a this 2D mesh in 3D space. Currently cells of the following types are
5146 * treated: INTERP_KERNEL::NORM_QUAD4.
5147 * The skew is computed as follow for a quad with points (a,b,c,d): let
5148 * \f$u=\vec{ab}+\vec{dc}\f$ and \f$v=\vec{ac}+\vec{bd}\f$
5149 * then the skew is computed as:
5151 * s=\frac{u}{|u|}\cdot\frac{v}{|v|}
5154 * For a cell of other type an exception is thrown.
5155 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5156 * cells and one time, lying on \a this mesh. The caller is to delete this
5157 * field using decrRef() as it is no more needed.
5158 * \throw If the coordinates array is not set.
5159 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5160 * \throw If the connectivity data array has more than one component.
5161 * \throw If the connectivity data array has a named component.
5162 * \throw If the connectivity index data array has more than one component.
5163 * \throw If the connectivity index data array has a named component.
5164 * \throw If \a this->getMeshDimension() != 2.
5165 * \throw If \a this->getSpaceDimension() != 3.
5166 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5168 MEDCouplingFieldDouble *MEDCouplingUMesh::getSkewField() const
5170 checkConsistencyLight();
5171 int spaceDim=getSpaceDimension();
5172 int meshDim=getMeshDimension();
5174 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : SpaceDimension must be equal to 3 !");
5176 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : MeshDimension must be equal to 2 !");
5177 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5179 int nbOfCells=getNumberOfCells();
5180 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5181 arr->alloc(nbOfCells,1);
5182 double *pt=arr->getPointer();
5183 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5184 const int *conn=_nodal_connec->begin();
5185 const int *connI=_nodal_connec_index->begin();
5186 const double *coo=_coords->begin();
5188 for(int i=0;i<nbOfCells;i++,pt++)
5190 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5193 case INTERP_KERNEL::NORM_QUAD4:
5195 FillInCompact3DMode(3,4,conn+1,coo,tmp);
5196 *pt=INTERP_KERNEL::quadSkew(tmp);
5200 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : A cell with not manged type (NORM_QUAD4) has been detected !");
5202 conn+=connI[i+1]-connI[i];
5204 ret->setName("Skew");
5205 ret->synchronizeTimeWithSupport();
5210 * 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.
5212 * \return a new instance of field containing the result. The returned instance has to be deallocated by the caller.
5214 * \sa getSkewField, getWarpField, getAspectRatioField, getEdgeRatioField
5216 MEDCouplingFieldDouble *MEDCouplingUMesh::computeDiameterField() const
5218 checkConsistencyLight();
5219 MCAuto<MEDCouplingFieldDouble> ret(MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME));
5221 std::set<INTERP_KERNEL::NormalizedCellType> types;
5222 ComputeAllTypesInternal(types,_nodal_connec,_nodal_connec_index);
5223 int spaceDim(getSpaceDimension()),nbCells(getNumberOfCells());
5224 MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
5225 arr->alloc(nbCells,1);
5226 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++)
5228 INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::DiameterCalculator> dc(INTERP_KERNEL::CellModel::GetCellModel(*it).buildInstanceOfDiameterCalulator(spaceDim));
5229 MCAuto<DataArrayInt> cellIds(giveCellsWithType(*it));
5230 dc->computeForListOfCellIdsUMeshFrmt(cellIds->begin(),cellIds->end(),_nodal_connec_index->begin(),_nodal_connec->begin(),getCoords()->begin(),arr->getPointer());
5233 ret->setName("Diameter");
5238 * This method aggregate the bbox of each cell and put it into bbox parameter (xmin,xmax,ymin,ymax,zmin,zmax).
5240 * \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)
5241 * For all other cases this input parameter is ignored.
5242 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5244 * \throw If \a this is not fully set (coordinates and connectivity).
5245 * \throw If a cell in \a this has no valid nodeId.
5246 * \sa MEDCouplingUMesh::getBoundingBoxForBBTreeFast, MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5248 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree(double arcDetEps) const
5250 int mDim(getMeshDimension()),sDim(getSpaceDimension());
5251 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.
5252 return getBoundingBoxForBBTreeFast();
5253 if((mDim==2 && sDim==2) || (mDim==1 && sDim==2))
5255 bool presenceOfQuadratic(false);
5256 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=_types.begin();it!=_types.end();it++)
5258 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(*it));
5259 if(cm.isQuadratic())
5260 presenceOfQuadratic=true;
5262 if(!presenceOfQuadratic)
5263 return getBoundingBoxForBBTreeFast();
5264 if(mDim==2 && sDim==2)
5265 return getBoundingBoxForBBTree2DQuadratic(arcDetEps);
5267 return getBoundingBoxForBBTree1DQuadratic(arcDetEps);
5269 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) !");
5273 * This method aggregate the bbox of each cell only considering the nodes constituting each cell and put it into bbox parameter.
5274 * So meshes having quadratic cells the computed bounding boxes can be invalid !
5276 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5278 * \throw If \a this is not fully set (coordinates and connectivity).
5279 * \throw If a cell in \a this has no valid nodeId.
5281 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTreeFast() const
5283 checkFullyDefined();
5284 int spaceDim(getSpaceDimension()),nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
5285 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5286 double *bbox(ret->getPointer());
5287 for(int i=0;i<nbOfCells*spaceDim;i++)
5289 bbox[2*i]=std::numeric_limits<double>::max();
5290 bbox[2*i+1]=-std::numeric_limits<double>::max();
5292 const double *coordsPtr(_coords->begin());
5293 const int *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5294 for(int i=0;i<nbOfCells;i++)
5296 int offset=connI[i]+1;
5297 int nbOfNodesForCell(connI[i+1]-offset),kk(0);
5298 for(int j=0;j<nbOfNodesForCell;j++)
5300 int nodeId=conn[offset+j];
5301 if(nodeId>=0 && nodeId<nbOfNodes)
5303 for(int k=0;k<spaceDim;k++)
5305 bbox[2*spaceDim*i+2*k]=std::min(bbox[2*spaceDim*i+2*k],coordsPtr[spaceDim*nodeId+k]);
5306 bbox[2*spaceDim*i+2*k+1]=std::max(bbox[2*spaceDim*i+2*k+1],coordsPtr[spaceDim*nodeId+k]);
5313 std::ostringstream oss; oss << "MEDCouplingUMesh::getBoundingBoxForBBTree : cell #" << i << " contains no valid nodeId !";
5314 throw INTERP_KERNEL::Exception(oss.str());
5321 * This method aggregates the bbox of each 2D cell in \a this considering the whole shape. This method is particularly
5322 * useful for 2D meshes having quadratic cells
5323 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5324 * the two extremities of the arc of circle).
5326 * \param [in] arcDetEps - a parameter specifying in case of 2D quadratic polygon cell the detection limit between linear and arc circle. (By default 1e-12)
5327 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5328 * \throw If \a this is not fully defined.
5329 * \throw If \a this is not a mesh with meshDimension equal to 2.
5330 * \throw If \a this is not a mesh with spaceDimension equal to 2.
5331 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic
5333 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic(double arcDetEps) const
5335 checkFullyDefined();
5336 int spaceDim(getSpaceDimension()),mDim(getMeshDimension()),nbOfCells(getNumberOfCells());
5337 if(spaceDim!=2 || mDim!=2)
5338 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!");
5339 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5340 double *bbox(ret->getPointer());
5341 const double *coords(_coords->begin());
5342 const int *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5343 for(int i=0;i<nbOfCells;i++,bbox+=4,connI++)
5345 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5346 int sz(connI[1]-connI[0]-1);
5347 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=arcDetEps;
5348 std::vector<INTERP_KERNEL::Node *> nodes(sz);
5349 INTERP_KERNEL::QuadraticPolygon *pol(0);
5350 for(int j=0;j<sz;j++)
5352 int nodeId(conn[*connI+1+j]);
5353 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5355 if(!cm.isQuadratic())
5356 pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
5358 pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
5359 INTERP_KERNEL::Bounds b; b.prepareForAggregation(); pol->fillBounds(b); delete pol;
5360 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax();
5366 * This method aggregates the bbox of each 1D cell in \a this considering the whole shape. This method is particularly
5367 * useful for 2D meshes having quadratic cells
5368 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5369 * the two extremities of the arc of circle).
5371 * \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)
5372 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5373 * \throw If \a this is not fully defined.
5374 * \throw If \a this is not a mesh with meshDimension equal to 1.
5375 * \throw If \a this is not a mesh with spaceDimension equal to 2.
5376 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5378 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic(double arcDetEps) const
5380 checkFullyDefined();
5381 int spaceDim(getSpaceDimension()),mDim(getMeshDimension()),nbOfCells(getNumberOfCells());
5382 if(spaceDim!=2 || mDim!=1)
5383 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!");
5384 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5385 double *bbox(ret->getPointer());
5386 const double *coords(_coords->begin());
5387 const int *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5388 for(int i=0;i<nbOfCells;i++,bbox+=4,connI++)
5390 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5391 int sz(connI[1]-connI[0]-1);
5392 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=arcDetEps;
5393 std::vector<INTERP_KERNEL::Node *> nodes(sz);
5394 INTERP_KERNEL::Edge *edge(0);
5395 for(int j=0;j<sz;j++)
5397 int nodeId(conn[*connI+1+j]);
5398 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5400 if(!cm.isQuadratic())
5401 edge=INTERP_KERNEL::QuadraticPolygon::BuildLinearEdge(nodes);
5403 edge=INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(nodes);
5404 const INTERP_KERNEL::Bounds& b(edge->getBounds());
5405 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax(); edge->decrRef();
5412 namespace MEDCouplingImpl
5417 ConnReader(const int *c, int val):_conn(c),_val(val) { }
5418 bool operator() (const int& pos) { return _conn[pos]!=_val; }
5427 ConnReader2(const int *c, int val):_conn(c),_val(val) { }
5428 bool operator() (const int& pos) { return _conn[pos]==_val; }
5438 * This method expects that \a this is sorted by types. If not an exception will be thrown.
5439 * This method returns in the same format as code (see MEDCouplingUMesh::checkTypeConsistencyAndContig or MEDCouplingUMesh::splitProfilePerType) how
5440 * \a this is composed in cell types.
5441 * The returned array is of size 3*n where n is the number of different types present in \a this.
5442 * For every k in [0,n] ret[3*k+2]==-1 because it has no sense here.
5443 * This parameter is kept only for compatibility with other methode listed above.
5445 std::vector<int> MEDCouplingUMesh::getDistributionOfTypes() const
5447 checkConnectivityFullyDefined();
5448 const int *conn=_nodal_connec->begin();
5449 const int *connI=_nodal_connec_index->begin();
5450 const int *work=connI;
5451 int nbOfCells=getNumberOfCells();
5452 std::size_t n=getAllGeoTypes().size();
5453 std::vector<int> ret(3*n,-1); //ret[3*k+2]==-1 because it has no sense here
5454 std::set<INTERP_KERNEL::NormalizedCellType> types;
5455 for(std::size_t i=0;work!=connI+nbOfCells;i++)
5457 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn[*work];
5458 if(types.find(typ)!=types.end())
5460 std::ostringstream oss; oss << "MEDCouplingUMesh::getDistributionOfTypes : Type " << INTERP_KERNEL::CellModel::GetCellModel(typ).getRepr();
5461 oss << " is not contiguous !";
5462 throw INTERP_KERNEL::Exception(oss.str());
5466 const int *work2=std::find_if(work+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,typ));
5467 ret[3*i+1]=(int)std::distance(work,work2);
5474 * This method is used to check that this has contiguous cell type in same order than described in \a code.
5475 * only for types cell, type node is not managed.
5476 * Format of \a code is the following. \a code should be of size 3*n and non empty. If not an exception is thrown.
5477 * foreach k in [0,n) on 3*k pos represent the geometric type and 3*k+1 number of elements of type 3*k.
5478 * 3*k+2 refers if different from -1 the pos in 'idsPerType' to get the corresponding array.
5479 * If 2 or more same geometric type is in \a code and exception is thrown too.
5481 * This method firstly checks
5482 * If it exists k so that 3*k geometric type is not in geometric types of this an exception will be thrown.
5483 * If it exists k so that 3*k geometric type exists but the number of consecutive cell types does not match,
5484 * an exception is thrown too.
5486 * If all geometric types in \a code are exactly those in \a this null pointer is returned.
5487 * If it exists a geometric type in \a this \b not in \a code \b no exception is thrown
5488 * and a DataArrayInt instance is returned that the user has the responsability to deallocate.
5490 DataArrayInt *MEDCouplingUMesh::checkTypeConsistencyAndContig(const std::vector<int>& code, const std::vector<const DataArrayInt *>& idsPerType) const
5493 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code is empty, should not !");
5494 std::size_t sz=code.size();
5497 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code size is NOT %3 !");
5498 std::vector<INTERP_KERNEL::NormalizedCellType> types;
5500 bool isNoPflUsed=true;
5501 for(std::size_t i=0;i<n;i++)
5502 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)code[3*i])==types.end())
5504 types.push_back((INTERP_KERNEL::NormalizedCellType)code[3*i]);
5506 if(_types.find((INTERP_KERNEL::NormalizedCellType)code[3*i])==_types.end())
5507 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : expected geo types not in this !");
5508 isNoPflUsed=isNoPflUsed && (code[3*i+2]==-1);
5511 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code contains duplication of types in unstructured mesh !");
5514 if(!checkConsecutiveCellTypesAndOrder(&types[0],&types[0]+types.size()))
5515 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : non contiguous type !");
5516 if(types.size()==_types.size())
5519 MCAuto<DataArrayInt> ret=DataArrayInt::New();
5521 int *retPtr=ret->getPointer();
5522 const int *connI=_nodal_connec_index->begin();
5523 const int *conn=_nodal_connec->begin();
5524 int nbOfCells=getNumberOfCells();
5527 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++,kk++)
5529 i=std::find_if(i,connI+nbOfCells,MEDCouplingImpl::ConnReader2(conn,(int)(*it)));
5530 int offset=(int)std::distance(connI,i);
5531 const int *j=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)(*it)));
5532 int nbOfCellsOfCurType=(int)std::distance(i,j);
5533 if(code[3*kk+2]==-1)
5534 for(int k=0;k<nbOfCellsOfCurType;k++)
5538 int idInIdsPerType=code[3*kk+2];
5539 if(idInIdsPerType>=0 && idInIdsPerType<(int)idsPerType.size())
5541 const DataArrayInt *zePfl=idsPerType[idInIdsPerType];
5544 zePfl->checkAllocated();
5545 if(zePfl->getNumberOfComponents()==1)
5547 for(const int *k=zePfl->begin();k!=zePfl->end();k++,retPtr++)
5549 if(*k>=0 && *k<nbOfCellsOfCurType)
5550 *retPtr=(*k)+offset;
5553 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : the section " << kk << " points to the profile #" << idInIdsPerType;
5554 oss << ", and this profile contains a value " << *k << " should be in [0," << nbOfCellsOfCurType << ") !";
5555 throw INTERP_KERNEL::Exception(oss.str());
5560 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of a profile with nb of compo != 1 !");
5563 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of null profile !");
5567 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : at section " << kk << " of code it points to the array #" << idInIdsPerType;
5568 oss << " should be in [0," << idsPerType.size() << ") !";
5569 throw INTERP_KERNEL::Exception(oss.str());
5578 * This method makes the hypothesis that \a this is sorted by type. If not an exception will be thrown.
5579 * 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.
5580 * 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.
5581 * This method has 1 input \a profile and 3 outputs \a code \a idsInPflPerType and \a idsPerType.
5583 * \param [in] profile
5584 * \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.
5585 * \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,
5586 * \a idsInPflPerType[i] stores the tuple ids in \a profile that correspond to the geometric type code[3*i+0]
5587 * \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.
5588 * This vector can be empty in case of all geometric type cells are fully covered in ascending in the given input \a profile.
5589 * \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
5591 void MEDCouplingUMesh::splitProfilePerType(const DataArrayInt *profile, std::vector<int>& code, std::vector<DataArrayInt *>& idsInPflPerType, std::vector<DataArrayInt *>& idsPerType) const
5594 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile is NULL !");
5595 if(profile->getNumberOfComponents()!=1)
5596 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile should have exactly one component !");
5597 checkConnectivityFullyDefined();
5598 const int *conn=_nodal_connec->begin();
5599 const int *connI=_nodal_connec_index->begin();
5600 int nbOfCells=getNumberOfCells();
5601 std::vector<INTERP_KERNEL::NormalizedCellType> types;
5602 std::vector<int> typeRangeVals(1);
5603 for(const int *i=connI;i!=connI+nbOfCells;)
5605 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5606 if(std::find(types.begin(),types.end(),curType)!=types.end())
5608 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : current mesh is not sorted by type !");
5610 types.push_back(curType);
5611 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
5612 typeRangeVals.push_back((int)std::distance(connI,i));
5615 DataArrayInt *castArr=0,*rankInsideCast=0,*castsPresent=0;
5616 profile->splitByValueRange(&typeRangeVals[0],&typeRangeVals[0]+typeRangeVals.size(),castArr,rankInsideCast,castsPresent);
5617 MCAuto<DataArrayInt> tmp0=castArr;
5618 MCAuto<DataArrayInt> tmp1=rankInsideCast;
5619 MCAuto<DataArrayInt> tmp2=castsPresent;
5621 int nbOfCastsFinal=castsPresent->getNumberOfTuples();
5622 code.resize(3*nbOfCastsFinal);
5623 std::vector< MCAuto<DataArrayInt> > idsInPflPerType2;
5624 std::vector< MCAuto<DataArrayInt> > idsPerType2;
5625 for(int i=0;i<nbOfCastsFinal;i++)
5627 int castId=castsPresent->getIJ(i,0);
5628 MCAuto<DataArrayInt> tmp3=castArr->findIdsEqual(castId);
5629 idsInPflPerType2.push_back(tmp3);
5630 code[3*i]=(int)types[castId];
5631 code[3*i+1]=tmp3->getNumberOfTuples();
5632 MCAuto<DataArrayInt> tmp4=rankInsideCast->selectByTupleId(tmp3->begin(),tmp3->begin()+tmp3->getNumberOfTuples());
5633 if(!tmp4->isIota(typeRangeVals[castId+1]-typeRangeVals[castId]))
5635 tmp4->copyStringInfoFrom(*profile);
5636 idsPerType2.push_back(tmp4);
5637 code[3*i+2]=(int)idsPerType2.size()-1;
5644 std::size_t sz2=idsInPflPerType2.size();
5645 idsInPflPerType.resize(sz2);
5646 for(std::size_t i=0;i<sz2;i++)
5648 DataArrayInt *locDa=idsInPflPerType2[i];
5650 idsInPflPerType[i]=locDa;
5652 std::size_t sz=idsPerType2.size();
5653 idsPerType.resize(sz);
5654 for(std::size_t i=0;i<sz;i++)
5656 DataArrayInt *locDa=idsPerType2[i];
5658 idsPerType[i]=locDa;
5663 * This method is here too emulate the MEDMEM behaviour on BDC (buildDescendingConnectivity). Hoping this method becomes deprecated very soon.
5664 * This method make the assumption that \a this and 'nM1LevMesh' mesh lyies on same coords (same pointer) as MED and MEDMEM does.
5665 * The following equality should be verified 'nM1LevMesh->getMeshDimension()==this->getMeshDimension()-1'
5666 * 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.
5668 MEDCouplingUMesh *MEDCouplingUMesh::emulateMEDMEMBDC(const MEDCouplingUMesh *nM1LevMesh, DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *&revDesc, DataArrayInt *&revDescIndx, DataArrayInt *& nM1LevMeshIds, DataArrayInt *&meshnM1Old2New) const
5670 checkFullyDefined();
5671 nM1LevMesh->checkFullyDefined();
5672 if(getMeshDimension()-1!=nM1LevMesh->getMeshDimension())
5673 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : The mesh passed as first argument should have a meshDim equal to this->getMeshDimension()-1 !" );
5674 if(_coords!=nM1LevMesh->getCoords())
5675 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : 'this' and mesh in first argument should share the same coords : Use tryToShareSameCoords method !");
5676 MCAuto<DataArrayInt> tmp0=DataArrayInt::New();
5677 MCAuto<DataArrayInt> tmp1=DataArrayInt::New();
5678 MCAuto<MEDCouplingUMesh> ret1=buildDescendingConnectivity(desc,descIndx,tmp0,tmp1);
5679 MCAuto<DataArrayInt> ret0=ret1->sortCellsInMEDFileFrmt();
5680 desc->transformWithIndArr(ret0->begin(),ret0->begin()+ret0->getNbOfElems());
5681 MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
5682 tmp->setConnectivity(tmp0,tmp1);
5683 tmp->renumberCells(ret0->begin(),false);
5684 revDesc=tmp->getNodalConnectivity();
5685 revDescIndx=tmp->getNodalConnectivityIndex();
5686 DataArrayInt *ret=0;
5687 if(!ret1->areCellsIncludedIn(nM1LevMesh,2,ret))
5690 ret->getMaxValue(tmp2);
5692 std::ostringstream oss; oss << "MEDCouplingUMesh::emulateMEDMEMBDC : input N-1 mesh present a cell not in descending mesh ... Id of cell is " << tmp2 << " !";
5693 throw INTERP_KERNEL::Exception(oss.str());
5698 revDescIndx->incrRef();
5701 meshnM1Old2New=ret0;
5706 * Permutes the nodal connectivity arrays so that the cells are sorted by type, which is
5707 * necessary for writing the mesh to MED file. Additionally returns a permutation array
5708 * in "Old to New" mode.
5709 * \return DataArrayInt * - a new instance of DataArrayInt. The caller is to delete
5710 * this array using decrRef() as it is no more needed.
5711 * \throw If the nodal connectivity of cells is not defined.
5713 DataArrayInt *MEDCouplingUMesh::sortCellsInMEDFileFrmt()
5715 checkConnectivityFullyDefined();
5716 MCAuto<DataArrayInt> ret=getRenumArrForMEDFileFrmt();
5717 renumberCells(ret->begin(),false);
5722 * This methods checks that cells are sorted by their types.
5723 * This method makes asumption (no check) that connectivity is correctly set before calling.
5725 bool MEDCouplingUMesh::checkConsecutiveCellTypes() const
5727 checkFullyDefined();
5728 const int *conn=_nodal_connec->begin();
5729 const int *connI=_nodal_connec_index->begin();
5730 int nbOfCells=getNumberOfCells();
5731 std::set<INTERP_KERNEL::NormalizedCellType> types;
5732 for(const int *i=connI;i!=connI+nbOfCells;)
5734 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5735 if(types.find(curType)!=types.end())
5737 types.insert(curType);
5738 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
5744 * This method is a specialization of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method that is called here.
5745 * The geometric type order is specified by MED file.
5747 * \sa MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder
5749 bool MEDCouplingUMesh::checkConsecutiveCellTypesForMEDFileFrmt() const
5751 return checkConsecutiveCellTypesAndOrder(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
5755 * This method performs the same job as checkConsecutiveCellTypes except that the order of types sequence is analyzed to check
5756 * that the order is specified in array defined by [ \a orderBg , \a orderEnd ).
5757 * If there is some geo types in \a this \b NOT in [ \a orderBg, \a orderEnd ) it is OK (return true) if contiguous.
5758 * If there is some geo types in [ \a orderBg, \a orderEnd ) \b NOT in \a this it is OK too (return true) if contiguous.
5760 bool MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
5762 checkFullyDefined();
5763 const int *conn=_nodal_connec->begin();
5764 const int *connI=_nodal_connec_index->begin();
5765 int nbOfCells=getNumberOfCells();
5769 std::set<INTERP_KERNEL::NormalizedCellType> sg;
5770 for(const int *i=connI;i!=connI+nbOfCells;)
5772 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5773 const INTERP_KERNEL::NormalizedCellType *isTypeExists=std::find(orderBg,orderEnd,curType);
5774 if(isTypeExists!=orderEnd)
5776 int pos=(int)std::distance(orderBg,isTypeExists);
5780 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
5784 if(sg.find(curType)==sg.end())
5786 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
5797 * This method returns 2 newly allocated DataArrayInt instances. The first is an array of size 'this->getNumberOfCells()' with one component,
5798 * 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
5799 * 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'.
5801 DataArrayInt *MEDCouplingUMesh::getLevArrPerCellTypes(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd, DataArrayInt *&nbPerType) const
5803 checkConnectivityFullyDefined();
5804 int nbOfCells=getNumberOfCells();
5805 const int *conn=_nodal_connec->begin();
5806 const int *connI=_nodal_connec_index->begin();
5807 MCAuto<DataArrayInt> tmpa=DataArrayInt::New();
5808 MCAuto<DataArrayInt> tmpb=DataArrayInt::New();
5809 tmpa->alloc(nbOfCells,1);
5810 tmpb->alloc((int)std::distance(orderBg,orderEnd),1);
5811 tmpb->fillWithZero();
5812 int *tmp=tmpa->getPointer();
5813 int *tmp2=tmpb->getPointer();
5814 for(const int *i=connI;i!=connI+nbOfCells;i++)
5816 const INTERP_KERNEL::NormalizedCellType *where=std::find(orderBg,orderEnd,(INTERP_KERNEL::NormalizedCellType)conn[*i]);
5819 int pos=(int)std::distance(orderBg,where);
5821 tmp[std::distance(connI,i)]=pos;
5825 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*i]);
5826 std::ostringstream oss; oss << "MEDCouplingUMesh::getLevArrPerCellTypes : Cell #" << std::distance(connI,i);
5827 oss << " has a type " << cm.getRepr() << " not in input array of type !";
5828 throw INTERP_KERNEL::Exception(oss.str());
5831 nbPerType=tmpb.retn();
5836 * This method behaves exactly as MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec but the order is those defined in MED file spec.
5838 * \return a new object containing the old to new correspondance.
5840 * \sa MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec, MEDCouplingUMesh::sortCellsInMEDFileFrmt.
5842 DataArrayInt *MEDCouplingUMesh::getRenumArrForMEDFileFrmt() const
5844 return getRenumArrForConsecutiveCellTypesSpec(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
5848 * 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.
5849 * This method returns an array of size getNumberOfCells() that gives a renumber array old2New that can be used as input of MEDCouplingMesh::renumberCells.
5850 * The mesh after this call to MEDCouplingMesh::renumberCells will pass the test of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder with the same inputs.
5851 * The returned array minimizes the permutations that is to say the order of cells inside same geometric type remains the same.
5853 DataArrayInt *MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
5855 DataArrayInt *nbPerType=0;
5856 MCAuto<DataArrayInt> tmpa=getLevArrPerCellTypes(orderBg,orderEnd,nbPerType);
5857 nbPerType->decrRef();
5858 return tmpa->buildPermArrPerLevel();
5862 * This method reorganize the cells of \a this so that the cells with same geometric types are put together.
5863 * The number of cells remains unchanged after the call of this method.
5864 * This method tries to minimizes the number of needed permutations. So, this method behaves not exactly as
5865 * MEDCouplingUMesh::sortCellsInMEDFileFrmt.
5867 * \return the array giving the correspondance old to new.
5869 DataArrayInt *MEDCouplingUMesh::rearrange2ConsecutiveCellTypes()
5871 checkFullyDefined();
5873 const int *conn=_nodal_connec->begin();
5874 const int *connI=_nodal_connec_index->begin();
5875 int nbOfCells=getNumberOfCells();
5876 std::vector<INTERP_KERNEL::NormalizedCellType> types;
5877 for(const int *i=connI;i!=connI+nbOfCells && (types.size()!=_types.size());)
5878 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)conn[*i])==types.end())
5880 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5881 types.push_back(curType);
5882 for(i++;i!=connI+nbOfCells && (INTERP_KERNEL::NormalizedCellType)conn[*i]==curType;i++);
5884 DataArrayInt *ret=DataArrayInt::New();
5885 ret->alloc(nbOfCells,1);
5886 int *retPtr=ret->getPointer();
5887 std::fill(retPtr,retPtr+nbOfCells,-1);
5889 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
5891 for(const int *i=connI;i!=connI+nbOfCells;i++)
5892 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
5893 retPtr[std::distance(connI,i)]=newCellId++;
5895 renumberCells(retPtr,false);
5900 * This method splits \a this into as mush as untructured meshes that consecutive set of same type cells.
5901 * So this method has typically a sense if MEDCouplingUMesh::checkConsecutiveCellTypes has a sense.
5902 * This method makes asumption that connectivity is correctly set before calling.
5904 std::vector<MEDCouplingUMesh *> MEDCouplingUMesh::splitByType() const
5906 checkConnectivityFullyDefined();
5907 const int *conn=_nodal_connec->begin();
5908 const int *connI=_nodal_connec_index->begin();
5909 int nbOfCells=getNumberOfCells();
5910 std::vector<MEDCouplingUMesh *> ret;
5911 for(const int *i=connI;i!=connI+nbOfCells;)
5913 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5914 int beginCellId=(int)std::distance(connI,i);
5915 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
5916 int endCellId=(int)std::distance(connI,i);
5917 int sz=endCellId-beginCellId;
5918 int *cells=new int[sz];
5919 for(int j=0;j<sz;j++)
5920 cells[j]=beginCellId+j;
5921 MEDCouplingUMesh *m=(MEDCouplingUMesh *)buildPartOfMySelf(cells,cells+sz,true);
5929 * This method performs the opposite operation than those in MEDCoupling1SGTUMesh::buildUnstructured.
5930 * If \a this is a single geometric type unstructured mesh, it will be converted into a more compact data structure,
5931 * MEDCoupling1GTUMesh instance. The returned instance will aggregate the same DataArrayDouble instance of coordinates than \a this.
5933 * \return a newly allocated instance, that the caller must manage.
5934 * \throw If \a this contains more than one geometric type.
5935 * \throw If the nodal connectivity of \a this is not fully defined.
5936 * \throw If the internal data is not coherent.
5938 MEDCoupling1GTUMesh *MEDCouplingUMesh::convertIntoSingleGeoTypeMesh() const
5940 checkConnectivityFullyDefined();
5941 if(_types.size()!=1)
5942 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : current mesh does not contain exactly one geometric type !");
5943 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
5944 MCAuto<MEDCoupling1GTUMesh> ret=MEDCoupling1GTUMesh::New(getName(),typ);
5945 ret->setCoords(getCoords());
5946 MEDCoupling1SGTUMesh *retC=dynamic_cast<MEDCoupling1SGTUMesh *>((MEDCoupling1GTUMesh*)ret);
5949 MCAuto<DataArrayInt> c=convertNodalConnectivityToStaticGeoTypeMesh();
5950 retC->setNodalConnectivity(c);
5954 MEDCoupling1DGTUMesh *retD=dynamic_cast<MEDCoupling1DGTUMesh *>((MEDCoupling1GTUMesh*)ret);
5956 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : Internal error !");
5957 DataArrayInt *c=0,*ci=0;
5958 convertNodalConnectivityToDynamicGeoTypeMesh(c,ci);
5959 MCAuto<DataArrayInt> cs(c),cis(ci);
5960 retD->setNodalConnectivity(cs,cis);
5965 DataArrayInt *MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh() const
5967 checkConnectivityFullyDefined();
5968 if(_types.size()!=1)
5969 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : current mesh does not contain exactly one geometric type !");
5970 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
5971 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
5974 std::ostringstream oss; oss << "MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : this contains a single geo type (" << cm.getRepr() << ") but ";
5975 oss << "this type is dynamic ! Only static geometric type is possible for that type ! call convertNodalConnectivityToDynamicGeoTypeMesh instead !";
5976 throw INTERP_KERNEL::Exception(oss.str());
5978 int nbCells=getNumberOfCells();
5980 int nbNodesPerCell=(int)cm.getNumberOfNodes();
5981 MCAuto<DataArrayInt> connOut=DataArrayInt::New(); connOut->alloc(nbCells*nbNodesPerCell,1);
5982 int *outPtr=connOut->getPointer();
5983 const int *conn=_nodal_connec->begin();
5984 const int *connI=_nodal_connec_index->begin();
5986 for(int i=0;i<nbCells;i++,connI++)
5988 if(conn[connI[0]]==typi && connI[1]-connI[0]==nbNodesPerCell)
5989 outPtr=std::copy(conn+connI[0]+1,conn+connI[1],outPtr);
5992 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 << ") !";
5993 throw INTERP_KERNEL::Exception(oss.str());
5996 return connOut.retn();
6000 * Convert the nodal connectivity of the mesh so that all the cells are of dynamic types (polygon or quadratic
6001 * polygon). This returns the corresponding new nodal connectivity in \ref numbering-indirect format.
6005 void MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh(DataArrayInt *&nodalConn, DataArrayInt *&nodalConnIndex) const
6007 static const char msg0[]="MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : nodal connectivity in this are invalid ! Call checkConsistency !";
6008 checkConnectivityFullyDefined();
6009 if(_types.size()!=1)
6010 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6011 int nbCells=getNumberOfCells(),lgth=_nodal_connec->getNumberOfTuples();
6013 throw INTERP_KERNEL::Exception(msg0);
6014 MCAuto<DataArrayInt> c(DataArrayInt::New()),ci(DataArrayInt::New());
6015 c->alloc(lgth-nbCells,1); ci->alloc(nbCells+1,1);
6016 int *cp(c->getPointer()),*cip(ci->getPointer());
6017 const int *incp(_nodal_connec->begin()),*incip(_nodal_connec_index->begin());
6019 for(int i=0;i<nbCells;i++,cip++,incip++)
6021 int strt(incip[0]+1),stop(incip[1]);//+1 to skip geo type
6022 int delta(stop-strt);
6025 if((strt>=0 && strt<lgth) && (stop>=0 && stop<=lgth))
6026 cp=std::copy(incp+strt,incp+stop,cp);
6028 throw INTERP_KERNEL::Exception(msg0);
6031 throw INTERP_KERNEL::Exception(msg0);
6032 cip[1]=cip[0]+delta;
6034 nodalConn=c.retn(); nodalConnIndex=ci.retn();
6038 * This method takes in input a vector of MEDCouplingUMesh instances lying on the same coordinates with same mesh dimensions.
6039 * Each mesh in \b ms must be sorted by type with the same order (typically using MEDCouplingUMesh::sortCellsInMEDFileFrmt).
6040 * This method is particulary useful for MED file interaction. It allows to aggregate several meshes and keeping the type sorting
6041 * and the track of the permutation by chunk of same geotype cells to retrieve it. The traditional formats old2new and new2old
6042 * are not used here to avoid the build of big permutation array.
6044 * \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
6045 * those specified in MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6046 * \param [out] szOfCellGrpOfSameType is a newly allocated DataArrayInt instance whose number of tuples is equal to the number of chunks of same geotype
6047 * in all meshes in \b ms. The accumulation of all values of this array is equal to the number of cells of returned mesh.
6048 * \param [out] idInMsOfCellGrpOfSameType is a newly allocated DataArrayInt instance having the same size than \b szOfCellGrpOfSameType. This
6049 * output array gives for each chunck of same type the corresponding mesh id in \b ms.
6050 * \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
6051 * is sorted by type following the geo cell types order of MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6053 MEDCouplingUMesh *MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& ms,
6054 DataArrayInt *&szOfCellGrpOfSameType,
6055 DataArrayInt *&idInMsOfCellGrpOfSameType)
6057 std::vector<const MEDCouplingUMesh *> ms2;
6058 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms.begin();it!=ms.end();it++)
6061 (*it)->checkConnectivityFullyDefined();
6065 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : input vector is empty !");
6066 const DataArrayDouble *refCoo=ms2[0]->getCoords();
6067 int meshDim=ms2[0]->getMeshDimension();
6068 std::vector<const MEDCouplingUMesh *> m1ssm;
6069 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmAuto;
6071 std::vector<const MEDCouplingUMesh *> m1ssmSingle;
6072 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmSingleAuto;
6074 MCAuto<DataArrayInt> ret1(DataArrayInt::New()),ret2(DataArrayInt::New());
6075 ret1->alloc(0,1); ret2->alloc(0,1);
6076 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms2.begin();it!=ms2.end();it++,rk++)
6078 if(meshDim!=(*it)->getMeshDimension())
6079 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshdims mismatch !");
6080 if(refCoo!=(*it)->getCoords())
6081 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshes are not shared by a single coordinates coords !");
6082 std::vector<MEDCouplingUMesh *> sp=(*it)->splitByType();
6083 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<const MEDCouplingUMesh *> >(m1ssm));
6084 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<MCAuto<MEDCouplingUMesh> > >(m1ssmAuto));
6085 for(std::vector<MEDCouplingUMesh *>::const_iterator it2=sp.begin();it2!=sp.end();it2++)
6087 MEDCouplingUMesh *singleCell=static_cast<MEDCouplingUMesh *>((*it2)->buildPartOfMySelf(&fake,&fake+1,true));
6088 m1ssmSingleAuto.push_back(singleCell);
6089 m1ssmSingle.push_back(singleCell);
6090 ret1->pushBackSilent((*it2)->getNumberOfCells()); ret2->pushBackSilent(rk);
6093 MCAuto<MEDCouplingUMesh> m1ssmSingle2=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmSingle);
6094 MCAuto<DataArrayInt> renum=m1ssmSingle2->sortCellsInMEDFileFrmt();
6095 std::vector<const MEDCouplingUMesh *> m1ssmfinal(m1ssm.size());
6096 for(std::size_t i=0;i<m1ssm.size();i++)
6097 m1ssmfinal[renum->getIJ(i,0)]=m1ssm[i];
6098 MCAuto<MEDCouplingUMesh> ret0=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmfinal);
6099 szOfCellGrpOfSameType=ret1->renumber(renum->begin());
6100 idInMsOfCellGrpOfSameType=ret2->renumber(renum->begin());
6105 * This method returns a newly created DataArrayInt instance.
6106 * This method retrieves cell ids in [ \a begin, \a end ) that have the type \a type.
6108 DataArrayInt *MEDCouplingUMesh::keepCellIdsByType(INTERP_KERNEL::NormalizedCellType type, const int *begin, const int *end) const
6110 checkFullyDefined();
6111 const int *conn=_nodal_connec->begin();
6112 const int *connIndex=_nodal_connec_index->begin();
6113 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(0,1);
6114 for(const int *w=begin;w!=end;w++)
6115 if((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]==type)
6116 ret->pushBackSilent(*w);
6121 * This method makes the assumption that da->getNumberOfTuples()<this->getNumberOfCells(). This method makes the assumption that ids contained in 'da'
6122 * are in [0:getNumberOfCells())
6124 DataArrayInt *MEDCouplingUMesh::convertCellArrayPerGeoType(const DataArrayInt *da) const
6126 checkFullyDefined();
6127 const int *conn=_nodal_connec->begin();
6128 const int *connI=_nodal_connec_index->begin();
6129 int nbOfCells=getNumberOfCells();
6130 std::set<INTERP_KERNEL::NormalizedCellType> types(getAllGeoTypes());
6131 int *tmp=new int[nbOfCells];
6132 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
6135 for(const int *i=connI;i!=connI+nbOfCells;i++)
6136 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
6137 tmp[std::distance(connI,i)]=j++;
6139 DataArrayInt *ret=DataArrayInt::New();
6140 ret->alloc(da->getNumberOfTuples(),da->getNumberOfComponents());
6141 ret->copyStringInfoFrom(*da);
6142 int *retPtr=ret->getPointer();
6143 const int *daPtr=da->begin();
6144 int nbOfElems=da->getNbOfElems();
6145 for(int k=0;k<nbOfElems;k++)
6146 retPtr[k]=tmp[daPtr[k]];
6152 * This method reduced number of cells of this by keeping cells whose type is different from 'type' and if type=='type'
6153 * This method \b works \b for mesh sorted by type.
6154 * cells whose ids is in 'idsPerGeoType' array.
6155 * This method conserves coords and name of mesh.
6157 MEDCouplingUMesh *MEDCouplingUMesh::keepSpecifiedCells(INTERP_KERNEL::NormalizedCellType type, const int *idsPerGeoTypeBg, const int *idsPerGeoTypeEnd) const
6159 std::vector<int> code=getDistributionOfTypes();
6160 std::size_t nOfTypesInThis=code.size()/3;
6161 int sz=0,szOfType=0;
6162 for(std::size_t i=0;i<nOfTypesInThis;i++)
6167 szOfType=code[3*i+1];
6169 for(const int *work=idsPerGeoTypeBg;work!=idsPerGeoTypeEnd;work++)
6170 if(*work<0 || *work>=szOfType)
6172 std::ostringstream oss; oss << "MEDCouplingUMesh::keepSpecifiedCells : Request on type " << type << " at place #" << std::distance(idsPerGeoTypeBg,work) << " value " << *work;
6173 oss << ". It should be in [0," << szOfType << ") !";
6174 throw INTERP_KERNEL::Exception(oss.str());
6176 MCAuto<DataArrayInt> idsTokeep=DataArrayInt::New(); idsTokeep->alloc(sz+(int)std::distance(idsPerGeoTypeBg,idsPerGeoTypeEnd),1);
6177 int *idsPtr=idsTokeep->getPointer();
6179 for(std::size_t i=0;i<nOfTypesInThis;i++)
6182 for(int j=0;j<code[3*i+1];j++)
6185 idsPtr=std::transform(idsPerGeoTypeBg,idsPerGeoTypeEnd,idsPtr,std::bind2nd(std::plus<int>(),offset));
6186 offset+=code[3*i+1];
6188 MCAuto<MEDCouplingUMesh> ret=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(idsTokeep->begin(),idsTokeep->end(),true));
6189 ret->copyTinyInfoFrom(this);
6194 * This method returns a vector of size 'this->getNumberOfCells()'.
6195 * This method retrieves for each cell in \a this if it is linear (false) or quadratic(true).
6197 std::vector<bool> MEDCouplingUMesh::getQuadraticStatus() const
6199 int ncell=getNumberOfCells();
6200 std::vector<bool> ret(ncell);
6201 const int *cI=getNodalConnectivityIndex()->begin();
6202 const int *c=getNodalConnectivity()->begin();
6203 for(int i=0;i<ncell;i++)
6205 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[i]];
6206 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6207 ret[i]=cm.isQuadratic();
6213 * Returns a newly created mesh (with ref count ==1) that contains merge of \a this and \a other.
6215 MEDCouplingMesh *MEDCouplingUMesh::mergeMyselfWith(const MEDCouplingMesh *other) const
6217 if(other->getType()!=UNSTRUCTURED)
6218 throw INTERP_KERNEL::Exception("Merge of umesh only available with umesh each other !");
6219 const MEDCouplingUMesh *otherC=static_cast<const MEDCouplingUMesh *>(other);
6220 return MergeUMeshes(this,otherC);
6224 * Returns a new DataArrayDouble holding barycenters of all cells. The barycenter is
6225 * computed by averaging coordinates of cell nodes, so this method is not a right
6226 * choice for degnerated meshes (not well oriented, cells with measure close to zero).
6227 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
6228 * this->getNumberOfCells() tuples per \a this->getSpaceDimension()
6229 * components. The caller is to delete this array using decrRef() as it is
6231 * \throw If the coordinates array is not set.
6232 * \throw If the nodal connectivity of cells is not defined.
6233 * \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
6235 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMass() const
6237 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6238 int spaceDim=getSpaceDimension();
6239 int nbOfCells=getNumberOfCells();
6240 ret->alloc(nbOfCells,spaceDim);
6241 ret->copyStringInfoFrom(*getCoords());
6242 double *ptToFill=ret->getPointer();
6243 const int *nodal=_nodal_connec->begin();
6244 const int *nodalI=_nodal_connec_index->begin();
6245 const double *coor=_coords->begin();
6246 for(int i=0;i<nbOfCells;i++)
6248 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6249 INTERP_KERNEL::computeBarycenter2<int,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[i]+1,nodalI[i+1]-nodalI[i]-1,coor,spaceDim,ptToFill);
6256 * This method computes for each cell in \a this, the location of the iso barycenter of nodes constituting
6257 * the cell. Contrary to badly named MEDCouplingUMesh::computeCellCenterOfMass method that returns the center of inertia of the
6259 * \return a newly allocated DataArrayDouble instance that the caller has to deal with. The returned
6260 * DataArrayDouble instance will have \c this->getNumberOfCells() tuples and \c this->getSpaceDimension() components.
6262 * \sa MEDCouplingUMesh::computeCellCenterOfMass
6263 * \throw If \a this is not fully defined (coordinates and connectivity)
6264 * \throw If there is presence in nodal connectivity in \a this of node ids not in [0, \c this->getNumberOfNodes() )
6266 DataArrayDouble *MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell() const
6268 checkFullyDefined();
6269 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6270 int spaceDim=getSpaceDimension();
6271 int nbOfCells=getNumberOfCells();
6272 int nbOfNodes=getNumberOfNodes();
6273 ret->alloc(nbOfCells,spaceDim);
6274 double *ptToFill=ret->getPointer();
6275 const int *nodal=_nodal_connec->begin();
6276 const int *nodalI=_nodal_connec_index->begin();
6277 const double *coor=_coords->begin();
6278 for(int i=0;i<nbOfCells;i++,ptToFill+=spaceDim)
6280 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6281 std::fill(ptToFill,ptToFill+spaceDim,0.);
6282 if(type!=INTERP_KERNEL::NORM_POLYHED)
6284 for(const int *conn=nodal+nodalI[i]+1;conn!=nodal+nodalI[i+1];conn++)
6286 if(*conn>=0 && *conn<nbOfNodes)
6287 std::transform(coor+spaceDim*conn[0],coor+spaceDim*(conn[0]+1),ptToFill,ptToFill,std::plus<double>());
6290 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of nodeId #" << *conn << " should be in [0," << nbOfNodes << ") !";
6291 throw INTERP_KERNEL::Exception(oss.str());
6294 int nbOfNodesInCell=nodalI[i+1]-nodalI[i]-1;
6295 if(nbOfNodesInCell>0)
6296 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies<double>(),1./(double)nbOfNodesInCell));
6299 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of cell with no nodes !";
6300 throw INTERP_KERNEL::Exception(oss.str());
6305 std::set<int> s(nodal+nodalI[i]+1,nodal+nodalI[i+1]);
6307 for(std::set<int>::const_iterator it=s.begin();it!=s.end();it++)
6309 if(*it>=0 && *it<nbOfNodes)
6310 std::transform(coor+spaceDim*(*it),coor+spaceDim*((*it)+1),ptToFill,ptToFill,std::plus<double>());
6313 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell polyhedron cell #" << i << " presence of nodeId #" << *it << " should be in [0," << nbOfNodes << ") !";
6314 throw INTERP_KERNEL::Exception(oss.str());
6318 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies<double>(),1./(double)s.size()));
6321 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on polyhedron cell #" << i << " there are no nodes !";
6322 throw INTERP_KERNEL::Exception(oss.str());
6330 * Returns a new DataArrayDouble holding barycenters of specified cells. The
6331 * barycenter is computed by averaging coordinates of cell nodes. The cells to treat
6332 * are specified via an array of cell ids.
6333 * \warning Validity of the specified cell ids is not checked!
6334 * Valid range is [ 0, \a this->getNumberOfCells() ).
6335 * \param [in] begin - an array of cell ids of interest.
6336 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
6337 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size ( \a
6338 * end - \a begin ) tuples per \a this->getSpaceDimension() components. The
6339 * caller is to delete this array using decrRef() as it is no more needed.
6340 * \throw If the coordinates array is not set.
6341 * \throw If the nodal connectivity of cells is not defined.
6343 * \if ENABLE_EXAMPLES
6344 * \ref cpp_mcumesh_getPartBarycenterAndOwner "Here is a C++ example".<br>
6345 * \ref py_mcumesh_getPartBarycenterAndOwner "Here is a Python example".
6348 DataArrayDouble *MEDCouplingUMesh::getPartBarycenterAndOwner(const int *begin, const int *end) const
6350 DataArrayDouble *ret=DataArrayDouble::New();
6351 int spaceDim=getSpaceDimension();
6352 int nbOfTuple=(int)std::distance(begin,end);
6353 ret->alloc(nbOfTuple,spaceDim);
6354 double *ptToFill=ret->getPointer();
6355 double *tmp=new double[spaceDim];
6356 const int *nodal=_nodal_connec->begin();
6357 const int *nodalI=_nodal_connec_index->begin();
6358 const double *coor=_coords->begin();
6359 for(const int *w=begin;w!=end;w++)
6361 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[*w]];
6362 INTERP_KERNEL::computeBarycenter2<int,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[*w]+1,nodalI[*w+1]-nodalI[*w]-1,coor,spaceDim,ptToFill);
6370 * 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".
6371 * So the returned instance will have 4 components and \c this->getNumberOfCells() tuples.
6372 * So this method expects that \a this has a spaceDimension equal to 3 and meshDimension equal to 2.
6373 * The computation of the plane equation is done using each time the 3 first nodes of 2D cells.
6374 * This method is useful to detect 2D cells in 3D space that are not coplanar.
6376 * \return DataArrayDouble * - a new instance of DataArrayDouble having 4 components and a number of tuples equal to number of cells in \a this.
6377 * \throw If spaceDim!=3 or meshDim!=2.
6378 * \throw If connectivity of \a this is invalid.
6379 * \throw If connectivity of a cell in \a this points to an invalid node.
6381 DataArrayDouble *MEDCouplingUMesh::computePlaneEquationOf3DFaces() const
6383 MCAuto<DataArrayDouble> ret(DataArrayDouble::New());
6384 int nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
6385 if(getSpaceDimension()!=3 || getMeshDimension()!=2)
6386 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computePlaneEquationOf3DFaces : This method must be applied on a mesh having meshDimension equal 2 and a spaceDimension equal to 3 !");
6387 ret->alloc(nbOfCells,4);
6388 double *retPtr(ret->getPointer());
6389 const int *nodal(_nodal_connec->begin()),*nodalI(_nodal_connec_index->begin());
6390 const double *coor(_coords->begin());
6391 for(int i=0;i<nbOfCells;i++,nodalI++,retPtr+=4)
6393 double matrix[16]={0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,0},matrix2[16];
6394 if(nodalI[1]-nodalI[0]>=4)
6396 double aa[3]={coor[nodal[nodalI[0]+1+1]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6397 coor[nodal[nodalI[0]+1+1]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6398 coor[nodal[nodalI[0]+1+1]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]}
6399 ,bb[3]={coor[nodal[nodalI[0]+1+2]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6400 coor[nodal[nodalI[0]+1+2]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6401 coor[nodal[nodalI[0]+1+2]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]};
6402 double cc[3]={aa[1]*bb[2]-aa[2]*bb[1],aa[2]*bb[0]-aa[0]*bb[2],aa[0]*bb[1]-aa[1]*bb[0]};
6403 for(int j=0;j<3;j++)
6405 int nodeId(nodal[nodalI[0]+1+j]);
6406 if(nodeId>=0 && nodeId<nbOfNodes)
6407 std::copy(coor+nodeId*3,coor+(nodeId+1)*3,matrix+4*j);
6410 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! This cell points to an invalid nodeId : " << nodeId << " !";
6411 throw INTERP_KERNEL::Exception(oss.str());
6414 if(sqrt(cc[0]*cc[0]+cc[1]*cc[1]+cc[2]*cc[2])>1e-7)
6416 INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6417 retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6421 if(nodalI[1]-nodalI[0]==4)
6423 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : cell" << i << " : Presence of The 3 colinear points !";
6424 throw INTERP_KERNEL::Exception(oss.str());
6427 double dd[3]={0.,0.,0.};
6428 for(int offset=nodalI[0]+1;offset<nodalI[1];offset++)
6429 std::transform(coor+3*nodal[offset],coor+3*(nodal[offset]+1),dd,dd,std::plus<double>());
6430 int nbOfNodesInCell(nodalI[1]-nodalI[0]-1);
6431 std::transform(dd,dd+3,dd,std::bind2nd(std::multiplies<double>(),1./(double)nbOfNodesInCell));
6432 std::copy(dd,dd+3,matrix+4*2);
6433 INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6434 retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6439 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! Must be constitued by more than 3 nodes !";
6440 throw INTERP_KERNEL::Exception(oss.str());
6447 * This method expects as input a DataArrayDouble non nul instance 'da' that should be allocated. If not an exception is thrown.
6450 MEDCouplingUMesh *MEDCouplingUMesh::Build0DMeshFromCoords(DataArrayDouble *da)
6453 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build0DMeshFromCoords : instance of DataArrayDouble must be not null !");
6454 da->checkAllocated();
6455 std::string name(da->getName());
6456 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New(name,0));
6458 ret->setName("Mesh");
6460 int nbOfTuples(da->getNumberOfTuples());
6461 MCAuto<DataArrayInt> c(DataArrayInt::New()),cI(DataArrayInt::New());
6462 c->alloc(2*nbOfTuples,1);
6463 cI->alloc(nbOfTuples+1,1);
6464 int *cp(c->getPointer()),*cip(cI->getPointer());
6466 for(int i=0;i<nbOfTuples;i++)
6468 *cp++=INTERP_KERNEL::NORM_POINT1;
6472 ret->setConnectivity(c,cI,true);
6476 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::Build1DMeshFromCoords(DataArrayDouble *da)
6479 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build01MeshFromCoords : instance of DataArrayDouble must be not null !");
6480 da->checkAllocated();
6481 std::string name(da->getName());
6482 MCAuto<MEDCouplingUMesh> ret;
6484 MCAuto<MEDCouplingCMesh> tmp(MEDCouplingCMesh::New());
6485 MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
6486 arr->alloc(da->getNumberOfTuples());
6487 tmp->setCoordsAt(0,arr);
6488 ret=tmp->buildUnstructured();
6492 ret->setName("Mesh");
6499 * Creates a new MEDCouplingUMesh by concatenating two given meshes of the same dimension.
6500 * Cells and nodes of
6501 * the first mesh precede cells and nodes of the second mesh within the result mesh.
6502 * \param [in] mesh1 - the first mesh.
6503 * \param [in] mesh2 - the second mesh.
6504 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6505 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6506 * is no more needed.
6507 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
6508 * \throw If the coordinates array is not set in none of the meshes.
6509 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
6510 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
6512 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
6514 std::vector<const MEDCouplingUMesh *> tmp(2);
6515 tmp[0]=const_cast<MEDCouplingUMesh *>(mesh1); tmp[1]=const_cast<MEDCouplingUMesh *>(mesh2);
6516 return MergeUMeshes(tmp);
6520 * Creates a new MEDCouplingUMesh by concatenating all given meshes of the same dimension.
6521 * Cells and nodes of
6522 * the *i*-th mesh precede cells and nodes of the (*i*+1)-th mesh within the result mesh.
6523 * \param [in] a - a vector of meshes (MEDCouplingUMesh) to concatenate.
6524 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6525 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6526 * is no more needed.
6527 * \throw If \a a.size() == 0.
6528 * \throw If \a a[ *i* ] == NULL.
6529 * \throw If the coordinates array is not set in none of the meshes.
6530 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
6531 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
6533 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const std::vector<const MEDCouplingUMesh *>& a)
6535 std::size_t sz=a.size();
6537 return MergeUMeshesLL(a);
6538 for(std::size_t ii=0;ii<sz;ii++)
6541 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshes : item #" << ii << " in input array of size "<< sz << " is empty !";
6542 throw INTERP_KERNEL::Exception(oss.str());
6544 std::vector< MCAuto<MEDCouplingUMesh> > bb(sz);
6545 std::vector< const MEDCouplingUMesh * > aa(sz);
6547 for(std::size_t i=0;i<sz && spaceDim==-3;i++)
6549 const MEDCouplingUMesh *cur=a[i];
6550 const DataArrayDouble *coo=cur->getCoords();
6552 spaceDim=coo->getNumberOfComponents();
6555 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : no spaceDim specified ! unable to perform merge !");
6556 for(std::size_t i=0;i<sz;i++)
6558 bb[i]=a[i]->buildSetInstanceFromThis(spaceDim);
6561 return MergeUMeshesLL(aa);
6565 * Creates a new MEDCouplingUMesh by concatenating cells of two given meshes of same
6566 * dimension and sharing the node coordinates array.
6567 * All cells of the first mesh precede all cells of the second mesh
6568 * within the result mesh.
6569 * \param [in] mesh1 - the first mesh.
6570 * \param [in] mesh2 - the second mesh.
6571 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6572 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6573 * is no more needed.
6574 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
6575 * \throw If the meshes do not share the node coordinates array.
6576 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
6577 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
6579 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
6581 std::vector<const MEDCouplingUMesh *> tmp(2);
6582 tmp[0]=mesh1; tmp[1]=mesh2;
6583 return MergeUMeshesOnSameCoords(tmp);
6587 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
6588 * dimension and sharing the node coordinates array.
6589 * All cells of the *i*-th mesh precede all cells of the
6590 * (*i*+1)-th mesh within the result mesh.
6591 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
6592 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6593 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6594 * is no more needed.
6595 * \throw If \a a.size() == 0.
6596 * \throw If \a a[ *i* ] == NULL.
6597 * \throw If the meshes do not share the node coordinates array.
6598 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
6599 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
6601 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes)
6604 throw INTERP_KERNEL::Exception("meshes input parameter is expected to be non empty.");
6605 for(std::size_t ii=0;ii<meshes.size();ii++)
6608 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshesOnSameCoords : item #" << ii << " in input array of size "<< meshes.size() << " is empty !";
6609 throw INTERP_KERNEL::Exception(oss.str());
6611 const DataArrayDouble *coords=meshes.front()->getCoords();
6612 int meshDim=meshes.front()->getMeshDimension();
6613 std::vector<const MEDCouplingUMesh *>::const_iterator iter=meshes.begin();
6615 int meshIndexLgth=0;
6616 for(;iter!=meshes.end();iter++)
6618 if(coords!=(*iter)->getCoords())
6619 throw INTERP_KERNEL::Exception("meshes does not share the same coords ! Try using tryToShareSameCoords method !");
6620 if(meshDim!=(*iter)->getMeshDimension())
6621 throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, FuseUMeshesOnSameCoords impossible !");
6622 meshLgth+=(*iter)->getNodalConnectivityArrayLen();
6623 meshIndexLgth+=(*iter)->getNumberOfCells();
6625 MCAuto<DataArrayInt> nodal=DataArrayInt::New();
6626 nodal->alloc(meshLgth,1);
6627 int *nodalPtr=nodal->getPointer();
6628 MCAuto<DataArrayInt> nodalIndex=DataArrayInt::New();
6629 nodalIndex->alloc(meshIndexLgth+1,1);
6630 int *nodalIndexPtr=nodalIndex->getPointer();
6632 for(iter=meshes.begin();iter!=meshes.end();iter++)
6634 const int *nod=(*iter)->getNodalConnectivity()->begin();
6635 const int *index=(*iter)->getNodalConnectivityIndex()->begin();
6636 int nbOfCells=(*iter)->getNumberOfCells();
6637 int meshLgth2=(*iter)->getNodalConnectivityArrayLen();
6638 nodalPtr=std::copy(nod,nod+meshLgth2,nodalPtr);
6639 if(iter!=meshes.begin())
6640 nodalIndexPtr=std::transform(index+1,index+nbOfCells+1,nodalIndexPtr,std::bind2nd(std::plus<int>(),offset));
6642 nodalIndexPtr=std::copy(index,index+nbOfCells+1,nodalIndexPtr);
6645 MEDCouplingUMesh *ret=MEDCouplingUMesh::New();
6646 ret->setName("merge");
6647 ret->setMeshDimension(meshDim);
6648 ret->setConnectivity(nodal,nodalIndex,true);
6649 ret->setCoords(coords);
6654 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
6655 * dimension and sharing the node coordinates array. Cells of the *i*-th mesh precede
6656 * cells of the (*i*+1)-th mesh within the result mesh. Duplicates of cells are
6657 * removed from \a this mesh and arrays mapping between new and old cell ids in "Old to
6658 * New" mode are returned for each input mesh.
6659 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
6660 * \param [in] compType - specifies a cell comparison technique. For meaning of its
6661 * valid values [0,1,2], see zipConnectivityTraducer().
6662 * \param [in,out] corr - an array of DataArrayInt, of the same size as \a
6663 * meshes. The *i*-th array describes cell ids mapping for \a meshes[ *i* ]
6664 * mesh. The caller is to delete each of the arrays using decrRef() as it is
6666 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6667 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6668 * is no more needed.
6669 * \throw If \a meshes.size() == 0.
6670 * \throw If \a meshes[ *i* ] == NULL.
6671 * \throw If the meshes do not share the node coordinates array.
6672 * \throw If \a meshes[ *i* ]->getMeshDimension() < 0.
6673 * \throw If the \a meshes are of different dimension (getMeshDimension()).
6674 * \throw If the nodal connectivity of cells of any of \a meshes is not defined.
6675 * \throw If the nodal connectivity any of \a meshes includes an invalid id.
6677 MEDCouplingUMesh *MEDCouplingUMesh::FuseUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes, int compType, std::vector<DataArrayInt *>& corr)
6679 //All checks are delegated to MergeUMeshesOnSameCoords
6680 MCAuto<MEDCouplingUMesh> ret=MergeUMeshesOnSameCoords(meshes);
6681 MCAuto<DataArrayInt> o2n=ret->zipConnectivityTraducer(compType);
6682 corr.resize(meshes.size());
6683 std::size_t nbOfMeshes=meshes.size();
6685 const int *o2nPtr=o2n->begin();
6686 for(std::size_t i=0;i<nbOfMeshes;i++)
6688 DataArrayInt *tmp=DataArrayInt::New();
6689 int curNbOfCells=meshes[i]->getNumberOfCells();
6690 tmp->alloc(curNbOfCells,1);
6691 std::copy(o2nPtr+offset,o2nPtr+offset+curNbOfCells,tmp->getPointer());
6692 offset+=curNbOfCells;
6693 tmp->setName(meshes[i]->getName());
6700 * Makes all given meshes share the nodal connectivity array. The common connectivity
6701 * array is created by concatenating the connectivity arrays of all given meshes. All
6702 * the given meshes must be of the same space dimension but dimension of cells **can
6703 * differ**. This method is particulary useful in MEDLoader context to build a \ref
6704 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
6705 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
6706 * \param [in,out] meshes - a vector of meshes to update.
6707 * \throw If any of \a meshes is NULL.
6708 * \throw If the coordinates array is not set in any of \a meshes.
6709 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
6710 * \throw If \a meshes are of different space dimension.
6712 void MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords(const std::vector<MEDCouplingUMesh *>& meshes)
6714 std::size_t sz=meshes.size();
6717 std::vector< const DataArrayDouble * > coords(meshes.size());
6718 std::vector< const DataArrayDouble * >::iterator it2=coords.begin();
6719 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++,it2++)
6723 (*it)->checkConnectivityFullyDefined();
6724 const DataArrayDouble *coo=(*it)->getCoords();
6729 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
6730 oss << " has no coordinate array defined !";
6731 throw INTERP_KERNEL::Exception(oss.str());
6736 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
6737 oss << " is null !";
6738 throw INTERP_KERNEL::Exception(oss.str());
6741 MCAuto<DataArrayDouble> res=DataArrayDouble::Aggregate(coords);
6742 std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();
6743 int offset=(*it)->getNumberOfNodes();
6744 (*it++)->setCoords(res);
6745 for(;it!=meshes.end();it++)
6747 int oldNumberOfNodes=(*it)->getNumberOfNodes();
6748 (*it)->setCoords(res);
6749 (*it)->shiftNodeNumbersInConn(offset);
6750 offset+=oldNumberOfNodes;
6755 * Merges nodes coincident with a given precision within all given meshes that share
6756 * the nodal connectivity array. The given meshes **can be of different** mesh
6757 * dimension. This method is particulary useful in MEDLoader context to build a \ref
6758 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
6759 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
6760 * \param [in,out] meshes - a vector of meshes to update.
6761 * \param [in] eps - the precision used to detect coincident nodes (infinite norm).
6762 * \throw If any of \a meshes is NULL.
6763 * \throw If the \a meshes do not share the same node coordinates array.
6764 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
6766 void MEDCouplingUMesh::MergeNodesOnUMeshesSharingSameCoords(const std::vector<MEDCouplingUMesh *>& meshes, double eps)
6770 std::set<const DataArrayDouble *> s;
6771 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
6774 s.insert((*it)->getCoords());
6777 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 !";
6778 throw INTERP_KERNEL::Exception(oss.str());
6783 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 !";
6784 throw INTERP_KERNEL::Exception(oss.str());
6786 const DataArrayDouble *coo=*(s.begin());
6790 DataArrayInt *comm,*commI;
6791 coo->findCommonTuples(eps,-1,comm,commI);
6792 MCAuto<DataArrayInt> tmp1(comm),tmp2(commI);
6793 int oldNbOfNodes=coo->getNumberOfTuples();
6795 MCAuto<DataArrayInt> o2n=DataArrayInt::ConvertIndexArrayToO2N(oldNbOfNodes,comm->begin(),commI->begin(),commI->end(),newNbOfNodes);
6796 if(oldNbOfNodes==newNbOfNodes)
6798 MCAuto<DataArrayDouble> newCoords=coo->renumberAndReduce(o2n->begin(),newNbOfNodes);
6799 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
6801 (*it)->renumberNodesInConn(o2n->begin());
6802 (*it)->setCoords(newCoords);
6808 * This static operates only for coords in 3D. The polygon is specfied by its connectivity nodes in [ \a begin , \a end ).
6810 bool MEDCouplingUMesh::IsPolygonWellOriented(bool isQuadratic, const double *vec, const int *begin, const int *end, const double *coords)
6813 double v[3]={0.,0.,0.};
6814 std::size_t sz=std::distance(begin,end);
6819 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];
6820 v[1]+=coords[3*begin[i]+2]*coords[3*begin[(i+1)%sz]]-coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+2];
6821 v[2]+=coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+1]-coords[3*begin[i]+1]*coords[3*begin[(i+1)%sz]];
6823 double ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
6825 // Try using quadratic points if standard points are degenerated (for example a QPOLYG with two
6826 // SEG3 forming a circle):
6827 if (fabs(ret) < INTERP_KERNEL::DEFAULT_ABS_TOL && isQuadratic)
6829 v[0] = 0.0; v[1] = 0.0; v[2] = 0.0;
6830 for(std::size_t j=0;j<sz;j++)
6832 if (j%2) // current point i is quadratic, next point i+1 is standard
6835 ip1 = (j+1)%sz; // ip1 = "i+1"
6837 else // current point i is standard, next point i+1 is quadratic
6842 v[0]+=coords[3*begin[i]+1]*coords[3*begin[ip1]+2]-coords[3*begin[i]+2]*coords[3*begin[ip1]+1];
6843 v[1]+=coords[3*begin[i]+2]*coords[3*begin[ip1]]-coords[3*begin[i]]*coords[3*begin[ip1]+2];
6844 v[2]+=coords[3*begin[i]]*coords[3*begin[ip1]+1]-coords[3*begin[i]+1]*coords[3*begin[ip1]];
6846 ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
6852 * The polyhedron is specfied by its connectivity nodes in [ \a begin , \a end ).
6854 bool MEDCouplingUMesh::IsPolyhedronWellOriented(const int *begin, const int *end, const double *coords)
6856 std::vector<std::pair<int,int> > edges;
6857 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
6858 const int *bgFace=begin;
6859 for(std::size_t i=0;i<nbOfFaces;i++)
6861 const int *endFace=std::find(bgFace+1,end,-1);
6862 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
6863 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
6865 std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
6866 if(std::find(edges.begin(),edges.end(),p1)!=edges.end())
6868 edges.push_back(p1);
6872 return INTERP_KERNEL::calculateVolumeForPolyh2<int,INTERP_KERNEL::ALL_C_MODE>(begin,(int)std::distance(begin,end),coords)>-EPS_FOR_POLYH_ORIENTATION;
6876 * The 3D extruded static cell (PENTA6,HEXA8,HEXAGP12...) its connectivity nodes in [ \a begin , \a end ).
6878 bool MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented(const int *begin, const int *end, const double *coords)
6880 double vec0[3],vec1[3];
6881 std::size_t sz=std::distance(begin,end);
6883 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented : the length of nodal connectivity of extruded cell is not even !");
6884 int nbOfNodes=(int)sz/2;
6885 INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(begin,nbOfNodes,coords,vec0);
6886 const double *pt0=coords+3*begin[0];
6887 const double *pt1=coords+3*begin[nbOfNodes];
6888 vec1[0]=pt1[0]-pt0[0]; vec1[1]=pt1[1]-pt0[1]; vec1[2]=pt1[2]-pt0[2];
6889 return (vec0[0]*vec1[0]+vec0[1]*vec1[1]+vec0[2]*vec1[2])<0.;
6892 void MEDCouplingUMesh::CorrectExtrudedStaticCell(int *begin, int *end)
6894 std::size_t sz=std::distance(begin,end);
6895 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz];
6896 std::size_t nbOfNodes(sz/2);
6897 std::copy(begin,end,(int *)tmp);
6898 for(std::size_t j=1;j<nbOfNodes;j++)
6900 begin[j]=tmp[nbOfNodes-j];
6901 begin[j+nbOfNodes]=tmp[nbOfNodes+nbOfNodes-j];
6905 bool MEDCouplingUMesh::IsTetra4WellOriented(const int *begin, const int *end, const double *coords)
6907 std::size_t sz=std::distance(begin,end);
6909 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsTetra4WellOriented : Tetra4 cell with not 4 nodes ! Call checkConsistency !");
6910 double vec0[3],vec1[3];
6911 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[1],*pt2=coords+3*begin[2],*pt3=coords+3*begin[3];
6912 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];
6913 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;
6916 bool MEDCouplingUMesh::IsPyra5WellOriented(const int *begin, const int *end, const double *coords)
6918 std::size_t sz=std::distance(begin,end);
6920 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsPyra5WellOriented : Pyra5 cell with not 5 nodes ! Call checkConsistency !");
6922 INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(begin,4,coords,vec0);
6923 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[4];
6924 return (vec0[0]*(pt1[0]-pt0[0])+vec0[1]*(pt1[1]-pt0[1])+vec0[2]*(pt1[2]-pt0[2]))<0.;
6928 * 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 )
6929 * 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
6932 * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not.
6933 * \param [in] coords the coordinates with nb of components exactly equal to 3
6934 * \param [in] begin begin of the nodal connectivity (geometric type included) of a single polyhedron cell
6935 * \param [in] end end of nodal connectivity of a single polyhedron cell (excluded)
6936 * \param [out] res the result is put at the end of the vector without any alteration of the data.
6938 void MEDCouplingUMesh::SimplifyPolyhedronCell(double eps, const DataArrayDouble *coords, const int *begin, const int *end, DataArrayInt *res)
6940 int nbFaces=std::count(begin+1,end,-1)+1;
6941 MCAuto<DataArrayDouble> v=DataArrayDouble::New(); v->alloc(nbFaces,3);
6942 double *vPtr=v->getPointer();
6943 MCAuto<DataArrayDouble> p=DataArrayDouble::New(); p->alloc(nbFaces,1);
6944 double *pPtr=p->getPointer();
6945 const int *stFaceConn=begin+1;
6946 for(int i=0;i<nbFaces;i++,vPtr+=3,pPtr++)
6948 const int *endFaceConn=std::find(stFaceConn,end,-1);
6949 ComputeVecAndPtOfFace(eps,coords->begin(),stFaceConn,endFaceConn,vPtr,pPtr);
6950 stFaceConn=endFaceConn+1;
6952 pPtr=p->getPointer(); vPtr=v->getPointer();
6953 DataArrayInt *comm1=0,*commI1=0;
6954 v->findCommonTuples(eps,-1,comm1,commI1);
6955 MCAuto<DataArrayInt> comm1Auto(comm1),commI1Auto(commI1);
6956 const int *comm1Ptr=comm1->begin();
6957 const int *commI1Ptr=commI1->begin();
6958 int nbOfGrps1=commI1Auto->getNumberOfTuples()-1;
6959 res->pushBackSilent((int)INTERP_KERNEL::NORM_POLYHED);
6961 MCAuto<MEDCouplingUMesh> mm=MEDCouplingUMesh::New("",3);
6962 mm->setCoords(const_cast<DataArrayDouble *>(coords)); mm->allocateCells(1); mm->insertNextCell(INTERP_KERNEL::NORM_POLYHED,(int)std::distance(begin+1,end),begin+1);
6963 mm->finishInsertingCells();
6965 for(int i=0;i<nbOfGrps1;i++)
6967 int vecId=comm1Ptr[commI1Ptr[i]];
6968 MCAuto<DataArrayDouble> tmpgrp2=p->selectByTupleId(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
6969 DataArrayInt *comm2=0,*commI2=0;
6970 tmpgrp2->findCommonTuples(eps,-1,comm2,commI2);
6971 MCAuto<DataArrayInt> comm2Auto(comm2),commI2Auto(commI2);
6972 const int *comm2Ptr=comm2->begin();
6973 const int *commI2Ptr=commI2->begin();
6974 int nbOfGrps2=commI2Auto->getNumberOfTuples()-1;
6975 for(int j=0;j<nbOfGrps2;j++)
6977 if(commI2Ptr[j+1]-commI2Ptr[j]<=1)
6979 res->insertAtTheEnd(begin,end);
6980 res->pushBackSilent(-1);
6984 int pointId=comm1Ptr[commI1Ptr[i]+comm2Ptr[commI2Ptr[j]]];
6985 MCAuto<DataArrayInt> ids2=comm2->selectByTupleIdSafeSlice(commI2Ptr[j],commI2Ptr[j+1],1);
6986 ids2->transformWithIndArr(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
6987 DataArrayInt *tmp0=DataArrayInt::New(),*tmp1=DataArrayInt::New(),*tmp2=DataArrayInt::New(),*tmp3=DataArrayInt::New();
6988 MCAuto<MEDCouplingUMesh> mm2=mm->buildDescendingConnectivity(tmp0,tmp1,tmp2,tmp3); tmp0->decrRef(); tmp1->decrRef(); tmp2->decrRef(); tmp3->decrRef();
6989 MCAuto<MEDCouplingUMesh> mm3=static_cast<MEDCouplingUMesh *>(mm2->buildPartOfMySelf(ids2->begin(),ids2->end(),true));
6990 MCAuto<DataArrayInt> idsNodeTmp=mm3->zipCoordsTraducer();
6991 MCAuto<DataArrayInt> idsNode=idsNodeTmp->invertArrayO2N2N2O(mm3->getNumberOfNodes());
6992 const int *idsNodePtr=idsNode->begin();
6993 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];
6994 double vec[3]; vec[0]=vPtr[3*vecId+1]; vec[1]=-vPtr[3*vecId]; vec[2]=0.;
6995 double norm=vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2];
6996 if(std::abs(norm)>eps)
6998 double angle=INTERP_KERNEL::EdgeArcCircle::SafeAsin(norm);
6999 mm3->rotate(center,vec,angle);
7001 mm3->changeSpaceDimension(2);
7002 MCAuto<MEDCouplingUMesh> mm4=mm3->buildSpreadZonesWithPoly();
7003 const int *conn4=mm4->getNodalConnectivity()->begin();
7004 const int *connI4=mm4->getNodalConnectivityIndex()->begin();
7005 int nbOfCells=mm4->getNumberOfCells();
7006 for(int k=0;k<nbOfCells;k++)
7009 for(const int *work=conn4+connI4[k]+1;work!=conn4+connI4[k+1];work++,l++)
7010 res->pushBackSilent(idsNodePtr[*work]);
7011 res->pushBackSilent(-1);
7016 res->popBackSilent();
7020 * 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
7021 * through origin. The plane is defined by its nodal connectivity [ \b begin, \b end ).
7023 * \param [in] eps below that value the dot product of 2 vectors is considered as colinears
7024 * \param [in] coords coordinates expected to have 3 components.
7025 * \param [in] begin start of the nodal connectivity of the face.
7026 * \param [in] end end of the nodal connectivity (excluded) of the face.
7027 * \param [out] v the normalized vector of size 3
7028 * \param [out] p the pos of plane
7030 void MEDCouplingUMesh::ComputeVecAndPtOfFace(double eps, const double *coords, const int *begin, const int *end, double *v, double *p)
7032 std::size_t nbPoints=std::distance(begin,end);
7034 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeVecAndPtOfFace : < of 3 points in face ! not able to find a plane on that face !");
7035 double vec[3]={0.,0.,0.};
7037 bool refFound=false;
7038 for(;j<nbPoints-1 && !refFound;j++)
7040 vec[0]=coords[3*begin[j+1]]-coords[3*begin[j]];
7041 vec[1]=coords[3*begin[j+1]+1]-coords[3*begin[j]+1];
7042 vec[2]=coords[3*begin[j+1]+2]-coords[3*begin[j]+2];
7043 double norm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
7047 vec[0]/=norm; vec[1]/=norm; vec[2]/=norm;
7050 for(std::size_t i=j;i<nbPoints-1;i++)
7053 curVec[0]=coords[3*begin[i+1]]-coords[3*begin[i]];
7054 curVec[1]=coords[3*begin[i+1]+1]-coords[3*begin[i]+1];
7055 curVec[2]=coords[3*begin[i+1]+2]-coords[3*begin[i]+2];
7056 double norm=sqrt(curVec[0]*curVec[0]+curVec[1]*curVec[1]+curVec[2]*curVec[2]);
7059 curVec[0]/=norm; curVec[1]/=norm; curVec[2]/=norm;
7060 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];
7061 norm=sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
7064 v[0]/=norm; v[1]/=norm; v[2]/=norm;
7065 *p=v[0]*coords[3*begin[i]]+v[1]*coords[3*begin[i]+1]+v[2]*coords[3*begin[i]+2];
7069 throw INTERP_KERNEL::Exception("Not able to find a normal vector of that 3D face !");
7073 * This method tries to obtain a well oriented polyhedron.
7074 * If the algorithm fails, an exception will be thrown.
7076 void MEDCouplingUMesh::TryToCorrectPolyhedronOrientation(int *begin, int *end, const double *coords)
7078 std::list< std::pair<int,int> > edgesOK,edgesFinished;
7079 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
7080 std::vector<bool> isPerm(nbOfFaces,false);//field on faces False: I don't know, True : oriented
7082 int *bgFace=begin,*endFace=std::find(begin+1,end,-1);
7083 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
7084 for(std::size_t l=0;l<nbOfEdgesInFace;l++) { std::pair<int,int> p1(bgFace[l],bgFace[(l+1)%nbOfEdgesInFace]); edgesOK.push_back(p1); }
7086 while(std::find(isPerm.begin(),isPerm.end(),false)!=isPerm.end())
7089 std::size_t smthChanged=0;
7090 for(std::size_t i=0;i<nbOfFaces;i++)
7092 endFace=std::find(bgFace+1,end,-1);
7093 nbOfEdgesInFace=std::distance(bgFace,endFace);
7097 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7099 std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7100 std::pair<int,int> p2(p1.second,p1.first);
7101 bool b1=std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end();
7102 bool b2=std::find(edgesOK.begin(),edgesOK.end(),p2)!=edgesOK.end();
7103 if(b1 || b2) { b=b2; isPerm[i]=true; smthChanged++; break; }
7108 std::reverse(bgFace+1,endFace);
7109 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7111 std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7112 std::pair<int,int> p2(p1.second,p1.first);
7113 if(std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end())
7114 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7115 if(std::find(edgesFinished.begin(),edgesFinished.end(),p1)!=edgesFinished.end() || std::find(edgesFinished.begin(),edgesFinished.end(),p2)!=edgesFinished.end())
7116 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7117 std::list< std::pair<int,int> >::iterator it=std::find(edgesOK.begin(),edgesOK.end(),p2);
7118 if(it!=edgesOK.end())
7121 edgesFinished.push_back(p1);
7124 edgesOK.push_back(p1);
7131 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired !"); }
7133 if(!edgesOK.empty())
7134 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired : Some edges are shared only once !"); }
7135 if(INTERP_KERNEL::calculateVolumeForPolyh2<int,INTERP_KERNEL::ALL_C_MODE>(begin,(int)std::distance(begin,end),coords)<-EPS_FOR_POLYH_ORIENTATION)
7136 {//not lucky ! The first face was not correctly oriented : reorient all faces...
7138 for(std::size_t i=0;i<nbOfFaces;i++)
7140 endFace=std::find(bgFace+1,end,-1);
7141 std::reverse(bgFace+1,endFace);
7149 * This method makes the assumption spacedimension == meshdimension == 2.
7150 * This method works only for linear cells.
7152 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYGON in pos#0)
7154 DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMesh() const
7156 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
7157 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : meshdimension, spacedimension must be equal to 2 !");
7158 MCAuto<MEDCouplingUMesh> skin(computeSkin());
7159 int oldNbOfNodes(skin->getNumberOfNodes());
7160 MCAuto<DataArrayInt> o2n(skin->zipCoordsTraducer());
7161 int nbOfNodesExpected(skin->getNumberOfNodes());
7162 MCAuto<DataArrayInt> n2o(o2n->invertArrayO2N2N2O(oldNbOfNodes));
7163 int nbCells(skin->getNumberOfCells());
7164 if(nbCells==nbOfNodesExpected)
7165 return buildUnionOf2DMeshLinear(skin,n2o);
7166 else if(2*nbCells==nbOfNodesExpected)
7167 return buildUnionOf2DMeshQuadratic(skin,n2o);
7169 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : the mesh 2D in input appears to be not in a single part of a 2D mesh !");
7173 * This method makes the assumption spacedimension == meshdimension == 3.
7174 * This method works only for linear cells.
7176 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYHED in pos#0)
7178 DataArrayInt *MEDCouplingUMesh::buildUnionOf3DMesh() const
7180 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
7181 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf3DMesh : meshdimension, spacedimension must be equal to 2 !");
7182 MCAuto<MEDCouplingUMesh> m=computeSkin();
7183 const int *conn=m->getNodalConnectivity()->begin();
7184 const int *connI=m->getNodalConnectivityIndex()->begin();
7185 int nbOfCells=m->getNumberOfCells();
7186 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(m->getNodalConnectivity()->getNumberOfTuples(),1);
7187 int *work=ret->getPointer(); *work++=INTERP_KERNEL::NORM_POLYHED;
7190 work=std::copy(conn+connI[0]+1,conn+connI[1],work);
7191 for(int i=1;i<nbOfCells;i++)
7194 work=std::copy(conn+connI[i]+1,conn+connI[i+1],work);
7200 * \brief Creates a graph of cell neighbors
7201 * \return MEDCouplingSkyLineArray * - an sky line array the user should delete.
7202 * In the sky line array, graph arcs are stored in terms of (index,value) notation.
7204 * - index: 0 3 5 6 6
7205 * - value: 1 2 3 2 3 3
7206 * means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7207 * Arcs are not doubled but reflexive (1,1) arcs are present for each cell
7209 MEDCouplingSkyLineArray* MEDCouplingUMesh::generateGraph() const
7211 checkConnectivityFullyDefined();
7213 int meshDim = this->getMeshDimension();
7214 MEDCoupling::DataArrayInt* indexr=MEDCoupling::DataArrayInt::New();
7215 MEDCoupling::DataArrayInt* revConn=MEDCoupling::DataArrayInt::New();
7216 this->getReverseNodalConnectivity(revConn,indexr);
7217 const int* indexr_ptr=indexr->begin();
7218 const int* revConn_ptr=revConn->begin();
7220 const MEDCoupling::DataArrayInt* index;
7221 const MEDCoupling::DataArrayInt* conn;
7222 conn=this->getNodalConnectivity(); // it includes a type as the 1st element!!!
7223 index=this->getNodalConnectivityIndex();
7224 int nbCells=this->getNumberOfCells();
7225 const int* index_ptr=index->begin();
7226 const int* conn_ptr=conn->begin();
7228 //creating graph arcs (cell to cell relations)
7229 //arcs are stored in terms of (index,value) notation
7232 // means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7233 // in present version arcs are not doubled but reflexive (1,1) arcs are present for each cell
7235 //warning here one node have less than or equal effective number of cell with it
7236 //but cell could have more than effective nodes
7237 //because other equals nodes in other domain (with other global inode)
7238 std::vector <int> cell2cell_index(nbCells+1,0);
7239 std::vector <int> cell2cell;
7240 cell2cell.reserve(3*nbCells);
7242 for (int icell=0; icell<nbCells;icell++)
7244 std::map<int,int > counter;
7245 for (int iconn=index_ptr[icell]+1; iconn<index_ptr[icell+1];iconn++)
7247 int inode=conn_ptr[iconn];
7248 for (int iconnr=indexr_ptr[inode]; iconnr<indexr_ptr[inode+1];iconnr++)
7250 int icell2=revConn_ptr[iconnr];
7251 std::map<int,int>::iterator iter=counter.find(icell2);
7252 if (iter!=counter.end()) (iter->second)++;
7253 else counter.insert(std::make_pair(icell2,1));
7256 for (std::map<int,int>::const_iterator iter=counter.begin();
7257 iter!=counter.end(); iter++)
7258 if (iter->second >= meshDim)
7260 cell2cell_index[icell+1]++;
7261 cell2cell.push_back(iter->first);
7266 cell2cell_index[0]=0;
7267 for (int icell=0; icell<nbCells;icell++)
7268 cell2cell_index[icell+1]=cell2cell_index[icell]+cell2cell_index[icell+1];
7270 //filling up index and value to create skylinearray structure
7271 MEDCouplingSkyLineArray * array(MEDCouplingSkyLineArray::New(cell2cell_index,cell2cell));
7276 void MEDCouplingUMesh::writeVTKLL(std::ostream& ofs, const std::string& cellData, const std::string& pointData, DataArrayByte *byteData) const
7278 int nbOfCells=getNumberOfCells();
7280 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::writeVTK : the unstructured mesh has no cells !");
7281 ofs << " <" << getVTKDataSetType() << ">\n";
7282 ofs << " <Piece NumberOfPoints=\"" << getNumberOfNodes() << "\" NumberOfCells=\"" << nbOfCells << "\">\n";
7283 ofs << " <PointData>\n" << pointData << std::endl;
7284 ofs << " </PointData>\n";
7285 ofs << " <CellData>\n" << cellData << std::endl;
7286 ofs << " </CellData>\n";
7287 ofs << " <Points>\n";
7288 if(getSpaceDimension()==3)
7289 _coords->writeVTK(ofs,8,"Points",byteData);
7292 MCAuto<DataArrayDouble> coo=_coords->changeNbOfComponents(3,0.);
7293 coo->writeVTK(ofs,8,"Points",byteData);
7295 ofs << " </Points>\n";
7296 ofs << " <Cells>\n";
7297 const int *cPtr=_nodal_connec->begin();
7298 const int *cIPtr=_nodal_connec_index->begin();
7299 MCAuto<DataArrayInt> faceoffsets=DataArrayInt::New(); faceoffsets->alloc(nbOfCells,1);
7300 MCAuto<DataArrayInt> types=DataArrayInt::New(); types->alloc(nbOfCells,1);
7301 MCAuto<DataArrayInt> offsets=DataArrayInt::New(); offsets->alloc(nbOfCells,1);
7302 MCAuto<DataArrayInt> connectivity=DataArrayInt::New(); connectivity->alloc(_nodal_connec->getNumberOfTuples()-nbOfCells,1);
7303 int *w1=faceoffsets->getPointer(),*w2=types->getPointer(),*w3=offsets->getPointer(),*w4=connectivity->getPointer();
7304 int szFaceOffsets=0,szConn=0;
7305 for(int i=0;i<nbOfCells;i++,w1++,w2++,w3++)
7308 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]!=INTERP_KERNEL::NORM_POLYHED)
7311 *w3=szConn+cIPtr[i+1]-cIPtr[i]-1; szConn+=cIPtr[i+1]-cIPtr[i]-1;
7312 w4=std::copy(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],w4);
7316 int deltaFaceOffset=cIPtr[i+1]-cIPtr[i]+1;
7317 *w1=szFaceOffsets+deltaFaceOffset; szFaceOffsets+=deltaFaceOffset;
7318 std::set<int> c(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1]); c.erase(-1);
7319 *w3=szConn+(int)c.size(); szConn+=(int)c.size();
7320 w4=std::copy(c.begin(),c.end(),w4);
7323 types->transformWithIndArr(MEDCOUPLING2VTKTYPETRADUCER,MEDCOUPLING2VTKTYPETRADUCER+INTERP_KERNEL::NORM_MAXTYPE+1);
7324 types->writeVTK(ofs,8,"UInt8","types",byteData);
7325 offsets->writeVTK(ofs,8,"Int32","offsets",byteData);
7326 if(szFaceOffsets!=0)
7327 {//presence of Polyhedra
7328 connectivity->reAlloc(szConn);
7329 faceoffsets->writeVTK(ofs,8,"Int32","faceoffsets",byteData);
7330 MCAuto<DataArrayInt> faces=DataArrayInt::New(); faces->alloc(szFaceOffsets,1);
7331 w1=faces->getPointer();
7332 for(int i=0;i<nbOfCells;i++)
7333 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]==INTERP_KERNEL::NORM_POLYHED)
7335 int nbFaces=std::count(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],-1)+1;
7337 const int *w6=cPtr+cIPtr[i]+1,*w5=0;
7338 for(int j=0;j<nbFaces;j++)
7340 w5=std::find(w6,cPtr+cIPtr[i+1],-1);
7341 *w1++=(int)std::distance(w6,w5);
7342 w1=std::copy(w6,w5,w1);
7346 faces->writeVTK(ofs,8,"Int32","faces",byteData);
7348 connectivity->writeVTK(ofs,8,"Int32","connectivity",byteData);
7349 ofs << " </Cells>\n";
7350 ofs << " </Piece>\n";
7351 ofs << " </" << getVTKDataSetType() << ">\n";
7354 void MEDCouplingUMesh::reprQuickOverview(std::ostream& stream) const
7356 stream << "MEDCouplingUMesh C++ instance at " << this << ". Name : \"" << getName() << "\".";
7358 { stream << " Not set !"; return ; }
7359 stream << " Mesh dimension : " << _mesh_dim << ".";
7363 { stream << " No coordinates set !"; return ; }
7364 if(!_coords->isAllocated())
7365 { stream << " Coordinates set but not allocated !"; return ; }
7366 stream << " Space dimension : " << _coords->getNumberOfComponents() << "." << std::endl;
7367 stream << "Number of nodes : " << _coords->getNumberOfTuples() << ".";
7368 if(!_nodal_connec_index)
7369 { stream << std::endl << "Nodal connectivity NOT set !"; return ; }
7370 if(!_nodal_connec_index->isAllocated())
7371 { stream << std::endl << "Nodal connectivity set but not allocated !"; return ; }
7372 int lgth=_nodal_connec_index->getNumberOfTuples();
7373 int cpt=_nodal_connec_index->getNumberOfComponents();
7374 if(cpt!=1 || lgth<1)
7376 stream << std::endl << "Number of cells : " << lgth-1 << ".";
7379 std::string MEDCouplingUMesh::getVTKDataSetType() const
7381 return std::string("UnstructuredGrid");
7384 std::string MEDCouplingUMesh::getVTKFileExtension() const
7386 return std::string("vtu");
7392 * Provides a renumbering of the cells of this (which has to be a piecewise connected 1D line), so that
7393 * the segments of the line are indexed in consecutive order (i.e. cells \a i and \a i+1 are neighbors).
7394 * This doesn't modify the mesh. This method only works using nodal connectivity consideration. Coordinates of nodes are ignored here.
7395 * The caller is to deal with the resulting DataArrayInt.
7396 * \throw If the coordinate array is not set.
7397 * \throw If the nodal connectivity of the cells is not defined.
7398 * \throw If m1 is not a mesh of dimension 2, or m1 is not a mesh of dimension 1
7399 * \throw If m2 is not a (piecewise) line (i.e. if a point has more than 2 adjacent segments)
7401 * \sa DataArrayInt::sortEachPairToMakeALinkedList
7403 DataArrayInt *MEDCouplingUMesh::orderConsecutiveCells1D() const
7405 checkFullyDefined();
7406 if(getMeshDimension()!=1)
7407 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D works on unstructured mesh with meshdim = 1 !");
7409 // Check that this is a line (and not a more complex 1D mesh) - each point is used at most by 2 segments:
7410 MCAuto<DataArrayInt> _d(DataArrayInt::New()),_dI(DataArrayInt::New());
7411 MCAuto<DataArrayInt> _rD(DataArrayInt::New()),_rDI(DataArrayInt::New());
7412 MCAuto<MEDCouplingUMesh> m_points(buildDescendingConnectivity(_d, _dI, _rD, _rDI));
7413 const int *d(_d->begin()), *dI(_dI->begin());
7414 const int *rD(_rD->begin()), *rDI(_rDI->begin());
7415 MCAuto<DataArrayInt> _dsi(_rDI->deltaShiftIndex());
7416 const int * dsi(_dsi->begin());
7417 MCAuto<DataArrayInt> dsii = _dsi->findIdsNotInRange(0,3);
7419 if (dsii->getNumberOfTuples())
7420 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D only work with a mesh being a (piecewise) connected line!");
7422 int nc(getNumberOfCells());
7423 MCAuto<DataArrayInt> result(DataArrayInt::New());
7424 result->alloc(nc,1);
7426 // set of edges not used so far
7427 std::set<int> edgeSet;
7428 for (int i=0; i<nc; edgeSet.insert(i), i++);
7432 // while we have points with only one neighbor segments
7435 std::list<int> linePiece;
7436 // fills a list of consecutive segment linked to startSeg. This can go forward or backward.
7437 for (int direction=0;direction<2;direction++) // direction=0 --> forward, direction=1 --> backward
7439 // Fill the list forward (resp. backward) from the start segment:
7440 int activeSeg = startSeg;
7441 int prevPointId = -20;
7443 while (!edgeSet.empty())
7445 if (!(direction == 1 && prevPointId==-20)) // prevent adding twice startSeg
7448 linePiece.push_back(activeSeg);
7450 linePiece.push_front(activeSeg);
7451 edgeSet.erase(activeSeg);
7454 int ptId1 = d[dI[activeSeg]], ptId2 = d[dI[activeSeg]+1];
7455 ptId = direction ? (ptId1 == prevPointId ? ptId2 : ptId1) : (ptId2 == prevPointId ? ptId1 : ptId2);
7456 if (dsi[ptId] == 1) // hitting the end of the line
7459 int seg1 = rD[rDI[ptId]], seg2 = rD[rDI[ptId]+1];
7460 activeSeg = (seg1 == activeSeg) ? seg2 : seg1;
7463 // Done, save final piece into DA:
7464 std::copy(linePiece.begin(), linePiece.end(), result->getPointer()+newIdx);
7465 newIdx += linePiece.size();
7467 // identify next valid start segment (one which is not consumed)
7468 if(!edgeSet.empty())
7469 startSeg = *(edgeSet.begin());
7471 while (!edgeSet.empty());
7472 return result.retn();
7476 * This method split some of edges of 2D cells in \a this. The edges to be split are specified in \a subNodesInSeg
7477 * and in \a subNodesInSegI using \ref numbering-indirect storage mode.
7478 * To do the work this method can optionally needs information about middle of subedges for quadratic cases if
7479 * a minimal creation of new nodes is wanted.
7480 * So this method try to reduce at most the number of new nodes. The only case that can lead this method to add
7481 * nodes if a SEG3 is split without information of middle.
7482 * \b WARNING : is returned value is different from 0 a call to MEDCouplingUMesh::mergeNodes is necessary to
7483 * avoid to have a non conform mesh.
7485 * \return int - the number of new nodes created (in most of cases 0).
7487 * \throw If \a this is not coherent.
7488 * \throw If \a this has not spaceDim equal to 2.
7489 * \throw If \a this has not meshDim equal to 2.
7490 * \throw If some subcells needed to be split are orphan.
7491 * \sa MEDCouplingUMesh::conformize2D
7493 int MEDCouplingUMesh::split2DCells(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI, const DataArrayInt *midOpt, const DataArrayInt *midOptI)
7495 if(!desc || !descI || !subNodesInSeg || !subNodesInSegI)
7496 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : the 4 first arrays must be not null !");
7497 desc->checkAllocated(); descI->checkAllocated(); subNodesInSeg->checkAllocated(); subNodesInSegI->checkAllocated();
7498 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
7499 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : This method only works for meshes with spaceDim=2 and meshDim=2 !");
7500 if(midOpt==0 && midOptI==0)
7502 split2DCellsLinear(desc,descI,subNodesInSeg,subNodesInSegI);
7505 else if(midOpt!=0 && midOptI!=0)
7506 return split2DCellsQuadratic(desc,descI,subNodesInSeg,subNodesInSegI,midOpt,midOptI);
7508 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : middle parameters must be set to null for all or not null for all.");
7512 * 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
7513 * 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
7514 * the geometric cell type set to INTERP_KERNEL::NORM_POLYGON.
7515 * 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
7516 * 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.
7518 * \return false if the input connectivity represents already the convex hull, true if the input cell needs to be reordered.
7520 bool MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis(const double *coords, const int *nodalConnBg, const int *nodalConnEnd, DataArrayInt *nodalConnecOut)
7522 std::size_t sz=std::distance(nodalConnBg,nodalConnEnd);
7525 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)*nodalConnBg);
7526 if(cm.getDimension()==2)
7528 const int *node=nodalConnBg+1;
7529 int startNode=*node++;
7530 double refX=coords[2*startNode];
7531 for(;node!=nodalConnEnd;node++)
7533 if(coords[2*(*node)]<refX)
7536 refX=coords[2*startNode];
7539 std::vector<int> tmpOut; tmpOut.reserve(sz); tmpOut.push_back(startNode);
7543 double angle0=-M_PI/2;
7548 double angleNext=0.;
7549 while(nextNode!=startNode)
7553 for(node=nodalConnBg+1;node!=nodalConnEnd;node++)
7555 if(*node!=tmpOut.back() && *node!=prevNode)
7557 tmp2[0]=coords[2*(*node)]-coords[2*tmpOut.back()]; tmp2[1]=coords[2*(*node)+1]-coords[2*tmpOut.back()+1];
7558 double angleM=INTERP_KERNEL::EdgeArcCircle::GetAbsoluteAngle(tmp2,tmp1);
7563 res=angle0-angleM+2.*M_PI;
7572 if(nextNode!=startNode)
7574 angle0=angleNext-M_PI;
7577 prevNode=tmpOut.back();
7578 tmpOut.push_back(nextNode);
7581 std::vector<int> tmp3(2*(sz-1));
7582 std::vector<int>::iterator it=std::copy(nodalConnBg+1,nodalConnEnd,tmp3.begin());
7583 std::copy(nodalConnBg+1,nodalConnEnd,it);
7584 if(std::search(tmp3.begin(),tmp3.end(),tmpOut.begin(),tmpOut.end())!=tmp3.end())
7586 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
7589 if(std::search(tmp3.rbegin(),tmp3.rend(),tmpOut.begin(),tmpOut.end())!=tmp3.rend())
7591 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
7596 nodalConnecOut->pushBackSilent((int)INTERP_KERNEL::NORM_POLYGON);
7597 nodalConnecOut->insertAtTheEnd(tmpOut.begin(),tmpOut.end());
7602 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
7605 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
7609 * This method works on an input pair (\b arr, \b arrIndx) where \b arr indexes is in \b arrIndx.
7610 * 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.
7612 * \param [in] idsToRemoveBg begin of set of ids to remove in \b arr (included)
7613 * \param [in] idsToRemoveEnd end of set of ids to remove in \b arr (excluded)
7614 * \param [in,out] arr array in which the remove operation will be done.
7615 * \param [in,out] arrIndx array in the remove operation will modify
7616 * \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])
7617 * \return true if \b arr and \b arrIndx have been modified, false if not.
7619 bool MEDCouplingUMesh::RemoveIdsFromIndexedArrays(const int *idsToRemoveBg, const int *idsToRemoveEnd, DataArrayInt *arr, DataArrayInt *arrIndx, int offsetForRemoval)
7621 if(!arrIndx || !arr)
7622 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::RemoveIdsFromIndexedArrays : some input arrays are empty !");
7623 if(offsetForRemoval<0)
7624 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::RemoveIdsFromIndexedArrays : offsetForRemoval should be >=0 !");
7625 std::set<int> s(idsToRemoveBg,idsToRemoveEnd);
7626 int nbOfGrps=arrIndx->getNumberOfTuples()-1;
7627 int *arrIPtr=arrIndx->getPointer();
7630 const int *arrPtr=arr->begin();
7631 std::vector<int> arrOut;//no utility to switch to DataArrayInt because copy always needed
7632 for(int i=0;i<nbOfGrps;i++,arrIPtr++)
7634 if(*arrIPtr-previousArrI>offsetForRemoval)
7636 for(const int *work=arrPtr+previousArrI+offsetForRemoval;work!=arrPtr+*arrIPtr;work++)
7638 if(s.find(*work)==s.end())
7639 arrOut.push_back(*work);
7642 previousArrI=*arrIPtr;
7643 *arrIPtr=(int)arrOut.size();
7645 if(arr->getNumberOfTuples()==(int)arrOut.size())
7647 arr->alloc((int)arrOut.size(),1);
7648 std::copy(arrOut.begin(),arrOut.end(),arr->getPointer());
7653 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn
7654 * (\ref numbering-indirect).
7655 * This method returns the result of the extraction ( specified by a set of ids in [\b idsOfSelectBg , \b idsOfSelectEnd ) ).
7656 * The selection of extraction is done standardly in new2old format.
7657 * This method returns indexed arrays (\ref numbering-indirect) using 2 arrays (arrOut,arrIndexOut).
7659 * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
7660 * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
7661 * \param [in] arrIn arr origin array from which the extraction will be done.
7662 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7663 * \param [out] arrOut the resulting array
7664 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
7665 * \sa MEDCouplingUMesh::ExtractFromIndexedArraysSlice
7667 void MEDCouplingUMesh::ExtractFromIndexedArrays(const int *idsOfSelectBg, const int *idsOfSelectEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
7668 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
7670 if(!arrIn || !arrIndxIn)
7671 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : input pointer is NULL !");
7672 arrIn->checkAllocated(); arrIndxIn->checkAllocated();
7673 if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1)
7674 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : input arrays must have exactly one component !");
7675 std::size_t sz=std::distance(idsOfSelectBg,idsOfSelectEnd);
7676 const int *arrInPtr=arrIn->begin();
7677 const int *arrIndxPtr=arrIndxIn->begin();
7678 int nbOfGrps=arrIndxIn->getNumberOfTuples()-1;
7680 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : The format of \"arrIndxIn\" is invalid ! Its nb of tuples should be >=1 !");
7681 int maxSizeOfArr=arrIn->getNumberOfTuples();
7682 MCAuto<DataArrayInt> arro=DataArrayInt::New();
7683 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
7684 arrIo->alloc((int)(sz+1),1);
7685 const int *idsIt=idsOfSelectBg;
7686 int *work=arrIo->getPointer();
7689 for(std::size_t i=0;i<sz;i++,work++,idsIt++)
7691 if(*idsIt>=0 && *idsIt<nbOfGrps)
7692 lgth+=arrIndxPtr[*idsIt+1]-arrIndxPtr[*idsIt];
7695 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " ! Must be in [0," << nbOfGrps << ") !";
7696 throw INTERP_KERNEL::Exception(oss.str());
7702 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " and at this pos arrIndxIn[" << *idsIt;
7703 oss << "+1]-arrIndxIn[" << *idsIt << "] < 0 ! The input index array is bugged !";
7704 throw INTERP_KERNEL::Exception(oss.str());
7707 arro->alloc(lgth,1);
7708 work=arro->getPointer();
7709 idsIt=idsOfSelectBg;
7710 for(std::size_t i=0;i<sz;i++,idsIt++)
7712 if(arrIndxPtr[*idsIt]>=0 && arrIndxPtr[*idsIt+1]<=maxSizeOfArr)
7713 work=std::copy(arrInPtr+arrIndxPtr[*idsIt],arrInPtr+arrIndxPtr[*idsIt+1],work);
7716 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " arrIndx[" << *idsIt << "] must be >= 0 and arrIndx[";
7717 oss << *idsIt << "+1] <= " << maxSizeOfArr << " (the size of arrIn)!";
7718 throw INTERP_KERNEL::Exception(oss.str());
7722 arrIndexOut=arrIo.retn();
7726 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn
7727 * (\ref numbering-indirect).
7728 * 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 ).
7729 * The selection of extraction is done standardly in new2old format.
7730 * This method returns indexed arrays (\ref numbering-indirect) using 2 arrays (arrOut,arrIndexOut).
7732 * \param [in] idsOfSelectStart begin of set of ids of the input extraction (included)
7733 * \param [in] idsOfSelectStop end of set of ids of the input extraction (excluded)
7734 * \param [in] idsOfSelectStep
7735 * \param [in] arrIn arr origin array from which the extraction will be done.
7736 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7737 * \param [out] arrOut the resulting array
7738 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
7739 * \sa MEDCouplingUMesh::ExtractFromIndexedArrays
7741 void MEDCouplingUMesh::ExtractFromIndexedArraysSlice(int idsOfSelectStart, int idsOfSelectStop, int idsOfSelectStep, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
7742 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
7744 if(!arrIn || !arrIndxIn)
7745 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : input pointer is NULL !");
7746 arrIn->checkAllocated(); arrIndxIn->checkAllocated();
7747 if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1)
7748 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : input arrays must have exactly one component !");
7749 int sz=DataArrayInt::GetNumberOfItemGivenBESRelative(idsOfSelectStart,idsOfSelectStop,idsOfSelectStep,"MEDCouplingUMesh::ExtractFromIndexedArraysSlice : Input slice ");
7750 const int *arrInPtr=arrIn->begin();
7751 const int *arrIndxPtr=arrIndxIn->begin();
7752 int nbOfGrps=arrIndxIn->getNumberOfTuples()-1;
7754 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : The format of \"arrIndxIn\" is invalid ! Its nb of tuples should be >=1 !");
7755 int maxSizeOfArr=arrIn->getNumberOfTuples();
7756 MCAuto<DataArrayInt> arro=DataArrayInt::New();
7757 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
7758 arrIo->alloc((int)(sz+1),1);
7759 int idsIt=idsOfSelectStart;
7760 int *work=arrIo->getPointer();
7763 for(int i=0;i<sz;i++,work++,idsIt+=idsOfSelectStep)
7765 if(idsIt>=0 && idsIt<nbOfGrps)
7766 lgth+=arrIndxPtr[idsIt+1]-arrIndxPtr[idsIt];
7769 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " ! Must be in [0," << nbOfGrps << ") !";
7770 throw INTERP_KERNEL::Exception(oss.str());
7776 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " and at this pos arrIndxIn[" << idsIt;
7777 oss << "+1]-arrIndxIn[" << idsIt << "] < 0 ! The input index array is bugged !";
7778 throw INTERP_KERNEL::Exception(oss.str());
7781 arro->alloc(lgth,1);
7782 work=arro->getPointer();
7783 idsIt=idsOfSelectStart;
7784 for(int i=0;i<sz;i++,idsIt+=idsOfSelectStep)
7786 if(arrIndxPtr[idsIt]>=0 && arrIndxPtr[idsIt+1]<=maxSizeOfArr)
7787 work=std::copy(arrInPtr+arrIndxPtr[idsIt],arrInPtr+arrIndxPtr[idsIt+1],work);
7790 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " arrIndx[" << idsIt << "] must be >= 0 and arrIndx[";
7791 oss << idsIt << "+1] <= " << maxSizeOfArr << " (the size of arrIn)!";
7792 throw INTERP_KERNEL::Exception(oss.str());
7796 arrIndexOut=arrIo.retn();
7800 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
7801 * 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
7802 * cellIds \b in [ \b idsOfSelectBg , \b idsOfSelectEnd ) a copy coming from the corresponding values in input pair (\b srcArr, \b srcArrIndex).
7803 * This method is an generalization of MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx that performs the same thing but by without building explicitely a result output arrays.
7805 * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
7806 * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
7807 * \param [in] arrIn arr origin array from which the extraction will be done.
7808 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7809 * \param [in] srcArr input array that will be used as source of copy for ids in [ \b idsOfSelectBg, \b idsOfSelectEnd )
7810 * \param [in] srcArrIndex index array of \b srcArr
7811 * \param [out] arrOut the resulting array
7812 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
7814 * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx
7816 void MEDCouplingUMesh::SetPartOfIndexedArrays(const int *idsOfSelectBg, const int *idsOfSelectEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
7817 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex,
7818 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
7820 if(arrIn==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
7821 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArrays : presence of null pointer in input parameter !");
7822 MCAuto<DataArrayInt> arro=DataArrayInt::New();
7823 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
7824 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
7825 std::vector<bool> v(nbOfTuples,true);
7827 const int *arrIndxInPtr=arrIndxIn->begin();
7828 const int *srcArrIndexPtr=srcArrIndex->begin();
7829 for(const int *it=idsOfSelectBg;it!=idsOfSelectEnd;it++,srcArrIndexPtr++)
7831 if(*it>=0 && *it<nbOfTuples)
7834 offset+=(srcArrIndexPtr[1]-srcArrIndexPtr[0])-(arrIndxInPtr[*it+1]-arrIndxInPtr[*it]);
7838 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArrays : On pos #" << std::distance(idsOfSelectBg,it) << " value is " << *it << " not in [0," << nbOfTuples << ") !";
7839 throw INTERP_KERNEL::Exception(oss.str());
7842 srcArrIndexPtr=srcArrIndex->begin();
7843 arrIo->alloc(nbOfTuples+1,1);
7844 arro->alloc(arrIn->getNumberOfTuples()+offset,1);
7845 const int *arrInPtr=arrIn->begin();
7846 const int *srcArrPtr=srcArr->begin();
7847 int *arrIoPtr=arrIo->getPointer(); *arrIoPtr++=0;
7848 int *arroPtr=arro->getPointer();
7849 for(int ii=0;ii<nbOfTuples;ii++,arrIoPtr++)
7853 arroPtr=std::copy(arrInPtr+arrIndxInPtr[ii],arrInPtr+arrIndxInPtr[ii+1],arroPtr);
7854 *arrIoPtr=arrIoPtr[-1]+(arrIndxInPtr[ii+1]-arrIndxInPtr[ii]);
7858 std::size_t pos=std::distance(idsOfSelectBg,std::find(idsOfSelectBg,idsOfSelectEnd,ii));
7859 arroPtr=std::copy(srcArrPtr+srcArrIndexPtr[pos],srcArrPtr+srcArrIndexPtr[pos+1],arroPtr);
7860 *arrIoPtr=arrIoPtr[-1]+(srcArrIndexPtr[pos+1]-srcArrIndexPtr[pos]);
7864 arrIndexOut=arrIo.retn();
7868 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
7869 * This method is an specialization of MEDCouplingUMesh::SetPartOfIndexedArrays in the case of assignement do not modify the index in \b arrIndxIn.
7871 * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
7872 * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
7873 * \param [in,out] arrInOut arr origin array from which the extraction will be done.
7874 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7875 * \param [in] srcArr input array that will be used as source of copy for ids in [ \b idsOfSelectBg , \b idsOfSelectEnd )
7876 * \param [in] srcArrIndex index array of \b srcArr
7878 * \sa MEDCouplingUMesh::SetPartOfIndexedArrays
7880 void MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx(const int *idsOfSelectBg, const int *idsOfSelectEnd, DataArrayInt *arrInOut, const DataArrayInt *arrIndxIn,
7881 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex)
7883 if(arrInOut==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
7884 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx : presence of null pointer in input parameter !");
7885 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
7886 const int *arrIndxInPtr=arrIndxIn->begin();
7887 const int *srcArrIndexPtr=srcArrIndex->begin();
7888 int *arrInOutPtr=arrInOut->getPointer();
7889 const int *srcArrPtr=srcArr->begin();
7890 for(const int *it=idsOfSelectBg;it!=idsOfSelectEnd;it++,srcArrIndexPtr++)
7892 if(*it>=0 && *it<nbOfTuples)
7894 if(srcArrIndexPtr[1]-srcArrIndexPtr[0]==arrIndxInPtr[*it+1]-arrIndxInPtr[*it])
7895 std::copy(srcArrPtr+srcArrIndexPtr[0],srcArrPtr+srcArrIndexPtr[1],arrInOutPtr+arrIndxInPtr[*it]);
7898 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] !";
7899 throw INTERP_KERNEL::Exception(oss.str());
7904 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx : On pos #" << std::distance(idsOfSelectBg,it) << " value is " << *it << " not in [0," << nbOfTuples << ") !";
7905 throw INTERP_KERNEL::Exception(oss.str());
7911 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
7912 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
7913 * 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]].
7914 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
7915 * A negative value in \b arrIn means that it is ignored.
7916 * 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.
7918 * \param [in] arrIn arr origin array from which the extraction will be done.
7919 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7920 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
7921 * \sa MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed, MEDCouplingUMesh::partitionBySpreadZone
7923 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGradually(const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn)
7925 int seed=0,nbOfDepthPeelingPerformed=0;
7926 return ComputeSpreadZoneGraduallyFromSeed(&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfDepthPeelingPerformed);
7930 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
7931 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
7932 * 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]].
7933 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
7934 * A negative value in \b arrIn means that it is ignored.
7935 * 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.
7936 * \param [in] seedBg the begin pointer (included) of an array containing the seed of the search zone
7937 * \param [in] seedEnd the end pointer (not included) of an array containing the seed of the search zone
7938 * \param [in] arrIn arr origin array from which the extraction will be done.
7939 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7940 * \param [in] nbOfDepthPeeling the max number of peels requested in search. By default -1, that is to say, no limit.
7941 * \param [out] nbOfDepthPeelingPerformed the number of peels effectively performed. May be different from \a nbOfDepthPeeling
7942 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
7943 * \sa MEDCouplingUMesh::partitionBySpreadZone
7945 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(const int *seedBg, const int *seedEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn, int nbOfDepthPeeling, int& nbOfDepthPeelingPerformed)
7947 nbOfDepthPeelingPerformed=0;
7949 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed : arrIndxIn input pointer is NULL !");
7950 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
7953 DataArrayInt *ret=DataArrayInt::New(); ret->alloc(0,1);
7957 std::vector<bool> fetched(nbOfTuples,false);
7958 return ComputeSpreadZoneGraduallyFromSeedAlg(fetched,seedBg,seedEnd,arrIn,arrIndxIn,nbOfDepthPeeling,nbOfDepthPeelingPerformed);
7963 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
7964 * 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
7965 * cellIds \b in [\b idsOfSelectBg, \b idsOfSelectEnd) a copy coming from the corresponding values in input pair (\b srcArr, \b srcArrIndex).
7966 * This method is an generalization of MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx that performs the same thing but by without building explicitely a result output arrays.
7968 * \param [in] start begin of set of ids of the input extraction (included)
7969 * \param [in] end end of set of ids of the input extraction (excluded)
7970 * \param [in] step step of the set of ids in range mode.
7971 * \param [in] arrIn arr origin array from which the extraction will be done.
7972 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7973 * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd)
7974 * \param [in] srcArrIndex index array of \b srcArr
7975 * \param [out] arrOut the resulting array
7976 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
7978 * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx MEDCouplingUMesh::SetPartOfIndexedArrays
7980 void MEDCouplingUMesh::SetPartOfIndexedArraysSlice(int start, int end, int step, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
7981 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex,
7982 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
7984 if(arrIn==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
7985 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSlice : presence of null pointer in input parameter !");
7986 MCAuto<DataArrayInt> arro=DataArrayInt::New();
7987 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
7988 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
7990 const int *arrIndxInPtr=arrIndxIn->begin();
7991 const int *srcArrIndexPtr=srcArrIndex->begin();
7992 int nbOfElemsToSet=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::SetPartOfIndexedArraysSlice : ");
7994 for(int i=0;i<nbOfElemsToSet;i++,srcArrIndexPtr++,it+=step)
7996 if(it>=0 && it<nbOfTuples)
7997 offset+=(srcArrIndexPtr[1]-srcArrIndexPtr[0])-(arrIndxInPtr[it+1]-arrIndxInPtr[it]);
8000 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSlice : On pos #" << i << " value is " << it << " not in [0," << nbOfTuples << ") !";
8001 throw INTERP_KERNEL::Exception(oss.str());
8004 srcArrIndexPtr=srcArrIndex->begin();
8005 arrIo->alloc(nbOfTuples+1,1);
8006 arro->alloc(arrIn->getNumberOfTuples()+offset,1);
8007 const int *arrInPtr=arrIn->begin();
8008 const int *srcArrPtr=srcArr->begin();
8009 int *arrIoPtr=arrIo->getPointer(); *arrIoPtr++=0;
8010 int *arroPtr=arro->getPointer();
8011 for(int ii=0;ii<nbOfTuples;ii++,arrIoPtr++)
8013 int pos=DataArray::GetPosOfItemGivenBESRelativeNoThrow(ii,start,end,step);
8016 arroPtr=std::copy(arrInPtr+arrIndxInPtr[ii],arrInPtr+arrIndxInPtr[ii+1],arroPtr);
8017 *arrIoPtr=arrIoPtr[-1]+(arrIndxInPtr[ii+1]-arrIndxInPtr[ii]);
8021 arroPtr=std::copy(srcArrPtr+srcArrIndexPtr[pos],srcArrPtr+srcArrIndexPtr[pos+1],arroPtr);
8022 *arrIoPtr=arrIoPtr[-1]+(srcArrIndexPtr[pos+1]-srcArrIndexPtr[pos]);
8026 arrIndexOut=arrIo.retn();
8030 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
8031 * This method is an specialization of MEDCouplingUMesh::SetPartOfIndexedArrays in the case of assignement do not modify the index in \b arrIndxIn.
8033 * \param [in] start begin of set of ids of the input extraction (included)
8034 * \param [in] end end of set of ids of the input extraction (excluded)
8035 * \param [in] step step of the set of ids in range mode.
8036 * \param [in,out] arrInOut arr origin array from which the extraction will be done.
8037 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
8038 * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd)
8039 * \param [in] srcArrIndex index array of \b srcArr
8041 * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSlice MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx
8043 void MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice(int start, int end, int step, DataArrayInt *arrInOut, const DataArrayInt *arrIndxIn,
8044 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex)
8046 if(arrInOut==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
8047 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : presence of null pointer in input parameter !");
8048 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
8049 const int *arrIndxInPtr=arrIndxIn->begin();
8050 const int *srcArrIndexPtr=srcArrIndex->begin();
8051 int *arrInOutPtr=arrInOut->getPointer();
8052 const int *srcArrPtr=srcArr->begin();
8053 int nbOfElemsToSet=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : ");
8055 for(int i=0;i<nbOfElemsToSet;i++,srcArrIndexPtr++,it+=step)
8057 if(it>=0 && it<nbOfTuples)
8059 if(srcArrIndexPtr[1]-srcArrIndexPtr[0]==arrIndxInPtr[it+1]-arrIndxInPtr[it])
8060 std::copy(srcArrPtr+srcArrIndexPtr[0],srcArrPtr+srcArrIndexPtr[1],arrInOutPtr+arrIndxInPtr[it]);
8063 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : On pos #" << i << " id (idsOfSelectBg[" << i << "]) is " << it << " arrIndxIn[id+1]-arrIndxIn[id]!=srcArrIndex[pos+1]-srcArrIndex[pos] !";
8064 throw INTERP_KERNEL::Exception(oss.str());
8069 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : On pos #" << i << " value is " << it << " not in [0," << nbOfTuples << ") !";
8070 throw INTERP_KERNEL::Exception(oss.str());
8076 * \b this is expected to be a mesh fully defined whose spaceDim==meshDim.
8077 * It returns a new allocated mesh having the same mesh dimension and lying on same coordinates.
8078 * The returned mesh contains as poly cells as number of contiguous zone (regarding connectivity).
8079 * A spread contiguous zone is built using poly cells (polyhedra in 3D, polygons in 2D and polyline in 1D).
8080 * The sum of measure field of returned mesh is equal to the sum of measure field of this.
8082 * \return a newly allocated mesh lying on the same coords than \b this with same meshdimension than \b this.
8084 MEDCouplingUMesh *MEDCouplingUMesh::buildSpreadZonesWithPoly() const
8086 checkFullyDefined();
8087 int mdim=getMeshDimension();
8088 int spaceDim=getSpaceDimension();
8090 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension and spacedimension do not match !");
8091 std::vector<DataArrayInt *> partition=partitionBySpreadZone();
8092 std::vector< MCAuto<DataArrayInt> > partitionAuto; partitionAuto.reserve(partition.size());
8093 std::copy(partition.begin(),partition.end(),std::back_insert_iterator<std::vector< MCAuto<DataArrayInt> > >(partitionAuto));
8094 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
8095 ret->setCoords(getCoords());
8096 ret->allocateCells((int)partition.size());
8098 for(std::vector<DataArrayInt *>::const_iterator it=partition.begin();it!=partition.end();it++)
8100 MCAuto<MEDCouplingUMesh> tmp=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf((*it)->begin(),(*it)->end(),true));
8101 MCAuto<DataArrayInt> cell;
8105 cell=tmp->buildUnionOf2DMesh();
8108 cell=tmp->buildUnionOf3DMesh();
8111 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension supported are [2,3] ! Not implemented yet for others !");
8114 ret->insertNextCell((INTERP_KERNEL::NormalizedCellType)cell->getIJSafe(0,0),cell->getNumberOfTuples()-1,cell->begin()+1);
8117 ret->finishInsertingCells();
8122 * This method partitions \b this into contiguous zone.
8123 * This method only needs a well defined connectivity. Coordinates are not considered here.
8124 * This method returns a vector of \b newly allocated arrays that the caller has to deal with.
8126 std::vector<DataArrayInt *> MEDCouplingUMesh::partitionBySpreadZone() const
8128 DataArrayInt *neigh=0,*neighI=0;
8129 computeNeighborsOfCells(neigh,neighI);
8130 MCAuto<DataArrayInt> neighAuto(neigh),neighIAuto(neighI);
8131 return PartitionBySpreadZone(neighAuto,neighIAuto);
8134 std::vector<DataArrayInt *> MEDCouplingUMesh::PartitionBySpreadZone(const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn)
8136 if(!arrIn || !arrIndxIn)
8137 throw INTERP_KERNEL::Exception("PartitionBySpreadZone : null input pointers !");
8138 arrIn->checkAllocated(); arrIndxIn->checkAllocated();
8139 int nbOfTuples(arrIndxIn->getNumberOfTuples());
8140 if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1 || nbOfTuples<1)
8141 throw INTERP_KERNEL::Exception("PartitionBySpreadZone : invalid arrays in input !");
8142 int nbOfCellsCur(nbOfTuples-1);
8143 std::vector<DataArrayInt *> ret;
8146 std::vector<bool> fetchedCells(nbOfCellsCur,false);
8147 std::vector< MCAuto<DataArrayInt> > ret2;
8149 while(seed<nbOfCellsCur)
8151 int nbOfPeelPerformed=0;
8152 ret2.push_back(ComputeSpreadZoneGraduallyFromSeedAlg(fetchedCells,&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfPeelPerformed));
8153 seed=(int)std::distance(fetchedCells.begin(),std::find(fetchedCells.begin()+seed,fetchedCells.end(),false));
8155 for(std::vector< MCAuto<DataArrayInt> >::iterator it=ret2.begin();it!=ret2.end();it++)
8156 ret.push_back((*it).retn());
8161 * This method returns given a distribution of cell type (returned for example by MEDCouplingUMesh::getDistributionOfTypes method and customized after) a
8162 * newly allocated DataArrayInt instance with 2 components ready to be interpreted as input of DataArrayInt::findRangeIdForEachTuple method.
8164 * \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.
8165 * \return a newly allocated DataArrayInt to be managed by the caller.
8166 * \throw In case of \a code has not the right format (typically of size 3*n)
8168 DataArrayInt *MEDCouplingUMesh::ComputeRangesFromTypeDistribution(const std::vector<int>& code)
8170 MCAuto<DataArrayInt> ret=DataArrayInt::New();
8171 std::size_t nb=code.size()/3;
8172 if(code.size()%3!=0)
8173 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeRangesFromTypeDistribution : invalid input code !");
8174 ret->alloc((int)nb,2);
8175 int *retPtr=ret->getPointer();
8176 for(std::size_t i=0;i<nb;i++,retPtr+=2)
8178 retPtr[0]=code[3*i+2];
8179 retPtr[1]=code[3*i+2]+code[3*i+1];
8185 * This method expects that \a this a 3D mesh (spaceDim=3 and meshDim=3) with all coordinates and connectivities set.
8186 * All cells in \a this are expected to be linear 3D cells.
8187 * This method will split **all** 3D cells in \a this into INTERP_KERNEL::NORM_TETRA4 cells and put them in the returned mesh.
8188 * It leads to an increase to number of cells.
8189 * This method contrary to MEDCouplingUMesh::simplexize can append coordinates in \a this to perform its work.
8190 * The \a nbOfAdditionalPoints returned value informs about it. If > 0, the coordinates array in returned mesh will have \a nbOfAdditionalPoints
8191 * more tuples (nodes) than in \a this. Anyway, all the nodes in \a this (with the same order) will be in the returned mesh.
8193 * \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.
8194 * For all other cells, the splitting policy will be ignored. See INTERP_KERNEL::SplittingPolicy for the images.
8195 * \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.
8196 * \param [out] n2oCells - A new instance of DataArrayInt holding, for each new cell,
8197 * an id of old cell producing it. The caller is to delete this array using
8198 * decrRef() as it is no more needed.
8199 * \return MEDCoupling1SGTUMesh * - the mesh containing only INTERP_KERNEL::NORM_TETRA4 cells.
8201 * \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
8202 * the policy PLANAR_FACE_6 should be used on a mesh sorted with MEDCoupling1SGTUMesh::sortHexa8EachOther.
8204 * \throw If \a this is not a 3D mesh (spaceDim==3 and meshDim==3).
8205 * \throw If \a this is not fully constituted with linear 3D cells.
8206 * \sa MEDCouplingUMesh::simplexize, MEDCoupling1SGTUMesh::sortHexa8EachOther
8208 MEDCoupling1SGTUMesh *MEDCouplingUMesh::tetrahedrize(int policy, DataArrayInt *& n2oCells, int& nbOfAdditionalPoints) const
8210 INTERP_KERNEL::SplittingPolicy pol((INTERP_KERNEL::SplittingPolicy)policy);
8211 checkConnectivityFullyDefined();
8212 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
8213 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tetrahedrize : only available for mesh with meshdim == 3 and spacedim == 3 !");
8214 int nbOfCells(getNumberOfCells()),nbNodes(getNumberOfNodes());
8215 MCAuto<MEDCoupling1SGTUMesh> ret0(MEDCoupling1SGTUMesh::New(getName(),INTERP_KERNEL::NORM_TETRA4));
8216 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(nbOfCells,1);
8217 int *retPt(ret->getPointer());
8218 MCAuto<DataArrayInt> newConn(DataArrayInt::New()); newConn->alloc(0,1);
8219 MCAuto<DataArrayDouble> addPts(DataArrayDouble::New()); addPts->alloc(0,1);
8220 const int *oldc(_nodal_connec->begin());
8221 const int *oldci(_nodal_connec_index->begin());
8222 const double *coords(_coords->begin());
8223 for(int i=0;i<nbOfCells;i++,oldci++,retPt++)
8225 std::vector<int> a; std::vector<double> b;
8226 INTERP_KERNEL::SplitIntoTetras(pol,(INTERP_KERNEL::NormalizedCellType)oldc[oldci[0]],oldc+oldci[0]+1,oldc+oldci[1],coords,a,b);
8227 std::size_t nbOfTet(a.size()/4); *retPt=(int)nbOfTet;
8228 const int *aa(&a[0]);
8231 for(std::vector<int>::iterator it=a.begin();it!=a.end();it++)
8233 *it=(-(*(it))-1+nbNodes);
8234 addPts->insertAtTheEnd(b.begin(),b.end());
8235 nbNodes+=(int)b.size()/3;
8237 for(std::size_t j=0;j<nbOfTet;j++,aa+=4)
8238 newConn->insertAtTheEnd(aa,aa+4);
8240 if(!addPts->empty())
8242 addPts->rearrange(3);
8243 nbOfAdditionalPoints=addPts->getNumberOfTuples();
8244 addPts=DataArrayDouble::Aggregate(getCoords(),addPts);
8245 ret0->setCoords(addPts);
8249 nbOfAdditionalPoints=0;
8250 ret0->setCoords(getCoords());
8252 ret0->setNodalConnectivity(newConn);
8254 ret->computeOffsetsFull();
8255 n2oCells=ret->buildExplicitArrOfSliceOnScaledArr(0,nbOfCells,1);
8259 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),
8260 _own_cell(true),_cell_id(-1),_nb_cell(0)
8265 _nb_cell=mesh->getNumberOfCells();
8269 MEDCouplingUMeshCellIterator::~MEDCouplingUMeshCellIterator()
8277 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh, MEDCouplingUMeshCell *itc, int bg, int end):_mesh(mesh),_cell(itc),
8278 _own_cell(false),_cell_id(bg-1),
8285 MEDCouplingUMeshCell *MEDCouplingUMeshCellIterator::nextt()
8288 if(_cell_id<_nb_cell)
8297 MEDCouplingUMeshCellByTypeEntry::MEDCouplingUMeshCellByTypeEntry(MEDCouplingUMesh *mesh):_mesh(mesh)
8303 MEDCouplingUMeshCellByTypeIterator *MEDCouplingUMeshCellByTypeEntry::iterator()
8305 return new MEDCouplingUMeshCellByTypeIterator(_mesh);
8308 MEDCouplingUMeshCellByTypeEntry::~MEDCouplingUMeshCellByTypeEntry()
8314 MEDCouplingUMeshCellEntry::MEDCouplingUMeshCellEntry(MEDCouplingUMesh *mesh, INTERP_KERNEL::NormalizedCellType type, MEDCouplingUMeshCell *itc, int bg, int end):_mesh(mesh),_type(type),
8322 MEDCouplingUMeshCellEntry::~MEDCouplingUMeshCellEntry()
8328 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCellEntry::getType() const
8333 int MEDCouplingUMeshCellEntry::getNumberOfElems() const
8338 MEDCouplingUMeshCellIterator *MEDCouplingUMeshCellEntry::iterator()
8340 return new MEDCouplingUMeshCellIterator(_mesh,_itc,_bg,_end);
8343 MEDCouplingUMeshCellByTypeIterator::MEDCouplingUMeshCellByTypeIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),_cell_id(0),_nb_cell(0)
8348 _nb_cell=mesh->getNumberOfCells();
8352 MEDCouplingUMeshCellByTypeIterator::~MEDCouplingUMeshCellByTypeIterator()
8359 MEDCouplingUMeshCellEntry *MEDCouplingUMeshCellByTypeIterator::nextt()
8361 const int *c=_mesh->getNodalConnectivity()->begin();
8362 const int *ci=_mesh->getNodalConnectivityIndex()->begin();
8363 if(_cell_id<_nb_cell)
8365 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[_cell_id]];
8366 int nbOfElems=(int)std::distance(ci+_cell_id,std::find_if(ci+_cell_id,ci+_nb_cell,MEDCouplingImpl::ConnReader(c,type)));
8367 int startId=_cell_id;
8368 _cell_id+=nbOfElems;
8369 return new MEDCouplingUMeshCellEntry(_mesh,type,_cell,startId,_cell_id);
8375 MEDCouplingUMeshCell::MEDCouplingUMeshCell(MEDCouplingUMesh *mesh):_conn(0),_conn_indx(0),_conn_lgth(NOTICABLE_FIRST_VAL)
8379 _conn=mesh->getNodalConnectivity()->getPointer();
8380 _conn_indx=mesh->getNodalConnectivityIndex()->getPointer();
8384 void MEDCouplingUMeshCell::next()
8386 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8391 _conn_lgth=_conn_indx[1]-_conn_indx[0];
8394 std::string MEDCouplingUMeshCell::repr() const
8396 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8398 std::ostringstream oss; oss << "Cell Type " << INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)_conn[0]).getRepr();
8400 std::copy(_conn+1,_conn+_conn_lgth,std::ostream_iterator<int>(oss," "));
8404 return std::string("MEDCouplingUMeshCell::repr : Invalid pos");
8407 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCell::getType() const
8409 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8410 return (INTERP_KERNEL::NormalizedCellType)_conn[0];
8412 return INTERP_KERNEL::NORM_ERROR;
8415 const int *MEDCouplingUMeshCell::getAllConn(int& lgth) const
8418 if(_conn_lgth!=NOTICABLE_FIRST_VAL)