1 // Copyright (C) 2007-2022 CEA/DEN, EDF R&D
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 // Author : Anthony Geay (EDF R&D)
21 #include "MEDCouplingUMesh.txx"
22 #include "MEDCouplingCMesh.hxx"
23 #include "MEDCoupling1GTUMesh.hxx"
24 #include "MEDCouplingFieldDouble.hxx"
25 #include "MEDCouplingSkyLineArray.hxx"
26 #include "CellModel.hxx"
27 #include "VolSurfUser.txx"
28 #include "InterpolationUtils.hxx"
29 #include "PointLocatorAlgos.txx"
31 #include "BBTreeDst.txx"
32 #include "SplitterTetra.hxx"
33 #include "DiameterCalculator.hxx"
34 #include "DirectedBoundingBox.hxx"
35 #include "InterpKernelMatrixTools.hxx"
36 #include "InterpKernelMeshQuality.hxx"
37 #include "InterpKernelCellSimplify.hxx"
38 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
39 #include "InterpKernelAutoPtr.hxx"
40 #include "InterpKernelGeo2DNode.hxx"
41 #include "InterpKernelGeo2DEdgeLin.hxx"
42 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
43 #include "InterpKernelGeo2DQuadraticPolygon.hxx"
44 #include "OrientationInverter.hxx"
45 #include "MEDCouplingUMesh_internal.hxx"
55 using namespace MEDCoupling;
57 double MEDCouplingUMesh::EPS_FOR_POLYH_ORIENTATION=1.e-14;
61 const INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::MEDMEM_ORDER[N_MEDMEM_ORDER] = { INTERP_KERNEL::NORM_POINT1, INTERP_KERNEL::NORM_SEG2, INTERP_KERNEL::NORM_SEG3, INTERP_KERNEL::NORM_SEG4, INTERP_KERNEL::NORM_POLYL, INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4, INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_TRI7, INTERP_KERNEL::NORM_QUAD8, INTERP_KERNEL::NORM_QUAD9, INTERP_KERNEL::NORM_POLYGON, INTERP_KERNEL::NORM_QPOLYG, INTERP_KERNEL::NORM_TETRA4, INTERP_KERNEL::NORM_PYRA5, INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXA8, INTERP_KERNEL::NORM_HEXGP12, INTERP_KERNEL::NORM_TETRA10, INTERP_KERNEL::NORM_PYRA13, INTERP_KERNEL::NORM_PENTA15, INTERP_KERNEL::NORM_PENTA18, INTERP_KERNEL::NORM_HEXA20, INTERP_KERNEL::NORM_HEXA27, INTERP_KERNEL::NORM_POLYHED };
64 MEDCouplingUMesh *MEDCouplingUMesh::New()
66 return new MEDCouplingUMesh;
69 MEDCouplingUMesh *MEDCouplingUMesh::New(const std::string& meshName, int meshDim)
71 MEDCouplingUMesh *ret=new MEDCouplingUMesh;
72 ret->setName(meshName);
73 ret->setMeshDimension(meshDim);
78 * Returns a new MEDCouplingUMesh which is a full copy of \a this one. No data is shared
79 * between \a this and the new mesh.
80 * \return MEDCouplingUMesh * - a new instance of MEDCouplingMesh. The caller is to
81 * delete this mesh using decrRef() as it is no more needed.
83 MEDCouplingUMesh *MEDCouplingUMesh::deepCopy() const
90 * Returns a new MEDCouplingUMesh which is a copy of \a this one.
91 * \param [in] recDeepCpy - if \a true, the copy is deep, else all data arrays of \a
92 * this mesh are shared by the new mesh.
93 * \return MEDCouplingUMesh * - a new instance of MEDCouplingMesh. The caller is to
94 * delete this mesh using decrRef() as it is no more needed.
96 MEDCouplingUMesh *MEDCouplingUMesh::clone(bool recDeepCpy) const
98 return new MEDCouplingUMesh(*this,recDeepCpy);
102 * This method behaves mostly like MEDCouplingUMesh::deepCopy method, except that only nodal connectivity arrays are deeply copied.
103 * The coordinates are shared between \a this and the returned instance.
105 * \return MEDCouplingUMesh * - A new object instance holding the copy of \a this (deep for connectivity, shallow for coordiantes)
106 * \sa MEDCouplingUMesh::deepCopy
108 MEDCouplingUMesh *MEDCouplingUMesh::deepCopyConnectivityOnly() const
110 checkConnectivityFullyDefined();
111 MCAuto<MEDCouplingUMesh> ret=clone(false);
112 MCAuto<DataArrayIdType> c(getNodalConnectivity()->deepCopy()),ci(getNodalConnectivityIndex()->deepCopy());
113 ret->setConnectivity(c,ci);
117 void MEDCouplingUMesh::shallowCopyConnectivityFrom(const MEDCouplingPointSet *other)
120 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is null !");
121 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
123 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is not an MEDCouplingUMesh instance !");
124 MEDCouplingUMesh *otherC2=const_cast<MEDCouplingUMesh *>(otherC);//sorry :(
125 setConnectivity(otherC2->getNodalConnectivity(),otherC2->getNodalConnectivityIndex(),true);
128 std::size_t MEDCouplingUMesh::getHeapMemorySizeWithoutChildren() const
130 std::size_t ret(MEDCouplingPointSet::getHeapMemorySizeWithoutChildren());
134 std::vector<const BigMemoryObject *> MEDCouplingUMesh::getDirectChildrenWithNull() const
136 std::vector<const BigMemoryObject *> ret(MEDCouplingPointSet::getDirectChildrenWithNull());
137 ret.push_back(_nodal_connec);
138 ret.push_back(_nodal_connec_index);
142 void MEDCouplingUMesh::updateTime() const
144 MEDCouplingPointSet::updateTime();
147 updateTimeWith(*_nodal_connec);
149 if(_nodal_connec_index)
151 updateTimeWith(*_nodal_connec_index);
155 MEDCouplingUMesh::MEDCouplingUMesh():_mesh_dim(-2),_nodal_connec(0),_nodal_connec_index(0)
160 * Checks if \a this mesh is well defined. If no exception is thrown by this method,
161 * then \a this mesh is most probably is writable, exchangeable and available for most
162 * of algorithms. When a mesh is constructed from scratch, it is a good habit to call
163 * this method to check that all is in order with \a this mesh.
164 * \throw If the mesh dimension is not set.
165 * \throw If the coordinates array is not set (if mesh dimension != -1 ).
166 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
167 * \throw If the connectivity data array has more than one component.
168 * \throw If the connectivity data array has a named component.
169 * \throw If the connectivity index data array has more than one component.
170 * \throw If the connectivity index data array has a named component.
172 void MEDCouplingUMesh::checkConsistencyLight() const
175 throw INTERP_KERNEL::Exception("No mesh dimension specified !");
177 MEDCouplingPointSet::checkConsistencyLight();
178 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
180 if(ToIdType(INTERP_KERNEL::CellModel::GetCellModel(*iter).getDimension())!=_mesh_dim)
182 std::ostringstream message;
183 message << "Mesh invalid because dimension is " << _mesh_dim << " and there is presence of cell(s) with type " << (*iter);
184 throw INTERP_KERNEL::Exception(message.str().c_str());
189 if(_nodal_connec->getNumberOfComponents()!=1)
190 throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to be with number of components set to one !");
191 if(_nodal_connec->getInfoOnComponent(0)!="")
192 throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to have no info on its single component !");
196 throw INTERP_KERNEL::Exception("Nodal connectivity array is not defined !");
197 if(_nodal_connec_index)
199 if(_nodal_connec_index->getNumberOfComponents()!=1)
200 throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to be with number of components set to one !");
201 if(_nodal_connec_index->getInfoOnComponent(0)!="")
202 throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to have no info on its single component !");
206 throw INTERP_KERNEL::Exception("Nodal connectivity index array is not defined !");
210 * Checks if \a this mesh is well defined. If no exception is thrown by this method,
211 * then \a this mesh is informatically clean, most probably is writable, exchangeable and available for all
212 * algorithms. <br> In addition to the checks performed by checkConsistencyLight(), this
213 * method thoroughly checks the nodal connectivity. For more geometrical checking
214 * checkGeomConsistency method is better than this.
216 * \sa MEDCouplingUMesh::checkGeomConsistency
218 * \param [in] eps - a not used parameter.
219 * \throw If the mesh dimension is not set.
220 * \throw If the coordinates array is not set (if mesh dimension != -1 ).
221 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
222 * \throw If the connectivity data array has more than one component.
223 * \throw If the connectivity data array has a named component.
224 * \throw If the connectivity index data array has more than one component.
225 * \throw If the connectivity index data array has a named component.
226 * \throw If number of nodes defining an element does not correspond to the type of element.
227 * \throw If the nodal connectivity includes an invalid node id.
229 void MEDCouplingUMesh::checkConsistency(double eps) const
231 checkConsistencyLight();
234 int meshDim=getMeshDimension();
235 mcIdType nbOfNodes=getNumberOfNodes();
236 mcIdType nbOfCells=getNumberOfCells();
237 const mcIdType *ptr=_nodal_connec->getConstPointer();
238 const mcIdType *ptrI=_nodal_connec_index->getConstPointer();
239 for(mcIdType i=0;i<nbOfCells;i++)
241 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)ptr[ptrI[i]]);
242 if(ToIdType(cm.getDimension())!=meshDim)
244 std::ostringstream oss;
245 oss << "MEDCouplingUMesh::checkConsistency : cell << #" << i<< " with type Type " << cm.getRepr() << " in 'this' whereas meshdim == " << meshDim << " !";
246 throw INTERP_KERNEL::Exception(oss.str());
248 mcIdType nbOfNodesInCell=ptrI[i+1]-ptrI[i]-1;
250 if(nbOfNodesInCell!=ToIdType(cm.getNumberOfNodes()))
252 std::ostringstream oss;
253 oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with static Type '" << cm.getRepr() << "' has " << cm.getNumberOfNodes();
254 oss << " nodes whereas in connectivity there is " << nbOfNodesInCell << " nodes ! Looks very bad !";
255 throw INTERP_KERNEL::Exception(oss.str());
257 if(cm.isQuadratic() && cm.isDynamic() && meshDim == 2)
258 if (nbOfNodesInCell % 2 || nbOfNodesInCell < 4)
260 std::ostringstream oss;
261 oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with quadratic type '" << cm.getRepr() << "' has " << nbOfNodesInCell;
262 oss << " nodes. This should be even, and greater or equal than 4!! Looks very bad!";
263 throw INTERP_KERNEL::Exception(oss.str());
265 for(const mcIdType *w=ptr+ptrI[i]+1;w!=ptr+ptrI[i+1];w++)
270 if(nodeId>=nbOfNodes)
272 std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " whereas there are only " << nbOfNodes << " nodes in the mesh !";
273 throw INTERP_KERNEL::Exception(oss.str());
278 std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " in connectivity ! sounds bad !";
279 throw INTERP_KERNEL::Exception(oss.str());
283 if((INTERP_KERNEL::NormalizedCellType)(ptr[ptrI[i]])!=INTERP_KERNEL::NORM_POLYHED)
285 std::ostringstream oss; oss << "Cell #" << i << " is built with node #-1 in connectivity ! sounds bad !";
286 throw INTERP_KERNEL::Exception(oss.str());
294 * This method adds some geometrical checks in addition to the informatical check of checkConsistency method.
295 * This method in particular checks that a same node is not repeated several times in a cell.
297 * \throw If there is a presence a multiple same node ID in nodal connectivity of cell.
299 void MEDCouplingUMesh::checkGeomConsistency(double eps) const
301 this->checkConsistency(eps);
302 auto nbOfCells(getNumberOfCells());
303 const mcIdType *ptr(_nodal_connec->begin()),*ptrI(_nodal_connec_index->begin());
304 for(auto icell = 0 ; icell < nbOfCells ; ++icell)
306 std::set<mcIdType> s(ptr+ptrI[icell]+1,ptr+ptrI[icell+1]);
307 if(ToIdType(s.size())==ptrI[icell+1]-ptrI[icell]-1)
309 std::ostringstream oss; oss << "MEDCouplingUMesh::checkGeomConsistency : for cell #" << icell << " presence of multiple same nodeID !";
310 throw INTERP_KERNEL::Exception(oss.str());
316 * Sets dimension of \a this mesh. The mesh dimension in general depends on types of
317 * elements contained in the mesh. For more info on the mesh dimension see
318 * \ref MEDCouplingUMeshPage.
319 * \param [in] meshDim - a new mesh dimension.
320 * \throw If \a meshDim is invalid. A valid range is <em> -1 <= meshDim <= 3</em>.
322 void MEDCouplingUMesh::setMeshDimension(int meshDim)
324 if(meshDim<-1 || meshDim>3)
325 throw INTERP_KERNEL::Exception("Invalid meshDim specified ! Must be greater or equal to -1 and lower or equal to 3 !");
331 * Allocates memory to store an estimation of the given number of cells.
332 * The closer the estimation to the number of cells effectively inserted, the less need the library requires
333 * to reallocate memory. If the number of cells to be inserted is not known simply assign 0 to this parameter.
334 * If a nodal connectivity previously existed before the call of this method, it will be reset.
336 * \param [in] nbOfCells - estimation of the number of cell \a this mesh will contain.
338 * \if ENABLE_EXAMPLES
339 * \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
340 * \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
343 void MEDCouplingUMesh::allocateCells(mcIdType nbOfCells)
346 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::allocateCells : the input number of cells should be >= 0 !");
347 if(_nodal_connec_index)
349 _nodal_connec_index->decrRef();
353 _nodal_connec->decrRef();
355 _nodal_connec_index=DataArrayIdType::New();
356 _nodal_connec_index->reserve(nbOfCells+1);
357 _nodal_connec_index->pushBackSilent(0);
358 _nodal_connec=DataArrayIdType::New();
359 _nodal_connec->reserve(2*nbOfCells);
365 * Appends a cell to the connectivity array. For deeper understanding what is
366 * happening see \ref MEDCouplingUMeshNodalConnectivity.
367 * \param [in] type - type of cell to add.
368 * \param [in] size - number of nodes constituting this cell.
369 * \param [in] nodalConnOfCell - the connectivity of the cell to add.
371 * \if ENABLE_EXAMPLES
372 * \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
373 * \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
376 void MEDCouplingUMesh::insertNextCell(INTERP_KERNEL::NormalizedCellType type, mcIdType size, const mcIdType *nodalConnOfCell)
378 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
379 if(_nodal_connec_index==0)
380 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::insertNextCell : nodal connectivity not set ! invoke allocateCells before calling insertNextCell !");
381 if(ToIdType(cm.getDimension())==_mesh_dim)
384 if(size!=ToIdType(cm.getNumberOfNodes()))
386 std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : Trying to push a " << cm.getRepr() << " cell with a size of " << size;
387 oss << " ! Expecting " << cm.getNumberOfNodes() << " !";
388 throw INTERP_KERNEL::Exception(oss.str());
390 mcIdType idx=_nodal_connec_index->back();
391 mcIdType val=idx+size+1;
392 _nodal_connec_index->pushBackSilent(val);
393 _nodal_connec->writeOnPlace(idx,type,nodalConnOfCell,size);
398 std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : cell type " << cm.getRepr() << " has a dimension " << cm.getDimension();
399 oss << " whereas Mesh Dimension of current UMesh instance is set to " << _mesh_dim << " ! Please invoke \"setMeshDimension\" method before or invoke ";
400 oss << "\"MEDCouplingUMesh::New\" static method with 2 parameters name and meshDimension !";
401 throw INTERP_KERNEL::Exception(oss.str());
406 * Compacts data arrays to release unused memory. This method is to be called after
407 * finishing cell insertion using \a this->insertNextCell().
409 * \if ENABLE_EXAMPLES
410 * \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
411 * \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
414 void MEDCouplingUMesh::finishInsertingCells()
416 _nodal_connec->pack();
417 _nodal_connec_index->pack();
418 _nodal_connec->declareAsNew();
419 _nodal_connec_index->declareAsNew();
424 * Entry point for iteration over cells of this. Warning the returned cell iterator should be deallocated.
425 * Useful for python users.
427 MEDCouplingUMeshCellIterator *MEDCouplingUMesh::cellIterator()
429 return new MEDCouplingUMeshCellIterator(this);
433 * Entry point for iteration over cells groups geo types per geotypes. Warning the returned cell iterator should be deallocated.
434 * If \a this is not so that the cells are grouped by geo types, this method will throw an exception.
435 * In this case MEDCouplingUMesh::sortCellsInMEDFileFrmt or MEDCouplingUMesh::rearrange2ConsecutiveCellTypes methods for example can be called before invoking this method.
436 * Useful for python users.
438 MEDCouplingUMeshCellByTypeEntry *MEDCouplingUMesh::cellsByType()
440 if(!checkConsecutiveCellTypes())
441 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::cellsByType : this mesh is not sorted by type !");
442 return new MEDCouplingUMeshCellByTypeEntry(this);
446 * Returns a set of all cell types available in \a this mesh.
447 * \return std::set<INTERP_KERNEL::NormalizedCellType> - the set of cell types.
448 * \warning this method does not throw any exception even if \a this is not defined.
449 * \sa MEDCouplingUMesh::getAllGeoTypesSorted
451 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypes() const
457 * This method returns the sorted list of geometric types in \a this.
458 * 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
459 * having the same geometric type. So a same geometric type can appear more than once if the cells are not sorted per geometric type.
461 * \throw if connectivity in \a this is not correctly defined.
463 * \sa MEDCouplingMesh::getAllGeoTypes
465 std::vector<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypesSorted() const
467 std::vector<INTERP_KERNEL::NormalizedCellType> ret;
468 checkConnectivityFullyDefined();
469 mcIdType nbOfCells=getNumberOfCells();
472 if(getNodalConnectivityArrayLen()<1)
473 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAllGeoTypesSorted : the connectivity in this seems invalid !");
474 const mcIdType *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin());
475 ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci++]);
476 for(mcIdType i=1;i<nbOfCells;i++,ci++)
477 if(ret.back()!=((INTERP_KERNEL::NormalizedCellType)c[*ci]))
478 ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci]);
483 * This method is a method that compares \a this and \a other.
484 * This method compares \b all attributes, even names and component names.
486 bool MEDCouplingUMesh::isEqualIfNotWhy(const MEDCouplingMesh *other, double prec, std::string& reason) const
489 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isEqualIfNotWhy : input other pointer is null !");
490 std::ostringstream oss; oss.precision(15);
491 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
494 reason="mesh given in input is not castable in MEDCouplingUMesh !";
497 if(!MEDCouplingPointSet::isEqualIfNotWhy(other,prec,reason))
499 if(_mesh_dim!=otherC->_mesh_dim)
501 oss << "umesh dimension mismatch : this mesh dimension=" << _mesh_dim << " other mesh dimension=" << otherC->_mesh_dim;
505 if(_types!=otherC->_types)
507 oss << "umesh geometric type mismatch :\nThis geometric types are :";
508 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
509 { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
510 oss << "\nOther geometric types are :";
511 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=otherC->_types.begin();iter!=otherC->_types.end();iter++)
512 { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
516 if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
517 if(_nodal_connec==0 || otherC->_nodal_connec==0)
519 reason="Only one UMesh between the two this and other has its nodal connectivity DataArrayInt defined !";
522 if(_nodal_connec!=otherC->_nodal_connec)
523 if(!_nodal_connec->isEqualIfNotWhy(*otherC->_nodal_connec,reason))
525 reason.insert(0,"Nodal connectivity DataArrayInt differ : ");
528 if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
529 if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
531 reason="Only one UMesh between the two this and other has its nodal connectivity index DataArrayInt defined !";
534 if(_nodal_connec_index!=otherC->_nodal_connec_index)
535 if(!_nodal_connec_index->isEqualIfNotWhy(*otherC->_nodal_connec_index,reason))
537 reason.insert(0,"Nodal connectivity index DataArrayInt differ : ");
544 * Checks if data arrays of this mesh (node coordinates, nodal
545 * connectivity of cells, etc) of two meshes are same. Textual data like name etc. are
547 * \param [in] other - the mesh to compare with.
548 * \param [in] prec - precision value used to compare node coordinates.
549 * \return bool - \a true if the two meshes are same.
551 bool MEDCouplingUMesh::isEqualWithoutConsideringStr(const MEDCouplingMesh *other, double prec) const
553 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
556 if(!MEDCouplingPointSet::isEqualWithoutConsideringStr(other,prec))
558 if(_mesh_dim!=otherC->_mesh_dim)
560 if(_types!=otherC->_types)
562 if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
563 if(_nodal_connec==0 || otherC->_nodal_connec==0)
565 if(_nodal_connec!=otherC->_nodal_connec)
566 if(!_nodal_connec->isEqualWithoutConsideringStr(*otherC->_nodal_connec))
568 if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
569 if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
571 if(_nodal_connec_index!=otherC->_nodal_connec_index)
572 if(!_nodal_connec_index->isEqualWithoutConsideringStr(*otherC->_nodal_connec_index))
578 * Checks if \a this and \a other meshes are geometrically equivalent with high
579 * probability, else an exception is thrown. The meshes are considered equivalent if
580 * (1) meshes contain the same number of nodes and the same number of elements of the
581 * same types (2) three cells of the two meshes (first, last and middle) are based
582 * on coincident nodes (with a specified precision).
583 * \param [in] other - the mesh to compare with.
584 * \param [in] prec - the precision used to compare nodes of the two meshes.
585 * \throw If the two meshes do not match.
587 void MEDCouplingUMesh::checkFastEquivalWith(const MEDCouplingMesh *other, double prec) const
589 MEDCouplingPointSet::checkFastEquivalWith(other,prec);
590 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
592 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkFastEquivalWith : Two meshes are not not unstructured !");
596 * Returns the reverse nodal connectivity. The reverse nodal connectivity enumerates
597 * cells each node belongs to.
598 * \warning For speed reasons, this method does not check if node ids in the nodal
599 * connectivity correspond to the size of node coordinates array.
600 * \param [in,out] revNodal - an array holding ids of cells sharing each node.
601 * \param [in,out] revNodalIndx - an array, of length \a this->getNumberOfNodes() + 1,
602 * dividing cell ids in \a revNodal into groups each referring to one
603 * node. Its every element (except the last one) is an index pointing to the
604 * first id of a group of cells. For example cells sharing the node #1 are
605 * described by following range of indices:
606 * [ \a revNodalIndx[1], \a revNodalIndx[2] ) and the cell ids are
607 * \a revNodal[ \a revNodalIndx[1] ], \a revNodal[ \a revNodalIndx[1] + 1], ...
608 * Number of cells sharing the *i*-th node is
609 * \a revNodalIndx[ *i*+1 ] - \a revNodalIndx[ *i* ].
610 * \throw If the coordinates array is not set.
611 * \throw If the nodal connectivity of cells is not defined.
613 * \if ENABLE_EXAMPLES
614 * \ref cpp_mcumesh_getReverseNodalConnectivity "Here is a C++ example".<br>
615 * \ref py_mcumesh_getReverseNodalConnectivity "Here is a Python example".
618 void MEDCouplingUMesh::getReverseNodalConnectivity(DataArrayIdType *revNodal, DataArrayIdType *revNodalIndx) const
621 mcIdType nbOfNodes(getNumberOfNodes());
622 mcIdType *revNodalIndxPtr=(mcIdType *)malloc((nbOfNodes+1)*sizeof(mcIdType));
623 revNodalIndx->useArray(revNodalIndxPtr,true,DeallocType::C_DEALLOC,nbOfNodes+1,1);
624 std::fill(revNodalIndxPtr,revNodalIndxPtr+nbOfNodes+1,0);
625 const mcIdType *conn(_nodal_connec->begin()),*connIndex(_nodal_connec_index->begin());
626 mcIdType nbOfCells(getNumberOfCells()),nbOfEltsInRevNodal(0);
627 for(mcIdType eltId=0;eltId<nbOfCells;eltId++)
629 const mcIdType *strtNdlConnOfCurCell(conn+connIndex[eltId]+1),*endNdlConnOfCurCell(conn+connIndex[eltId+1]);
630 for(const mcIdType *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
631 if(*iter>=0)//for polyhedrons
633 nbOfEltsInRevNodal++;
634 revNodalIndxPtr[(*iter)+1]++;
637 std::transform(revNodalIndxPtr+1,revNodalIndxPtr+nbOfNodes+1,revNodalIndxPtr,revNodalIndxPtr+1,std::plus<mcIdType>());
638 mcIdType *revNodalPtr=(mcIdType *)malloc(nbOfEltsInRevNodal*sizeof(mcIdType));
639 revNodal->useArray(revNodalPtr,true,DeallocType::C_DEALLOC,nbOfEltsInRevNodal,1);
640 std::fill(revNodalPtr,revNodalPtr+nbOfEltsInRevNodal,-1);
641 for(mcIdType eltId=0;eltId<nbOfCells;eltId++)
643 const mcIdType *strtNdlConnOfCurCell=conn+connIndex[eltId]+1;
644 const mcIdType *endNdlConnOfCurCell=conn+connIndex[eltId+1];
645 for(const mcIdType *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
646 if(*iter>=0)//for polyhedrons
647 *std::find_if(revNodalPtr+revNodalIndxPtr[*iter],revNodalPtr+revNodalIndxPtr[*iter+1],std::bind(std::equal_to<mcIdType>(),std::placeholders::_1,-1))=eltId;
652 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
653 * this->getMeshDimension(), that bound cells of \a this mesh. In addition arrays
654 * describing correspondence between cells of \a this and the result meshes are
655 * returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending connectivity,
656 * i.e. enumerate cells of the result mesh bounding each cell of \a this mesh. The
657 * arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
658 * i.e. enumerate cells of \a this mesh bounded by each cell of the result mesh.
659 * \warning For speed reasons, this method does not check if node ids in the nodal
660 * connectivity correspond to the size of node coordinates array.
661 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
662 * to write this mesh to the MED file, its cells must be sorted using
663 * sortCellsInMEDFileFrmt().
664 * \param [in,out] desc - the array containing cell ids of the result mesh bounding
665 * each cell of \a this mesh.
666 * \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
667 * dividing cell ids in \a desc into groups each referring to one
668 * cell of \a this mesh. Its every element (except the last one) is an index
669 * pointing to the first id of a group of cells. For example cells of the
670 * result mesh bounding the cell #1 of \a this mesh are described by following
672 * [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
673 * \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
674 * Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
675 * \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
676 * \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
677 * by each cell of the result mesh.
678 * \param [in,out] revDescIndx - the array, of length one more than number of cells
679 * in the result mesh,
680 * dividing cell ids in \a revDesc into groups each referring to one
681 * cell of the result mesh the same way as \a descIndx divides \a desc.
682 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is to
683 * delete this mesh using decrRef() as it is no more needed.
684 * \throw If the coordinates array is not set.
685 * \throw If the nodal connectivity of cells is node defined.
686 * \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
687 * revDescIndx == NULL.
689 * \if ENABLE_EXAMPLES
690 * \ref cpp_mcumesh_buildDescendingConnectivity "Here is a C++ example".<br>
691 * \ref py_mcumesh_buildDescendingConnectivity "Here is a Python example".
693 * \sa buildDescendingConnectivity2()
695 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
697 return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
701 * \a this has to have a mesh dimension equal to 3. If it is not the case an INTERP_KERNEL::Exception will be thrown.
702 * This behaves exactly as MEDCouplingUMesh::buildDescendingConnectivity does except that this method compute directly the transition from mesh dimension 3 to sub edges (dimension 1)
703 * in one shot. That is to say that this method is equivalent to 2 successive calls to MEDCouplingUMesh::buildDescendingConnectivity.
704 * This method returns 4 arrays and a mesh as MEDCouplingUMesh::buildDescendingConnectivity does.
705 * \sa MEDCouplingUMesh::buildDescendingConnectivity
707 MEDCouplingUMesh *MEDCouplingUMesh::explode3DMeshTo1D(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
710 if(getMeshDimension()!=3)
711 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explode3DMeshTo1D : This has to have a mesh dimension to 3 !");
712 return buildDescendingConnectivityGen<MinusTwoSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
716 * 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.
717 * This method works for both meshes with mesh dimension equal to 2 or 3. Dynamical cells are not supported (polygons, polyhedrons...)
719 * \sa explode3DMeshTo1D, buildDescendingConnectiviy
721 MEDCouplingUMesh *MEDCouplingUMesh::explodeMeshIntoMicroEdges(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
724 switch(getMeshDimension())
727 return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
729 return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
731 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explodeMeshIntoMicroEdges : Only 2D and 3D supported !");
736 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
737 * this->getMeshDimension(), that bound cells of \a this mesh. In
738 * addition arrays describing correspondence between cells of \a this and the result
739 * meshes are returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending
740 * connectivity, i.e. enumerate cells of the result mesh bounding each cell of \a this
741 * mesh. This method differs from buildDescendingConnectivity() in that apart
742 * from cell ids, \a desc returns mutual orientation of cells in \a this and the
743 * result meshes. So a positive id means that order of nodes in corresponding cells
744 * of two meshes is same, and a negative id means a reverse order of nodes. Since a
745 * cell with id #0 can't be negative, the array \a desc returns ids in FORTRAN mode,
746 * i.e. cell ids are one-based.
747 * Arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
748 * i.e. enumerate cells of \a this mesh bounded by each cell of the result mesh.
749 * \warning For speed reasons, this method does not check if node ids in the nodal
750 * connectivity correspond to the size of node coordinates array.
751 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
752 * to write this mesh to the MED file, its cells must be sorted using
753 * sortCellsInMEDFileFrmt().
754 * \param [in,out] desc - the array containing cell ids of the result mesh bounding
755 * each cell of \a this mesh.
756 * \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
757 * dividing cell ids in \a desc into groups each referring to one
758 * cell of \a this mesh. Its every element (except the last one) is an index
759 * pointing to the first id of a group of cells. For example cells of the
760 * result mesh bounding the cell #1 of \a this mesh are described by following
762 * [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
763 * \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
764 * Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
765 * \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
766 * \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
767 * by each cell of the result mesh.
768 * \param [in,out] revDescIndx - the array, of length one more than number of cells
769 * in the result mesh,
770 * dividing cell ids in \a revDesc into groups each referring to one
771 * cell of the result mesh the same way as \a descIndx divides \a desc.
772 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This result mesh
773 * shares the node coordinates array with \a this mesh. The caller is to
774 * delete this mesh using decrRef() as it is no more needed.
775 * \throw If the coordinates array is not set.
776 * \throw If the nodal connectivity of cells is node defined.
777 * \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
778 * revDescIndx == NULL.
780 * \if ENABLE_EXAMPLES
781 * \ref cpp_mcumesh_buildDescendingConnectivity2 "Here is a C++ example".<br>
782 * \ref py_mcumesh_buildDescendingConnectivity2 "Here is a Python example".
784 * \sa buildDescendingConnectivity()
786 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity2(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
788 return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingOrientationSensitiveNbrer);
792 * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
793 * For speed reasons no check of this will be done. This method calls
794 * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
795 * This method lists for every cell in \b this its neighbor \b cells. To compute the result
796 * only connectivities are considered.
797 * The neighbor cells of a given cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
798 * The format of return is hence \ref numbering-indirect.
800 * \param [out] neighbors is an array storing all the neighbors of all cells in \b this. This array is newly
801 * allocated and should be dealt by the caller. \b neighborsIndx 2nd output
802 * parameter allows to select the right part in this array (\ref numbering-indirect). The number of tuples
803 * is equal to the last values in \b neighborsIndx.
804 * \param [out] neighborsIndx is an array of size this->getNumberOfCells()+1 newly allocated and should be
805 * dealt by the caller. This arrays allow to use the first output parameter \b neighbors (\ref numbering-indirect).
807 void MEDCouplingUMesh::computeNeighborsOfCells(DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIndx) const
809 MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
810 MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
811 MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
812 MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
813 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
815 ComputeNeighborsOfCellsAdv(desc,descIndx,revDesc,revDescIndx,neighbors,neighborsIndx);
819 * Given a set of identifiers indexed by the node IDs of the mesh (and given in the (\ref numbering-indirect format) ,
820 * re-arrange the data to produce a set indexed by cell IDs. The mapping between a node ID and a cell ID is done using the connectivity
821 * of the mesh (e.g. a triangular element will receive the information from its three vertices).
822 * Doublons are eliminated. If present in the inital dataset, the ID of the cell itself is also remooved.
824 * \param [in] nodeNeigh a set of identifiers (mcIdType) stored by node index (\ref numbering-indirect format)
825 * \param [in] nodeNeighI a set of identifiers (mcIdType) stored by node index (\ref numbering-indirect format)
826 * \param [out] cellNeigh This array is newly allocated and should be dealt by the caller. It contains the initial identifiers
827 * provided in the input parameters but stored now by cell index (See 2nd output parameter and \ref numbering-indirect).
828 * \param [out] cellNeighI is an array of size this->getNumberOfCells()+1 newly allocated and should be
829 * dealt by the caller. This arrays allow to use the first output parameter \b neighbors (\ref numbering-indirect).
831 * \raise if the number of tuples in nodeNeighI is not equal to the number of nodes in the mesh.
833 void MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne(const DataArrayIdType *nodeNeigh, const DataArrayIdType *nodeNeighI,
834 MCAuto<DataArrayIdType>& cellNeigh, MCAuto<DataArrayIdType>& cellNeighIndex) const
836 if(!nodeNeigh || !nodeNeighI)
837 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : null pointer !");
838 checkConsistencyLight();
839 nodeNeigh->checkAllocated(); nodeNeighI->checkAllocated();
840 nodeNeigh->checkNbOfComps(1,"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : node neigh");
841 nodeNeighI->checkNbOfComps(1,"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : node neigh index");
842 nodeNeighI->checkNbOfTuples(1+getNumberOfNodes(),"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : invalid length");
843 mcIdType nbCells=getNumberOfCells();
844 const mcIdType *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin()),*ne(nodeNeigh->begin()),*nei(nodeNeighI->begin());
845 cellNeigh=DataArrayIdType::New(); cellNeigh->alloc(0,1); cellNeighIndex=DataArrayIdType::New(); cellNeighIndex->alloc(1,1); cellNeighIndex->setIJ(0,0,0);
846 for(mcIdType i=0;i<nbCells;i++)
848 std::set<mcIdType> s;
849 for(const mcIdType *it=c+ci[i]+1;it!=c+ci[i+1];it++)
850 if(*it>=0) // avoid -1 in polygons or polyedrons
851 s.insert(ne+nei[*it],ne+nei[*it+1]);
853 cellNeigh->insertAtTheEnd(s.begin(),s.end());
854 cellNeighIndex->pushBackSilent(cellNeigh->getNumberOfTuples());
859 * This method is called by MEDCouplingUMesh::computeNeighborsOfCells. This methods performs the algorithm
860 * of MEDCouplingUMesh::computeNeighborsOfCells.
861 * This method is useful for users that want to reduce along a criterion the set of neighbours cell. This is
862 * typically the case to extract a set a neighbours,
863 * excluding a set of meshdim-1 cells in input descending connectivity.
864 * Typically \b desc, \b descIndx, \b revDesc and \b revDescIndx (\ref numbering-indirect) input params are
865 * the result of MEDCouplingUMesh::buildDescendingConnectivity.
866 * This method lists cell by cell in \b this which are its neighbors. To compute the result only connectivities
868 * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
870 * \param [in] desc descending connectivity array.
871 * \param [in] descIndx descending connectivity index array used to walk through \b desc (\ref numbering-indirect).
872 * \param [in] revDesc reverse descending connectivity array.
873 * \param [in] revDescIndx reverse descending connectivity index array used to walk through \b revDesc (\ref numbering-indirect).
874 * \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
875 * parameter allows to select the right part in this array. The number of tuples is equal to the last values in \b neighborsIndx.
876 * \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.
878 void MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(const DataArrayIdType *desc, const DataArrayIdType *descIndx, const DataArrayIdType *revDesc, const DataArrayIdType *revDescIndx,
879 DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIndx)
881 if(!desc || !descIndx || !revDesc || !revDescIndx)
882 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeNeighborsOfCellsAdv some input array is empty !");
883 const mcIdType *descPtr=desc->begin();
884 const mcIdType *descIPtr=descIndx->begin();
885 const mcIdType *revDescPtr=revDesc->begin();
886 const mcIdType *revDescIPtr=revDescIndx->begin();
888 mcIdType nbCells=descIndx->getNumberOfTuples()-1;
889 MCAuto<DataArrayIdType> out0=DataArrayIdType::New();
890 MCAuto<DataArrayIdType> out1=DataArrayIdType::New(); out1->alloc(nbCells+1,1);
891 mcIdType *out1Ptr=out1->getPointer();
893 out0->reserve(desc->getNumberOfTuples());
894 for(mcIdType i=0;i<nbCells;i++,descIPtr++,out1Ptr++)
896 for(const mcIdType *w1=descPtr+descIPtr[0];w1!=descPtr+descIPtr[1];w1++)
898 std::set<mcIdType> s(revDescPtr+revDescIPtr[*w1],revDescPtr+revDescIPtr[(*w1)+1]);
900 out0->insertAtTheEnd(s.begin(),s.end());
902 *out1Ptr=out0->getNumberOfTuples();
904 neighbors=out0.retn();
905 neighborsIndx=out1.retn();
909 * Explodes \a this into edges whatever its dimension.
911 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::explodeIntoEdges(MCAuto<DataArrayIdType>& desc, MCAuto<DataArrayIdType>& descIndex, MCAuto<DataArrayIdType>& revDesc, MCAuto<DataArrayIdType>& revDescIndx) const
914 int mdim(getMeshDimension());
915 desc=DataArrayIdType::New(); descIndex=DataArrayIdType::New(); revDesc=DataArrayIdType::New(); revDescIndx=DataArrayIdType::New();
916 MCAuto<MEDCouplingUMesh> mesh1D;
921 mesh1D=explode3DMeshTo1D(desc,descIndex,revDesc,revDescIndx);
926 mesh1D=buildDescendingConnectivity(desc,descIndex,revDesc,revDescIndx);
931 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2] !");
938 * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
939 * For speed reasons no check of this will be done. This method calls
940 * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
941 * This method lists for every node in \b this its neighbor \b nodes. To compute the result
942 * only connectivities are considered.
943 * The neighbor nodes of node having id 'nodeId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
945 * \param [out] neighbors is an array storing all the neighbors of all nodes in \b this. This array
946 * is newly allocated and should be dealt by the caller. \b neighborsIndx 2nd output
947 * parameter allows to select the right part in this array (\ref numbering-indirect).
948 * The number of tuples is equal to the last values in \b neighborsIndx.
949 * \param [out] neighborsIdx is an array of size this->getNumberOfCells()+1 newly allocated and should
950 * be dealt by the caller. This arrays allow to use the first output parameter \b neighbors.
952 * \sa MEDCouplingUMesh::computeEnlargedNeighborsOfNodes
954 void MEDCouplingUMesh::computeNeighborsOfNodes(DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIdx) const
957 mcIdType mdim(getMeshDimension()),nbNodes(getNumberOfNodes());
958 MCAuto<DataArrayIdType> desc(DataArrayIdType::New()),descIndx(DataArrayIdType::New()),revDesc(DataArrayIdType::New()),revDescIndx(DataArrayIdType::New());
959 MCConstAuto<MEDCouplingUMesh> mesh1D;
964 mesh1D=explode3DMeshTo1D(desc,descIndx,revDesc,revDescIndx);
969 mesh1D=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
974 mesh1D.takeRef(this);
979 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2,1] !");
982 desc=DataArrayIdType::New(); descIndx=DataArrayIdType::New(); revDesc=0; revDescIndx=0;
983 mesh1D->getReverseNodalConnectivity(desc,descIndx);
984 MCAuto<DataArrayIdType> ret0(DataArrayIdType::New());
985 ret0->alloc(desc->getNumberOfTuples(),1);
986 mcIdType *r0Pt(ret0->getPointer());
987 const mcIdType *c1DPtr(mesh1D->getNodalConnectivity()->begin()),*rn(desc->begin()),*rni(descIndx->begin());
988 for(mcIdType i=0;i<nbNodes;i++,rni++)
990 for(const mcIdType *oneDCellIt=rn+rni[0];oneDCellIt!=rn+rni[1];oneDCellIt++)
991 *r0Pt++=c1DPtr[3*(*oneDCellIt)+1]==i?c1DPtr[3*(*oneDCellIt)+2]:c1DPtr[3*(*oneDCellIt)+1];
993 neighbors=ret0.retn();
994 neighborsIdx=descIndx.retn();
998 * Computes enlarged neighbors for each nodes in \a this. The behavior of this method is close to MEDCouplingUMesh::computeNeighborsOfNodes except that the neighborhood of each node is wider here.
999 * A node j is considered to be in the neighborhood of i if and only if there is a cell in \a this containing in its nodal connectivity both i and j.
1000 * This method is useful to find ghost cells of a part of a mesh with a code based on fields on nodes.
1002 * \sa MEDCouplingUMesh::computeNeighborsOfNodes
1004 void MEDCouplingUMesh::computeEnlargedNeighborsOfNodes(MCAuto<DataArrayIdType> &neighbors, MCAuto<DataArrayIdType>& neighborsIdx) const
1006 checkFullyDefined();
1007 mcIdType nbOfNodes(getNumberOfNodes());
1008 const mcIdType *conn(_nodal_connec->begin()),*connIndex(_nodal_connec_index->begin());
1009 mcIdType nbOfCells=getNumberOfCells();
1010 std::vector< std::set<mcIdType> > st0(nbOfNodes);
1011 for(mcIdType eltId=0;eltId<nbOfCells;eltId++)
1013 const mcIdType *strtNdlConnOfCurCell(conn+connIndex[eltId]+1),*endNdlConnOfCurCell(conn+connIndex[eltId+1]);
1014 std::set<mcIdType> s(strtNdlConnOfCurCell,endNdlConnOfCurCell); s.erase(-1); //for polyhedrons
1015 for(std::set<mcIdType>::const_iterator iter2=s.begin();iter2!=s.end();iter2++)
1016 st0[*iter2].insert(s.begin(),s.end());
1018 neighborsIdx=DataArrayIdType::New(); neighborsIdx->alloc(nbOfNodes+1,1); neighborsIdx->setIJ(0,0,0);
1020 mcIdType *neighIdx(neighborsIdx->getPointer());
1021 for(std::vector< std::set<mcIdType> >::const_iterator it=st0.begin();it!=st0.end();it++,neighIdx++)
1024 neighIdx[1]=neighIdx[0];
1026 neighIdx[1]=neighIdx[0]+ToIdType((*it).size())-1;
1029 neighbors=DataArrayIdType::New(); neighbors->alloc(neighborsIdx->back(),1);
1031 const mcIdType *neighIdx(neighborsIdx->begin());
1032 mcIdType *neigh(neighbors->getPointer()),nodeId(0);
1033 for(std::vector< std::set<mcIdType> >::const_iterator it=st0.begin();it!=st0.end();it++,neighIdx++,nodeId++)
1035 std::set<mcIdType> s(*it); s.erase(nodeId);
1036 std::copy(s.begin(),s.end(),neigh+*neighIdx);
1042 * Converts specified cells to either polygons (if \a this is a 2D mesh) or
1043 * polyhedrons (if \a this is a 3D mesh). The cells to convert are specified by an
1044 * array of cell ids. Pay attention that after conversion all algorithms work slower
1045 * with \a this mesh than before conversion. <br> If an exception is thrown during the
1046 * conversion due presence of invalid ids in the array of cells to convert, as a
1047 * result \a this mesh contains some already converted elements. In this case the 2D
1048 * mesh remains valid but 3D mesh becomes \b inconsistent!
1049 * \warning This method can significantly modify the order of geometric types in \a this,
1050 * hence, to write this mesh to the MED file, its cells must be sorted using
1051 * sortCellsInMEDFileFrmt().
1052 * \param [in] cellIdsToConvertBg - the array holding ids of cells to convert.
1053 * \param [in] cellIdsToConvertEnd - a pointer to the last-plus-one-th element of \a
1054 * cellIdsToConvertBg.
1055 * \throw If the coordinates array is not set.
1056 * \throw If the nodal connectivity of cells is node defined.
1057 * \throw If dimension of \a this mesh is not either 2 or 3.
1059 * \if ENABLE_EXAMPLES
1060 * \ref cpp_mcumesh_convertToPolyTypes "Here is a C++ example".<br>
1061 * \ref py_mcumesh_convertToPolyTypes "Here is a Python example".
1064 void MEDCouplingUMesh::convertToPolyTypes(const mcIdType *cellIdsToConvertBg, const mcIdType *cellIdsToConvertEnd)
1066 checkFullyDefined();
1067 int dim=getMeshDimension();
1069 throw INTERP_KERNEL::Exception("Invalid mesh dimension : must be 2 or 3 !");
1070 mcIdType nbOfCells=getNumberOfCells();
1073 const mcIdType *connIndex=_nodal_connec_index->begin();
1074 mcIdType *conn=_nodal_connec->getPointer();
1075 for(const mcIdType *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1077 if(*iter>=0 && *iter<nbOfCells)
1079 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*iter]]);
1080 if(!cm.isQuadratic())
1081 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_POLYGON;
1083 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_QPOLYG;
1087 std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1088 oss << " in range [0," << nbOfCells << ") !";
1089 throw INTERP_KERNEL::Exception(oss.str());
1095 mcIdType *connIndex(_nodal_connec_index->getPointer());
1096 const mcIdType *connOld(_nodal_connec->getConstPointer());
1097 MCAuto<DataArrayIdType> connNew(DataArrayIdType::New()),connNewI(DataArrayIdType::New()); connNew->alloc(0,1); connNewI->alloc(1,1); connNewI->setIJ(0,0,0);
1098 std::vector<bool> toBeDone(nbOfCells,false);
1099 for(const mcIdType *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1101 if(*iter>=0 && *iter<nbOfCells)
1102 toBeDone[*iter]=true;
1105 std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1106 oss << " in range [0," << nbOfCells << ") !";
1107 throw INTERP_KERNEL::Exception(oss.str());
1110 for(mcIdType cellId=0;cellId<nbOfCells;cellId++)
1112 mcIdType pos(connIndex[cellId]),posP1(connIndex[cellId+1]);
1113 mcIdType lgthOld(posP1-pos-1);
1114 if(toBeDone[cellId])
1116 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connOld[pos]);
1117 unsigned nbOfFaces(cm.getNumberOfSons2(connOld+pos+1,lgthOld));
1118 mcIdType *tmp(new mcIdType[nbOfFaces*lgthOld+1]);
1119 mcIdType *work=tmp; *work++=INTERP_KERNEL::NORM_POLYHED;
1120 for(unsigned j=0;j<nbOfFaces;j++)
1122 INTERP_KERNEL::NormalizedCellType type;
1123 unsigned offset=cm.fillSonCellNodalConnectivity2(j,connOld+pos+1,lgthOld,work,type);
1127 std::size_t newLgth(std::distance(tmp,work)-1);//-1 for last -1
1128 connNew->pushBackValsSilent(tmp,tmp+newLgth);
1129 connNewI->pushBackSilent(connNewI->back()+ToIdType(newLgth));
1134 connNew->pushBackValsSilent(connOld+pos,connOld+posP1);
1135 connNewI->pushBackSilent(connNewI->back()+posP1-pos);
1138 setConnectivity(connNew,connNewI,false);//false because computeTypes called just behind.
1144 * Converts all cells to either polygons (if \a this is a 2D mesh) or
1145 * polyhedrons (if \a this is a 3D mesh).
1146 * \warning As this method is purely for user-friendliness and no optimization is
1147 * done to avoid construction of a useless vector, this method can be costly
1149 * \throw If the coordinates array is not set.
1150 * \throw If the nodal connectivity of cells is node defined.
1151 * \throw If dimension of \a this mesh is not either 2 or 3.
1153 void MEDCouplingUMesh::convertAllToPoly()
1155 mcIdType nbOfCells=getNumberOfCells();
1156 std::vector<mcIdType> cellIds(nbOfCells);
1157 for(mcIdType i=0;i<nbOfCells;i++)
1159 convertToPolyTypes(&cellIds[0],&cellIds[0]+ToIdType(cellIds.size()));
1163 * Fixes nodal connectivity of invalid cells of type NORM_POLYHED. This method
1164 * expects that all NORM_POLYHED cells have connectivity similar to that of prismatic
1165 * volumes like NORM_HEXA8, NORM_PENTA6 etc., i.e. the first half of nodes describes a
1166 * base facet of the volume and the second half of nodes describes an opposite facet
1167 * having the same number of nodes as the base one. This method converts such
1168 * connectivity to a valid polyhedral format where connectivity of each facet is
1169 * explicitly described and connectivity of facets are separated by -1. If \a this mesh
1170 * contains a NORM_POLYHED cell with a valid connectivity, or an invalid connectivity is
1171 * not as expected, an exception is thrown and the mesh remains unchanged. Care of
1172 * a correct orientation of the first facet of a polyhedron, else orientation of a
1173 * corrected cell is reverse.<br>
1174 * This method is useful to build an extruded unstructured mesh with polyhedrons as
1175 * it releases the user from boring description of polyhedra connectivity in the valid
1177 * \throw If \a this->getMeshDimension() != 3.
1178 * \throw If \a this->getSpaceDimension() != 3.
1179 * \throw If the nodal connectivity of cells is not defined.
1180 * \throw If the coordinates array is not set.
1181 * \throw If \a this mesh contains polyhedrons with the valid connectivity.
1182 * \throw If \a this mesh contains polyhedrons with odd number of nodes.
1184 * \if ENABLE_EXAMPLES
1185 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
1186 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
1189 void MEDCouplingUMesh::convertExtrudedPolyhedra()
1191 checkFullyDefined();
1192 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1193 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertExtrudedPolyhedra works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
1194 mcIdType nbOfCells=getNumberOfCells();
1195 MCAuto<DataArrayIdType> newCi=DataArrayIdType::New();
1196 newCi->alloc(nbOfCells+1,1);
1197 mcIdType *newci=newCi->getPointer();
1198 const mcIdType *ci=_nodal_connec_index->getConstPointer();
1199 const mcIdType *c=_nodal_connec->getConstPointer();
1201 for(mcIdType i=0;i<nbOfCells;i++)
1203 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1204 if(type==INTERP_KERNEL::NORM_POLYHED)
1206 if(std::count(c+ci[i]+1,c+ci[i+1],-1)!=0)
1208 std::ostringstream oss; oss << "MEDCouplingUMesh::convertExtrudedPolyhedra : cell # " << i << " is a polhedron BUT it has NOT exactly 1 face !";
1209 throw INTERP_KERNEL::Exception(oss.str());
1211 std::size_t n2=std::distance(c+ci[i]+1,c+ci[i+1]);
1214 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 !";
1215 throw INTERP_KERNEL::Exception(oss.str());
1217 mcIdType n1=ToIdType(n2/2);
1218 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)
1221 newci[i+1]=(ci[i+1]-ci[i])+newci[i];
1223 MCAuto<DataArrayIdType> newC=DataArrayIdType::New();
1224 newC->alloc(newci[nbOfCells],1);
1225 mcIdType *newc=newC->getPointer();
1226 for(mcIdType i=0;i<nbOfCells;i++)
1228 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1229 if(type==INTERP_KERNEL::NORM_POLYHED)
1231 std::size_t n1=std::distance(c+ci[i]+1,c+ci[i+1])/2;
1232 newc=std::copy(c+ci[i],c+ci[i]+n1+1,newc);
1234 for(std::size_t j=0;j<n1;j++)
1236 newc[j]=c[ci[i]+1+n1+(n1-j)%n1];
1238 newc[n1+5*j+1]=c[ci[i]+1+j];
1239 newc[n1+5*j+2]=c[ci[i]+1+j+n1];
1240 newc[n1+5*j+3]=c[ci[i]+1+(j+1)%n1+n1];
1241 newc[n1+5*j+4]=c[ci[i]+1+(j+1)%n1];
1246 newc=std::copy(c+ci[i],c+ci[i+1],newc);
1248 _nodal_connec_index->decrRef(); _nodal_connec_index=newCi.retn();
1249 _nodal_connec->decrRef(); _nodal_connec=newC.retn();
1254 * Converts all polygons (if \a this is a 2D mesh) or polyhedrons (if \a this is a 3D
1255 * mesh) to cells of classical types. This method is opposite to convertToPolyTypes().
1256 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
1257 * to write this mesh to the MED file, its cells must be sorted using
1258 * sortCellsInMEDFileFrmt().
1259 * \warning Cells (and most notably polyhedrons) must be correctly oriented for this to work
1260 * properly. See orientCorrectlyPolyhedrons() and arePolyhedronsNotCorrectlyOriented().
1261 * \return \c true if at least one cell has been converted, \c false else. In the
1262 * last case the nodal connectivity remains unchanged.
1263 * \throw If the coordinates array is not set.
1264 * \throw If the nodal connectivity of cells is not defined.
1265 * \throw If \a this->getMeshDimension() < 0.
1267 bool MEDCouplingUMesh::unPolyze()
1269 checkFullyDefined();
1270 int mdim=getMeshDimension();
1272 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::unPolyze works on umeshes with meshdim equals to 0, 1 2 or 3 !");
1275 mcIdType nbOfCells=getNumberOfCells();
1278 mcIdType initMeshLgth=getNodalConnectivityArrayLen();
1279 mcIdType *conn=_nodal_connec->getPointer();
1280 mcIdType *index=_nodal_connec_index->getPointer();
1281 mcIdType posOfCurCell=0;
1283 mcIdType lgthOfCurCell;
1285 for(mcIdType i=0;i<nbOfCells;i++)
1287 lgthOfCurCell=index[i+1]-posOfCurCell;
1288 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
1289 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
1290 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::NORM_ERROR;
1294 switch(cm.getDimension())
1298 INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[lgthOfCurCell-1];
1299 std::copy(conn+posOfCurCell+1,conn+posOfCurCell+lgthOfCurCell,(mcIdType *)tmp);
1300 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly2D(cm.isQuadratic(),tmp,lgthOfCurCell-1,conn+newPos+1,newLgth);
1305 mcIdType nbOfFaces,lgthOfPolyhConn;
1306 INTERP_KERNEL::AutoPtr<mcIdType> zipFullReprOfPolyh=INTERP_KERNEL::CellSimplify::getFullPolyh3DCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,nbOfFaces,lgthOfPolyhConn);
1307 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly3D(zipFullReprOfPolyh,nbOfFaces,lgthOfPolyhConn,conn+newPos+1,newLgth);
1310 /* case 1: // Not supported yet
1312 newType=(lgthOfCurCell==3)?INTERP_KERNEL::NORM_SEG2:INTERP_KERNEL::NORM_POLYL;
1317 ret=ret || (newType!=type);
1318 conn[newPos]=newType;
1320 posOfCurCell=index[i+1];
1325 std::copy(conn+posOfCurCell,conn+posOfCurCell+lgthOfCurCell,conn+newPos);
1326 newPos+=lgthOfCurCell;
1327 posOfCurCell+=lgthOfCurCell;
1331 if(newPos!=initMeshLgth)
1332 _nodal_connec->reAlloc(newPos);
1339 * This method expects that spaceDimension is equal to 3 and meshDimension equal to 3.
1340 * This method performs operation only on polyhedrons in \b this. If no polyhedrons exists in \b this, \b this remains unchanged.
1341 * This method allows to merge if any coplanar 3DSurf cells that may appear in some polyhedrons cells.
1343 * \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
1346 void MEDCouplingUMesh::simplifyPolyhedra(double eps)
1348 checkFullyDefined();
1349 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1350 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplifyPolyhedra : works on meshdimension 3 and spaceDimension 3 !");
1351 MCAuto<DataArrayDouble> coords=getCoords()->deepCopy();
1352 coords->recenterForMaxPrecision(eps);
1354 mcIdType nbOfCells=getNumberOfCells();
1355 const mcIdType *conn=_nodal_connec->getConstPointer();
1356 const mcIdType *index=_nodal_connec_index->getConstPointer();
1357 MCAuto<DataArrayIdType> connINew=DataArrayIdType::New();
1358 connINew->alloc(nbOfCells+1,1);
1359 mcIdType *connINewPtr=connINew->getPointer(); *connINewPtr++=0;
1360 MCAuto<DataArrayIdType> connNew=DataArrayIdType::New(); connNew->alloc(0,1);
1361 MCAuto<DataArrayIdType> E_Fi(DataArrayIdType::New()), E_F(DataArrayIdType::New()), F_Ei(DataArrayIdType::New()), F_E(DataArrayIdType::New());
1362 MCAuto<MEDCouplingUMesh> m_faces(buildDescendingConnectivity(E_F, E_Fi, F_E, F_Ei));
1364 for(mcIdType i=0;i<nbOfCells;i++,connINewPtr++)
1366 if(conn[index[i]]==ToIdType(INTERP_KERNEL::NORM_POLYHED))
1368 SimplifyPolyhedronCell(eps,coords, i,connNew, m_faces, E_Fi, E_F, F_Ei, F_E);
1372 connNew->insertAtTheEnd(conn+index[i],conn+index[i+1]);
1373 *connINewPtr=connNew->getNumberOfTuples();
1376 setConnectivity(connNew,connINew,false);
1380 * This method returns all node ids used in the connectivity of \b this. The data array returned has to be dealt by the caller.
1381 * The returned node ids are sorted ascendingly. This method is close to MEDCouplingUMesh::getNodeIdsInUse except
1382 * the format of the returned DataArrayIdType instance.
1384 * \return a newly allocated DataArrayIdType sorted ascendingly of fetched node ids.
1385 * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1387 DataArrayIdType *MEDCouplingUMesh::computeFetchedNodeIds() const
1389 checkConnectivityFullyDefined();
1390 const mcIdType *maxEltPt(std::max_element(_nodal_connec->begin(),_nodal_connec->end()));
1391 mcIdType maxElt(maxEltPt==_nodal_connec->end()?0:std::abs(*maxEltPt)+1);
1392 std::vector<bool> retS(maxElt,false);
1393 computeNodeIdsAlg(retS);
1394 return DataArrayIdType::BuildListOfSwitchedOn(retS);
1398 * \param [in,out] nodeIdsInUse an array of size typically equal to nbOfNodes.
1399 * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1401 void MEDCouplingUMesh::computeNodeIdsAlg(std::vector<bool>& nodeIdsInUse) const
1403 mcIdType nbOfNodes=ToIdType(nodeIdsInUse.size()),
1404 nbOfCells=getNumberOfCells();
1405 const mcIdType *connIndex(_nodal_connec_index->getConstPointer()),*conn(_nodal_connec->getConstPointer());
1406 for(mcIdType i=0;i<nbOfCells;i++)
1407 for(mcIdType j=connIndex[i]+1;j<connIndex[i+1];j++)
1410 if(conn[j]<nbOfNodes)
1411 nodeIdsInUse[conn[j]]=true;
1414 std::ostringstream oss; oss << "MEDCouplingUMesh::computeNodeIdsAlg : In cell #" << i << " presence of node id " << conn[j] << " not in [0," << nbOfNodes << ") !";
1415 throw INTERP_KERNEL::Exception(oss.str());
1422 struct MEDCouplingAccVisit
1424 MEDCouplingAccVisit():_new_nb_of_nodes(0) { }
1425 mcIdType operator()(mcIdType val) { if(val!=-1) return _new_nb_of_nodes++; else return -1; }
1426 mcIdType _new_nb_of_nodes;
1432 * Finds nodes not used in any cell and returns an array giving a new id to every node
1433 * by excluding the unused nodes, for which the array holds -1. The result array is
1434 * a mapping in "Old to New" mode.
1435 * \param [out] nbrOfNodesInUse - number of node ids present in the nodal connectivity.
1436 * \return DataArrayIdType * - a new instance of DataArrayIdType. Its length is \a
1437 * this->getNumberOfNodes(). It holds for each node of \a this mesh either -1
1438 * if the node is unused or a new id else. The caller is to delete this
1439 * array using decrRef() as it is no more needed.
1440 * \throw If the coordinates array is not set.
1441 * \throw If the nodal connectivity of cells is not defined.
1442 * \throw If the nodal connectivity includes an invalid id.
1444 * \if ENABLE_EXAMPLES
1445 * \ref cpp_mcumesh_getNodeIdsInUse "Here is a C++ example".<br>
1446 * \ref py_mcumesh_getNodeIdsInUse "Here is a Python example".
1448 * \sa computeFetchedNodeIds, computeNodeIdsAlg()
1450 DataArrayIdType *MEDCouplingUMesh::getNodeIdsInUse(mcIdType& nbrOfNodesInUse) const
1453 mcIdType nbOfNodes(getNumberOfNodes());
1454 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1455 ret->alloc(nbOfNodes,1);
1456 mcIdType *traducer=ret->getPointer();
1457 std::fill(traducer,traducer+nbOfNodes,-1);
1458 mcIdType nbOfCells=getNumberOfCells();
1459 const mcIdType *connIndex=_nodal_connec_index->getConstPointer();
1460 const mcIdType *conn=_nodal_connec->getConstPointer();
1461 for(mcIdType i=0;i<nbOfCells;i++)
1462 for(mcIdType j=connIndex[i]+1;j<connIndex[i+1];j++)
1465 if(conn[j]<nbOfNodes)
1466 traducer[conn[j]]=1;
1469 std::ostringstream oss; oss << "MEDCouplingUMesh::getNodeIdsInUse : In cell #" << i << " presence of node id " << conn[j] << " not in [0," << nbOfNodes << ") !";
1470 throw INTERP_KERNEL::Exception(oss.str());
1473 nbrOfNodesInUse=ToIdType(std::count(traducer,traducer+nbOfNodes,1));
1474 std::transform(traducer,traducer+nbOfNodes,traducer,MEDCouplingAccVisit());
1479 * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1480 * For each cell in \b this the number of nodes constituting cell is computed.
1481 * For each polyhedron cell, the sum of the number of nodes of each face constituting polyhedron cell is returned.
1482 * So for pohyhedrons some nodes can be counted several times in the returned result.
1484 * \return a newly allocated array
1485 * \sa MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell
1487 DataArrayIdType *MEDCouplingUMesh::computeNbOfNodesPerCell() const
1489 checkConnectivityFullyDefined();
1490 mcIdType nbOfCells=getNumberOfCells();
1491 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1492 ret->alloc(nbOfCells,1);
1493 mcIdType *retPtr=ret->getPointer();
1494 const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1495 const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1496 for(mcIdType i=0;i<nbOfCells;i++,retPtr++)
1498 if(conn[connI[i]]!=ToIdType(INTERP_KERNEL::NORM_POLYHED))
1499 *retPtr=connI[i+1]-connI[i]-1;
1501 *retPtr=connI[i+1]-connI[i]-1-ToIdType(std::count(conn+connI[i]+1,conn+connI[i+1],-1));
1507 * This method computes effective number of nodes per cell. That is to say nodes appearing several times in nodal connectivity of a cell,
1508 * will be counted only once here whereas it will be counted several times in MEDCouplingUMesh::computeNbOfNodesPerCell method.
1510 * \return DataArrayIdType * - new object to be deallocated by the caller.
1511 * \sa MEDCouplingUMesh::computeNbOfNodesPerCell
1513 DataArrayIdType *MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell() const
1515 checkConnectivityFullyDefined();
1516 mcIdType nbOfCells=getNumberOfCells();
1517 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1518 ret->alloc(nbOfCells,1);
1519 mcIdType *retPtr=ret->getPointer();
1520 const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1521 const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1522 for(mcIdType i=0;i<nbOfCells;i++,retPtr++)
1524 std::set<mcIdType> s(conn+connI[i]+1,conn+connI[i+1]);
1525 if(conn[connI[i]]!=ToIdType(INTERP_KERNEL::NORM_POLYHED))
1526 *retPtr=ToIdType(s.size());
1530 *retPtr=ToIdType(s.size());
1537 * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1538 * For each cell in \b this the number of faces constituting (entity of dimension this->getMeshDimension()-1) cell is computed.
1540 * \return a newly allocated array
1542 DataArrayIdType *MEDCouplingUMesh::computeNbOfFacesPerCell() const
1544 checkConnectivityFullyDefined();
1545 mcIdType nbOfCells=getNumberOfCells();
1546 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1547 ret->alloc(nbOfCells,1);
1548 mcIdType *retPtr=ret->getPointer();
1549 const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1550 const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1551 for(mcIdType i=0;i<nbOfCells;i++,retPtr++,connI++)
1553 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]);
1554 *retPtr=cm.getNumberOfSons2(conn+connI[0]+1,connI[1]-connI[0]-1);
1560 * Removes unused nodes (the node coordinates array is shorten) and returns an array
1561 * mapping between new and old node ids in "Old to New" mode. -1 values in the returned
1562 * array mean that the corresponding old node is no more used.
1563 * \return DataArrayIdType * - a new instance of DataArrayIdType of length \a
1564 * this->getNumberOfNodes() before call of this method. The caller is to
1565 * delete this array using decrRef() as it is no more needed.
1566 * \throw If the coordinates array is not set.
1567 * \throw If the nodal connectivity of cells is not defined.
1568 * \throw If the nodal connectivity includes an invalid id.
1569 * \sa areAllNodesFetched
1571 * \if ENABLE_EXAMPLES
1572 * \ref cpp_mcumesh_zipCoordsTraducer "Here is a C++ example".<br>
1573 * \ref py_mcumesh_zipCoordsTraducer "Here is a Python example".
1576 DataArrayIdType *MEDCouplingUMesh::zipCoordsTraducer()
1578 return MEDCouplingPointSet::zipCoordsTraducer();
1582 * This method stands if 'cell1' and 'cell2' are equals regarding 'compType' policy.
1583 * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1585 int MEDCouplingUMesh::AreCellsEqual(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2, int compType)
1590 return AreCellsEqualPolicy0(conn,connI,cell1,cell2);
1592 return AreCellsEqualPolicy1(conn,connI,cell1,cell2);
1594 return AreCellsEqualPolicy2(conn,connI,cell1,cell2);
1596 return AreCellsEqualPolicy2NoType(conn,connI,cell1,cell2);
1598 return AreCellsEqualPolicy7(conn,connI,cell1,cell2);
1600 throw INTERP_KERNEL::Exception("Unknown comparison asked ! Must be in 0,1,2,3 or 7.");
1604 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 0.
1606 int MEDCouplingUMesh::AreCellsEqualPolicy0(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1608 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1609 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;
1614 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 1.
1616 int MEDCouplingUMesh::AreCellsEqualPolicy1(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1618 mcIdType sz=connI[cell1+1]-connI[cell1];
1619 if(sz==connI[cell2+1]-connI[cell2])
1621 if(conn[connI[cell1]]==conn[connI[cell2]])
1623 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1624 unsigned dim=cm.getDimension();
1629 mcIdType sz1=2*(sz-1);
1630 INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz1];
1631 mcIdType *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(mcIdType *)tmp);
1632 std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1633 work=std::search((mcIdType *)tmp,(mcIdType *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1634 return work!=tmp+sz1?1:0;
1637 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;//case of SEG2 and SEG3
1640 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy1 : not implemented yet for meshdim == 3 !");
1647 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 2.
1649 int MEDCouplingUMesh::AreCellsEqualPolicy2(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1651 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1653 if(conn[connI[cell1]]==conn[connI[cell2]])
1655 std::set<mcIdType> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1656 std::set<mcIdType> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1664 * This method is less restrictive than AreCellsEqualPolicy2. Here the geometric type is absolutely not taken into account !
1666 int MEDCouplingUMesh::AreCellsEqualPolicy2NoType(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1668 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1670 std::set<mcIdType> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1671 std::set<mcIdType> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1678 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 7.
1680 int MEDCouplingUMesh::AreCellsEqualPolicy7(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1682 mcIdType sz=connI[cell1+1]-connI[cell1];
1683 if(sz==connI[cell2+1]-connI[cell2])
1685 if(conn[connI[cell1]]==conn[connI[cell2]])
1687 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1688 unsigned dim=cm.getDimension();
1693 mcIdType sz1=2*(sz-1);
1694 INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz1];
1695 mcIdType *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(mcIdType *)tmp);
1696 std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1697 work=std::search((mcIdType *)tmp,(mcIdType *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1702 std::reverse_iterator<mcIdType *> it1((mcIdType *)tmp+sz1);
1703 std::reverse_iterator<mcIdType *> it2((mcIdType *)tmp);
1704 if(std::search(it1,it2,conn+connI[cell2]+1,conn+connI[cell2+1])!=it2)
1711 {//case of SEG2 and SEG3
1712 if(std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1))
1714 if(!cm.isQuadratic())
1716 std::reverse_iterator<const mcIdType *> it1(conn+connI[cell1+1]);
1717 std::reverse_iterator<const mcIdType *> it2(conn+connI[cell1]+1);
1718 if(std::equal(it1,it2,conn+connI[cell2]+1))
1724 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])
1731 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy7 : not implemented yet for meshdim == 3 !");
1739 * This method find cells that are equal (regarding \a compType) in \a this. The comparison is specified by \a compType (see zipConnectivityTraducer).
1740 * This method keeps the coordinates of \a this. The comparison starts at rank \a startCellId cell id (included).
1741 * If \a startCellId is equal to 0 algorithm starts at cell #0 and for each cell candidates being searched have cell id higher than current cellId.
1742 * If \a startCellId is greater than 0 algorithm starts at cell #startCellId but for each cell all candidates are considered.
1743 * This method is time consuming.
1745 * \param [in] compType input specifying the technique used to compare cells each other.
1746 * - 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.
1747 * - 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)
1748 * and their type equal. For 1D mesh the policy 1 is equivalent to 0.
1749 * - 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
1750 * can be used for users not sensitive to orientation of cell
1751 * \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.
1752 * \param [out] commonCellsArr common cells ids (\ref numbering-indirect)
1753 * \param [out] commonCellsIArr common cells ids (\ref numbering-indirect)
1756 void MEDCouplingUMesh::findCommonCells(int compType, mcIdType startCellId, DataArrayIdType *& commonCellsArr, DataArrayIdType *& commonCellsIArr) const
1758 MCAuto<DataArrayIdType> revNodal=DataArrayIdType::New(),revNodalI=DataArrayIdType::New();
1759 getReverseNodalConnectivity(revNodal,revNodalI);
1760 FindCommonCellsAlg(compType,startCellId,_nodal_connec,_nodal_connec_index,revNodal,revNodalI,commonCellsArr,commonCellsIArr);
1763 void MEDCouplingUMesh::FindCommonCellsAlg(int compType, mcIdType startCellId, const DataArrayIdType *nodal, const DataArrayIdType *nodalI, const DataArrayIdType *revNodal, const DataArrayIdType *revNodalI,
1764 DataArrayIdType *& commonCellsArr, DataArrayIdType *& commonCellsIArr)
1766 MCAuto<DataArrayIdType> commonCells=DataArrayIdType::New(),commonCellsI=DataArrayIdType::New(); commonCells->alloc(0,1);
1767 mcIdType nbOfCells=nodalI->getNumberOfTuples()-1;
1768 commonCellsI->reserve(1); commonCellsI->pushBackSilent(0);
1769 const mcIdType *revNodalPtr=revNodal->getConstPointer(),*revNodalIPtr=revNodalI->getConstPointer();
1770 const mcIdType *connPtr=nodal->getConstPointer(),*connIPtr=nodalI->getConstPointer();
1771 std::vector<bool> isFetched(nbOfCells,false);
1774 for(mcIdType i=startCellId;i<nbOfCells;i++)
1778 const mcIdType *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind(std::not_equal_to<mcIdType>(),std::placeholders::_1,-1));
1779 std::vector<mcIdType> v,v2;
1780 if(connOfNode!=connPtr+connIPtr[i+1])
1782 const mcIdType *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1783 v2.insert(v2.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1]);
1786 for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1790 const mcIdType *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1791 std::vector<mcIdType>::iterator it=std::set_intersection(v.begin(),v.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1792 v2.resize(std::distance(v2.begin(),it));
1796 if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1798 mcIdType pos=commonCellsI->back();
1799 commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1800 for(const mcIdType *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1801 isFetched[*it]=true;
1809 for(mcIdType i=startCellId;i<nbOfCells;i++)
1813 const mcIdType *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind(std::not_equal_to<mcIdType>(),std::placeholders::_1,-1));
1814 // v2 contains the result of successive intersections using rev nodal on on each node of cell #i
1815 std::vector<mcIdType> v,v2;
1816 if(connOfNode!=connPtr+connIPtr[i+1])
1818 v2.insert(v2.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1]);
1821 for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1825 std::vector<mcIdType>::iterator it=std::set_intersection(v.begin(),v.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1826 v2.resize(std::distance(v2.begin(),it));
1828 // v2 contains now candidates. Problem candidates are sorted using id rank.
1833 auto it(std::find(v2.begin(),v2.end(),i));
1834 std::swap(*v2.begin(),*it);
1836 if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1838 mcIdType newPos(commonCells->getNumberOfTuples());
1839 mcIdType pos(commonCellsI->back());
1840 std::sort(commonCells->getPointerSilent()+pos,commonCells->getPointerSilent()+newPos);
1841 commonCellsI->pushBackSilent(newPos);
1842 for(const mcIdType *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1843 isFetched[*it]=true;
1849 commonCellsArr=commonCells.retn();
1850 commonCellsIArr=commonCellsI.retn();
1854 * Checks if \a this mesh includes all cells of an \a other mesh, and returns an array
1855 * giving for each cell of the \a other an id of a cell in \a this mesh. A value larger
1856 * than \a this->getNumberOfCells() in the returned array means that there is no
1857 * corresponding cell in \a this mesh.
1858 * It is expected that \a this and \a other meshes share the same node coordinates
1859 * array, if it is not so an exception is thrown.
1860 * \param [in] other - the mesh to compare with.
1861 * \param [in] compType - specifies a cell comparison technique. For meaning of its
1862 * valid values [0,1,2], see zipConnectivityTraducer().
1863 * \param [out] arr - a new instance of DataArrayIdType returning correspondence
1864 * between cells of the two meshes. It contains \a other->getNumberOfCells()
1865 * values. The caller is to delete this array using
1866 * decrRef() as it is no more needed.
1867 * \return bool - \c true if all cells of \a other mesh are present in the \a this
1870 * \if ENABLE_EXAMPLES
1871 * \ref cpp_mcumesh_areCellsIncludedIn "Here is a C++ example".<br>
1872 * \ref py_mcumesh_areCellsIncludedIn "Here is a Python example".
1874 * \sa checkDeepEquivalOnSameNodesWith()
1875 * \sa checkGeoEquivalWith()
1877 bool MEDCouplingUMesh::areCellsIncludedIn(const MEDCouplingUMesh *other, int compType, DataArrayIdType *& arr) const
1879 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1880 mcIdType nbOfCells=getNumberOfCells();
1881 static const int possibleCompType[]={0,1,2};
1882 if(std::find(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),compType)==possibleCompType+sizeof(possibleCompType)/sizeof(int))
1884 std::ostringstream oss; oss << "MEDCouplingUMesh::areCellsIncludedIn : only following policies are possible : ";
1885 std::copy(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),std::ostream_iterator<int>(oss," "));
1887 throw INTERP_KERNEL::Exception(oss.str());
1890 if(other->getNumberOfCells()==0)
1892 MCAuto<DataArrayIdType> dftRet(DataArrayIdType::New()); dftRet->alloc(0,1); arr=dftRet.retn(); arr->setName(other->getName());
1895 DataArrayIdType *commonCells(nullptr),*commonCellsI(nullptr);
1896 mesh->findCommonCells(compType,nbOfCells,commonCells,commonCellsI);
1897 MCAuto<DataArrayIdType> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1898 mcIdType newNbOfCells=-1;
1899 MCAuto<DataArrayIdType> o2n = DataArrayIdType::ConvertIndexArrayToO2N(ToIdType(mesh->getNumberOfCells()),commonCells->begin(),commonCellsI->begin(),commonCellsI->end(),newNbOfCells);
1900 MCAuto<DataArrayIdType> p0(o2n->selectByTupleIdSafeSlice(0,nbOfCells,1));
1901 mcIdType maxPart(p0->getMaxValueInArray());
1902 bool ret(maxPart==newNbOfCells-1);
1903 MCAuto<DataArrayIdType> p1(p0->invertArrayO2N2N2O(newNbOfCells));
1904 // fill p1 array in case of presence of cells in other not in this
1905 mcIdType *pt(p1->getPointer());
1906 for(mcIdType i = maxPart ; i < newNbOfCells-1 ; ++i )
1909 MCAuto<DataArrayIdType> p2(o2n->subArray(nbOfCells));
1910 p2->transformWithIndArr(p1->begin(),p1->end()); p2->setName(other->getName());
1916 * This method makes the assumption that \a this and \a other share the same coords. If not an exception will be thrown !
1917 * This method tries to determine if \b other is fully included in \b this.
1918 * The main difference is that this method is not expected to throw exception.
1919 * This method has two outputs :
1921 * \param other other mesh
1922 * \param arr is an output parameter that returns a \b newly created instance. This array is of size 'other->getNumberOfCells()'.
1923 * \return If \a other is fully included in 'this 'true is returned. If not false is returned.
1925 bool MEDCouplingUMesh::areCellsIncludedInPolicy7(const MEDCouplingUMesh *other, DataArrayIdType *& arr) const
1927 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1928 DataArrayIdType *commonCells=0,*commonCellsI=0;
1929 mcIdType thisNbCells=getNumberOfCells();
1930 mesh->findCommonCells(7,thisNbCells,commonCells,commonCellsI);
1931 MCAuto<DataArrayIdType> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1932 const mcIdType *commonCellsPtr=commonCells->getConstPointer(),*commonCellsIPtr=commonCellsI->getConstPointer();
1933 mcIdType otherNbCells=other->getNumberOfCells();
1934 MCAuto<DataArrayIdType> arr2=DataArrayIdType::New();
1935 arr2->alloc(otherNbCells,1);
1936 arr2->fillWithZero();
1937 mcIdType *arr2Ptr=arr2->getPointer();
1938 mcIdType nbOfCommon=commonCellsI->getNumberOfTuples()-1;
1939 for(mcIdType i=0;i<nbOfCommon;i++)
1941 mcIdType start=commonCellsPtr[commonCellsIPtr[i]];
1942 if(start<thisNbCells)
1944 for(mcIdType j=commonCellsIPtr[i]+1;j!=commonCellsIPtr[i+1];j++)
1946 mcIdType sig=commonCellsPtr[j]>0?1:-1;
1947 mcIdType val=std::abs(commonCellsPtr[j])-1;
1948 if(val>=thisNbCells)
1949 arr2Ptr[val-thisNbCells]=sig*(start+1);
1953 arr2->setName(other->getName());
1954 if(arr2->presenceOfValue(0))
1960 MEDCouplingUMesh *MEDCouplingUMesh::mergeMyselfWithOnSameCoords(const MEDCouplingPointSet *other) const
1963 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : input other is null !");
1964 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
1966 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : the input other mesh is not of type unstructured !");
1967 std::vector<const MEDCouplingUMesh *> ms(2);
1970 return MergeUMeshesOnSameCoords(ms);
1974 * Build a sub part of \b this lying or not on the same coordinates than \b this (regarding value of \b keepCoords).
1975 * By default coordinates are kept. This method is close to MEDCouplingUMesh::buildPartOfMySelf except that here input
1976 * cellIds is not given explicitly but by a range python like.
1978 * \param start starting ID
1979 * \param end end ID (excluded)
1980 * \param step step size
1981 * \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.
1982 * \return a newly allocated
1984 * \warning This method modifies can generate an unstructured mesh whose cells are not sorted by geometric type order.
1985 * In view of the MED file writing, a renumbering of cells of returned unstructured mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
1987 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfSlice(mcIdType start, mcIdType end, mcIdType step, bool keepCoords) const
1989 if(getMeshDimension()!=-1)
1990 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelfSlice(start,end,step,keepCoords));
1993 mcIdType newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfSlice for -1 dimension mesh ");
1995 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
1997 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
1999 return const_cast<MEDCouplingUMesh *>(this);
2004 * Creates a new MEDCouplingUMesh containing specified cells of \a this mesh.
2005 * The result mesh shares or not the node coordinates array with \a this mesh depending
2006 * on \a keepCoords parameter.
2007 * \warning Cells of the result mesh can be \b not sorted by geometric type, hence,
2008 * to write this mesh to the MED file, its cells must be sorted using
2009 * sortCellsInMEDFileFrmt().
2010 * \param [in] begin - an array of cell ids to include to the new mesh.
2011 * \param [in] end - a pointer to last-plus-one-th element of \a begin.
2012 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2013 * array of \a this mesh, else "free" nodes are removed from the result mesh
2014 * by calling zipCoords().
2015 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2016 * to delete this mesh using decrRef() as it is no more needed.
2017 * \throw If the coordinates array is not set.
2018 * \throw If the nodal connectivity of cells is not defined.
2019 * \throw If any cell id in the array \a begin is not valid.
2021 * \if ENABLE_EXAMPLES
2022 * \ref cpp_mcumesh_buildPartOfMySelf "Here is a C++ example".<br>
2023 * \ref py_mcumesh_buildPartOfMySelf "Here is a Python example".
2026 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelf(const mcIdType *begin, const mcIdType *end, bool keepCoords) const
2028 if(getMeshDimension()!=-1)
2029 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelf(begin,end,keepCoords));
2033 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
2035 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
2037 return const_cast<MEDCouplingUMesh *>(this);
2042 * This method operates only on nodal connectivity on \b this. Coordinates of \b this is completely ignored here.
2044 * 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.
2045 * Size of [ \b cellIdsBg, \b cellIdsEnd ) ) must be equal to the number of cells of otherOnSameCoordsThanThis.
2046 * The number of cells of \b this will remain the same with this method.
2048 * \param [in] cellIdsBg begin of cell ids (included) of cells in this to assign
2049 * \param [in] cellIdsEnd end of cell ids (excluded) of cells in this to assign
2050 * \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 ).
2051 * Coordinate pointer of \b this and those of \b otherOnSameCoordsThanThis must be the same
2053 void MEDCouplingUMesh::setPartOfMySelf(const mcIdType *cellIdsBg, const mcIdType *cellIdsEnd, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2055 checkConnectivityFullyDefined();
2056 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2057 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2058 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelf : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2059 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2061 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2062 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2063 throw INTERP_KERNEL::Exception(oss.str());
2065 mcIdType nbOfCellsToModify( ToIdType((std::distance(cellIdsBg,cellIdsEnd))));
2066 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2068 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2069 throw INTERP_KERNEL::Exception(oss.str());
2071 mcIdType nbOfCells(getNumberOfCells());
2072 bool easyAssign(true);
2073 const mcIdType *connI(_nodal_connec_index->begin());
2074 const mcIdType *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->begin();
2075 for(const mcIdType *it=cellIdsBg;it!=cellIdsEnd && easyAssign;it++,connIOther++)
2077 if(*it>=0 && *it<nbOfCells)
2079 easyAssign=(connIOther[1]-connIOther[0])==(connI[*it+1]-connI[*it]);
2083 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : On pos #" << std::distance(cellIdsBg,it) << " id is equal to " << *it << " which is not in [0," << nbOfCells << ") !";
2084 throw INTERP_KERNEL::Exception(oss.str());
2089 DataArrayIdType::SetPartOfIndexedArraysSameIdx(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2094 DataArrayIdType *arrOut=0,*arrIOut=0;
2095 DataArrayIdType::SetPartOfIndexedArrays(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2097 MCAuto<DataArrayIdType> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2098 setConnectivity(arrOut,arrIOut,true);
2102 void MEDCouplingUMesh::setPartOfMySelfSlice(mcIdType start, mcIdType end, mcIdType step, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2104 checkConnectivityFullyDefined();
2105 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2106 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2107 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelfSlice : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2108 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2110 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2111 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2112 throw INTERP_KERNEL::Exception(oss.str());
2114 mcIdType nbOfCellsToModify=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::setPartOfMySelfSlice : ");
2115 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2117 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2118 throw INTERP_KERNEL::Exception(oss.str());
2120 mcIdType nbOfCells=getNumberOfCells();
2121 bool easyAssign=true;
2122 const mcIdType *connI=_nodal_connec_index->getConstPointer();
2123 const mcIdType *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2125 for(mcIdType i=0;i<nbOfCellsToModify && easyAssign;i++,it+=step,connIOther++)
2127 if(it>=0 && it<nbOfCells)
2129 easyAssign=(connIOther[1]-connIOther[0])==(connI[it+1]-connI[it]);
2133 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : On pos #" << i << " id is equal to " << it << " which is not in [0," << nbOfCells << ") !";
2134 throw INTERP_KERNEL::Exception(oss.str());
2139 DataArrayIdType::SetPartOfIndexedArraysSameIdxSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2144 DataArrayIdType *arrOut=0,*arrIOut=0;
2145 DataArrayIdType::SetPartOfIndexedArraysSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2147 MCAuto<DataArrayIdType> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2148 setConnectivity(arrOut,arrIOut,true);
2154 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2155 * this->getMeshDimension(), that bound some cells of \a this mesh.
2156 * The cells of lower dimension to include to the result mesh are selected basing on
2157 * specified node ids and the value of \a fullyIn parameter. If \a fullyIn ==\c true, a
2158 * cell is copied if its all nodes are in the array \a begin of node ids. If \a fullyIn
2159 * ==\c false, a cell is copied if any its node is in the array of node ids. The
2160 * created mesh shares the node coordinates array with \a this mesh.
2161 * \param [in] begin - the array of node ids.
2162 * \param [in] end - a pointer to the (last+1)-th element of \a begin.
2163 * \param [in] fullyIn - if \c true, then cells whose all nodes are in the
2164 * array \a begin are added, else cells whose any node is in the
2165 * array \a begin are added.
2166 * \return MEDCouplingUMesh * - new instance of MEDCouplingUMesh. The caller is
2167 * to delete this mesh using decrRef() as it is no more needed.
2168 * \throw If the coordinates array is not set.
2169 * \throw If the nodal connectivity of cells is not defined.
2170 * \throw If any node id in \a begin is not valid.
2172 * \if ENABLE_EXAMPLES
2173 * \ref cpp_mcumesh_buildFacePartOfMySelfNode "Here is a C++ example".<br>
2174 * \ref py_mcumesh_buildFacePartOfMySelfNode "Here is a Python example".
2177 MEDCouplingUMesh *MEDCouplingUMesh::buildFacePartOfMySelfNode(const mcIdType *begin, const mcIdType *end, bool fullyIn) const
2179 MCAuto<DataArrayIdType> desc,descIndx,revDesc,revDescIndx;
2180 desc=DataArrayIdType::New(); descIndx=DataArrayIdType::New(); revDesc=DataArrayIdType::New(); revDescIndx=DataArrayIdType::New();
2181 MCAuto<MEDCouplingUMesh> subMesh=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2182 desc=0; descIndx=0; revDesc=0; revDescIndx=0;
2183 return static_cast<MEDCouplingUMesh*>(subMesh->buildPartOfMySelfNode(begin,end,fullyIn));
2187 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2188 * this->getMeshDimension(), which bound only one cell of \a this mesh.
2189 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2190 * array of \a this mesh, else "free" nodes are removed from the result mesh
2191 * by calling zipCoords().
2192 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2193 * to delete this mesh using decrRef() as it is no more needed.
2194 * \throw If the coordinates array is not set.
2195 * \throw If the nodal connectivity of cells is not defined.
2197 * \if ENABLE_EXAMPLES
2198 * \ref cpp_mcumesh_buildBoundaryMesh "Here is a C++ example".<br>
2199 * \ref py_mcumesh_buildBoundaryMesh "Here is a Python example".
2202 MEDCouplingUMesh *MEDCouplingUMesh::buildBoundaryMesh(bool keepCoords) const
2204 DataArrayIdType *desc=DataArrayIdType::New();
2205 DataArrayIdType *descIndx=DataArrayIdType::New();
2206 DataArrayIdType *revDesc=DataArrayIdType::New();
2207 DataArrayIdType *revDescIndx=DataArrayIdType::New();
2209 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2212 descIndx->decrRef();
2213 mcIdType nbOfCells=meshDM1->getNumberOfCells();
2214 const mcIdType *revDescIndxC=revDescIndx->getConstPointer();
2215 std::vector<mcIdType> boundaryCells;
2216 for(mcIdType i=0;i<nbOfCells;i++)
2217 if(revDescIndxC[i+1]-revDescIndxC[i]==1)
2218 boundaryCells.push_back(i);
2219 revDescIndx->decrRef();
2220 MEDCouplingUMesh *ret=meshDM1->buildPartOfMySelf(&boundaryCells[0],&boundaryCells[0]+boundaryCells.size(),keepCoords);
2225 * This method returns a newly created DataArrayIdType instance containing ids of cells located in boundary.
2226 * A cell is detected to be on boundary if it contains one or more than one face having only one father.
2227 * This method makes the assumption that \a this is fully defined (coords,connectivity). If not an exception will be thrown.
2229 DataArrayIdType *MEDCouplingUMesh::findCellIdsOnBoundary() const
2231 checkFullyDefined();
2232 MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
2233 MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
2234 MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
2235 MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
2237 buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx)->decrRef();
2238 desc=(DataArrayIdType*)0; descIndx=(DataArrayIdType*)0;
2240 MCAuto<DataArrayIdType> tmp=revDescIndx->deltaShiftIndex();
2241 MCAuto<DataArrayIdType> faceIds=tmp->findIdsEqual(1); tmp=(DataArrayIdType*)0;
2242 const mcIdType *revDescPtr=revDesc->getConstPointer();
2243 const mcIdType *revDescIndxPtr=revDescIndx->getConstPointer();
2244 mcIdType nbOfCells=getNumberOfCells();
2245 std::vector<bool> ret1(nbOfCells,false);
2247 for(const mcIdType *pt=faceIds->begin();pt!=faceIds->end();pt++)
2248 if(!ret1[revDescPtr[revDescIndxPtr[*pt]]])
2249 { ret1[revDescPtr[revDescIndxPtr[*pt]]]=true; sz++; }
2251 DataArrayIdType *ret2=DataArrayIdType::New();
2253 mcIdType *ret2Ptr=ret2->getPointer();
2255 for(std::vector<bool>::const_iterator it=ret1.begin();it!=ret1.end();it++,sz++)
2258 ret2->setName("BoundaryCells");
2263 * This method finds in \b this the cell ids that lie on mesh \b otherDimM1OnSameCoords.
2264 * \b this and \b otherDimM1OnSameCoords have to lie on the same coordinate array pointer. The coherency of that coords array with connectivity
2265 * of \b this and \b otherDimM1OnSameCoords is not important here because this method works only on connectivity.
2266 * this->getMeshDimension() - 1 must be equal to otherDimM1OnSameCoords.getMeshDimension()
2268 * s0 is the cell ids set in \b this lying on at least one node in the fetched nodes in \b otherDimM1OnSameCoords.
2269 * 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
2270 * equals a cell in \b otherDimM1OnSameCoords.
2272 * \throw if \b otherDimM1OnSameCoords is not part of constituent of \b this, or if coordinate pointer of \b this and \b otherDimM1OnSameCoords
2273 * are not same, or if this->getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension()
2275 * \param [in] otherDimM1OnSameCoords other mesh
2276 * \param [out] cellIdsRk0 a newly allocated array containing the cell ids of s0 (which are cell ids of \b this) in the above algorithm.
2277 * \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
2278 * cellIdsRk1->transformWithIndArr(cellIdsRk0->begin(),cellIdsRk0->end());
2280 void MEDCouplingUMesh::findCellIdsLyingOn(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayIdType *&cellIdsRk0, DataArrayIdType *&cellIdsRk1) const
2282 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2283 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : coordinates pointer are not the same ! Use tryToShareSameCoords method !");
2284 checkConnectivityFullyDefined();
2285 otherDimM1OnSameCoords.checkConnectivityFullyDefined();
2286 if(getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension())
2287 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : invalid mesh dimension of input mesh regarding meshdimesion of this !");
2288 MCAuto<DataArrayIdType> fetchedNodeIds1=otherDimM1OnSameCoords.computeFetchedNodeIds();
2289 MCAuto<DataArrayIdType> s0arr=getCellIdsLyingOnNodes(fetchedNodeIds1->begin(),fetchedNodeIds1->end(),false);
2290 MCAuto<MEDCouplingUMesh> thisPart=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(s0arr->begin(),s0arr->end(),true));
2291 MCAuto<DataArrayIdType> descThisPart=DataArrayIdType::New(),descIThisPart=DataArrayIdType::New(),revDescThisPart=DataArrayIdType::New(),revDescIThisPart=DataArrayIdType::New();
2292 MCAuto<MEDCouplingUMesh> thisPartConsti=thisPart->buildDescendingConnectivity(descThisPart,descIThisPart,revDescThisPart,revDescIThisPart);
2293 const mcIdType *revDescThisPartPtr=revDescThisPart->getConstPointer(),*revDescIThisPartPtr=revDescIThisPart->getConstPointer();
2294 DataArrayIdType *idsOtherInConsti=0;
2295 bool b=thisPartConsti->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsOtherInConsti);
2296 MCAuto<DataArrayIdType> idsOtherInConstiAuto(idsOtherInConsti);
2298 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : the given mdim-1 mesh in other is not a constituent of this !");
2299 std::set<mcIdType> s1;
2300 for(const mcIdType *idOther=idsOtherInConsti->begin();idOther!=idsOtherInConsti->end();idOther++)
2301 s1.insert(revDescThisPartPtr+revDescIThisPartPtr[*idOther],revDescThisPartPtr+revDescIThisPartPtr[*idOther+1]);
2302 MCAuto<DataArrayIdType> s1arr_renum1=DataArrayIdType::New(); s1arr_renum1->alloc(s1.size(),1); std::copy(s1.begin(),s1.end(),s1arr_renum1->getPointer());
2303 s1arr_renum1->sort();
2304 cellIdsRk0=s0arr.retn();
2305 //cellIdsRk1=s_renum1.retn();
2306 cellIdsRk1=s1arr_renum1.retn();
2310 * 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
2311 * returned. This subpart of meshdim-1 mesh is built using meshdim-1 cells in it shared only one cell in \b this.
2313 * \return a newly allocated mesh lying on the same coordinates than \b this. The caller has to deal with returned mesh.
2315 MEDCouplingUMesh *MEDCouplingUMesh::computeSkin() const
2317 MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
2318 MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
2319 MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
2320 MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
2322 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2323 revDesc=0; desc=0; descIndx=0;
2324 MCAuto<DataArrayIdType> revDescIndx2=revDescIndx->deltaShiftIndex();
2325 MCAuto<DataArrayIdType> part=revDescIndx2->findIdsEqual(1);
2326 return static_cast<MEDCouplingUMesh *>(meshDM1->buildPartOfMySelf(part->begin(),part->end(),true));
2330 * Finds nodes lying on the boundary of \a this mesh.
2331 * \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of found
2332 * nodes. The caller is to delete this array using decrRef() as it is no
2334 * \throw If the coordinates array is not set.
2335 * \throw If the nodal connectivity of cells is node defined.
2337 * \if ENABLE_EXAMPLES
2338 * \ref cpp_mcumesh_findBoundaryNodes "Here is a C++ example".<br>
2339 * \ref py_mcumesh_findBoundaryNodes "Here is a Python example".
2342 DataArrayIdType *MEDCouplingUMesh::findBoundaryNodes() const
2344 MCAuto<MEDCouplingUMesh> skin=computeSkin();
2345 return skin->computeFetchedNodeIds();
2348 MEDCouplingUMesh *MEDCouplingUMesh::buildUnstructured() const
2351 return const_cast<MEDCouplingUMesh *>(this);
2355 * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2356 * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2357 * 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.
2358 * If a node is in the boundary of \b this \b and in the boundary of \b otherDimM1OnSameCoords this node is considered as needed to be duplicated.
2359 * 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.
2361 * \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
2362 * parameter is altered during the call.
2363 * \return node ids which need to be duplicated following the algorithm explained above.
2366 DataArrayIdType* MEDCouplingUMesh::findNodesToDuplicate(const MEDCouplingUMesh& otherDimM1OnSameCoords) const
2368 // DEBUG NOTE: in case of issue with the algorithm in this method, see Python script in resources/dev
2369 // which mimicks the C++
2370 using DAInt = MCAuto<DataArrayIdType>;
2371 using MCUMesh = MCAuto<MEDCouplingUMesh>;
2373 checkFullyDefined();
2374 otherDimM1OnSameCoords.checkFullyDefined();
2375 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2376 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : meshes do not share the same coords array !");
2377 if(otherDimM1OnSameCoords.getMeshDimension()!=getMeshDimension()-1)
2378 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the mesh given in other parameter must have this->getMeshDimension()-1 !");
2380 // Checking star-shaped M1 group:
2381 DAInt dt0=DataArrayIdType::New(),dit0=DataArrayIdType::New(),rdt0=DataArrayIdType::New(),rdit0=DataArrayIdType::New();
2382 MCUMesh meshM2 = otherDimM1OnSameCoords.buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); // 2D: a mesh of points, 3D: a mesh of segs
2383 DAInt dsi = rdit0->deltaShiftIndex();
2384 DAInt idsTmp0 = dsi->findIdsNotInRange(-1, 3); // for 2D: if a point is connected to more than 2 segs. For 3D: if a seg is connected to more than two faces.
2385 if(idsTmp0->getNumberOfTuples())
2386 throw INTERP_KERNEL::Exception("MEDFileUMesh::buildInnerBoundaryAlongM1Group: group is too complex: some points (or edges) have more than two connected segments (or faces)!");
2387 dt0=0; dit0=0; rdt0=0; rdit0=0; idsTmp0=0;
2389 // Get extreme nodes from the group (they won't be duplicated except if they also lie on bound of M0 -- see below),
2390 // ie nodes belonging to the boundary "cells" (might be points) of M1
2391 DAInt xtremIdsM2 = dsi->findIdsEqual(1); dsi = 0;
2392 MCUMesh meshM2Part = static_cast<MEDCouplingUMesh *>(meshM2->buildPartOfMySelf(xtremIdsM2->begin(), xtremIdsM2->end(),true));
2393 DAInt xtrem = meshM2Part->computeFetchedNodeIds();
2394 // Remove from the list points on the boundary of the M0 mesh (those need duplication!)
2395 dt0=DataArrayIdType::New(),dit0=DataArrayIdType::New(),rdt0=DataArrayIdType::New(),rdit0=DataArrayIdType::New();
2396 MCUMesh m0desc = buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); dt0=0; dit0=0; rdt0=0;
2397 dsi = rdit0->deltaShiftIndex(); rdit0=0;
2398 DAInt boundSegs = dsi->findIdsEqual(1); dsi = 0; // boundary segs/faces of the M0 mesh
2399 MCUMesh m0descSkin = static_cast<MEDCouplingUMesh *>(m0desc->buildPartOfMySelf(boundSegs->begin(),boundSegs->end(), true));
2400 DAInt fNodes = m0descSkin->computeFetchedNodeIds();
2401 // In 3D, some points on the boundary of M0 will NOT be duplicated (where as in 2D, points on the boundary of M0 are always duplicated)
2402 // Think of a partial (plane) crack in a cube: the points at the tip of the crack and not located inside the volume of the cube are not duplicated
2403 // although they are technically on the skin of the cube.
2405 if (getMeshDimension() == 3)
2407 DAInt dnu1=DataArrayIdType::New(), dnu2=DataArrayIdType::New(), dnu3=DataArrayIdType::New(), dnu4=DataArrayIdType::New();
2408 MCUMesh m0descSkinDesc = m0descSkin->buildDescendingConnectivity(dnu1, dnu2, dnu3, dnu4); // all segments of the skin of the 3D (M0) mesh
2409 dnu1=0;dnu2=0;dnu3=0;dnu4=0;
2410 DataArrayIdType * corresp=0;
2411 meshM2->areCellsIncludedIn(m0descSkinDesc,2,corresp);
2412 // validIds is the list of segments which are on both the skin of *this*, and in the segments of the M1 group
2413 // In the cube example above, this is a U shape polyline.
2414 DAInt validIds = corresp->findIdsInRange(0, meshM2->getNumberOfCells());
2416 if (validIds->getNumberOfTuples())
2418 // Build the set of segments which are: in the desc mesh of the skin of the 3D mesh (M0) **and** in the desc mesh of the M1 group:
2419 // (the U-shaped polyline described above)
2420 MCUMesh m1IntersecSkin = static_cast<MEDCouplingUMesh *>(m0descSkinDesc->buildPartOfMySelf(validIds->begin(), validIds->end(), true));
2421 // Its boundary nodes should no be duplicated (this is for example the tip of the crack inside the cube described above)
2422 DAInt notDuplSkin = m1IntersecSkin->findBoundaryNodes();
2423 DAInt fNodes1 = fNodes->buildSubstraction(notDuplSkin);
2425 // Specific logic to handle singular points :
2426 // - a point on this U-shape line used in a cell which has no face in common with M1 is deemed singular.
2427 // - indeed, if duplicated, such a point would lead to the duplication of a cell which has no face touching M1 ! The
2428 // algorithm would be duplicating too much ...
2429 // This is a costly algorithm so only go into it if a simple (non sufficient) criteria is met: a node connected to more than 3 segs in meshM2:
2430 dnu1=DataArrayIdType::New(), dnu2=DataArrayIdType::New(), dnu3=DataArrayIdType::New(), rdit0=DataArrayIdType::New();
2431 MCUMesh meshM2Desc = meshM2->buildDescendingConnectivity(dnu1, dnu2, dnu3, rdit0); // a mesh made of node cells
2432 dnu1=0;dnu2=0;dnu3=0;
2433 dsi = rdit0->deltaShiftIndex(); rdit0=0;
2434 DAInt singPoints = dsi->findIdsNotInRange(-1,4) ; dsi=0;// points connected to (strictly) more than 3 segments
2435 if (singPoints->getNumberOfTuples())
2437 DAInt boundNodes = m1IntersecSkin->computeFetchedNodeIds();
2438 // If a point on this U-shape line is connected to cells which do not share any face with M1, then it
2439 // should not be duplicated
2440 // 1. Extract N D cells touching U-shape line:
2441 DAInt cellsAroundBN = getCellIdsLyingOnNodes(boundNodes->begin(), boundNodes->end(), false); // false= take cell in, even if not all nodes are in dupl
2442 MCUMesh mAroundBN = static_cast<MEDCouplingUMesh *>(this->buildPartOfMySelf(cellsAroundBN->begin(), cellsAroundBN->end(), true));
2443 DAInt descBN=DataArrayIdType::New(), descIBN=DataArrayIdType::New(), revDescBN=DataArrayIdType::New(), revDescIBN=DataArrayIdType::New();
2444 MCUMesh mAroundBNDesc = mAroundBN->buildDescendingConnectivity(descBN,descIBN,revDescBN,revDescIBN);
2445 // 2. Identify cells in sub-mesh mAroundBN which have a face in common with M1
2446 DataArrayIdType *idsOfM1BNt;
2447 mAroundBNDesc->areCellsIncludedIn(&otherDimM1OnSameCoords,2, idsOfM1BNt);
2448 DAInt idsOfM1BN(idsOfM1BNt);
2449 mcIdType nCells=mAroundBN->getNumberOfCells(), nCellsDesc=mAroundBNDesc->getNumberOfCells();
2450 DAInt idsTouch=DataArrayIdType::New(); idsTouch->alloc(0,1);
2451 const mcIdType *revDescIBNP=revDescIBN->begin(), *revDescBNP=revDescBN->begin();
2452 for(const auto& v: *idsOfM1BN)
2454 if (v >= nCellsDesc) // Keep valid match only
2456 mcIdType idx0 = revDescIBNP[v];
2457 // Keep the two cells on either side of the face v of M1:
2458 mcIdType c1=revDescBNP[idx0], c2=revDescBNP[idx0+1];
2459 idsTouch->pushBackSilent(c1); idsTouch->pushBackSilent(c2);
2461 // 3. Build complement
2462 DAInt idsTouchCompl = idsTouch->buildComplement(nCells);
2463 MCUMesh mAroundBNStrict = static_cast<MEDCouplingUMesh *>(mAroundBN->buildPartOfMySelf(idsTouchCompl->begin(), idsTouchCompl->end(), true));
2464 DAInt nod3 = mAroundBNStrict->computeFetchedNodeIds();
2465 DAInt inters = boundNodes->buildIntersection(nod3);
2466 fNodes1 = fNodes1->buildSubstraction(inters); // reminder: fNodes1 represent nodes that need dupl.
2468 notDup = xtrem->buildSubstraction(fNodes1);
2470 else // if (validIds-> ...)
2471 notDup = xtrem->buildSubstraction(fNodes);
2474 notDup = xtrem->buildSubstraction(fNodes);
2476 DAInt m1Nodes = otherDimM1OnSameCoords.computeFetchedNodeIds();
2477 DAInt dupl = m1Nodes->buildSubstraction(notDup);
2483 * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2484 * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2485 * This method is part of the MEDFileUMesh::buildInnerBoundaryAlongM1Group() algorithm.
2486 * Given a set of nodes to duplicate, this method identifies which cells should have their connectivity modified
2487 * to produce the inner boundary. It is typically called after findNodesToDuplicate().
2489 * \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
2490 * parameter is altered during the call.
2491 * \param [in] nodeIdsToDuplicateBg node ids needed to be duplicated, as returned by findNodesToDuplicate.
2492 * \param [in] nodeIdsToDuplicateEnd node ids needed to be duplicated, as returned by findNodesToDuplicate.
2493 * \param [out] cellIdsNeededToBeRenum cell ids in \b this in which the renumber of nodes should be performed.
2494 * \param [out] cellIdsNotModified cell ids in \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.
2497 void MEDCouplingUMesh::findCellsToRenumber(const MEDCouplingUMesh& otherDimM1OnSameCoords, const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd,
2498 DataArrayIdType *& cellIdsNeededToBeRenum, DataArrayIdType *& cellIdsNotModified) const
2500 // DEBUG NOTE: in case of issue with the algorithm in this method, see Python script in resources/dev
2501 // which mimicks the C++
2502 using DAInt = MCAuto<DataArrayIdType>;
2503 using MCUMesh = MCAuto<MEDCouplingUMesh>;
2505 checkFullyDefined();
2506 otherDimM1OnSameCoords.checkFullyDefined();
2507 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2508 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellsToRenumber: meshes do not share the same coords array !");
2509 if(otherDimM1OnSameCoords.getMeshDimension()!=getMeshDimension()-1)
2510 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellsToRenumber: the mesh given in other parameter must have this->getMeshDimension()-1 !");
2512 DAInt cellsAroundGroupLarge = getCellIdsLyingOnNodes(nodeIdsToDuplicateBg, nodeIdsToDuplicateEnd, false); // false= take cell in, even if not all nodes are in dupl
2515 MCUMesh mAroundGrpLarge=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(cellsAroundGroupLarge->begin(),cellsAroundGroupLarge->end(),true));
2516 DAInt descL=DataArrayIdType::New(),descIL=DataArrayIdType::New(),revDescL=DataArrayIdType::New(),revDescIL=DataArrayIdType::New();
2517 MCUMesh mArGrpLargeDesc=mAroundGrpLarge->buildDescendingConnectivity(descL,descIL,revDescL,revDescIL);
2518 const mcIdType *descILP=descIL->begin(), *descLP=descL->begin();
2520 // Extract now all N D cells which have a complete face in touch with the group:
2521 // 1. Identify cells of M1 group in sub-mesh mAroundGrp
2522 DataArrayIdType *idsOfM1t;
2523 mArGrpLargeDesc->areCellsIncludedIn(&otherDimM1OnSameCoords,2, idsOfM1t);
2524 DAInt idsOfM1Large(idsOfM1t);
2525 mcIdType nL = mArGrpLargeDesc->getNumberOfCells();
2526 DAInt idsStrict = DataArrayIdType::New(); idsStrict->alloc(0,1);
2527 // 2. Build map giving for each cell ID in mAroundGrp (not in mAroundGrpLarge) the corresponding cell
2528 // ID on the other side of the crack:
2529 std::map<mcIdType, mcIdType> toOtherSide, pos;
2531 const mcIdType *revDescILP=revDescIL->begin(), *revDescLP=revDescL->begin();
2532 for(const auto& v: *idsOfM1Large)
2534 if (v >= nL) // Keep valid match only
2536 mcIdType idx0 = revDescILP[v];
2537 // Keep the two cells on either side of the face v of M1:
2538 mcIdType c1=revDescLP[idx0], c2=revDescLP[idx0+1];
2539 DAInt t1=idsStrict->findIdsEqual(c1), t2=idsStrict->findIdsEqual(c2);
2541 if (!t1->getNumberOfTuples())
2542 { pos[c1] = cnt++; idsStrict->pushBackSilent(c1); }
2543 if (!t2->getNumberOfTuples())
2544 { pos[c2] = cnt++; idsStrict->pushBackSilent(c2); }
2546 mcIdType k1 = pos[c1], k2=pos[c2];
2547 toOtherSide[k1] = k2;
2548 toOtherSide[k2] = k1;
2551 DAInt cellsAroundGroup = cellsAroundGroupLarge->selectByTupleId(idsStrict->begin(), idsStrict->end());
2552 MCUMesh mAroundGrp = static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(cellsAroundGroup->begin(), cellsAroundGroup->end(), true));
2553 mcIdType nCells=cellsAroundGroup->getNumberOfTuples(), nCellsLarge=cellsAroundGroupLarge->getNumberOfTuples();
2554 DAInt desc=DataArrayIdType::New(),descI=DataArrayIdType::New(),revDesc=DataArrayIdType::New(),revDescI=DataArrayIdType::New();
2555 MCUMesh mArGrpDesc=mAroundGrp->buildDescendingConnectivity(desc,descI,revDesc,revDescI);
2556 DataArrayIdType *idsOfM1t2;
2557 mArGrpDesc->areCellsIncludedIn(&otherDimM1OnSameCoords,2, idsOfM1t2); // TODO can we avoid recomputation here?
2558 DAInt idsOfM1(idsOfM1t2);
2560 // Neighbor information of the mesh WITH the crack (some neighbors are removed):
2561 // In the neighbor information remove the connection between high dimension cells and its low level constituents which are part
2562 // of the frontier given in parameter (i.e. the cells of low dimension from the group delimiting the crack):
2563 DataArrayIdType::RemoveIdsFromIndexedArrays(idsOfM1->begin(), idsOfM1->end(),desc,descI);
2564 // Compute the neighbor of each cell in mAroundGrp, taking into account the broken link above. Two
2565 // cells on either side of the crack (defined by the mesh of low dimension) are not neighbor anymore.
2566 DataArrayIdType *neight=0, *neighIt=0;
2567 MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(desc,descI,revDesc,revDescI, neight, neighIt);
2568 DAInt neigh(neight), neighI(neighIt);
2570 // For each initial connex part of the M1 mesh (or said differently for each independent crack):
2571 mcIdType seed=0, nIter=0;
2572 mcIdType nIterMax = nCells+1; // Safety net for the loop
2573 DAInt hitCells = DataArrayIdType::New(); hitCells->alloc(nCells,1);
2574 mcIdType* hitCellsP = hitCells->rwBegin();
2575 hitCells->fillWithValue(0); // 0 : not hit, +x: one side of the crack, -x: other side of the crack, with 'x' the index of the connex component
2576 mcIdType PING_FULL, PONG_FULL;
2577 mcIdType MAX_CP = 10000; // the choices below assume we won't have more than 10000 different connex parts ...
2578 mcIdType PING_FULL_init = 0, PING_PART = MAX_CP;
2579 mcIdType PONG_FULL_init = 0, PONG_PART = -MAX_CP;
2581 while (nIter < nIterMax)
2583 DAInt t = hitCells->findIdsEqual(0);
2584 if(!t->getNumberOfTuples())
2586 mcIdType seed = t->getIJ(0,0);
2589 PING_FULL = PING_FULL_init+cnt;
2590 PONG_FULL = PONG_FULL_init-cnt;
2591 // while the connex bits in correspondance on either side of the crack are not fully covered
2592 while(!done && nIter < nIterMax) // Start of the ping-pong
2595 // Identify connex zone around the seed - this zone corresponds to some cells on the other side
2596 // of the crack that might extend further away. So we will need to compute spread zone on the other side
2597 // too ... and this process can repeat, hence the "ping-pong" logic.
2599 DAInt spreadZone = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neigh,neighI, -1, dnu);
2601 for(const mcIdType& s: *spreadZone)
2603 hitCellsP[s] = PING_FULL;
2604 const auto& it = toOtherSide.find(s);
2605 if (it != toOtherSide.end())
2607 mcIdType other = it->second;
2608 if (hitCellsP[other] != PONG_FULL)
2610 // On the other side of the crack we hit a cell which was not fully covered previously by the
2611 // ComputeSpreadZone process, so we are not done yet, ComputeSreadZone will need to be applied there
2613 hitCellsP[other] = PONG_PART;
2614 // Compute next seed, i.e. a cell on the other side of the crack
2621 // we might have several disjoint PONG parts in front of a single PING connex part:
2622 DAInt idsPong = hitCells->findIdsEqual(PONG_PART);
2623 if (idsPong->getNumberOfTuples())
2625 seed = idsPong->getIJ(0,0);
2628 continue; // continue without switching side (or break if 'done' remains false)
2632 // Go to the other side
2633 std::swap(PING_FULL, PONG_FULL);
2634 std::swap(PING_PART, PONG_PART);
2636 } // while (!done ...)
2637 DAInt nonHitCells = hitCells->findIdsEqual(0);
2638 if (nonHitCells->getNumberOfTuples())
2639 seed = nonHitCells->getIJ(0,0);
2642 } // while (nIter < nIterMax ...
2643 if (nIter >= nIterMax)
2644 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellsToRenumber: Too many iterations - should not happen");
2646 // Now we have handled all N D cells which have a face touching the M1 group. It remains the cells
2647 // which are just touching the group by one (or several) node(s) (see for example testBuildInnerBoundaryAlongM1Group4)
2648 // All those cells are in direct contact with a cell which is either PING_FULL or PONG_FULL
2649 // So first reproject the PING/PONG info onto mAroundGrpLarge:
2650 DAInt hitCellsLarge = DataArrayIdType::New(); hitCellsLarge->alloc(nCellsLarge,1);
2651 hitCellsLarge->fillWithValue(0);
2652 mcIdType *hitCellsLargeP=hitCellsLarge->rwBegin(), tt=0;
2653 for(const auto &i: *idsStrict)
2654 { hitCellsLargeP[i] = hitCellsP[tt++]; }
2655 DAInt nonHitCells = hitCellsLarge->findIdsEqual(0);
2656 // Neighbor information in mAroundGrpLarge:
2657 DataArrayIdType *neighLt=0, *neighILt=0;
2658 MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(descL,descIL,revDescL,revDescIL, neighLt, neighILt);
2659 DAInt neighL(neighLt), neighIL(neighILt);
2660 const mcIdType *neighILP=neighIL->begin(), *neighLP=neighL->begin();
2661 for(const auto& c : *nonHitCells)
2663 mcIdType cnt00 = neighILP[c];
2664 for (const mcIdType *n=neighLP+cnt00; cnt00 < neighILP[c+1]; n++, cnt00++)
2666 mcIdType neighVal = hitCellsLargeP[*n];
2667 if (neighVal != 0 && std::abs(neighVal) < MAX_CP) // (@test_T0) second part of the test to skip cells being assigned and target only cells assigned in the first part of the algo above
2669 mcIdType currVal = hitCellsLargeP[c];
2670 if (currVal != 0) // Several neighbors have a candidate number
2672 // Unfortunately in some weird cases (see testBuildInnerBoundary8) a cell in mAroundGrpLarge
2673 // might have as neighbor two conflicting spread zone ...
2674 if (currVal*neighVal < 0)
2676 // If we arrive here, the cell was already assigned a number and we found a neighbor with
2677 // a different sign ... we must swap the whole spread zone!!
2678 DAInt ids1 = hitCellsLarge->findIdsEqual(neighVal), ids1b = hitCellsLarge->findIdsEqual(-neighVal);
2679 DAInt ids2 = hitCellsLarge->findIdsEqual(MAX_CP*neighVal), ids2b = hitCellsLarge->findIdsEqual(-MAX_CP*neighVal);
2680 // A nice little lambda to multiply part of a DAInt by -1 ...
2681 auto mul_part_min1 = [hitCellsLargeP](const DAInt& ids) { for(const auto& i: *ids) hitCellsLargeP[i] *= -1; };
2682 mul_part_min1(ids1);
2683 mul_part_min1(ids1b);
2684 mul_part_min1(ids2);
2685 mul_part_min1(ids2b);
2688 else // First assignation
2689 hitCellsLargeP[c] = MAX_CP*neighVal; // Same sign, but different value to preserve PING_FULL and PONG_FULL
2693 DAInt cellsRet1 = hitCellsLarge->findIdsInRange(1,MAX_CP*MAX_CP); // Positive spread zone number
2694 DAInt cellsRet2 = hitCellsLarge->findIdsInRange(-MAX_CP*MAX_CP, 0); // Negative spread zone number
2696 if (cellsRet1->getNumberOfTuples() + cellsRet2->getNumberOfTuples() != cellsAroundGroupLarge->getNumberOfTuples())
2697 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellsToRenumber: Some cells not hit - Internal error should not happen");
2698 cellsRet1->transformWithIndArr(cellsAroundGroupLarge->begin(),cellsAroundGroupLarge->end());
2699 cellsRet2->transformWithIndArr(cellsAroundGroupLarge->begin(),cellsAroundGroupLarge->end());
2701 cellIdsNeededToBeRenum=cellsRet1.retn();
2702 cellIdsNotModified=cellsRet2.retn();
2706 * This method operates a modification of the connectivity and coords in \b this.
2707 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2708 * its ids will be modified to id this->getNumberOfNodes()+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2709 * More explicitly the renumber array in nodes is not explicitly given in old2new to avoid to build a big array of renumbering whereas typically few node ids needs to be
2710 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id this->getNumberOfNodes()+0, node id nodeIdsToDuplicateBg[1] will have id this->getNumberOfNodes()+1,
2711 * node id nodeIdsToDuplicateBg[2] will have id this->getNumberOfNodes()+2...
2713 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2715 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2716 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2718 void MEDCouplingUMesh::duplicateNodes(const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd)
2720 mcIdType nbOfNodes=getNumberOfNodes();
2721 duplicateNodesInCoords(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd);
2722 duplicateNodesInConn(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,nbOfNodes);
2726 * This method renumbers only nodal connectivity in \a this. The renumbering is only an offset applied. So this method is a specialization of
2727 * \a renumberNodesInConn. \b WARNING, this method does not check that the resulting node ids in the nodal connectivity is in a valid range !
2729 * \param [in] offset - specifies the offset to be applied on each element of connectivity.
2731 * \sa renumberNodesInConn
2733 void MEDCouplingUMesh::renumberNodesWithOffsetInConn(mcIdType offset)
2735 checkConnectivityFullyDefined();
2736 mcIdType *conn(getNodalConnectivity()->getPointer());
2737 const mcIdType *connIndex(getNodalConnectivityIndex()->getConstPointer());
2738 mcIdType nbOfCells=getNumberOfCells();
2739 for(mcIdType i=0;i<nbOfCells;i++)
2740 for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2742 mcIdType& node=conn[iconn];
2743 if(node>=0)//avoid polyhedron separator
2748 _nodal_connec->declareAsNew();
2753 * Same than renumberNodesInConn(const mcIdType *) except that here the format of old-to-new traducer is using map instead
2754 * 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
2757 void MEDCouplingUMesh::renumberNodesInConn(const INTERP_KERNEL::HashMap<mcIdType,mcIdType>& newNodeNumbersO2N)
2759 this->renumberNodesInConnT< INTERP_KERNEL::HashMap<mcIdType,mcIdType> >(newNodeNumbersO2N);
2763 * Same than renumberNodesInConn(const mcIdType *) except that here the format of old-to-new traducer is using map instead
2764 * 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
2767 void MEDCouplingUMesh::renumberNodesInConn(const std::map<mcIdType,mcIdType>& newNodeNumbersO2N)
2769 this->renumberNodesInConnT< std::map<mcIdType,mcIdType> >(newNodeNumbersO2N);
2773 * Changes ids of nodes within the nodal connectivity arrays according to a permutation
2774 * array in "Old to New" mode. The node coordinates array is \b not changed by this method.
2775 * This method is a generalization of shiftNodeNumbersInConn().
2776 * \warning This method performs no check of validity of new ids. **Use it with care !**
2777 * \param [in] newNodeNumbersO2N - a permutation array, of length \a
2778 * this->getNumberOfNodes(), in "Old to New" mode.
2779 * See \ref numbering for more info on renumbering modes.
2780 * \throw If the nodal connectivity of cells is not defined.
2782 * \if ENABLE_EXAMPLES
2783 * \ref cpp_mcumesh_renumberNodesInConn "Here is a C++ example".<br>
2784 * \ref py_mcumesh_renumberNodesInConn "Here is a Python example".
2787 void MEDCouplingUMesh::renumberNodesInConn(const mcIdType *newNodeNumbersO2N)
2789 checkConnectivityFullyDefined();
2790 mcIdType *conn=getNodalConnectivity()->getPointer();
2791 const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2792 mcIdType nbOfCells=getNumberOfCells();
2793 for(mcIdType i=0;i<nbOfCells;i++)
2794 for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2796 mcIdType& node=conn[iconn];
2797 if(node>=0)//avoid polyhedron separator
2799 node=newNodeNumbersO2N[node];
2802 _nodal_connec->declareAsNew();
2807 * This method renumbers nodes \b in \b connectivity \b only \b without \b any \b reference \b to \b coords.
2808 * This method performs no check on the fact that new coordinate ids are valid. \b Use \b it \b with \b care !
2809 * This method is an specialization of \ref MEDCoupling::MEDCouplingUMesh::renumberNodesInConn "renumberNodesInConn method".
2811 * \param [in] delta specifies the shift size applied to nodeId in nodal connectivity in \b this.
2813 void MEDCouplingUMesh::shiftNodeNumbersInConn(mcIdType delta)
2815 checkConnectivityFullyDefined();
2816 mcIdType *conn=getNodalConnectivity()->getPointer();
2817 const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2818 mcIdType nbOfCells=getNumberOfCells();
2819 for(mcIdType i=0;i<nbOfCells;i++)
2820 for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2822 mcIdType& node=conn[iconn];
2823 if(node>=0)//avoid polyhedron separator
2828 _nodal_connec->declareAsNew();
2833 * This method operates a modification of the connectivity in \b this.
2834 * 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.
2835 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2836 * its ids will be modified to id offset+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2837 * More explicitly the renumber array in nodes is not explicitly given in old2new to avoid to build a big array of renumbering whereas typically few node ids needs to be
2838 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id offset+0, node id nodeIdsToDuplicateBg[1] will have id offset+1,
2839 * node id nodeIdsToDuplicateBg[2] will have id offset+2...
2841 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2842 * As an another consequense after the call of this method \b this can be transiently non cohrent.
2844 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2845 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2846 * \param [in] offset the offset applied to all node ids in connectivity that are in [ \a nodeIdsToDuplicateBg, \a nodeIdsToDuplicateEnd ).
2848 void MEDCouplingUMesh::duplicateNodesInConn(const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd, mcIdType offset)
2850 checkConnectivityFullyDefined();
2851 std::map<mcIdType,mcIdType> m;
2852 mcIdType val=offset;
2853 for(const mcIdType *work=nodeIdsToDuplicateBg;work!=nodeIdsToDuplicateEnd;work++,val++)
2855 mcIdType *conn=getNodalConnectivity()->getPointer();
2856 const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2857 mcIdType nbOfCells=getNumberOfCells();
2858 for(mcIdType i=0;i<nbOfCells;i++)
2859 for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2861 mcIdType& node=conn[iconn];
2862 if(node>=0)//avoid polyhedron separator
2864 std::map<mcIdType,mcIdType>::iterator it=m.find(node);
2873 * This method renumbers cells of \a this using the array specified by [old2NewBg;old2NewBg+getNumberOfCells())
2875 * Contrary to MEDCouplingPointSet::renumberNodes, this method makes a permutation without any fuse of cell.
2876 * After the call of this method the number of cells remains the same as before.
2878 * If 'check' equals true the method will check that any elements in [ \a old2NewBg; \a old2NewEnd ) is unique ; if not
2879 * an INTERP_KERNEL::Exception will be thrown. When 'check' equals true [ \a old2NewBg ; \a old2NewEnd ) is not expected to
2880 * be strictly in [0;this->getNumberOfCells()).
2882 * If 'check' equals false the method will not check the content of [ \a old2NewBg ; \a old2NewEnd ).
2883 * To avoid any throw of SIGSEGV when 'check' equals false, the elements in [ \a old2NewBg ; \a old2NewEnd ) should be unique and
2884 * should be contained in[0;this->getNumberOfCells()).
2886 * \param [in] old2NewBg is expected to be a dynamically allocated pointer of size at least equal to this->getNumberOfCells()
2887 * \param check whether to check content of old2NewBg
2889 void MEDCouplingUMesh::renumberCells(const mcIdType *old2NewBg, bool check)
2891 checkConnectivityFullyDefined();
2892 mcIdType nbCells=getNumberOfCells();
2893 const mcIdType *array=old2NewBg;
2895 array=DataArrayIdType::CheckAndPreparePermutation(old2NewBg,old2NewBg+nbCells);
2897 const mcIdType *conn=_nodal_connec->getConstPointer();
2898 const mcIdType *connI=_nodal_connec_index->getConstPointer();
2899 MCAuto<DataArrayIdType> o2n=DataArrayIdType::New(); o2n->useArray(array,false,DeallocType::C_DEALLOC,nbCells,1);
2900 MCAuto<DataArrayIdType> n2o=o2n->invertArrayO2N2N2O(nbCells);
2901 const mcIdType *n2oPtr=n2o->begin();
2902 MCAuto<DataArrayIdType> newConn=DataArrayIdType::New();
2903 newConn->alloc(_nodal_connec->getNumberOfTuples(),_nodal_connec->getNumberOfComponents());
2904 newConn->copyStringInfoFrom(*_nodal_connec);
2905 MCAuto<DataArrayIdType> newConnI=DataArrayIdType::New();
2906 newConnI->alloc(_nodal_connec_index->getNumberOfTuples(),_nodal_connec_index->getNumberOfComponents());
2907 newConnI->copyStringInfoFrom(*_nodal_connec_index);
2909 mcIdType *newC=newConn->getPointer();
2910 mcIdType *newCI=newConnI->getPointer();
2913 for(mcIdType i=0;i<nbCells;i++)
2915 mcIdType pos=n2oPtr[i];
2916 mcIdType nbOfElts=connI[pos+1]-connI[pos];
2917 newC=std::copy(conn+connI[pos],conn+connI[pos+1],newC);
2922 setConnectivity(newConn,newConnI);
2924 free(const_cast<mcIdType *>(array));
2928 * Finds cells whose bounding boxes intersect a given bounding box.
2929 * \param [in] bbox - an array defining the bounding box via coordinates of its
2930 * extremum points in "no interlace" mode, i.e. xMin, xMax, yMin, yMax, zMin,
2932 * \param [in] eps - a factor used to increase size of the bounding box of cell
2933 * before comparing it with \a bbox. This factor is multiplied by the maximal
2934 * extent of the bounding box of cell to produce an addition to this bounding box.
2935 * \return DataArrayIdType * - a new instance of DataArrayIdType holding ids for found
2936 * cells. The caller is to delete this array using decrRef() as it is no more
2938 * \throw If the coordinates array is not set.
2939 * \throw If the nodal connectivity of cells is not defined.
2941 * \if ENABLE_EXAMPLES
2942 * \ref cpp_mcumesh_getCellsInBoundingBox "Here is a C++ example".<br>
2943 * \ref py_mcumesh_getCellsInBoundingBox "Here is a Python example".
2946 DataArrayIdType *MEDCouplingUMesh::getCellsInBoundingBox(const double *bbox, double eps) const
2948 MCAuto<DataArrayIdType> elems=DataArrayIdType::New(); elems->alloc(0,1);
2949 if(getMeshDimension()==-1)
2951 elems->pushBackSilent(0);
2952 return elems.retn();
2954 int dim=getSpaceDimension();
2955 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2956 const mcIdType* conn = getNodalConnectivity()->getConstPointer();
2957 const mcIdType* conn_index= getNodalConnectivityIndex()->getConstPointer();
2958 const double* coords = getCoords()->getConstPointer();
2959 mcIdType nbOfCells=getNumberOfCells();
2960 for ( mcIdType ielem=0; ielem<nbOfCells;ielem++ )
2962 for (int i=0; i<dim; i++)
2964 elem_bb[i*2]=std::numeric_limits<double>::max();
2965 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2968 for (mcIdType inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2970 mcIdType node= conn[inode];
2971 if(node>=0)//avoid polyhedron separator
2973 for (int idim=0; idim<dim; idim++)
2975 if ( coords[node*dim+idim] < elem_bb[idim*2] )
2977 elem_bb[idim*2] = coords[node*dim+idim] ;
2979 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2981 elem_bb[idim*2+1] = coords[node*dim+idim] ;
2986 if (intersectsBoundingBox(elem_bb, bbox, dim, eps))
2987 elems->pushBackSilent(ielem);
2989 return elems.retn();
2993 * Given a boundary box 'bbox' returns elements 'elems' contained in this 'bbox' or touching 'bbox' (within 'eps' distance).
2994 * Warning 'elems' is incremented during the call so if elems is not empty before call returned elements will be
2995 * added in 'elems' parameter.
2997 DataArrayIdType *MEDCouplingUMesh::getCellsInBoundingBox(const INTERP_KERNEL::DirectedBoundingBox& bbox, double eps)
2999 MCAuto<DataArrayIdType> elems=DataArrayIdType::New(); elems->alloc(0,1);
3000 if(getMeshDimension()==-1)
3002 elems->pushBackSilent(0);
3003 return elems.retn();
3005 int dim=getSpaceDimension();
3006 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
3007 const mcIdType* conn = getNodalConnectivity()->getConstPointer();
3008 const mcIdType* conn_index= getNodalConnectivityIndex()->getConstPointer();
3009 const double* coords = getCoords()->getConstPointer();
3010 mcIdType nbOfCells=getNumberOfCells();
3011 for ( mcIdType ielem=0; ielem<nbOfCells;ielem++ )
3013 for (int i=0; i<dim; i++)
3015 elem_bb[i*2]=std::numeric_limits<double>::max();
3016 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
3019 for (mcIdType inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
3021 mcIdType node= conn[inode];
3022 if(node>=0)//avoid polyhedron separator
3024 for (int idim=0; idim<dim; idim++)
3026 if ( coords[node*dim+idim] < elem_bb[idim*2] )
3028 elem_bb[idim*2] = coords[node*dim+idim] ;
3030 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
3032 elem_bb[idim*2+1] = coords[node*dim+idim] ;
3037 if(intersectsBoundingBox(bbox, elem_bb, dim, eps))
3038 elems->pushBackSilent(ielem);
3040 return elems.retn();
3044 * Returns a type of a cell by its id.
3045 * \param [in] cellId - the id of the cell of interest.
3046 * \return INTERP_KERNEL::NormalizedCellType - enumeration item describing the cell type.
3047 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
3049 INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::getTypeOfCell(mcIdType cellId) const
3051 const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
3052 if(cellId<_nodal_connec_index->getNbOfElems()-1)
3053 return (INTERP_KERNEL::NormalizedCellType) pt[ptI[cellId]];
3056 std::ostringstream oss; oss << "MEDCouplingUMesh::getTypeOfCell : Requesting type of cell #" << cellId << " but it should be in [0," << _nodal_connec_index->getNbOfElems()-1 << ") !";
3057 throw INTERP_KERNEL::Exception(oss.str());
3062 * This method returns a newly allocated array containing cell ids (ascendingly sorted) whose geometric type are equal to type.
3063 * This method does not throw exception if geometric type \a type is not in \a this.
3064 * This method throws an INTERP_KERNEL::Exception if meshdimension of \b this is not equal to those of \b type.
3065 * The coordinates array is not considered here.
3067 * \param [in] type the geometric type
3068 * \return cell ids in this having geometric type \a type.
3070 DataArrayIdType *MEDCouplingUMesh::giveCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
3073 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
3075 checkConnectivityFullyDefined();
3076 mcIdType nbCells=getNumberOfCells();
3077 int mdim=getMeshDimension();
3078 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
3079 if(mdim!=ToIdType(cm.getDimension()))
3080 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::giveCellsWithType : Mismatch between mesh dimension and dimension of the cell !");
3081 const mcIdType *ptI=_nodal_connec_index->getConstPointer();
3082 const mcIdType *pt=_nodal_connec->getConstPointer();
3083 for(mcIdType i=0;i<nbCells;i++)
3085 if((INTERP_KERNEL::NormalizedCellType)pt[ptI[i]]==type)
3086 ret->pushBackSilent(i);
3092 * Returns nb of cells having the geometric type \a type. No throw if no cells in \a this has the geometric type \a type.
3094 mcIdType MEDCouplingUMesh::getNumberOfCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
3096 const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
3097 mcIdType nbOfCells(getNumberOfCells()),ret(0);
3098 for(mcIdType i=0;i<nbOfCells;i++)
3099 if((INTERP_KERNEL::NormalizedCellType) pt[ptI[i]]==type)
3105 * Returns the nodal connectivity of a given cell.
3106 * The separator of faces within polyhedron connectivity (-1) is not returned, thus
3107 * all returned node ids can be used in getCoordinatesOfNode().
3108 * \param [in] cellId - an id of the cell of interest.
3109 * \param [in,out] conn - a vector where the node ids are appended. It is not
3110 * cleared before the appending.
3111 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
3113 void MEDCouplingUMesh::getNodeIdsOfCell(mcIdType cellId, std::vector<mcIdType>& conn) const
3115 const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
3116 for(const mcIdType *w=pt+ptI[cellId]+1;w!=pt+ptI[cellId+1];w++)
3121 std::string MEDCouplingUMesh::simpleRepr() const
3123 static const char msg0[]="No coordinates specified !";
3124 std::ostringstream ret;
3125 ret << "Unstructured mesh with name : \"" << getName() << "\"\n";
3126 ret << "Description of mesh : \"" << getDescription() << "\"\n";
3128 double tt=getTime(tmpp1,tmpp2);
3129 ret << "Time attached to the mesh [unit] : " << tt << " [" << getTimeUnit() << "]\n";
3130 ret << "Iteration : " << tmpp1 << " Order : " << tmpp2 << "\n";
3132 { ret << "Mesh dimension : " << _mesh_dim << "\nSpace dimension : "; }
3134 { ret << " Mesh dimension has not been set or is invalid !"; }
3137 const int spaceDim=getSpaceDimension();
3138 ret << spaceDim << "\nInfo attached on space dimension : ";
3139 for(int i=0;i<spaceDim;i++)
3140 ret << "\"" << _coords->getInfoOnComponent(i) << "\" ";
3144 ret << msg0 << "\n";
3145 ret << "Number of nodes : ";
3147 ret << getNumberOfNodes() << "\n";
3149 ret << msg0 << "\n";
3150 ret << "Number of cells : ";
3151 if(_nodal_connec!=0 && _nodal_connec_index!=0)
3152 ret << getNumberOfCells() << "\n";
3154 ret << "No connectivity specified !" << "\n";
3155 ret << "Cell types present : ";
3156 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
3158 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter);
3159 ret << cm.getRepr() << " ";
3165 std::string MEDCouplingUMesh::advancedRepr() const
3167 std::ostringstream ret;
3168 ret << simpleRepr();
3169 ret << "\nCoordinates array : \n___________________\n\n";
3171 _coords->reprWithoutNameStream(ret);
3173 ret << "No array set !\n";
3174 ret << "\n\nConnectivity arrays : \n_____________________\n\n";
3175 reprConnectivityOfThisLL(ret);
3180 * This method returns a C++ code that is a dump of \a this.
3181 * This method will throw if this is not fully defined.
3183 std::string MEDCouplingUMesh::cppRepr() const
3185 static const char coordsName[]="coords";
3186 static const char connName[]="conn";
3187 static const char connIName[]="connI";
3188 checkFullyDefined();
3189 std::ostringstream ret; ret << "// coordinates" << std::endl;
3190 _coords->reprCppStream(coordsName,ret); ret << std::endl << "// connectivity" << std::endl;
3191 _nodal_connec->reprCppStream(connName,ret); ret << std::endl;
3192 _nodal_connec_index->reprCppStream(connIName,ret); ret << std::endl;
3193 ret << "MEDCouplingUMesh *mesh=MEDCouplingUMesh::New(\"" << getName() << "\"," << getMeshDimension() << ");" << std::endl;
3194 ret << "mesh->setCoords(" << coordsName << ");" << std::endl;
3195 ret << "mesh->setConnectivity(" << connName << "," << connIName << ",true);" << std::endl;
3196 ret << coordsName << "->decrRef(); " << connName << "->decrRef(); " << connIName << "->decrRef();" << std::endl;
3200 std::string MEDCouplingUMesh::reprConnectivityOfThis() const
3202 std::ostringstream ret;
3203 reprConnectivityOfThisLL(ret);
3208 * This method builds a newly allocated instance (with the same name than \a this) that the caller has the responsibility to deal with.
3209 * This method returns an instance with all arrays allocated (connectivity, connectivity index, coordinates)
3210 * but with length of these arrays set to 0. It allows to define an "empty" mesh (with nor cells nor nodes but compliant with
3213 * This method expects that \a this has a mesh dimension set and higher or equal to 0. If not an exception will be thrown.
3214 * 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
3215 * with number of tuples set to 0, if not the array is taken as this in the returned instance.
3217 MEDCouplingUMesh *MEDCouplingUMesh::buildSetInstanceFromThis(std::size_t spaceDim) const
3219 int mdim=getMeshDimension();
3221 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSetInstanceFromThis : invalid mesh dimension ! Should be >= 0 !");
3222 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
3223 MCAuto<DataArrayIdType> tmp1,tmp2;
3224 bool needToCpyCT=true;
3227 tmp1=DataArrayIdType::New(); tmp1->alloc(0,1);
3235 if(!_nodal_connec_index)
3237 tmp2=DataArrayIdType::New(); tmp2->alloc(1,1); tmp2->setIJ(0,0,0);
3242 tmp2=_nodal_connec_index;
3245 ret->setConnectivity(tmp1,tmp2,false);
3250 MCAuto<DataArrayDouble> coords=DataArrayDouble::New(); coords->alloc(0,spaceDim);
3251 ret->setCoords(coords);
3254 ret->setCoords(_coords);
3258 mcIdType MEDCouplingUMesh::getNumberOfNodesInCell(mcIdType cellId) const
3260 const mcIdType *ptI=_nodal_connec_index->getConstPointer();
3261 const mcIdType *pt=_nodal_connec->getConstPointer();
3262 if(pt[ptI[cellId]]!=INTERP_KERNEL::NORM_POLYHED)
3263 return ptI[cellId+1]-ptI[cellId]-1;
3265 return ToIdType(std::count_if(pt+ptI[cellId]+1,pt+ptI[cellId+1],std::bind(std::not_equal_to<mcIdType>(),std::placeholders::_1,-1)));
3269 * Returns types of cells of the specified part of \a this mesh.
3270 * This method avoids computing sub-mesh explicitly to get its types.
3271 * \param [in] begin - an array of cell ids of interest.
3272 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3273 * \return std::set<INTERP_KERNEL::NormalizedCellType> - a set of enumeration items
3274 * describing the cell types.
3275 * \throw If the coordinates array is not set.
3276 * \throw If the nodal connectivity of cells is not defined.
3277 * \sa getAllGeoTypes()
3279 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getTypesOfPart(const mcIdType *begin, const mcIdType *end) const
3281 checkFullyDefined();
3282 std::set<INTERP_KERNEL::NormalizedCellType> ret;
3283 const mcIdType *conn=_nodal_connec->getConstPointer();
3284 const mcIdType *connIndex=_nodal_connec_index->getConstPointer();
3285 for(const mcIdType *w=begin;w!=end;w++)
3286 ret.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]);
3291 * Defines the nodal connectivity using given connectivity arrays in \ref numbering-indirect format.
3292 * Optionally updates
3293 * a set of types of cells constituting \a this mesh.
3294 * This method is for advanced users having prepared their connectivity before. For
3295 * more info on using this method see \ref MEDCouplingUMeshAdvBuild.
3296 * \param [in] conn - the nodal connectivity array.
3297 * \param [in] connIndex - the nodal connectivity index array.
3298 * \param [in] isComputingTypes - if \c true, the set of types constituting \a this
3301 void MEDCouplingUMesh::setConnectivity(DataArrayIdType *conn, DataArrayIdType *connIndex, bool isComputingTypes)
3303 DataArrayIdType::SetArrayIn(conn,_nodal_connec);
3304 DataArrayIdType::SetArrayIn(connIndex,_nodal_connec_index);
3305 if(isComputingTypes)
3311 * Copy constructor. If 'deepCopy' is false \a this is a shallow copy of other.
3312 * If 'deeCpy' is true all arrays (coordinates and connectivities) are deeply copied.
3314 MEDCouplingUMesh::MEDCouplingUMesh(const MEDCouplingUMesh& other, bool deepCpy):MEDCouplingPointSet(other,deepCpy),_mesh_dim(other._mesh_dim),
3315 _nodal_connec(0),_nodal_connec_index(0),
3316 _types(other._types)
3318 if(other._nodal_connec)
3319 _nodal_connec=other._nodal_connec->performCopyOrIncrRef(deepCpy);
3320 if(other._nodal_connec_index)
3321 _nodal_connec_index=other._nodal_connec_index->performCopyOrIncrRef(deepCpy);
3324 MEDCouplingUMesh::~MEDCouplingUMesh()
3327 _nodal_connec->decrRef();
3328 if(_nodal_connec_index)
3329 _nodal_connec_index->decrRef();
3333 * Recomputes a set of cell types of \a this mesh. For more info see
3334 * \ref MEDCouplingUMeshNodalConnectivity.
3336 void MEDCouplingUMesh::computeTypes()
3338 ComputeAllTypesInternal(_types,_nodal_connec,_nodal_connec_index);
3343 * Returns a number of cells constituting \a this mesh.
3344 * \return mcIdType - the number of cells in \a this mesh.
3345 * \throw If the nodal connectivity of cells is not defined.
3347 mcIdType MEDCouplingUMesh::getNumberOfCells() const
3349 if(_nodal_connec_index)
3350 return _nodal_connec_index->getNumberOfTuples()-1;
3355 throw INTERP_KERNEL::Exception("Unable to get number of cells because no connectivity specified !");
3359 * Returns a dimension of \a this mesh, i.e. a dimension of cells constituting \a this
3360 * mesh. For more info see \ref meshes.
3361 * \return int - the dimension of \a this mesh.
3362 * \throw If the mesh dimension is not defined using setMeshDimension().
3364 int MEDCouplingUMesh::getMeshDimension() const
3367 throw INTERP_KERNEL::Exception("No mesh dimension specified !");
3372 * Returns a length of the nodal connectivity array.
3373 * This method is for test reason. Normally the integer returned is not useable by
3374 * user. For more info see \ref MEDCouplingUMeshNodalConnectivity.
3375 * \return mcIdType - the length of the nodal connectivity array.
3377 mcIdType MEDCouplingUMesh::getNodalConnectivityArrayLen() const
3379 return _nodal_connec->getNbOfElems();
3383 * First step of serialization process. Used by ParaMEDMEM and MEDCouplingCorba to transfert data between process.
3385 void MEDCouplingUMesh::getTinySerializationInformation(std::vector<double>& tinyInfoD, std::vector<mcIdType>& tinyInfo, std::vector<std::string>& littleStrings) const
3387 MEDCouplingPointSet::getTinySerializationInformation(tinyInfoD,tinyInfo,littleStrings);
3388 tinyInfo.push_back(ToIdType(getMeshDimension()));
3389 tinyInfo.push_back(getNumberOfCells());
3391 tinyInfo.push_back(getNodalConnectivityArrayLen());
3393 tinyInfo.push_back(-1);
3397 * First step of unserialization process.
3399 bool MEDCouplingUMesh::isEmptyMesh(const std::vector<mcIdType>& tinyInfo) const
3401 return tinyInfo[6]<=0;
3405 * Second step of serialization process.
3406 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3407 * \param a1 DataArrayDouble
3408 * \param a2 DataArrayDouble
3409 * \param littleStrings string vector
3411 void MEDCouplingUMesh::resizeForUnserialization(const std::vector<mcIdType>& tinyInfo, DataArrayIdType *a1, DataArrayDouble *a2, std::vector<std::string>& littleStrings) const
3413 MEDCouplingPointSet::resizeForUnserialization(tinyInfo,a1,a2,littleStrings);
3415 a1->alloc(tinyInfo[7]+tinyInfo[6]+1,1);
3419 * Third and final step of serialization process.
3421 void MEDCouplingUMesh::serialize(DataArrayIdType *&a1, DataArrayDouble *&a2) const
3423 MEDCouplingPointSet::serialize(a1,a2);
3424 if(getMeshDimension()>-1)
3426 a1=DataArrayIdType::New();
3427 a1->alloc(getNodalConnectivityArrayLen()+getNumberOfCells()+1,1);
3428 mcIdType *ptA1=a1->getPointer();
3429 const mcIdType *conn=getNodalConnectivity()->getConstPointer();
3430 const mcIdType *index=getNodalConnectivityIndex()->getConstPointer();
3431 ptA1=std::copy(index,index+getNumberOfCells()+1,ptA1);
3432 std::copy(conn,conn+getNodalConnectivityArrayLen(),ptA1);
3439 * Second and final unserialization process.
3440 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3442 void MEDCouplingUMesh::unserialization(const std::vector<double>& tinyInfoD, const std::vector<mcIdType>& tinyInfo, const DataArrayIdType *a1, DataArrayDouble *a2, const std::vector<std::string>& littleStrings)
3444 MEDCouplingPointSet::unserialization(tinyInfoD,tinyInfo,a1,a2,littleStrings);
3445 setMeshDimension(FromIdType<int>(tinyInfo[5]));
3449 const mcIdType *recvBuffer=a1->getConstPointer();
3450 MCAuto<DataArrayIdType> myConnecIndex=DataArrayIdType::New();
3451 myConnecIndex->alloc(tinyInfo[6]+1,1);
3452 std::copy(recvBuffer,recvBuffer+tinyInfo[6]+1,myConnecIndex->getPointer());
3453 MCAuto<DataArrayIdType> myConnec=DataArrayIdType::New();
3454 myConnec->alloc(tinyInfo[7],1);
3455 std::copy(recvBuffer+tinyInfo[6]+1,recvBuffer+tinyInfo[6]+1+tinyInfo[7],myConnec->getPointer());
3456 setConnectivity(myConnec, myConnecIndex);
3463 * Returns a new MEDCouplingFieldDouble containing volumes of cells constituting \a this
3465 * For 1D cells, the returned field contains lengths.<br>
3466 * For 2D cells, the returned field contains areas.<br>
3467 * For 3D cells, the returned field contains volumes.
3468 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3469 * orientation, i.e. the volume is always positive.
3470 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on cells
3471 * and one time . The caller is to delete this field using decrRef() as it is no
3474 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureField(bool isAbs) const
3476 std::string name="MeasureOfMesh_";
3478 mcIdType nbelem=getNumberOfCells();
3479 MCAuto<MEDCouplingFieldDouble> field=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3480 field->setName(name);
3481 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3482 array->alloc(nbelem,1);
3483 double *area_vol=array->getPointer();
3484 field->setArray(array) ; array=0;
3485 field->setMesh(const_cast<MEDCouplingUMesh *>(this));
3486 field->synchronizeTimeWithMesh();
3487 if(getMeshDimension()!=-1)
3490 INTERP_KERNEL::NormalizedCellType type;
3491 int dim_space=getSpaceDimension();
3492 const double *coords=getCoords()->getConstPointer();
3493 const mcIdType *connec=getNodalConnectivity()->getConstPointer();
3494 const mcIdType *connec_index=getNodalConnectivityIndex()->getConstPointer();
3495 for(mcIdType iel=0;iel<nbelem;iel++)
3497 ipt=connec_index[iel];
3498 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3499 area_vol[iel]=INTERP_KERNEL::computeVolSurfOfCell2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,connec+ipt+1,connec_index[iel+1]-ipt-1,coords,dim_space);
3502 std::transform(area_vol,area_vol+nbelem,area_vol,[](double c){return fabs(c);});
3506 area_vol[0]=std::numeric_limits<double>::max();
3508 return field.retn();
3512 * Returns a new DataArrayDouble containing volumes of specified cells of \a this
3514 * For 1D cells, the returned array contains lengths.<br>
3515 * For 2D cells, the returned array contains areas.<br>
3516 * For 3D cells, the returned array contains volumes.
3517 * This method avoids building explicitly a part of \a this mesh to perform the work.
3518 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3519 * orientation, i.e. the volume is always positive.
3520 * \param [in] begin - an array of cell ids of interest.
3521 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3522 * \return DataArrayDouble * - a new instance of DataArrayDouble. The caller is to
3523 * delete this array using decrRef() as it is no more needed.
3525 * \if ENABLE_EXAMPLES
3526 * \ref cpp_mcumesh_getPartMeasureField "Here is a C++ example".<br>
3527 * \ref py_mcumesh_getPartMeasureField "Here is a Python example".
3529 * \sa getMeasureField()
3531 DataArrayDouble *MEDCouplingUMesh::getPartMeasureField(bool isAbs, const mcIdType *begin, const mcIdType *end) const
3533 std::string name="PartMeasureOfMesh_";
3535 std::size_t nbelem=std::distance(begin,end);
3536 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3537 array->setName(name);
3538 array->alloc(nbelem,1);
3539 double *area_vol=array->getPointer();
3540 if(getMeshDimension()!=-1)
3543 INTERP_KERNEL::NormalizedCellType type;
3544 int dim_space=getSpaceDimension();
3545 const double *coords=getCoords()->getConstPointer();
3546 const mcIdType *connec=getNodalConnectivity()->getConstPointer();
3547 const mcIdType *connec_index=getNodalConnectivityIndex()->getConstPointer();
3548 for(const mcIdType *iel=begin;iel!=end;iel++)
3550 ipt=connec_index[*iel];
3551 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3552 *area_vol++=INTERP_KERNEL::computeVolSurfOfCell2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,connec+ipt+1,connec_index[*iel+1]-ipt-1,coords,dim_space);
3555 std::transform(array->getPointer(),area_vol,array->getPointer(),[](double c){return fabs(c);});
3559 area_vol[0]=std::numeric_limits<double>::max();
3561 return array.retn();
3565 * Returns a new MEDCouplingFieldDouble containing volumes of cells of a dual mesh of
3566 * \a this one. The returned field contains the dual cell volume for each corresponding
3567 * node in \a this mesh. In other words, the field returns the getMeasureField() of
3568 * the dual mesh in P1 sens of \a this.<br>
3569 * For 1D cells, the returned field contains lengths.<br>
3570 * For 2D cells, the returned field contains areas.<br>
3571 * For 3D cells, the returned field contains volumes.
3572 * This method is useful to check "P1*" conservative interpolators.
3573 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3574 * orientation, i.e. the volume is always positive.
3575 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3576 * nodes and one time. The caller is to delete this array using decrRef() as
3577 * it is no more needed.
3579 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureFieldOnNode(bool isAbs) const
3581 MCAuto<MEDCouplingFieldDouble> tmp=getMeasureField(isAbs);
3582 std::string name="MeasureOnNodeOfMesh_";
3584 mcIdType nbNodes=getNumberOfNodes();
3585 MCAuto<DataArrayDouble> nnpc;
3587 MCAuto<DataArrayIdType> tmp2(computeNbOfNodesPerCell());
3588 nnpc=tmp2->convertToDblArr();
3590 std::for_each(nnpc->rwBegin(),nnpc->rwEnd(),[](double& v) { v=1./v; });
3591 const double *nnpcPtr(nnpc->begin());
3592 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_NODES);
3593 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3594 array->alloc(nbNodes,1);
3595 double *valsToFill=array->getPointer();
3596 std::fill(valsToFill,valsToFill+nbNodes,0.);
3597 const double *values=tmp->getArray()->getConstPointer();
3598 MCAuto<DataArrayIdType> da=DataArrayIdType::New();
3599 MCAuto<DataArrayIdType> daInd=DataArrayIdType::New();
3600 getReverseNodalConnectivity(da,daInd);
3601 const mcIdType *daPtr=da->getConstPointer();
3602 const mcIdType *daIPtr=daInd->getConstPointer();
3603 for(mcIdType i=0;i<nbNodes;i++)
3604 for(const mcIdType *cell=daPtr+daIPtr[i];cell!=daPtr+daIPtr[i+1];cell++)
3605 valsToFill[i]+=nnpcPtr[*cell]*values[*cell];
3607 ret->setArray(array);
3612 * Returns a new MEDCouplingFieldDouble holding normal vectors to cells of \a this
3613 * mesh. The returned normal vectors to each cell have a norm2 equal to 1.
3614 * The computed vectors have <em> this->getMeshDimension()+1 </em> components
3615 * and are normalized.
3616 * <br> \a this can be either
3617 * - a 2D mesh in 2D or 3D space or
3618 * - an 1D mesh in 2D space.
3620 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3621 * cells and one time. The caller is to delete this field using decrRef() as
3622 * it is no more needed.
3623 * \throw If the nodal connectivity of cells is not defined.
3624 * \throw If the coordinates array is not set.
3625 * \throw If the mesh dimension is not set.
3626 * \throw If the mesh and space dimension is not as specified above.
3628 MEDCouplingFieldDouble *MEDCouplingUMesh::buildOrthogonalField() const
3630 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3631 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3632 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3633 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3634 mcIdType nbOfCells=getNumberOfCells();
3635 int nbComp=getMeshDimension()+1;
3636 array->alloc(nbOfCells,nbComp);
3637 double *vals=array->getPointer();
3638 const mcIdType *connI=_nodal_connec_index->getConstPointer();
3639 const mcIdType *conn=_nodal_connec->getConstPointer();
3640 const double *coords=_coords->getConstPointer();
3641 if(getMeshDimension()==2)
3643 if(getSpaceDimension()==3)
3645 MCAuto<DataArrayDouble> loc=computeCellCenterOfMass();
3646 const double *locPtr=loc->getConstPointer();
3647 for(mcIdType i=0;i<nbOfCells;i++,vals+=3)
3649 mcIdType offset=connI[i];
3650 INTERP_KERNEL::crossprod<3>(locPtr+3*i,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3651 double n=INTERP_KERNEL::norm<3>(vals);
3652 std::transform(vals,vals+3,vals,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3657 MCAuto<MEDCouplingFieldDouble> isAbs=getMeasureField(false);
3658 const double *isAbsPtr=isAbs->getArray()->begin();
3659 for(mcIdType i=0;i<nbOfCells;i++,isAbsPtr++)
3660 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=*isAbsPtr>0.?1.:-1.; }
3663 else//meshdimension==1
3666 for(mcIdType i=0;i<nbOfCells;i++)
3668 mcIdType offset=connI[i];
3669 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3670 double n=INTERP_KERNEL::norm<2>(tmp);
3671 std::transform(tmp,tmp+2,tmp,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3676 ret->setArray(array);
3678 ret->synchronizeTimeWithSupport();
3683 * Returns a new MEDCouplingFieldDouble holding normal vectors to specified cells of
3684 * \a this mesh. The computed vectors have <em> this->getMeshDimension()+1 </em> components
3685 * and are normalized.
3686 * <br> \a this can be either
3687 * - a 2D mesh in 2D or 3D space or
3688 * - an 1D mesh in 2D space.
3690 * This method avoids building explicitly a part of \a this mesh to perform the work.
3691 * \param [in] begin - an array of cell ids of interest.
3692 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3693 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3694 * cells and one time. The caller is to delete this field using decrRef() as
3695 * it is no more needed.
3696 * \throw If the nodal connectivity of cells is not defined.
3697 * \throw If the coordinates array is not set.
3698 * \throw If the mesh dimension is not set.
3699 * \throw If the mesh and space dimension is not as specified above.
3700 * \sa buildOrthogonalField()
3702 * \if ENABLE_EXAMPLES
3703 * \ref cpp_mcumesh_buildPartOrthogonalField "Here is a C++ example".<br>
3704 * \ref py_mcumesh_buildPartOrthogonalField "Here is a Python example".
3707 MEDCouplingFieldDouble *MEDCouplingUMesh::buildPartOrthogonalField(const mcIdType *begin, const mcIdType *end) const
3709 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3710 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3711 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3712 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3713 std::size_t nbelems=std::distance(begin,end);
3714 int nbComp=getMeshDimension()+1;
3715 array->alloc(nbelems,nbComp);
3716 double *vals=array->getPointer();
3717 const mcIdType *connI=_nodal_connec_index->getConstPointer();
3718 const mcIdType *conn=_nodal_connec->getConstPointer();
3719 const double *coords=_coords->getConstPointer();
3720 if(getMeshDimension()==2)
3722 if(getSpaceDimension()==3)
3724 MCAuto<DataArrayDouble> loc=getPartBarycenterAndOwner(begin,end);
3725 const double *locPtr=loc->getConstPointer();
3726 for(const mcIdType *i=begin;i!=end;i++,vals+=3,locPtr+=3)
3728 mcIdType offset=connI[*i];
3729 INTERP_KERNEL::crossprod<3>(locPtr,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3730 double n=INTERP_KERNEL::norm<3>(vals);
3731 std::transform(vals,vals+3,vals,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3736 for(std::size_t i=0;i<nbelems;i++)
3737 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=1.; }
3740 else//meshdimension==1
3743 for(const mcIdType *i=begin;i!=end;i++)
3745 mcIdType offset=connI[*i];
3746 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3747 double n=INTERP_KERNEL::norm<2>(tmp);
3748 std::transform(tmp,tmp+2,tmp,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3753 ret->setArray(array);
3755 ret->synchronizeTimeWithSupport();
3760 * Returns a new MEDCouplingFieldDouble holding a direction vector for each SEG2 in \a
3761 * this 1D mesh. The computed vectors have <em> this->getSpaceDimension() </em> components
3762 * and are \b not normalized.
3763 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3764 * cells and one time. The caller is to delete this field using decrRef() as
3765 * it is no more needed.
3766 * \throw If the nodal connectivity of cells is not defined.
3767 * \throw If the coordinates array is not set.
3768 * \throw If \a this->getMeshDimension() != 1.
3769 * \throw If \a this mesh includes cells of type other than SEG2.
3771 MEDCouplingFieldDouble *MEDCouplingUMesh::buildDirectionVectorField() const
3773 if(getMeshDimension()!=1)
3774 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for buildDirectionVectorField !");
3775 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3776 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for buildDirectionVectorField !");
3777 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3778 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3779 mcIdType nbOfCells=getNumberOfCells();
3780 int spaceDim=getSpaceDimension();
3781 array->alloc(nbOfCells,spaceDim);
3782 double *pt=array->getPointer();
3783 const double *coo=getCoords()->getConstPointer();
3784 std::vector<mcIdType> conn;
3786 for(mcIdType i=0;i<nbOfCells;i++)
3789 getNodeIdsOfCell(i,conn);
3790 pt=std::transform(coo+conn[1]*spaceDim,coo+(conn[1]+1)*spaceDim,coo+conn[0]*spaceDim,pt,std::minus<double>());
3792 ret->setArray(array);
3794 ret->synchronizeTimeWithSupport();
3799 * Creates a 2D mesh by cutting \a this 3D mesh with a plane. In addition to the mesh,
3800 * returns a new DataArrayIdType, of length equal to the number of 2D cells in the result
3801 * mesh, holding, for each cell in the result mesh, an id of a 3D cell it comes
3802 * from. If a result face is shared by two 3D cells, then the face in included twice in
3804 * \param [in] origin - 3 components of a point defining location of the plane.
3805 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3806 * must be greater than 1e-6.
3807 * \param [in] eps - half-thickness of the plane.
3808 * \param [out] cellIds - a new instance of DataArrayIdType holding ids of 3D cells
3809 * producing correspondent 2D cells. The caller is to delete this array
3810 * using decrRef() as it is no more needed.
3811 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This mesh does
3812 * not share the node coordinates array with \a this mesh. The caller is to
3813 * delete this mesh using decrRef() as it is no more needed.
3814 * \throw If the coordinates array is not set.
3815 * \throw If the nodal connectivity of cells is not defined.
3816 * \throw If \a this->getMeshDimension() != 3 or \a this->getSpaceDimension() != 3.
3817 * \throw If magnitude of \a vec is less than 1e-6.
3818 * \throw If the plane does not intersect any 3D cell of \a this mesh.
3819 * \throw If \a this includes quadratic cells.
3821 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3D(const double *origin, const double *vec, double eps, DataArrayIdType *&cellIds) const
3823 checkFullyDefined();
3824 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3825 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3826 MCAuto<DataArrayIdType> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3827 if(candidates->empty())
3828 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane considering bounding boxes !");
3829 std::vector<mcIdType> nodes;
3830 DataArrayIdType *cellIds1D=0;
3831 MCAuto<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3832 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3833 MCAuto<DataArrayIdType> desc1=DataArrayIdType::New(),desc2=DataArrayIdType::New();
3834 MCAuto<DataArrayIdType> descIndx1=DataArrayIdType::New(),descIndx2=DataArrayIdType::New();
3835 MCAuto<DataArrayIdType> revDesc1=DataArrayIdType::New(),revDesc2=DataArrayIdType::New();
3836 MCAuto<DataArrayIdType> revDescIndx1=DataArrayIdType::New(),revDescIndx2=DataArrayIdType::New();
3837 MCAuto<MEDCouplingUMesh> mDesc2=subMesh->buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2);//meshDim==2 spaceDim==3
3838 revDesc2=0; revDescIndx2=0;
3839 MCAuto<MEDCouplingUMesh> mDesc1=mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3840 revDesc1=0; revDescIndx1=0;
3841 //Marking all 1D cells that contained at least one node located on the plane
3842 //the intersection between those cells and the plane, which consist of the nodes previously tagged, thus don't need to be computed afterwards
3843 //(if said intersection is computed in MEDCouplingUMesh::split3DCurveWithPlane, then we might create additional nodes
3844 //due to accuracy errors when the needed nodes already exist)
3845 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),false,cellIds1D);
3846 MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3848 std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3849 for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3851 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3852 std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(mDesc2->getNumberOfCells());
3853 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->getConstPointer(),mDesc2->getNodalConnectivityIndex()->getConstPointer(),
3854 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3855 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3856 MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New()),cellIds2(DataArrayIdType::New());
3857 connI->pushBackSilent(0); conn->alloc(0,1); cellIds2->alloc(0,1);
3858 subMesh->assemblyForSplitFrom3DSurf(cut3DSurf,desc2->getConstPointer(),descIndx2->getConstPointer(),conn,connI,cellIds2);
3859 if(cellIds2->empty())
3860 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3861 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3D",2);
3862 ret->setCoords(mDesc1->getCoords());
3863 ret->setConnectivity(conn,connI,true);
3864 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3869 * Creates an 1D mesh by cutting \a this 2D mesh in 3D space with a plane. In
3870 addition to the mesh, returns a new DataArrayIdType, 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
3871 from. If a result segment is shared by two 2D cells, then the segment in included twice in
3873 * \param [in] origin - 3 components of a point defining location of the plane.
3874 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3875 * must be greater than 1e-6.
3876 * \param [in] eps - half-thickness of the plane.
3877 * \param [out] cellIds - a new instance of DataArrayIdType holding ids of faces
3878 * producing correspondent segments. The caller is to delete this array
3879 * using decrRef() as it is no more needed.
3880 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This is an 1D
3881 * mesh in 3D space. This mesh does not share the node coordinates array with
3882 * \a this mesh. The caller is to delete this mesh using decrRef() as it is
3884 * \throw If the coordinates array is not set.
3885 * \throw If the nodal connectivity of cells is not defined.
3886 * \throw If \a this->getMeshDimension() != 2 or \a this->getSpaceDimension() != 3.
3887 * \throw If magnitude of \a vec is less than 1e-6.
3888 * \throw If the plane does not intersect any 2D cell of \a this mesh.
3889 * \throw If \a this includes quadratic cells.
3891 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3DSurf(const double *origin, const double *vec, double eps, DataArrayIdType *&cellIds) const
3893 checkFullyDefined();
3894 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
3895 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf works on umeshes with meshdim equal to 2 and spaceDim equal to 3 !");
3896 MCAuto<DataArrayIdType> candidates(getCellIdsCrossingPlane(origin,vec,eps));
3897 if(candidates->empty())
3898 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3D surf cells in this intercepts the specified plane considering bounding boxes !");
3899 std::vector<mcIdType> nodes;
3900 DataArrayIdType *cellIds1D(0);
3901 MCAuto<MEDCouplingUMesh> subMesh(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3902 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3903 MCAuto<DataArrayIdType> desc1(DataArrayIdType::New()),descIndx1(DataArrayIdType::New()),revDesc1(DataArrayIdType::New()),revDescIndx1(DataArrayIdType::New());
3904 MCAuto<MEDCouplingUMesh> mDesc1(subMesh->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3905 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3906 MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3908 std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3909 for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3911 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3912 mcIdType ncellsSub=subMesh->getNumberOfCells();
3913 std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(ncellsSub);
3914 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,subMesh->getNodalConnectivity()->getConstPointer(),subMesh->getNodalConnectivityIndex()->getConstPointer(),
3915 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3916 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3917 MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New()),cellIds2(DataArrayIdType::New()); connI->pushBackSilent(0);
3919 const mcIdType *nodal=subMesh->getNodalConnectivity()->getConstPointer();
3920 const mcIdType *nodalI=subMesh->getNodalConnectivityIndex()->getConstPointer();
3921 for(mcIdType i=0;i<ncellsSub;i++)
3923 if(cut3DSurf[i].first!=-1 && cut3DSurf[i].second!=-1)
3925 if(cut3DSurf[i].first!=-2)
3927 conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_SEG2)); conn->pushBackSilent(cut3DSurf[i].first); conn->pushBackSilent(cut3DSurf[i].second);
3928 connI->pushBackSilent(conn->getNumberOfTuples());
3929 cellIds2->pushBackSilent(i);
3933 mcIdType cellId3DSurf=cut3DSurf[i].second;
3934 mcIdType offset=nodalI[cellId3DSurf]+1;
3935 mcIdType nbOfEdges=nodalI[cellId3DSurf+1]-offset;
3936 for(mcIdType j=0;j<nbOfEdges;j++)
3938 conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_SEG2)); conn->pushBackSilent(nodal[offset+j]); conn->pushBackSilent(nodal[offset+(j+1)%nbOfEdges]);
3939 connI->pushBackSilent(conn->getNumberOfTuples());
3940 cellIds2->pushBackSilent(cellId3DSurf);
3945 if(cellIds2->empty())
3946 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3DSurf cells in this intercepts the specified plane !");
3947 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3DSurf",1);
3948 ret->setCoords(mDesc1->getCoords());
3949 ret->setConnectivity(conn,connI,true);
3950 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3954 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::clipSingle3DCellByPlane(const double origin[3], const double vec[3], double eps) const
3956 checkFullyDefined();
3957 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3958 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3959 if(getNumberOfCells()!=1)
3960 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works only on mesh containing exactly one cell !");
3962 std::vector<mcIdType> nodes;
3963 findNodesOnPlane(origin,vec,eps,nodes);
3964 MCAuto<DataArrayIdType> desc1(DataArrayIdType::New()),desc2(DataArrayIdType::New()),descIndx1(DataArrayIdType::New()),descIndx2(DataArrayIdType::New()),revDesc1(DataArrayIdType::New()),revDesc2(DataArrayIdType::New()),revDescIndx1(DataArrayIdType::New()),revDescIndx2(DataArrayIdType::New());
3965 MCAuto<MEDCouplingUMesh> mDesc2(buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2));//meshDim==2 spaceDim==3
3966 revDesc2=0; revDescIndx2=0;
3967 MCAuto<MEDCouplingUMesh> mDesc1(mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3968 revDesc1=0; revDescIndx1=0;
3969 DataArrayIdType *cellIds1D(0);
3970 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3971 MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3972 std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3973 for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3977 mcIdType oldNbNodes(mDesc1->getNumberOfNodes());
3978 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3979 sameNbNodes=(mDesc1->getNumberOfNodes()==oldNbNodes);
3981 std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(mDesc2->getNumberOfCells());
3982 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->begin(),mDesc2->getNodalConnectivityIndex()->begin(),
3983 mDesc1->getNodalConnectivity()->begin(),mDesc1->getNodalConnectivityIndex()->begin(),
3984 desc1->begin(),descIndx1->begin(),cut3DSurf);
3985 MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New());
3986 connI->pushBackSilent(0); conn->alloc(0,1);
3988 MCAuto<DataArrayIdType> cellIds2(DataArrayIdType::New()); cellIds2->alloc(0,1);
3989 assemblyForSplitFrom3DSurf(cut3DSurf,desc2->begin(),descIndx2->begin(),conn,connI,cellIds2);
3990 if(cellIds2->empty())
3991 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3993 std::vector<std::vector<mcIdType> > res;
3994 buildSubCellsFromCut(cut3DSurf,desc2->begin(),descIndx2->begin(),mDesc1->getCoords()->begin(),eps,res);
3995 std::size_t sz(res.size());
3996 if(ToIdType(res.size())==mDesc1->getNumberOfCells() && sameNbNodes)
3997 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane : cell is not clipped !");
3998 for(std::size_t i=0;i<sz;i++)
4000 conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYGON));
4001 conn->insertAtTheEnd(res[i].begin(),res[i].end());
4002 connI->pushBackSilent(conn->getNumberOfTuples());
4004 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
4005 ret->setCoords(mDesc1->getCoords());
4006 ret->setConnectivity(conn,connI,true);
4007 mcIdType nbCellsRet(ret->getNumberOfCells());
4009 MCAuto<DataArrayDouble> vec2(DataArrayDouble::New()); vec2->alloc(1,3); std::copy(vec,vec+3,vec2->getPointer());
4010 MCAuto<MEDCouplingFieldDouble> ortho(ret->buildOrthogonalField());
4011 MCAuto<DataArrayDouble> ortho2(ortho->getArray()->selectByTupleIdSafeSlice(0,1,1));
4012 MCAuto<DataArrayDouble> dott(DataArrayDouble::Dot(ortho2,vec2));
4013 MCAuto<DataArrayDouble> ccm(ret->computeCellCenterOfMass());
4014 MCAuto<DataArrayDouble> occm;
4016 MCAuto<DataArrayDouble> pt(DataArrayDouble::New()); pt->alloc(1,3); std::copy(origin,origin+3,pt->getPointer());
4017 occm=DataArrayDouble::Substract(ccm,pt);
4019 vec2=DataArrayDouble::New(); vec2->alloc(nbCellsRet,3);
4020 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);
4021 MCAuto<DataArrayDouble> dott2(DataArrayDouble::Dot(occm,vec2));
4023 const mcIdType *cPtr(ret->getNodalConnectivity()->begin()),*ciPtr(ret->getNodalConnectivityIndex()->begin());
4024 MCAuto<MEDCouplingUMesh> ret2(MEDCouplingUMesh::New("Clip3D",3));
4025 ret2->setCoords(mDesc1->getCoords());
4026 MCAuto<DataArrayIdType> conn2(DataArrayIdType::New()),conn2I(DataArrayIdType::New());
4027 conn2I->pushBackSilent(0); conn2->alloc(0,1);
4028 std::vector<mcIdType> cell0(1,ToIdType(INTERP_KERNEL::NORM_POLYHED));
4029 std::vector<mcIdType> cell1(1,ToIdType(INTERP_KERNEL::NORM_POLYHED));
4030 if(dott->getIJ(0,0)>0)
4032 cell0.insert(cell0.end(),cPtr+1,cPtr+ciPtr[1]);
4033 std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell1,cell1.end()));
4037 cell1.insert(cell1.end(),cPtr+1,cPtr+ciPtr[1]);
4038 std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell0,cell0.end()));
4040 for(mcIdType i=1;i<nbCellsRet;i++)
4042 if(dott2->getIJ(i,0)<0)
4044 if(ciPtr[i+1]-ciPtr[i]>=4)
4046 cell0.push_back(-1);
4047 cell0.insert(cell0.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
4052 if(ciPtr[i+1]-ciPtr[i]>=4)
4054 cell1.push_back(-1);
4055 cell1.insert(cell1.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
4059 conn2->insertAtTheEnd(cell0.begin(),cell0.end());
4060 conn2I->pushBackSilent(conn2->getNumberOfTuples());
4061 conn2->insertAtTheEnd(cell1.begin(),cell1.end());
4062 conn2I->pushBackSilent(conn2->getNumberOfTuples());
4063 ret2->setConnectivity(conn2,conn2I,true);
4064 ret2->checkConsistencyLight();
4065 ret2->orientCorrectlyPolyhedrons();
4070 * Finds cells whose bounding boxes intersect a given plane.
4071 * \param [in] origin - 3 components of a point defining location of the plane.
4072 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
4073 * must be greater than 1e-6.
4074 * \param [in] eps - half-thickness of the plane.
4075 * \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of the found
4076 * cells. The caller is to delete this array using decrRef() as it is no more
4078 * \throw If the coordinates array is not set.
4079 * \throw If the nodal connectivity of cells is not defined.
4080 * \throw If \a this->getSpaceDimension() != 3.
4081 * \throw If magnitude of \a vec is less than 1e-6.
4082 * \sa buildSlice3D()
4084 DataArrayIdType *MEDCouplingUMesh::getCellIdsCrossingPlane(const double *origin, const double *vec, double eps) const
4086 checkFullyDefined();
4087 if(getSpaceDimension()!=3)
4088 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with spaceDim equal to 3 !");
4089 double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
4091 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellIdsCrossingPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
4093 vec2[0]=vec[1]; vec2[1]=-vec[0]; vec2[2]=0.;//vec2 is the result of cross product of vec with (0,0,1)
4094 double angle=acos(vec[2]/normm);
4095 MCAuto<DataArrayIdType> cellIds;
4099 MCAuto<DataArrayDouble> coo=_coords->deepCopy();
4100 double normm2(sqrt(vec2[0]*vec2[0]+vec2[1]*vec2[1]+vec2[2]*vec2[2]));
4101 if(normm2/normm>1e-6)
4102 DataArrayDouble::Rotate3DAlg(origin,vec2,angle,coo->getNumberOfTuples(),coo->getPointer(),coo->getPointer());
4103 MCAuto<MEDCouplingUMesh> mw=clone(false);//false -> shallow copy
4105 mw->getBoundingBox(bbox);
4106 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
4107 cellIds=mw->getCellsInBoundingBox(bbox,eps);
4111 getBoundingBox(bbox);
4112 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
4113 cellIds=getCellsInBoundingBox(bbox,eps);
4115 return cellIds.retn();
4119 * This method checks that \a this is a contiguous mesh. The user is expected to call this method on a mesh with meshdim==1.
4120 * If not an exception will thrown. If this is an empty mesh with no cell an exception will be thrown too.
4121 * No consideration of coordinate is done by this method.
4122 * 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)
4123 * If not false is returned. In case that false is returned a call to MEDCoupling::MEDCouplingUMesh::mergeNodes could be useful.
4125 bool MEDCouplingUMesh::isContiguous1D() const
4127 if(getMeshDimension()!=1)
4128 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense only for 1D mesh !");
4129 mcIdType nbCells=getNumberOfCells();
4131 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense for non empty mesh !");
4132 const mcIdType *connI(_nodal_connec_index->begin()),*conn(_nodal_connec->begin());
4133 mcIdType ref=conn[connI[0]+2];
4134 for(mcIdType i=1;i<nbCells;i++)
4136 if(conn[connI[i]+1]!=ref)
4138 ref=conn[connI[i]+2];
4144 * This method is only callable on mesh with meshdim == 1 containing only SEG2 and spaceDim==3.
4145 * This method projects this on the 3D line defined by (pt,v). This methods first checks that all SEG2 are along v vector.
4146 * \param pt reference point of the line
4147 * \param v normalized director vector of the line
4148 * \param eps max precision before throwing an exception
4149 * \param res output of size this->getNumberOfCells
4151 void MEDCouplingUMesh::project1D(const double *pt, const double *v, double eps, double *res) const
4153 if(getMeshDimension()!=1)
4154 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for project1D !");
4155 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
4156 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for project1D !");
4157 if(getSpaceDimension()!=3)
4158 throw INTERP_KERNEL::Exception("Expected a umesh with spaceDim==3 for project1D !");
4159 MCAuto<MEDCouplingFieldDouble> f=buildDirectionVectorField();
4160 const double *fPtr=f->getArray()->getConstPointer();
4162 for(mcIdType i=0;i<getNumberOfCells();i++)
4164 const double *tmp1=fPtr+3*i;
4165 tmp[0]=tmp1[1]*v[2]-tmp1[2]*v[1];
4166 tmp[1]=tmp1[2]*v[0]-tmp1[0]*v[2];
4167 tmp[2]=tmp1[0]*v[1]-tmp1[1]*v[0];
4168 double n1=INTERP_KERNEL::norm<3>(tmp);
4169 n1/=INTERP_KERNEL::norm<3>(tmp1);
4171 throw INTERP_KERNEL::Exception("UMesh::Projection 1D failed !");
4173 const double *coo=getCoords()->getConstPointer();
4174 for(mcIdType i=0;i<getNumberOfNodes();i++)
4176 std::transform(coo+i*3,coo+i*3+3,pt,tmp,std::minus<double>());
4177 std::transform(tmp,tmp+3,v,tmp,std::multiplies<double>());
4178 res[i]=std::accumulate(tmp,tmp+3,0.);
4183 * 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.
4184 * \a this is expected to be a mesh so that its space dimension is equal to its
4185 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4186 * 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).
4188 * 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
4189 * 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).
4190 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4192 * So this method is more accurate (so, more costly) than simply searching for the closest point in \a this.
4193 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4195 * \param [in] ptBg the start pointer (included) of the coordinates of the point
4196 * \param [in] ptEnd the end pointer (not included) of the coordinates of the point
4197 * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4198 * \return the positive value of the distance.
4199 * \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
4201 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoints
4203 double MEDCouplingUMesh::distanceToPoint(const double *ptBg, const double *ptEnd, mcIdType& cellId) const
4205 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4206 if(meshDim!=spaceDim-1)
4207 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint works only for spaceDim=meshDim+1 !");
4208 if(meshDim!=2 && meshDim!=1)
4209 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint : only mesh dimension 2 and 1 are implemented !");
4210 checkFullyDefined();
4211 if(ToIdType(std::distance(ptBg,ptEnd))!=spaceDim)
4212 { 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()); }
4213 DataArrayIdType *ret1=0;
4214 MCAuto<DataArrayDouble> pts=DataArrayDouble::New(); pts->useArray(ptBg,false,DeallocType::C_DEALLOC,1,spaceDim);
4215 MCAuto<DataArrayDouble> ret0=distanceToPoints(pts,ret1);
4216 MCAuto<DataArrayIdType> ret1Safe(ret1);
4217 cellId=*ret1Safe->begin();
4218 return *ret0->begin();
4222 * This method computes the distance from each point of points serie \a pts (stored in a DataArrayDouble in which each tuple represents a point)
4223 * to \a this and the first \a cellId in \a this corresponding to the returned distance.
4224 * 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
4225 * 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).
4226 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4228 * \a this is expected to be a mesh so that its space dimension is equal to its
4229 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4230 * 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).
4232 * So this method is more accurate (so, more costly) than simply searching for each point in \a pts the closest point in \a this.
4233 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4235 * \param [in] pts the list of points in which each tuple represents a point
4236 * \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.
4237 * \return a newly allocated object to be dealed by the caller that tells for each point in \a pts the distance to \a this.
4238 * \throw if number of components of \a pts is not equal to the space dimension.
4239 * \throw if mesh dimension of \a this is not equal to space dimension - 1.
4240 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoint
4242 DataArrayDouble *MEDCouplingUMesh::distanceToPoints(const DataArrayDouble *pts, DataArrayIdType *& cellIds) const
4245 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : input points pointer is NULL !");
4246 pts->checkAllocated();
4247 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4248 if(meshDim!=spaceDim-1)
4249 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints works only for spaceDim=meshDim+1 !");
4250 if(meshDim!=2 && meshDim!=1)
4251 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only mesh dimension 2 and 1 are implemented !");
4252 if(ToIdType(pts->getNumberOfComponents())!=spaceDim)
4254 std::ostringstream oss; oss << "MEDCouplingUMesh::distanceToPoints : input pts DataArrayDouble has " << pts->getNumberOfComponents() << " components whereas it should be equal to " << spaceDim << " (mesh spaceDimension) !";
4255 throw INTERP_KERNEL::Exception(oss.str());
4257 checkFullyDefined();
4258 mcIdType nbCells=getNumberOfCells();
4260 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : no cells in this !");
4261 mcIdType nbOfPts=pts->getNumberOfTuples();
4262 MCAuto<DataArrayDouble> ret0=DataArrayDouble::New(); ret0->alloc(nbOfPts,1);
4263 MCAuto<DataArrayIdType> ret1=DataArrayIdType::New(); ret1->alloc(nbOfPts,1);
4264 const mcIdType *nc=_nodal_connec->begin(),*ncI=_nodal_connec_index->begin(); const double *coords=_coords->begin();
4265 double *ret0Ptr=ret0->getPointer(); mcIdType *ret1Ptr=ret1->getPointer(); const double *ptsPtr=pts->begin();
4266 MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree());
4267 const double *bbox(bboxArr->begin());
4272 BBTreeDst<3> myTree(bbox,0,0,nbCells);
4273 for(mcIdType i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=3)
4275 double x=std::numeric_limits<double>::max();
4276 std::vector<mcIdType> elems;
4277 myTree.getMinDistanceOfMax(ptsPtr,x);
4278 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4279 DistanceToPoint3DSurfAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4285 BBTreeDst<2> myTree(bbox,0,0,nbCells);
4286 for(mcIdType i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=2)
4288 double x=std::numeric_limits<double>::max();
4289 std::vector<mcIdType> elems;
4290 myTree.getMinDistanceOfMax(ptsPtr,x);
4291 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4292 DistanceToPoint2DCurveAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4297 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only spacedim 2 and 3 supported !");
4299 cellIds=ret1.retn();
4308 * Finds cells in contact with a ball (i.e. a point with precision).
4309 * 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.
4310 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4312 * \warning This method is suitable if the caller intends to evaluate only one
4313 * point, for more points getCellsContainingPoints() is recommended as it is
4315 * \param [in] pos - array of coordinates of the ball central point.
4316 * \param [in] eps - ball radius.
4317 * \return mcIdType - a smallest id of cells being in contact with the ball, -1 in case
4318 * if there are no such cells.
4319 * \throw If the coordinates array is not set.
4320 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4322 mcIdType MEDCouplingUMesh::getCellContainingPoint(const double *pos, double eps) const
4324 std::vector<mcIdType> elts;
4325 getCellsContainingPoint(pos,eps,elts);
4328 return elts.front();
4332 * Finds cells in contact with a ball (i.e. a point with precision).
4333 * 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.
4334 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4335 * \warning This method is suitable if the caller intends to evaluate only one
4336 * point, for more points getCellsContainingPoints() is recommended as it is
4338 * \param [in] pos - array of coordinates of the ball central point.
4339 * \param [in] eps - ball radius.
4340 * \param [out] elts - vector returning ids of the found cells. It is cleared
4341 * before inserting ids.
4342 * \throw If the coordinates array is not set.
4343 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4345 * \if ENABLE_EXAMPLES
4346 * \ref cpp_mcumesh_getCellsContainingPoint "Here is a C++ example".<br>
4347 * \ref py_mcumesh_getCellsContainingPoint "Here is a Python example".
4350 void MEDCouplingUMesh::getCellsContainingPoint(const double *pos, double eps, std::vector<mcIdType>& elts) const
4352 MCAuto<DataArrayIdType> eltsUg,eltsIndexUg;
4353 getCellsContainingPoints(pos,1,eps,eltsUg,eltsIndexUg);
4354 elts.clear(); elts.insert(elts.end(),eltsUg->begin(),eltsUg->end());
4357 void MEDCouplingUMesh::getCellsContainingPointsZeAlg(const double *pos, mcIdType nbOfPoints, double eps,
4358 MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex,
4359 std::function<bool(INTERP_KERNEL::NormalizedCellType,mcIdType)> sensibilityTo2DQuadraticLinearCellsFunc) const
4361 int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
4366 const double *coords=_coords->getConstPointer();
4367 getCellsContainingPointsAlg<3>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4370 throw INTERP_KERNEL::Exception("For spaceDim==3 only meshDim==3 implemented for getelementscontainingpoints !");
4372 else if(spaceDim==2)
4376 const double *coords=_coords->getConstPointer();
4377 getCellsContainingPointsAlg<2>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4380 throw INTERP_KERNEL::Exception("For spaceDim==2 only meshDim==2 implemented for getelementscontainingpoints !");
4382 else if(spaceDim==1)
4386 const double *coords=_coords->getConstPointer();
4387 getCellsContainingPointsAlg<1>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4390 throw INTERP_KERNEL::Exception("For spaceDim==1 only meshDim==1 implemented for getelementscontainingpoints !");
4393 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPoints : not managed for mdim not in [1,2,3] !");
4397 * Finds cells in contact with several balls (i.e. points with precision).
4398 * This method is an extension of getCellContainingPoint() and
4399 * getCellsContainingPoint() for the case of multiple points.
4400 * 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.
4401 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4402 * \param [in] pos - an array of coordinates of points in full interlace mode :
4403 * X0,Y0,Z0,X1,Y1,Z1,... Size of the array must be \a
4404 * this->getSpaceDimension() * \a nbOfPoints
4405 * \param [in] nbOfPoints - number of points to locate within \a this mesh.
4406 * \param [in] eps - radius of balls (i.e. the precision).
4407 * \param [out] elts - vector returning ids of found cells.
4408 * \param [out] eltsIndex - an array, of length \a nbOfPoints + 1,
4409 * dividing cell ids in \a elts into groups each referring to one
4410 * point. Its every element (except the last one) is an index pointing to the
4411 * first id of a group of cells. For example cells in contact with the *i*-th
4412 * point are described by following range of indices:
4413 * [ \a eltsIndex[ *i* ], \a eltsIndex[ *i*+1 ] ) and the cell ids are
4414 * \a elts[ \a eltsIndex[ *i* ]], \a elts[ \a eltsIndex[ *i* ] + 1 ], ...
4415 * Number of cells in contact with the *i*-th point is
4416 * \a eltsIndex[ *i*+1 ] - \a eltsIndex[ *i* ].
4417 * \throw If the coordinates array is not set.
4418 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4420 * \if ENABLE_EXAMPLES
4421 * \ref cpp_mcumesh_getCellsContainingPoints "Here is a C++ example".<br>
4422 * \ref py_mcumesh_getCellsContainingPoints "Here is a Python example".
4425 void MEDCouplingUMesh::getCellsContainingPoints(const double *pos, mcIdType nbOfPoints, double eps,
4426 MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex) const
4428 auto yesImSensibleTo2DQuadraticLinearCellsFunc([](INTERP_KERNEL::NormalizedCellType ct, int mdim) { return INTERP_KERNEL::CellModel::GetCellModel(ct).isQuadratic() && mdim == 2; } );
4429 this->getCellsContainingPointsZeAlg(pos,nbOfPoints,eps,elts,eltsIndex,yesImSensibleTo2DQuadraticLinearCellsFunc);
4433 * Behaves like MEDCouplingMesh::getCellsContainingPoints for cells in \a this that are linear.
4434 * For quadratic cells in \a this, this method behaves by just considering linear part of cells.
4435 * This method is here only for backward compatibility (interpolation GaussPoints to GaussPoints).
4437 * \sa MEDCouplingUMesh::getCellsContainingPoints, MEDCouplingRemapper::prepareNotInterpKernelOnlyGaussGauss
4439 void MEDCouplingUMesh::getCellsContainingPointsLinearPartOnlyOnNonDynType(const double *pos, mcIdType nbOfPoints, double eps, MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex) const
4441 auto noImNotSensibleTo2DQuadraticLinearCellsFunc([](INTERP_KERNEL::NormalizedCellType,mcIdType) { return false; } );
4442 this->getCellsContainingPointsZeAlg(pos,nbOfPoints,eps,elts,eltsIndex,noImNotSensibleTo2DQuadraticLinearCellsFunc);
4446 * Finds butterfly cells in \a this mesh. A 2D cell is considered to be butterfly if at
4447 * least two its edges intersect each other anywhere except their extremities. An
4448 * INTERP_KERNEL::NORM_NORI3 cell can \b not be butterfly.
4449 * \param [in,out] cells - a vector returning ids of the found cells. It is not
4450 * cleared before filling in.
4451 * \param [in] eps - precision.
4452 * \throw If \a this->getMeshDimension() != 2.
4453 * \throw If \a this->getSpaceDimension() != 2 && \a this->getSpaceDimension() != 3.
4455 void MEDCouplingUMesh::checkButterflyCells(std::vector<mcIdType>& cells, double eps) const
4457 const char msg[]="Butterfly detection work only for 2D cells with spaceDim==2 or 3!";
4458 if(getMeshDimension()!=2)
4459 throw INTERP_KERNEL::Exception(msg);
4460 int spaceDim=getSpaceDimension();
4461 if(spaceDim!=2 && spaceDim!=3)
4462 throw INTERP_KERNEL::Exception(msg);
4463 const mcIdType *conn=_nodal_connec->getConstPointer();
4464 const mcIdType *connI=_nodal_connec_index->getConstPointer();
4465 mcIdType nbOfCells=getNumberOfCells();
4466 std::vector<double> cell2DinS2;
4467 for(mcIdType i=0;i<nbOfCells;i++)
4469 mcIdType offset=connI[i];
4470 mcIdType nbOfNodesForCell=connI[i+1]-offset-1;
4471 if(nbOfNodesForCell<=3)
4473 bool isQuad=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[offset]).isQuadratic();
4474 project2DCellOnXY(conn+offset+1,conn+connI[i+1],cell2DinS2);
4475 if(isButterfly2DCell(cell2DinS2,isQuad,eps))
4482 * This method is typically requested to unbutterfly 2D linear cells in \b this.
4484 * 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.
4485 * 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.
4487 * For each 2D linear cell in \b this, this method builds the convex envelop (or the convex hull) of the current cell.
4488 * This convex envelop is computed using Jarvis march algorithm.
4489 * The coordinates and the number of cells of \b this remain unchanged on invocation of this method.
4490 * 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)
4491 * 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.
4493 * \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.
4494 * \sa MEDCouplingUMesh::colinearize2D
4496 DataArrayIdType *MEDCouplingUMesh::convexEnvelop2D()
4498 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
4499 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convexEnvelop2D works only for meshDim=2 and spaceDim=2 !");
4500 checkFullyDefined();
4501 const double *coords=getCoords()->getConstPointer();
4502 mcIdType nbOfCells=getNumberOfCells();
4503 MCAuto<DataArrayIdType> nodalConnecIndexOut=DataArrayIdType::New();
4504 nodalConnecIndexOut->alloc(nbOfCells+1,1);
4505 MCAuto<DataArrayIdType> nodalConnecOut(DataArrayIdType::New());
4506 mcIdType *workIndexOut=nodalConnecIndexOut->getPointer();
4508 const mcIdType *nodalConnecIn=_nodal_connec->getConstPointer();
4509 const mcIdType *nodalConnecIndexIn=_nodal_connec_index->getConstPointer();
4510 std::set<INTERP_KERNEL::NormalizedCellType> types;
4511 MCAuto<DataArrayIdType> isChanged(DataArrayIdType::New());
4512 isChanged->alloc(0,1);
4513 for(mcIdType i=0;i<nbOfCells;i++,workIndexOut++)
4515 mcIdType pos=nodalConnecOut->getNumberOfTuples();
4516 if(BuildConvexEnvelopOf2DCellJarvis(coords,nodalConnecIn+nodalConnecIndexIn[i],nodalConnecIn+nodalConnecIndexIn[i+1],nodalConnecOut))
4517 isChanged->pushBackSilent(i);
4518 types.insert((INTERP_KERNEL::NormalizedCellType)nodalConnecOut->getIJ(pos,0));
4519 workIndexOut[1]=nodalConnecOut->getNumberOfTuples();
4521 if(isChanged->empty())
4523 setConnectivity(nodalConnecOut,nodalConnecIndexOut,false);
4525 return isChanged.retn();
4529 * This method is \b NOT const because it can modify \a this.
4530 * \a this is expected to be an unstructured mesh with meshDim==2 and spaceDim==3. If not an exception will be thrown.
4531 * \param mesh1D is an unstructured mesh with MeshDim==1 and spaceDim==3. If not an exception will be thrown.
4532 * \param policy specifies the type of extrusion chosen:
4533 * - \b 0 for translation only (most simple): the cells of the 1D mesh represent the vectors along which the 2D mesh
4534 * will be repeated to build each level
4535 * - \b 1 for translation and rotation: the translation is done as above. For each level, an arc of circle is fitted on
4536 * 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
4537 * 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
4539 * \return an unstructured mesh with meshDim==3 and spaceDim==3. The returned mesh has the same coords than \a this.
4541 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMesh(const MEDCouplingUMesh *mesh1D, int policy)
4543 checkFullyDefined();
4544 mesh1D->checkFullyDefined();
4545 if(!mesh1D->isContiguous1D())
4546 throw INTERP_KERNEL::Exception("buildExtrudedMesh : 1D mesh passed in parameter is not contiguous !");
4547 if(getSpaceDimension()!=mesh1D->getSpaceDimension())
4548 throw INTERP_KERNEL::Exception("Invalid call to buildExtrudedMesh this and mesh1D must have same space dimension !");
4549 if((getMeshDimension()!=2 || getSpaceDimension()!=3) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
4550 throw INTERP_KERNEL::Exception("Invalid 'this' for buildExtrudedMesh method : must be (meshDim==2 and spaceDim==3) or (meshDim==1 and spaceDim==2) !");
4551 if(mesh1D->getMeshDimension()!=1)
4552 throw INTERP_KERNEL::Exception("Invalid 'mesh1D' for buildExtrudedMesh method : must be meshDim==1 !");
4554 if(isPresenceOfQuadratic())
4556 if(mesh1D->isFullyQuadratic())
4559 throw INTERP_KERNEL::Exception("Invalid 2D mesh and 1D mesh because 2D mesh has quadratic cells and 1D is not fully quadratic !");
4561 mcIdType oldNbOfNodes(getNumberOfNodes());
4562 MCAuto<DataArrayDouble> newCoords;
4567 newCoords=fillExtCoordsUsingTranslation(mesh1D,isQuad);
4572 newCoords=fillExtCoordsUsingTranslAndAutoRotation(mesh1D,isQuad);
4576 throw INTERP_KERNEL::Exception("Not implemented extrusion policy : must be in (0) !");
4578 setCoords(newCoords);
4579 MCAuto<MEDCouplingUMesh> ret(buildExtrudedMeshFromThisLowLev(oldNbOfNodes,isQuad));
4586 * Checks if \a this mesh is constituted by only quadratic cells.
4587 * \return bool - \c true if there are only quadratic cells in \a this mesh.
4588 * \throw If the coordinates array is not set.
4589 * \throw If the nodal connectivity of cells is not defined.
4591 bool MEDCouplingUMesh::isFullyQuadratic() const
4593 checkFullyDefined();
4595 mcIdType nbOfCells=getNumberOfCells();
4596 for(mcIdType i=0;i<nbOfCells && ret;i++)
4598 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4599 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4600 ret=cm.isQuadratic();
4606 * Checks if \a this mesh includes any quadratic cell.
4607 * \return bool - \c true if there is at least one quadratic cells in \a this mesh.
4608 * \throw If the coordinates array is not set.
4609 * \throw If the nodal connectivity of cells is not defined.
4611 bool MEDCouplingUMesh::isPresenceOfQuadratic() const
4613 checkFullyDefined();
4615 mcIdType nbOfCells=getNumberOfCells();
4616 for(mcIdType i=0;i<nbOfCells && !ret;i++)
4618 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4619 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4620 ret=cm.isQuadratic();
4626 * Converts all quadratic cells to linear ones. If there are no quadratic cells in \a
4627 * this mesh, it remains unchanged.
4628 * \throw If the coordinates array is not set.
4629 * \throw If the nodal connectivity of cells is not defined.
4631 void MEDCouplingUMesh::convertQuadraticCellsToLinear()
4633 checkFullyDefined();
4634 mcIdType nbOfCells=getNumberOfCells();
4636 const mcIdType *iciptr=_nodal_connec_index->begin();
4637 for(mcIdType i=0;i<nbOfCells;i++)
4639 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4640 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4641 if(cm.isQuadratic())
4643 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4644 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4645 if(!cml.isDynamic())
4646 delta+=cm.getNumberOfNodes()-cml.getNumberOfNodes();
4648 delta+=(iciptr[i+1]-iciptr[i]-1)/2;
4653 MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()),newConnI(DataArrayIdType::New());
4654 const mcIdType *icptr(_nodal_connec->begin());
4655 newConn->alloc(getNodalConnectivityArrayLen()-delta,1);
4656 newConnI->alloc(nbOfCells+1,1);
4657 mcIdType *ocptr(newConn->getPointer()),*ociptr(newConnI->getPointer());
4660 for(mcIdType i=0;i<nbOfCells;i++,ociptr++)
4662 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)icptr[iciptr[i]];
4663 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4664 if(!cm.isQuadratic())
4666 _types.insert(type);
4667 ocptr=std::copy(icptr+iciptr[i],icptr+iciptr[i+1],ocptr);
4668 ociptr[1]=ociptr[0]+iciptr[i+1]-iciptr[i];
4672 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4673 _types.insert(typel);
4674 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4675 mcIdType newNbOfNodes=cml.getNumberOfNodes();
4677 newNbOfNodes=(iciptr[i+1]-iciptr[i]-1)/2;
4678 *ocptr++=ToIdType(typel);
4679 ocptr=std::copy(icptr+iciptr[i]+1,icptr+iciptr[i]+newNbOfNodes+1,ocptr);
4680 ociptr[1]=ociptr[0]+newNbOfNodes+1;
4683 setConnectivity(newConn,newConnI,false);
4687 * This method converts all linear cell in \a this to quadratic one.
4688 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, here it is needed to specify the target
4689 * 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)
4690 * 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.
4691 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, the coordinates in \a this can be become bigger. All created nodes will be put at the
4692 * end of the existing coordinates.
4694 * \param [in] conversionType specifies the type of conversion expected. Only 0 (default) and 1 are supported presently. 0 those that creates the 'most' simple
4695 * corresponding quadratic cells. 1 is those creating the 'most' complex.
4696 * \return a newly created DataArrayIdType instance that the caller should deal with containing cell ids of converted cells.
4698 * \throw if \a this is not fully defined. It throws too if \a conversionType is not in [0,1].
4700 * \sa MEDCouplingUMesh::convertQuadraticCellsToLinear
4702 DataArrayIdType *MEDCouplingUMesh::convertLinearCellsToQuadratic(int conversionType)
4704 DataArrayIdType *conn=0,*connI=0;
4705 DataArrayDouble *coords=0;
4706 std::set<INTERP_KERNEL::NormalizedCellType> types;
4707 checkFullyDefined();
4708 MCAuto<DataArrayIdType> ret,connSafe,connISafe;
4709 MCAuto<DataArrayDouble> coordsSafe;
4710 int meshDim=getMeshDimension();
4711 switch(conversionType)
4717 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);
4718 connSafe=conn; connISafe=connI; coordsSafe=coords;
4721 ret=convertLinearCellsToQuadratic2D0(conn,connI,coords,types);
4722 connSafe=conn; connISafe=connI; coordsSafe=coords;
4725 ret=convertLinearCellsToQuadratic3D0(conn,connI,coords,types);
4726 connSafe=conn; connISafe=connI; coordsSafe=coords;
4729 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 0 mesh dimensions available are [1,2,3] !");
4737 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);//it is not a bug. In 1D policy 0 and 1 are equals
4738 connSafe=conn; connISafe=connI; coordsSafe=coords;
4741 ret=convertLinearCellsToQuadratic2D1(conn,connI,coords,types);
4742 connSafe=conn; connISafe=connI; coordsSafe=coords;
4745 ret=convertLinearCellsToQuadratic3D1(conn,connI,coords,types);
4746 connSafe=conn; connISafe=connI; coordsSafe=coords;
4749 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 1 mesh dimensions available are [1,2,3] !");
4754 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion type available are 0 (default, the simplest) and 1 (the most complex) !");
4756 setConnectivity(connSafe,connISafe,false);
4758 setCoords(coordsSafe);
4763 * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
4764 * so that the number of cells remains the same. Quadratic faces are converted to
4765 * polygons. This method works only for 2D meshes in
4766 * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
4767 * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
4768 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
4769 * \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
4770 * a polylinized edge constituting the input polygon.
4771 * \throw If the coordinates array is not set.
4772 * \throw If the nodal connectivity of cells is not defined.
4773 * \throw If \a this->getMeshDimension() != 2.
4774 * \throw If \a this->getSpaceDimension() != 2.
4776 void MEDCouplingUMesh::tessellate2D(double eps)
4778 int meshDim(getMeshDimension()),spaceDim(getSpaceDimension());
4780 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : works only with space dimension equal to 2 !");
4784 return tessellate2DCurveInternal(eps);
4786 return tessellate2DInternal(eps);
4788 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : mesh dimension must be in [1,2] !");
4794 * This method only works if \a this has spaceDimension equal to 2 and meshDimension also equal to 2.
4795 * This method allows to modify connectivity of cells in \a this that shares some edges in \a edgeIdsToBeSplit.
4796 * The nodes to be added in those 2D cells are defined by the pair of \a nodeIdsToAdd and \a nodeIdsIndexToAdd.
4797 * Length of \a nodeIdsIndexToAdd is expected to equal to length of \a edgeIdsToBeSplit + 1.
4798 * The node ids in \a nodeIdsToAdd should be valid. Those nodes have to be sorted exactly following exactly the direction of the edge.
4799 * This method can be seen as the opposite method of colinearize2D.
4800 * 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
4801 * to avoid to modify the numbering of existing nodes.
4803 * \param [in] nodeIdsToAdd - the list of node ids to be added (\a nodeIdsIndexToAdd array allows to walk on this array)
4804 * \param [in] nodeIdsIndexToAdd - the entry point of \a nodeIdsToAdd to point to the corresponding nodes to be added.
4805 * \param [in] mesh1Desc - 1st output of buildDescendingConnectivity2 on \a this.
4806 * \param [in] desc - 2nd output of buildDescendingConnectivity2 on \a this.
4807 * \param [in] descI - 3rd output of buildDescendingConnectivity2 on \a this.
4808 * \param [in] revDesc - 4th output of buildDescendingConnectivity2 on \a this.
4809 * \param [in] revDescI - 5th output of buildDescendingConnectivity2 on \a this.
4811 * \sa buildDescendingConnectivity2
4813 void MEDCouplingUMesh::splitSomeEdgesOf2DMesh(const DataArrayIdType *nodeIdsToAdd, const DataArrayIdType *nodeIdsIndexToAdd, const DataArrayIdType *edgeIdsToBeSplit,
4814 const MEDCouplingUMesh *mesh1Desc, const DataArrayIdType *desc, const DataArrayIdType *descI, const DataArrayIdType *revDesc, const DataArrayIdType *revDescI)
4816 if(!nodeIdsToAdd || !nodeIdsIndexToAdd || !edgeIdsToBeSplit || !mesh1Desc || !desc || !descI || !revDesc || !revDescI)
4817 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : input pointers must be not NULL !");
4818 nodeIdsToAdd->checkAllocated(); nodeIdsIndexToAdd->checkAllocated(); edgeIdsToBeSplit->checkAllocated(); desc->checkAllocated(); descI->checkAllocated(); revDesc->checkAllocated(); revDescI->checkAllocated();
4819 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
4820 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : this must have spacedim=meshdim=2 !");
4821 if(mesh1Desc->getSpaceDimension()!=2 || mesh1Desc->getMeshDimension()!=1)
4822 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : mesh1Desc must be the explosion of this with spaceDim=2 and meshDim = 1 !");
4823 //DataArrayIdType *out0(0),*outi0(0);
4824 //MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
4825 //MCAuto<DataArrayIdType> out0s(out0),outi0s(outi0);
4826 //out0s=out0s->buildUnique(); out0s->sort(true);
4832 * Divides every cell of \a this mesh into simplices (triangles in 2D and tetrahedra in 3D).
4833 * In addition, returns an array mapping new cells to old ones. <br>
4834 * This method typically increases the number of cells in \a this mesh
4835 * but the number of nodes remains \b unchanged.
4836 * That's why the 3D splitting policies
4837 * INTERP_KERNEL::GENERAL_24 and INTERP_KERNEL::GENERAL_48 are not available here.
4838 * \param [in] policy - specifies a pattern used for splitting.
4839 * The semantic of \a policy is:
4840 * - 0 - to split QUAD4 by cutting it along 0-2 diagonal (for 2D mesh only).
4841 * - 1 - to split QUAD4 by cutting it along 1-3 diagonal (for 2D mesh only).
4842 * - INTERP_KERNEL::PLANAR_FACE_5 - to split HEXA8 into 5 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4843 * - INTERP_KERNEL::PLANAR_FACE_6 - to split HEXA8 into 6 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4846 * \return DataArrayIdType * - a new instance of DataArrayIdType holding, for each new cell,
4847 * an id of old cell producing it. The caller is to delete this array using
4848 * decrRef() as it is no more needed.
4850 * \throw If \a policy is 0 or 1 and \a this->getMeshDimension() != 2.
4851 * \throw If \a policy is INTERP_KERNEL::PLANAR_FACE_5 or INTERP_KERNEL::PLANAR_FACE_6
4852 * and \a this->getMeshDimension() != 3.
4853 * \throw If \a policy is not one of the four discussed above.
4854 * \throw If the nodal connectivity of cells is not defined.
4855 * \sa MEDCouplingUMesh::tetrahedrize, MEDCoupling1SGTUMesh::sortHexa8EachOther
4857 DataArrayIdType *MEDCouplingUMesh::simplexize(int policy)
4862 return simplexizePol0();
4864 return simplexizePol1();
4865 case INTERP_KERNEL::PLANAR_FACE_5:
4866 return simplexizePlanarFace5();
4867 case INTERP_KERNEL::PLANAR_FACE_6:
4868 return simplexizePlanarFace6();
4870 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)");
4875 * Checks if \a this mesh is constituted by simplex cells only. Simplex cells are:
4876 * - 1D: INTERP_KERNEL::NORM_SEG2
4877 * - 2D: INTERP_KERNEL::NORM_TRI3
4878 * - 3D: INTERP_KERNEL::NORM_TETRA4.
4880 * This method is useful for users that need to use P1 field services as
4881 * MEDCouplingFieldDouble::getValueOn(), MEDCouplingField::buildMeasureField() etc.
4882 * All these methods need mesh support containing only simplex cells.
4883 * \return bool - \c true if there are only simplex cells in \a this mesh.
4884 * \throw If the coordinates array is not set.
4885 * \throw If the nodal connectivity of cells is not defined.
4886 * \throw If \a this->getMeshDimension() < 1.
4888 bool MEDCouplingUMesh::areOnlySimplexCells() const
4890 checkFullyDefined();
4891 int mdim=getMeshDimension();
4892 if(mdim<1 || mdim>3)
4893 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::areOnlySimplexCells : only available with meshes having a meshdim 1, 2 or 3 !");
4894 mcIdType nbCells=getNumberOfCells();
4895 const mcIdType *conn=_nodal_connec->begin();
4896 const mcIdType *connI=_nodal_connec_index->begin();
4897 for(mcIdType i=0;i<nbCells;i++)
4899 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4909 * Converts degenerated 2D or 3D linear cells of \a this mesh into cells of simpler
4910 * type. For example an INTERP_KERNEL::NORM_QUAD4 cell having only three unique nodes in
4911 * its connectivity is transformed into an INTERP_KERNEL::NORM_TRI3 cell.
4912 * Quadratic cells in 2D are also handled. In those cells edges where start=end=midpoint are removed.
4913 * This method does \b not perform geometrical checks and checks only nodal connectivity of cells,
4914 * so it can be useful to call mergeNodes() before calling this method.
4915 * \throw If \a this->getMeshDimension() <= 1.
4916 * \throw If the coordinates array is not set.
4917 * \throw If the nodal connectivity of cells is not defined.
4919 void MEDCouplingUMesh::convertDegeneratedCells()
4921 checkFullyDefined();
4922 if(getMeshDimension()<=1)
4923 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4924 mcIdType nbOfCells=getNumberOfCells();
4927 mcIdType initMeshLgth=getNodalConnectivityArrayLen();
4928 mcIdType *conn=_nodal_connec->getPointer();
4929 mcIdType *index=_nodal_connec_index->getPointer();
4930 mcIdType posOfCurCell=0;
4932 mcIdType lgthOfCurCell;
4933 for(mcIdType i=0;i<nbOfCells;i++)
4935 lgthOfCurCell=index[i+1]-posOfCurCell;
4936 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4938 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
4939 conn+newPos+1,newLgth);
4940 conn[newPos]=newType;
4942 posOfCurCell=index[i+1];
4945 if(newPos!=initMeshLgth)
4946 _nodal_connec->reAlloc(newPos);
4951 * Same as MEDCouplingUMesh::convertDegeneratedCells() plus deletion of the flat cells.
4952 * A cell is flat in the following cases:
4953 * - for a linear cell, all points in the connectivity are equal
4954 * - for a quadratic cell, either the above, or a quadratic polygon with two (linear) points and two
4955 * identical quadratic points
4956 * \return a new instance of DataArrayIdType holding ids of removed cells. The caller is to delete
4957 * this array using decrRef() as it is no more needed.
4959 DataArrayIdType *MEDCouplingUMesh::convertDegeneratedCellsAndRemoveFlatOnes()
4961 checkFullyDefined();
4962 if(getMeshDimension()<=1)
4963 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4964 mcIdType nbOfCells=getNumberOfCells();
4965 MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(0,1);
4968 mcIdType initMeshLgth=getNodalConnectivityArrayLen();
4969 mcIdType *conn=_nodal_connec->getPointer();
4970 mcIdType *index=_nodal_connec_index->getPointer();
4971 mcIdType posOfCurCell=0;
4973 mcIdType lgthOfCurCell, nbDelCells(0);
4974 for(mcIdType i=0;i<nbOfCells;i++)
4976 lgthOfCurCell=index[i+1]-posOfCurCell;
4977 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4979 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
4980 conn+newPos+1,newLgth);
4981 // Shall we delete the cell if it is completely degenerated:
4982 bool delCell=INTERP_KERNEL::CellSimplify::isFlatCell(conn, newPos, newLgth, newType);
4986 ret->pushBackSilent(i);
4988 else //if the cell is to be deleted, simply stay at the same place
4990 conn[newPos]=newType;
4993 posOfCurCell=index[i+1];
4994 index[i+1-nbDelCells]=newPos;
4996 if(newPos!=initMeshLgth)
4997 _nodal_connec->reAlloc(newPos);
4998 const mcIdType nCellDel=ret->getNumberOfTuples();
5000 _nodal_connec_index->reAlloc(nbOfCells-nCellDel+1);
5006 * This method remove null 1D cells from \a this. A 1D cell is considered null if start node is equal to end node.
5007 * Only connectivity is considered here.
5009 bool MEDCouplingUMesh::removeDegenerated1DCells()
5011 checkConnectivityFullyDefined();
5012 if(getMeshDimension()!=1)
5013 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::removeDegenerated1DCells works on umeshes with meshdim equals to 1 !");
5014 std::size_t nbCells(getNumberOfCells()),newSize(0),newSize2(0);
5015 const mcIdType *conn(getNodalConnectivity()->begin()),*conni(getNodalConnectivityIndex()->begin());
5017 for(std::size_t i=0;i<nbCells;i++)
5019 INTERP_KERNEL::NormalizedCellType ct((INTERP_KERNEL::NormalizedCellType)conn[conni[i]]);
5020 if(ct==INTERP_KERNEL::NORM_SEG2 || ct==INTERP_KERNEL::NORM_SEG3)
5022 if(conn[conni[i]+1]!=conn[conni[i]+2])
5025 newSize2+=conni[i+1]-conni[i];
5030 std::ostringstream oss; oss << "MEDCouplingUMesh::removeDegenerated1DCells : cell #" << i << " in this is not of type SEG2/SEG3 !";
5031 throw INTERP_KERNEL::Exception(oss.str());
5035 if(newSize==nbCells)//no cells has been removed -> do nothing
5037 MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()),newConnI(DataArrayIdType::New()); newConnI->alloc(newSize+1,1); newConn->alloc(newSize2,1);
5038 mcIdType *newConnPtr(newConn->getPointer()),*newConnIPtr(newConnI->getPointer()); newConnIPtr[0]=0;
5039 for(std::size_t i=0;i<nbCells;i++)
5041 if(conn[conni[i]+1]!=conn[conni[i]+2])
5043 newConnIPtr[1]=newConnIPtr[0]+conni[i+1]-conni[i];
5044 newConnPtr=std::copy(conn+conni[i],conn+conni[i+1],newConnPtr);
5048 setConnectivity(newConn,newConnI,true);
5053 * Finds incorrectly oriented cells of this 2D mesh in 3D space.
5054 * A cell is considered to be oriented correctly if an angle between its
5055 * normal vector and a given vector is less than \c PI / \c 2.
5056 * \param [in] vec - 3 components of the vector specifying the correct orientation of
5058 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
5060 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
5061 * is not cleared before filling in.
5062 * \throw If \a this->getMeshDimension() != 2.
5063 * \throw If \a this->getSpaceDimension() != 3.
5065 * \if ENABLE_EXAMPLES
5066 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
5067 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
5070 void MEDCouplingUMesh::are2DCellsNotCorrectlyOriented(const double *vec, bool polyOnly, std::vector<mcIdType>& cells) const
5072 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
5073 throw INTERP_KERNEL::Exception("Invalid mesh to apply are2DCellsNotCorrectlyOriented on it : must be meshDim==2 and spaceDim==3 !");
5074 mcIdType nbOfCells=getNumberOfCells();
5075 const mcIdType *conn=_nodal_connec->begin();
5076 const mcIdType *connI=_nodal_connec_index->begin();
5077 const double *coordsPtr=_coords->begin();
5078 for(mcIdType i=0;i<nbOfCells;i++)
5080 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5081 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
5083 bool isQuadratic=INTERP_KERNEL::CellModel::GetCellModel(type).isQuadratic();
5084 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5091 * Reverse connectivity of 2D cells whose orientation is not correct. A cell is
5092 * considered to be oriented correctly if an angle between its normal vector and a
5093 * given vector is less than \c PI / \c 2.
5094 * \param [in] vec - 3 components of the vector specifying the correct orientation of
5096 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
5098 * \throw If \a this->getMeshDimension() != 2.
5099 * \throw If \a this->getSpaceDimension() != 3.
5101 * \if ENABLE_EXAMPLES
5102 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
5103 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
5106 * \sa changeOrientationOfCells
5108 void MEDCouplingUMesh::orientCorrectly2DCells(const double *vec, bool polyOnly)
5110 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
5111 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectly2DCells on it : must be meshDim==2 and spaceDim==3 !");
5112 mcIdType nbOfCells=getNumberOfCells();
5113 mcIdType *conn(_nodal_connec->getPointer());
5114 const mcIdType *connI(_nodal_connec_index->begin());
5115 const double *coordsPtr(_coords->begin());
5116 bool isModified(false);
5117 for(mcIdType i=0;i<nbOfCells;i++)
5119 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5120 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
5122 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
5123 bool isQuadratic(cm.isQuadratic());
5124 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5127 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
5132 _nodal_connec->declareAsNew();
5137 * This method change the orientation of cells in \a this without any consideration of coordinates. Only connectivity is impacted.
5139 * \sa orientCorrectly2DCells
5141 void MEDCouplingUMesh::changeOrientationOfCells()
5143 int mdim(getMeshDimension());
5144 if(mdim!=2 && mdim!=1)
5145 throw INTERP_KERNEL::Exception("Invalid mesh to apply changeOrientationOfCells on it : must be meshDim==2 or meshDim==1 !");
5146 mcIdType nbOfCells=getNumberOfCells();
5147 mcIdType *conn(_nodal_connec->getPointer());
5148 const mcIdType *connI(_nodal_connec_index->begin());
5151 for(mcIdType i=0;i<nbOfCells;i++)
5153 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5154 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
5155 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
5160 for(mcIdType i=0;i<nbOfCells;i++)
5162 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5163 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
5164 cm.changeOrientationOf1D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
5170 * Finds incorrectly oriented polyhedral cells, i.e. polyhedrons having correctly
5171 * oriented facets. The normal vector of the facet should point out of the cell.
5172 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
5173 * is not cleared before filling in.
5174 * \throw If \a this->getMeshDimension() != 3.
5175 * \throw If \a this->getSpaceDimension() != 3.
5176 * \throw If the coordinates array is not set.
5177 * \throw If the nodal connectivity of cells is not defined.
5179 * \if ENABLE_EXAMPLES
5180 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
5181 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
5184 void MEDCouplingUMesh::arePolyhedronsNotCorrectlyOriented(std::vector<mcIdType>& cells) const
5186 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
5187 throw INTERP_KERNEL::Exception("Invalid mesh to apply arePolyhedronsNotCorrectlyOriented on it : must be meshDim==3 and spaceDim==3 !");
5188 mcIdType nbOfCells=getNumberOfCells();
5189 const mcIdType *conn=_nodal_connec->begin();
5190 const mcIdType *connI=_nodal_connec_index->begin();
5191 const double *coordsPtr=_coords->begin();
5192 for(mcIdType i=0;i<nbOfCells;i++)
5194 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5195 if(type==INTERP_KERNEL::NORM_POLYHED)
5197 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5204 * Tries to fix connectivity of polyhedra, so that normal vector of all facets to point
5206 * \throw If \a this->getMeshDimension() != 3.
5207 * \throw If \a this->getSpaceDimension() != 3.
5208 * \throw If the coordinates array is not set.
5209 * \throw If the nodal connectivity of cells is not defined.
5210 * \throw If the reparation fails.
5212 * \if ENABLE_EXAMPLES
5213 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
5214 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
5216 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
5218 void MEDCouplingUMesh::orientCorrectlyPolyhedrons()
5220 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
5221 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectlyPolyhedrons on it : must be meshDim==3 and spaceDim==3 !");
5222 mcIdType nbOfCells=getNumberOfCells();
5223 mcIdType *conn=_nodal_connec->getPointer();
5224 const mcIdType *connI=_nodal_connec_index->begin();
5225 const double *coordsPtr=_coords->begin();
5226 for(mcIdType i=0;i<nbOfCells;i++)
5228 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5229 if(type==INTERP_KERNEL::NORM_POLYHED)
5233 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5234 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
5236 catch(INTERP_KERNEL::Exception& e)
5238 std::ostringstream oss; oss << "Something wrong in polyhedron #" << i << " : " << e.what();
5239 throw INTERP_KERNEL::Exception(oss.str());
5247 * This method invert orientation of all cells in \a this.
5248 * After calling this method the absolute value of measure of cells in \a this are the same than before calling.
5249 * This method only operates on the connectivity so coordinates are not touched at all.
5251 void MEDCouplingUMesh::invertOrientationOfAllCells()
5253 checkConnectivityFullyDefined();
5254 std::set<INTERP_KERNEL::NormalizedCellType> gts(getAllGeoTypes());
5255 mcIdType *conn(_nodal_connec->getPointer());
5256 const mcIdType *conni(_nodal_connec_index->begin());
5257 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator gt=gts.begin();gt!=gts.end();gt++)
5259 INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::OrientationInverter> oi(INTERP_KERNEL::OrientationInverter::BuildInstanceFrom(*gt));
5260 MCAuto<DataArrayIdType> cwt(giveCellsWithType(*gt));
5261 for(const mcIdType *it=cwt->begin();it!=cwt->end();it++)
5262 oi->operate(conn+conni[*it]+1,conn+conni[*it+1]);
5268 * Finds and fixes incorrectly oriented linear extruded volumes (INTERP_KERNEL::NORM_HEXA8,
5269 * INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXGP12 etc) to respect the MED convention
5270 * according to which the first facet of the cell should be oriented to have the normal vector
5271 * pointing out of cell.
5272 * \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of fixed
5273 * cells. The caller is to delete this array using decrRef() as it is no more
5275 * \throw If \a this->getMeshDimension() != 3.
5276 * \throw If \a this->getSpaceDimension() != 3.
5277 * \throw If the coordinates array is not set.
5278 * \throw If the nodal connectivity of cells is not defined.
5280 * \if ENABLE_EXAMPLES
5281 * \ref cpp_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a C++ example".<br>
5282 * \ref py_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a Python example".
5284 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
5286 DataArrayIdType *MEDCouplingUMesh::findAndCorrectBadOriented3DExtrudedCells()
5288 const char msg[]="check3DCellsWellOriented detection works only for 3D cells !";
5289 if(getMeshDimension()!=3)
5290 throw INTERP_KERNEL::Exception(msg);
5291 int spaceDim=getSpaceDimension();
5293 throw INTERP_KERNEL::Exception(msg);
5295 mcIdType nbOfCells=getNumberOfCells();
5296 mcIdType *conn=_nodal_connec->getPointer();
5297 const mcIdType *connI=_nodal_connec_index->begin();
5298 const double *coo=getCoords()->begin();
5299 MCAuto<DataArrayIdType> cells(DataArrayIdType::New()); cells->alloc(0,1);
5300 for(mcIdType i=0;i<nbOfCells;i++)
5302 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5303 if(cm.isExtruded() && !cm.isDynamic() && !cm.isQuadratic())
5305 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coo))
5307 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
5308 cells->pushBackSilent(i);
5312 return cells.retn();
5316 * This method is a faster method to correct orientation of all 3D cells in \a this.
5317 * 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.
5318 * This method makes the hypothesis that \a this a coherent that is to say MEDCouplingUMesh::checkConsistency should throw no exception.
5320 * \return a newly allocated mcIdType array with one components containing cell ids renumbered to fit the convention of MED (MED file and MEDCoupling)
5321 * \sa MEDCouplingUMesh::orientCorrectlyPolyhedrons,
5323 DataArrayIdType *MEDCouplingUMesh::findAndCorrectBadOriented3DCells()
5325 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
5326 throw INTERP_KERNEL::Exception("Invalid mesh to apply findAndCorrectBadOriented3DCells on it : must be meshDim==3 and spaceDim==3 !");
5327 mcIdType nbOfCells=getNumberOfCells();
5328 mcIdType *conn=_nodal_connec->getPointer();
5329 const mcIdType *connI=_nodal_connec_index->begin();
5330 const double *coordsPtr=_coords->begin();
5331 MCAuto<DataArrayIdType> ret=DataArrayIdType::New(); ret->alloc(0,1);
5332 for(mcIdType i=0;i<nbOfCells;i++)
5334 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5337 case INTERP_KERNEL::NORM_TETRA4:
5339 if(!IsTetra4WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5341 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+3));
5342 ret->pushBackSilent(i);
5346 case INTERP_KERNEL::NORM_PYRA5:
5348 if(!IsPyra5WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5350 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+4));
5351 ret->pushBackSilent(i);
5355 case INTERP_KERNEL::NORM_PENTA6:
5356 case INTERP_KERNEL::NORM_HEXA8:
5357 case INTERP_KERNEL::NORM_HEXGP12:
5359 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5361 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
5362 ret->pushBackSilent(i);
5366 case INTERP_KERNEL::NORM_POLYHED:
5368 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5370 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
5371 ret->pushBackSilent(i);
5376 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 !");
5384 * This method has a sense for meshes with spaceDim==3 and meshDim==2.
5385 * If it is not the case an exception will be thrown.
5386 * This method is fast because the first cell of \a this is used to compute the plane.
5387 * \param vec output of size at least 3 used to store the normal vector (with norm equal to Area ) of searched plane.
5388 * \param pos output of size at least 3 used to store a point owned of searched plane.
5390 void MEDCouplingUMesh::getFastAveragePlaneOfThis(double *vec, double *pos) const
5392 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
5393 throw INTERP_KERNEL::Exception("Invalid mesh to apply getFastAveragePlaneOfThis on it : must be meshDim==2 and spaceDim==3 !");
5394 const mcIdType *conn=_nodal_connec->begin();
5395 const mcIdType *connI=_nodal_connec_index->begin();
5396 const double *coordsPtr=_coords->begin();
5397 INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(conn+1,connI[1]-connI[0]-1,coordsPtr,vec);
5398 std::copy(coordsPtr+3*conn[1],coordsPtr+3*conn[1]+3,pos);
5402 * Creates a new MEDCouplingFieldDouble holding Edge Ratio values of all
5403 * cells. Currently cells of the following types are treated:
5404 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5405 * For a cell of other type an exception is thrown.
5406 * Space dimension of a 2D mesh can be either 2 or 3.
5407 * The Edge Ratio of a cell \f$t\f$ is:
5408 * \f$\frac{|t|_\infty}{|t|_0}\f$,
5409 * where \f$|t|_\infty\f$ and \f$|t|_0\f$ respectively denote the greatest and
5410 * the smallest edge lengths of \f$t\f$.
5411 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5412 * cells and one time, lying on \a this mesh. The caller is to delete this
5413 * field using decrRef() as it is no more needed.
5414 * \throw If the coordinates array is not set.
5415 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5416 * \throw If the connectivity data array has more than one component.
5417 * \throw If the connectivity data array has a named component.
5418 * \throw If the connectivity index data array has more than one component.
5419 * \throw If the connectivity index data array has a named component.
5420 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
5421 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5422 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5424 MEDCouplingFieldDouble *MEDCouplingUMesh::getEdgeRatioField() const
5426 checkConsistencyLight();
5427 int spaceDim=getSpaceDimension();
5428 int meshDim=getMeshDimension();
5429 if(spaceDim!=2 && spaceDim!=3)
5430 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : SpaceDimension must be equal to 2 or 3 !");
5431 if(meshDim!=2 && meshDim!=3)
5432 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : MeshDimension must be equal to 2 or 3 !");
5433 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5435 mcIdType nbOfCells=getNumberOfCells();
5436 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5437 arr->alloc(nbOfCells,1);
5438 double *pt=arr->getPointer();
5439 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5440 const mcIdType *conn=_nodal_connec->begin();
5441 const mcIdType *connI=_nodal_connec_index->begin();
5442 const double *coo=_coords->begin();
5444 for(mcIdType i=0;i<nbOfCells;i++,pt++)
5446 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5449 case INTERP_KERNEL::NORM_TRI3:
5451 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5452 *pt=INTERP_KERNEL::triEdgeRatio(tmp);
5455 case INTERP_KERNEL::NORM_QUAD4:
5457 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5458 *pt=INTERP_KERNEL::quadEdgeRatio(tmp);
5461 case INTERP_KERNEL::NORM_TETRA4:
5463 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5464 *pt=INTERP_KERNEL::tetraEdgeRatio(tmp);
5468 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5470 conn+=connI[i+1]-connI[i];
5472 ret->setName("EdgeRatio");
5473 ret->synchronizeTimeWithSupport();
5478 * Creates a new MEDCouplingFieldDouble holding Aspect Ratio values of all
5479 * cells. Currently cells of the following types are treated:
5480 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5481 * For a cell of other type an exception is thrown.
5482 * Space dimension of a 2D mesh can be either 2 or 3.
5483 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5484 * cells and one time, lying on \a this mesh. The caller is to delete this
5485 * field using decrRef() as it is no more needed.
5486 * \throw If the coordinates array is not set.
5487 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5488 * \throw If the connectivity data array has more than one component.
5489 * \throw If the connectivity data array has a named component.
5490 * \throw If the connectivity index data array has more than one component.
5491 * \throw If the connectivity index data array has a named component.
5492 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
5493 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5494 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5496 MEDCouplingFieldDouble *MEDCouplingUMesh::getAspectRatioField() const
5498 checkConsistencyLight();
5499 int spaceDim=getSpaceDimension();
5500 int meshDim=getMeshDimension();
5501 if(spaceDim!=2 && spaceDim!=3)
5502 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : SpaceDimension must be equal to 2 or 3 !");
5503 if(meshDim!=2 && meshDim!=3)
5504 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : MeshDimension must be equal to 2 or 3 !");
5505 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5507 mcIdType nbOfCells=getNumberOfCells();
5508 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5509 arr->alloc(nbOfCells,1);
5510 double *pt=arr->getPointer();
5511 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5512 const mcIdType *conn=_nodal_connec->begin();
5513 const mcIdType *connI=_nodal_connec_index->begin();
5514 const double *coo=_coords->begin();
5516 for(mcIdType i=0;i<nbOfCells;i++,pt++)
5518 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5521 case INTERP_KERNEL::NORM_TRI3:
5523 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5524 *pt=INTERP_KERNEL::triAspectRatio(tmp);
5527 case INTERP_KERNEL::NORM_QUAD4:
5529 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5530 *pt=INTERP_KERNEL::quadAspectRatio(tmp);
5533 case INTERP_KERNEL::NORM_TETRA4:
5535 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5536 *pt=INTERP_KERNEL::tetraAspectRatio(tmp);
5540 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5542 conn+=connI[i+1]-connI[i];
5544 ret->setName("AspectRatio");
5545 ret->synchronizeTimeWithSupport();
5550 * Creates a new MEDCouplingFieldDouble holding Warping factor values of all
5551 * cells of \a this 2D mesh in 3D space. It is a measure of the "planarity" of 2D cell
5552 * in 3D space. Currently only cells of the following types are
5553 * treated: INTERP_KERNEL::NORM_QUAD4.
5554 * For a cell of other type an exception is thrown.
5555 * The warp field is computed as follows: let (a,b,c,d) be the points of the quad.
5557 * \f$t=\vec{da}\times\vec{ab}\f$,
5558 * \f$u=\vec{ab}\times\vec{bc}\f$
5559 * \f$v=\vec{bc}\times\vec{cd}\f$
5560 * \f$w=\vec{cd}\times\vec{da}\f$, the warp is defined as \f$W^3\f$ with
5562 * W=min(\frac{t}{|t|}\cdot\frac{v}{|v|}, \frac{u}{|u|}\cdot\frac{w}{|w|})
5564 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5565 * cells and one time, lying on \a this mesh. The caller is to delete this
5566 * field using decrRef() as it is no more needed.
5567 * \throw If the coordinates array is not set.
5568 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5569 * \throw If the connectivity data array has more than one component.
5570 * \throw If the connectivity data array has a named component.
5571 * \throw If the connectivity index data array has more than one component.
5572 * \throw If the connectivity index data array has a named component.
5573 * \throw If \a this->getMeshDimension() != 2.
5574 * \throw If \a this->getSpaceDimension() != 3.
5575 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5577 MEDCouplingFieldDouble *MEDCouplingUMesh::getWarpField() const
5579 checkConsistencyLight();
5580 int spaceDim=getSpaceDimension();
5581 int meshDim=getMeshDimension();
5583 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : SpaceDimension must be equal to 3 !");
5585 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : MeshDimension must be equal to 2 !");
5586 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5588 mcIdType nbOfCells=getNumberOfCells();
5589 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5590 arr->alloc(nbOfCells,1);
5591 double *pt=arr->getPointer();
5592 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5593 const mcIdType *conn=_nodal_connec->begin();
5594 const mcIdType *connI=_nodal_connec_index->begin();
5595 const double *coo=_coords->begin();
5597 for(mcIdType i=0;i<nbOfCells;i++,pt++)
5599 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5602 case INTERP_KERNEL::NORM_QUAD4:
5604 FillInCompact3DMode(3,4,conn+1,coo,tmp);
5605 *pt=INTERP_KERNEL::quadWarp(tmp);
5609 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : A cell with not manged type (NORM_QUAD4) has been detected !");
5611 conn+=connI[i+1]-connI[i];
5613 ret->setName("Warp");
5614 ret->synchronizeTimeWithSupport();
5620 * Creates a new MEDCouplingFieldDouble holding Skew factor values of all
5621 * cells of \a this 2D mesh in 3D space. Currently cells of the following types are
5622 * treated: INTERP_KERNEL::NORM_QUAD4.
5623 * The skew is computed as follow for a quad with points (a,b,c,d): let
5624 * \f$u=\vec{ab}+\vec{dc}\f$ and \f$v=\vec{ac}+\vec{bd}\f$
5625 * then the skew is computed as:
5627 * s=\frac{u}{|u|}\cdot\frac{v}{|v|}
5630 * For a cell of other type an exception is thrown.
5631 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5632 * cells and one time, lying on \a this mesh. The caller is to delete this
5633 * field using decrRef() as it is no more needed.
5634 * \throw If the coordinates array is not set.
5635 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5636 * \throw If the connectivity data array has more than one component.
5637 * \throw If the connectivity data array has a named component.
5638 * \throw If the connectivity index data array has more than one component.
5639 * \throw If the connectivity index data array has a named component.
5640 * \throw If \a this->getMeshDimension() != 2.
5641 * \throw If \a this->getSpaceDimension() != 3.
5642 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5644 MEDCouplingFieldDouble *MEDCouplingUMesh::getSkewField() const
5646 checkConsistencyLight();
5647 int spaceDim=getSpaceDimension();
5648 int meshDim=getMeshDimension();
5650 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : SpaceDimension must be equal to 3 !");
5652 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : MeshDimension must be equal to 2 !");
5653 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5655 mcIdType nbOfCells=getNumberOfCells();
5656 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5657 arr->alloc(nbOfCells,1);
5658 double *pt=arr->getPointer();
5659 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5660 const mcIdType *conn=_nodal_connec->begin();
5661 const mcIdType *connI=_nodal_connec_index->begin();
5662 const double *coo=_coords->begin();
5664 for(mcIdType i=0;i<nbOfCells;i++,pt++)
5666 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5669 case INTERP_KERNEL::NORM_QUAD4:
5671 FillInCompact3DMode(3,4,conn+1,coo,tmp);
5672 *pt=INTERP_KERNEL::quadSkew(tmp);
5676 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : A cell with not manged type (NORM_QUAD4) has been detected !");
5678 conn+=connI[i+1]-connI[i];
5680 ret->setName("Skew");
5681 ret->synchronizeTimeWithSupport();
5686 * 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.
5688 * \return a new instance of field containing the result. The returned instance has to be deallocated by the caller.
5690 * \sa getSkewField, getWarpField, getAspectRatioField, getEdgeRatioField
5692 MEDCouplingFieldDouble *MEDCouplingUMesh::computeDiameterField() const
5694 checkConsistencyLight();
5695 MCAuto<MEDCouplingFieldDouble> ret(MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME));
5697 std::set<INTERP_KERNEL::NormalizedCellType> types;
5698 ComputeAllTypesInternal(types,_nodal_connec,_nodal_connec_index);
5699 int spaceDim(getSpaceDimension());
5700 mcIdType nbCells(getNumberOfCells());
5701 MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
5702 arr->alloc(nbCells,1);
5703 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++)
5705 INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::DiameterCalculator> dc(INTERP_KERNEL::CellModel::GetCellModel(*it).buildInstanceOfDiameterCalulator(spaceDim));
5706 MCAuto<DataArrayIdType> cellIds(giveCellsWithType(*it));
5707 dc->computeForListOfCellIdsUMeshFrmt(cellIds->begin(),cellIds->end(),_nodal_connec_index->begin(),_nodal_connec->begin(),getCoords()->begin(),arr->getPointer());
5710 ret->setName("Diameter");
5715 * This method aggregate the bbox of each cell and put it into bbox parameter (xmin,xmax,ymin,ymax,zmin,zmax).
5717 * \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)
5718 * For all other cases this input parameter is ignored.
5719 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5721 * \throw If \a this is not fully set (coordinates and connectivity).
5722 * \throw If a cell in \a this has no valid nodeId.
5723 * \sa MEDCouplingUMesh::getBoundingBoxForBBTreeFast, MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5725 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree(double arcDetEps) const
5727 int mDim(getMeshDimension()),sDim(getSpaceDimension());
5728 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.
5729 return getBoundingBoxForBBTreeFast();
5730 if((mDim==2 && sDim==2) || (mDim==1 && sDim==2))
5732 bool presenceOfQuadratic(false);
5733 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=_types.begin();it!=_types.end();it++)
5735 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(*it));
5736 if(cm.isQuadratic())
5737 presenceOfQuadratic=true;
5739 if(!presenceOfQuadratic)
5740 return getBoundingBoxForBBTreeFast();
5741 if(mDim==2 && sDim==2)
5742 return getBoundingBoxForBBTree2DQuadratic(arcDetEps);
5744 return getBoundingBoxForBBTree1DQuadratic(arcDetEps);
5746 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) !");
5750 * This method aggregate the bbox of each cell only considering the nodes constituting each cell and put it into bbox parameter.
5751 * So meshes having quadratic cells the computed bounding boxes can be invalid !
5753 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5755 * \throw If \a this is not fully set (coordinates and connectivity).
5756 * \throw If a cell in \a this has no valid nodeId.
5758 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTreeFast() const
5760 checkFullyDefined();
5761 int spaceDim(getSpaceDimension());
5762 mcIdType nbOfCells(getNumberOfCells()), nbOfNodes(getNumberOfNodes());
5763 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5764 double *bbox(ret->getPointer());
5765 for(mcIdType i=0;i<nbOfCells*spaceDim;i++)
5767 bbox[2*i]=std::numeric_limits<double>::max();
5768 bbox[2*i+1]=-std::numeric_limits<double>::max();
5770 const double *coordsPtr(_coords->begin());
5771 const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5772 for(mcIdType i=0;i<nbOfCells;i++)
5774 mcIdType offset=connI[i]+1;
5775 mcIdType nbOfNodesForCell(connI[i+1]-offset),kk(0);
5776 for(mcIdType j=0;j<nbOfNodesForCell;j++)
5778 mcIdType nodeId=conn[offset+j];
5779 if(nodeId>=0 && nodeId<nbOfNodes)
5781 for(int k=0;k<spaceDim;k++)
5783 bbox[2*spaceDim*i+2*k]=std::min(bbox[2*spaceDim*i+2*k],coordsPtr[spaceDim*nodeId+k]);
5784 bbox[2*spaceDim*i+2*k+1]=std::max(bbox[2*spaceDim*i+2*k+1],coordsPtr[spaceDim*nodeId+k]);
5791 std::ostringstream oss; oss << "MEDCouplingUMesh::getBoundingBoxForBBTree : cell #" << i << " contains no valid nodeId !";
5792 throw INTERP_KERNEL::Exception(oss.str());
5799 * This method aggregates the bbox of each 2D cell in \a this considering the whole shape. This method is particularly
5800 * useful for 2D meshes having quadratic cells
5801 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5802 * the two extremities of the arc of circle).
5804 * \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)
5805 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5806 * \throw If \a this is not fully defined.
5807 * \throw If \a this is not a mesh with meshDimension equal to 2.
5808 * \throw If \a this is not a mesh with spaceDimension equal to 2.
5809 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic
5811 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic(double arcDetEps) const
5813 checkFullyDefined();
5814 INTERP_KERNEL::QuadraticPlanarPrecision arcPrec(arcDetEps);
5816 int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
5817 mcIdType nbOfCells=getNumberOfCells();
5818 if(spaceDim!=2 || mDim!=2)
5819 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!");
5820 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5821 double *bbox(ret->getPointer());
5822 const double *coords(_coords->begin());
5823 const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5824 for(mcIdType i=0;i<nbOfCells;i++,bbox+=4,connI++)
5826 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5827 mcIdType sz(connI[1]-connI[0]-1);
5828 std::vector<INTERP_KERNEL::Node *> nodes(sz);
5829 INTERP_KERNEL::QuadraticPolygon *pol(0);
5830 for(mcIdType j=0;j<sz;j++)
5832 mcIdType nodeId(conn[*connI+1+j]);
5833 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5835 if(!cm.isQuadratic())
5836 pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
5838 pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
5839 INTERP_KERNEL::Bounds b; b.prepareForAggregation(); pol->fillBounds(b); delete pol;
5840 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax();
5846 * This method aggregates the bbox of each 1D cell in \a this considering the whole shape. This method is particularly
5847 * useful for 2D meshes having quadratic cells
5848 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5849 * the two extremities of the arc of circle).
5851 * \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)
5852 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5853 * \throw If \a this is not fully defined.
5854 * \throw If \a this is not a mesh with meshDimension equal to 1.
5855 * \throw If \a this is not a mesh with spaceDimension equal to 2.
5856 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5858 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic(double arcDetEps) const
5860 checkFullyDefined();
5861 int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
5862 mcIdType nbOfCells=getNumberOfCells();
5863 if(spaceDim!=2 || mDim!=1)
5864 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!");
5865 INTERP_KERNEL::QuadraticPlanarPrecision arcPrec(arcDetEps);
5866 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5867 double *bbox(ret->getPointer());
5868 const double *coords(_coords->begin());
5869 const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5870 for(mcIdType i=0;i<nbOfCells;i++,bbox+=4,connI++)
5872 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5873 mcIdType sz(connI[1]-connI[0]-1);
5874 std::vector<INTERP_KERNEL::Node *> nodes(sz);
5875 INTERP_KERNEL::Edge *edge(0);
5876 for(mcIdType j=0;j<sz;j++)
5878 mcIdType nodeId(conn[*connI+1+j]);
5879 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5881 if(!cm.isQuadratic())
5882 edge=INTERP_KERNEL::QuadraticPolygon::BuildLinearEdge(nodes);
5884 edge=INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(nodes);
5885 const INTERP_KERNEL::Bounds& b(edge->getBounds());
5886 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax(); edge->decrRef();
5893 namespace MEDCouplingImpl
5898 ConnReader(const mcIdType *c, mcIdType val):_conn(c),_val(val) { }
5899 bool operator() (const mcIdType& pos) { return _conn[pos]!=_val; }
5901 const mcIdType *_conn;
5908 ConnReader2(const mcIdType *c, mcIdType val):_conn(c),_val(val) { }
5909 bool operator() (const mcIdType& pos) { return _conn[pos]==_val; }
5911 const mcIdType *_conn;
5919 * This method expects that \a this is sorted by types. If not an exception will be thrown.
5920 * This method returns in the same format as code (see MEDCouplingUMesh::checkTypeConsistencyAndContig or MEDCouplingUMesh::splitProfilePerType) how
5921 * \a this is composed in cell types.
5922 * The returned array is of size 3*n where n is the number of different types present in \a this.
5923 * For every k in [0,n] ret[3*k+2]==-1 because it has no sense here.
5924 * This parameter is kept only for compatibility with other method listed above.
5926 std::vector<mcIdType> MEDCouplingUMesh::getDistributionOfTypes() const
5928 checkConnectivityFullyDefined();
5929 const mcIdType *conn=_nodal_connec->begin();
5930 const mcIdType *connI=_nodal_connec_index->begin();
5931 const mcIdType *work=connI;
5932 mcIdType nbOfCells=getNumberOfCells();
5933 std::size_t n=getAllGeoTypes().size();
5934 std::vector<mcIdType> ret(3*n,-1); //ret[3*k+2]==-1 because it has no sense here
5935 std::set<INTERP_KERNEL::NormalizedCellType> types;
5936 for(std::size_t i=0;work!=connI+nbOfCells;i++)
5938 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn[*work];
5939 if(types.find(typ)!=types.end())
5941 std::ostringstream oss; oss << "MEDCouplingUMesh::getDistributionOfTypes : Type " << INTERP_KERNEL::CellModel::GetCellModel(typ).getRepr();
5942 oss << " is not contiguous !";
5943 throw INTERP_KERNEL::Exception(oss.str());
5947 const mcIdType *work2=std::find_if(work+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,typ));
5948 ret[3*i+1]=ToIdType(std::distance(work,work2));
5955 * This method is used to check that this has contiguous cell type in same order than described in \a code.
5956 * only for types cell, type node is not managed.
5957 * Format of \a code is the following. \a code should be of size 3*n and non empty. If not an exception is thrown.
5958 * foreach k in [0,n) on 3*k pos represent the geometric type and 3*k+1 number of elements of type 3*k.
5959 * 3*k+2 refers if different from -1 the pos in 'idsPerType' to get the corresponding array.
5960 * If 2 or more same geometric type is in \a code and exception is thrown too.
5962 * This method firstly checks
5963 * If it exists k so that 3*k geometric type is not in geometric types of this an exception will be thrown.
5964 * If it exists k so that 3*k geometric type exists but the number of consecutive cell types does not match,
5965 * an exception is thrown too.
5967 * If all geometric types in \a code are exactly those in \a this null pointer is returned.
5968 * If it exists a geometric type in \a this \b not in \a code \b no exception is thrown
5969 * and a DataArrayIdType instance is returned that the user has the responsibility to deallocate.
5971 DataArrayIdType *MEDCouplingUMesh::checkTypeConsistencyAndContig(const std::vector<mcIdType>& code, const std::vector<const DataArrayIdType *>& idsPerType) const
5974 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code is empty, should not !");
5975 std::size_t sz=code.size();
5978 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code size is NOT %3 !");
5979 std::vector<INTERP_KERNEL::NormalizedCellType> types;
5981 bool isNoPflUsed=true;
5982 for(std::size_t i=0;i<n;i++)
5983 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)code[3*i])==types.end())
5985 types.push_back((INTERP_KERNEL::NormalizedCellType)code[3*i]);
5987 if(_types.find((INTERP_KERNEL::NormalizedCellType)code[3*i])==_types.end())
5988 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : expected geo types not in this !");
5989 isNoPflUsed=isNoPflUsed && (code[3*i+2]==-1);
5992 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code contains duplication of types in unstructured mesh !");
5995 if(!checkConsecutiveCellTypesAndOrder(&types[0],&types[0]+types.size()))
5996 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : non contiguous type !");
5997 if(types.size()==_types.size())
6000 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
6002 mcIdType *retPtr=ret->getPointer();
6003 const mcIdType *connI=_nodal_connec_index->begin();
6004 const mcIdType *conn=_nodal_connec->begin();
6005 mcIdType nbOfCells=getNumberOfCells();
6006 const mcIdType *i=connI;
6008 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++,kk++)
6010 i=std::find_if(i,connI+nbOfCells,MEDCouplingImpl::ConnReader2(conn,ToIdType((*it))));
6011 mcIdType offset=ToIdType(std::distance(connI,i));
6012 const mcIdType *j=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType((*it))));
6013 mcIdType nbOfCellsOfCurType=ToIdType(std::distance(i,j));
6014 if(code[3*kk+2]==-1)
6015 for(mcIdType k=0;k<nbOfCellsOfCurType;k++)
6019 mcIdType idInIdsPerType=code[3*kk+2];
6020 if(idInIdsPerType>=0 && idInIdsPerType<ToIdType(idsPerType.size()))
6022 const DataArrayIdType *zePfl=idsPerType[idInIdsPerType];
6025 zePfl->checkAllocated();
6026 if(zePfl->getNumberOfComponents()==1)
6028 for(const mcIdType *k=zePfl->begin();k!=zePfl->end();k++,retPtr++)
6030 if(*k>=0 && *k<nbOfCellsOfCurType)
6031 *retPtr=(*k)+offset;
6034 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : the section " << kk << " points to the profile #" << idInIdsPerType;
6035 oss << ", and this profile contains a value " << *k << " should be in [0," << nbOfCellsOfCurType << ") !";
6036 throw INTERP_KERNEL::Exception(oss.str());
6041 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of a profile with nb of compo != 1 !");
6044 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of null profile !");
6048 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : at section " << kk << " of code it points to the array #" << idInIdsPerType;
6049 oss << " should be in [0," << idsPerType.size() << ") !";
6050 throw INTERP_KERNEL::Exception(oss.str());
6059 * This method makes the hypothesis that \a this is sorted by type. If not an exception will be thrown.
6060 * 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.
6061 * 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.
6062 * This method has 1 input \a profile and 3 outputs \a code \a idsInPflPerType and \a idsPerType.
6064 * \param [in] profile list of IDs constituing the profile
6065 * \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.
6066 * \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,
6067 * \a idsInPflPerType[i] stores the tuple ids in \a profile that correspond to the geometric type code[3*i+0]
6068 * \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.
6069 * This vector can be empty in case of all geometric type cells are fully covered in ascending in the given input \a profile.
6070 * \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
6072 void MEDCouplingUMesh::splitProfilePerType(const DataArrayIdType *profile, std::vector<mcIdType>& code, std::vector<DataArrayIdType *>& idsInPflPerType, std::vector<DataArrayIdType *>& idsPerType, bool smartPflKiller) const
6075 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile is NULL !");
6076 if(profile->getNumberOfComponents()!=1)
6077 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile should have exactly one component !");
6078 checkConnectivityFullyDefined();
6079 const mcIdType *conn=_nodal_connec->begin();
6080 const mcIdType *connI=_nodal_connec_index->begin();
6081 mcIdType nbOfCells=getNumberOfCells();
6082 std::vector<INTERP_KERNEL::NormalizedCellType> types;
6083 std::vector<mcIdType> typeRangeVals(1);
6084 for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6086 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6087 if(std::find(types.begin(),types.end(),curType)!=types.end())
6089 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : current mesh is not sorted by type !");
6091 types.push_back(curType);
6092 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6093 typeRangeVals.push_back(ToIdType(std::distance(connI,i)));
6096 DataArrayIdType *castArr=0,*rankInsideCast=0,*castsPresent=0;
6097 profile->splitByValueRange(&typeRangeVals[0],&typeRangeVals[0]+typeRangeVals.size(),castArr,rankInsideCast,castsPresent);
6098 MCAuto<DataArrayIdType> tmp0=castArr;
6099 MCAuto<DataArrayIdType> tmp1=rankInsideCast;
6100 MCAuto<DataArrayIdType> tmp2=castsPresent;
6102 mcIdType nbOfCastsFinal=castsPresent->getNumberOfTuples();
6103 code.resize(3*nbOfCastsFinal);
6104 std::vector< MCAuto<DataArrayIdType> > idsInPflPerType2;
6105 std::vector< MCAuto<DataArrayIdType> > idsPerType2;
6106 for(mcIdType i=0;i<nbOfCastsFinal;i++)
6108 mcIdType castId=castsPresent->getIJ(i,0);
6109 MCAuto<DataArrayIdType> tmp3=castArr->findIdsEqual(castId);
6110 idsInPflPerType2.push_back(tmp3);
6111 code[3*i]=ToIdType(types[castId]);
6112 code[3*i+1]=tmp3->getNumberOfTuples();
6113 MCAuto<DataArrayIdType> tmp4=rankInsideCast->selectByTupleId(tmp3->begin(),tmp3->begin()+tmp3->getNumberOfTuples());
6114 if(!smartPflKiller || !tmp4->isIota(typeRangeVals[castId+1]-typeRangeVals[castId]))
6116 tmp4->copyStringInfoFrom(*profile);
6117 idsPerType2.push_back(tmp4);
6118 code[3*i+2]=ToIdType(idsPerType2.size())-1;
6125 std::size_t sz2=idsInPflPerType2.size();
6126 idsInPflPerType.resize(sz2);
6127 for(std::size_t i=0;i<sz2;i++)
6129 DataArrayIdType *locDa=idsInPflPerType2[i];
6131 idsInPflPerType[i]=locDa;
6133 std::size_t sz=idsPerType2.size();
6134 idsPerType.resize(sz);
6135 for(std::size_t i=0;i<sz;i++)
6137 DataArrayIdType *locDa=idsPerType2[i];
6139 idsPerType[i]=locDa;
6144 * This method is here too emulate the MEDMEM behaviour on BDC (buildDescendingConnectivity). Hoping this method becomes deprecated very soon.
6145 * This method make the assumption that \a this and 'nM1LevMesh' mesh lyies on same coords (same pointer) as MED and MEDMEM does.
6146 * The following equality should be verified 'nM1LevMesh->getMeshDimension()==this->getMeshDimension()-1'
6147 * 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.
6149 MEDCouplingUMesh *MEDCouplingUMesh::emulateMEDMEMBDC(const MEDCouplingUMesh *nM1LevMesh, DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *&revDesc, DataArrayIdType *&revDescIndx, DataArrayIdType *& nM1LevMeshIds, DataArrayIdType *&meshnM1Old2New) const
6151 checkFullyDefined();
6152 nM1LevMesh->checkFullyDefined();
6153 if(getMeshDimension()-1!=nM1LevMesh->getMeshDimension())
6154 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : The mesh passed as first argument should have a meshDim equal to this->getMeshDimension()-1 !" );
6155 if(_coords!=nM1LevMesh->getCoords())
6156 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : 'this' and mesh in first argument should share the same coords : Use tryToShareSameCoords method !");
6157 MCAuto<DataArrayIdType> tmp0=DataArrayIdType::New();
6158 MCAuto<DataArrayIdType> tmp1=DataArrayIdType::New();
6159 MCAuto<MEDCouplingUMesh> ret1=buildDescendingConnectivity(desc,descIndx,tmp0,tmp1);
6160 MCAuto<DataArrayIdType> ret0=ret1->sortCellsInMEDFileFrmt();
6161 desc->transformWithIndArr(ret0->begin(),ret0->begin()+ret0->getNbOfElems());
6162 MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
6163 tmp->setConnectivity(tmp0,tmp1);
6164 tmp->renumberCells(ret0->begin(),false);
6165 revDesc=tmp->getNodalConnectivity();
6166 revDescIndx=tmp->getNodalConnectivityIndex();
6167 DataArrayIdType *ret=0;
6168 if(!ret1->areCellsIncludedIn(nM1LevMesh,2,ret))
6171 ret->getMaxValue(tmp2);
6173 std::ostringstream oss; oss << "MEDCouplingUMesh::emulateMEDMEMBDC : input N-1 mesh present a cell not in descending mesh ... Id of cell is " << tmp2 << " !";
6174 throw INTERP_KERNEL::Exception(oss.str());
6179 revDescIndx->incrRef();
6182 meshnM1Old2New=ret0;
6187 * Permutes the nodal connectivity arrays so that the cells are sorted by type, which is
6188 * necessary for writing the mesh to MED file. Additionally returns a permutation array
6189 * in "Old to New" mode.
6190 * \return DataArrayIdType * - a new instance of DataArrayIdType. The caller is to delete
6191 * this array using decrRef() as it is no more needed.
6192 * \throw If the nodal connectivity of cells is not defined.
6194 DataArrayIdType *MEDCouplingUMesh::sortCellsInMEDFileFrmt()
6196 checkConnectivityFullyDefined();
6197 MCAuto<DataArrayIdType> ret=getRenumArrForMEDFileFrmt();
6198 renumberCells(ret->begin(),false);
6203 * This methods checks that cells are sorted by their types.
6204 * This method makes asumption (no check) that connectivity is correctly set before calling.
6206 bool MEDCouplingUMesh::checkConsecutiveCellTypes() const
6208 checkFullyDefined();
6209 const mcIdType *conn=_nodal_connec->begin();
6210 const mcIdType *connI=_nodal_connec_index->begin();
6211 mcIdType nbOfCells=getNumberOfCells();
6212 std::set<INTERP_KERNEL::NormalizedCellType> types;
6213 for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6215 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6216 if(types.find(curType)!=types.end())
6218 types.insert(curType);
6219 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6225 * This method is a specialization of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method that is called here.
6226 * The geometric type order is specified by MED file.
6228 * \sa MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder
6230 bool MEDCouplingUMesh::checkConsecutiveCellTypesForMEDFileFrmt() const
6232 return checkConsecutiveCellTypesAndOrder(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
6236 * This method performs the same job as checkConsecutiveCellTypes except that the order of types sequence is analyzed to check
6237 * that the order is specified in array defined by [ \a orderBg , \a orderEnd ).
6238 * If there is some geo types in \a this \b NOT in [ \a orderBg, \a orderEnd ) it is OK (return true) if contiguous.
6239 * If there is some geo types in [ \a orderBg, \a orderEnd ) \b NOT in \a this it is OK too (return true) if contiguous.
6241 bool MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
6243 checkFullyDefined();
6244 const mcIdType *conn=_nodal_connec->begin();
6245 const mcIdType *connI=_nodal_connec_index->begin();
6246 mcIdType nbOfCells=getNumberOfCells();
6249 mcIdType lastPos=-1;
6250 std::set<INTERP_KERNEL::NormalizedCellType> sg;
6251 for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6253 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6254 const INTERP_KERNEL::NormalizedCellType *isTypeExists=std::find(orderBg,orderEnd,curType);
6255 if(isTypeExists!=orderEnd)
6257 mcIdType pos=ToIdType(std::distance(orderBg,isTypeExists));
6261 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6265 if(sg.find(curType)==sg.end())
6267 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6278 * This method returns 2 newly allocated DataArrayIdType instances. The first is an array of size 'this->getNumberOfCells()' with one component,
6279 * 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
6280 * number of tuples than input type array and with one component. This 2nd output array gives type by type the number of occurrence of type in 'this'.
6282 DataArrayIdType *MEDCouplingUMesh::getLevArrPerCellTypes(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd, DataArrayIdType *&nbPerType) const
6284 checkConnectivityFullyDefined();
6285 mcIdType nbOfCells=getNumberOfCells();
6286 const mcIdType *conn=_nodal_connec->begin();
6287 const mcIdType *connI=_nodal_connec_index->begin();
6288 MCAuto<DataArrayIdType> tmpa=DataArrayIdType::New();
6289 MCAuto<DataArrayIdType> tmpb=DataArrayIdType::New();
6290 tmpa->alloc(nbOfCells,1);
6291 tmpb->alloc(std::distance(orderBg,orderEnd),1);
6292 tmpb->fillWithZero();
6293 mcIdType *tmp=tmpa->getPointer();
6294 mcIdType *tmp2=tmpb->getPointer();
6295 for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6297 const INTERP_KERNEL::NormalizedCellType *where=std::find(orderBg,orderEnd,(INTERP_KERNEL::NormalizedCellType)conn[*i]);
6300 mcIdType pos=ToIdType(std::distance(orderBg,where));
6302 tmp[std::distance(connI,i)]=pos;
6306 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*i]);
6307 std::ostringstream oss; oss << "MEDCouplingUMesh::getLevArrPerCellTypes : Cell #" << std::distance(connI,i);
6308 oss << " has a type " << cm.getRepr() << " not in input array of type !";
6309 throw INTERP_KERNEL::Exception(oss.str());
6312 nbPerType=tmpb.retn();
6317 * This method behaves exactly as MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec but the order is those defined in MED file spec.
6319 * \return a new object containing the old to new correspondence.
6321 * \sa MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec, MEDCouplingUMesh::sortCellsInMEDFileFrmt.
6323 DataArrayIdType *MEDCouplingUMesh::getRenumArrForMEDFileFrmt() const
6325 return getRenumArrForConsecutiveCellTypesSpec(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
6329 * This method is similar to method MEDCouplingUMesh::rearrange2ConsecutiveCellTypes except that the type order is specified by [ \a orderBg , \a orderEnd ) (as MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method) and that this method is \b const and performs \b NO permutation in \a this.
6330 * This method returns an array of size getNumberOfCells() that gives a renumber array old2New that can be used as input of MEDCouplingMesh::renumberCells.
6331 * The mesh after this call to MEDCouplingMesh::renumberCells will pass the test of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder with the same inputs.
6332 * The returned array minimizes the permutations that is to say the order of cells inside same geometric type remains the same.
6334 DataArrayIdType *MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
6336 DataArrayIdType *nbPerType=0;
6337 MCAuto<DataArrayIdType> tmpa=getLevArrPerCellTypes(orderBg,orderEnd,nbPerType);
6338 nbPerType->decrRef();
6339 return tmpa->buildPermArrPerLevel();
6343 * This method reorganize the cells of \a this so that the cells with same geometric types are put together.
6344 * The number of cells remains unchanged after the call of this method.
6345 * This method tries to minimizes the number of needed permutations. So, this method behaves not exactly as
6346 * MEDCouplingUMesh::sortCellsInMEDFileFrmt.
6348 * \return the array giving the correspondence old to new.
6350 DataArrayIdType *MEDCouplingUMesh::rearrange2ConsecutiveCellTypes()
6352 checkFullyDefined();
6354 const mcIdType *conn=_nodal_connec->begin();
6355 const mcIdType *connI=_nodal_connec_index->begin();
6356 mcIdType nbOfCells=getNumberOfCells();
6357 std::vector<INTERP_KERNEL::NormalizedCellType> types;
6358 for(const mcIdType *i=connI;i!=connI+nbOfCells && (types.size()!=_types.size());)
6359 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)conn[*i])==types.end())
6361 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6362 types.push_back(curType);
6363 for(i++;i!=connI+nbOfCells && (INTERP_KERNEL::NormalizedCellType)conn[*i]==curType;i++);
6365 DataArrayIdType *ret=DataArrayIdType::New();
6366 ret->alloc(nbOfCells,1);
6367 mcIdType *retPtr=ret->getPointer();
6368 std::fill(retPtr,retPtr+nbOfCells,-1);
6369 mcIdType newCellId=0;
6370 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
6372 for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6373 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
6374 retPtr[std::distance(connI,i)]=newCellId++;
6376 renumberCells(retPtr,false);
6381 * This method splits \a this into as mush as untructured meshes that consecutive set of same type cells.
6382 * So this method has typically a sense if MEDCouplingUMesh::checkConsecutiveCellTypes has a sense.
6383 * This method makes asumption that connectivity is correctly set before calling.
6385 std::vector<MEDCouplingUMesh *> MEDCouplingUMesh::splitByType() const
6387 checkConnectivityFullyDefined();
6388 const mcIdType *conn=_nodal_connec->begin();
6389 const mcIdType *connI=_nodal_connec_index->begin();
6390 mcIdType nbOfCells=getNumberOfCells();
6391 std::vector<MEDCouplingUMesh *> ret;
6392 for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6394 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6395 mcIdType beginCellId=ToIdType(std::distance(connI,i));
6396 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6397 mcIdType endCellId=ToIdType(std::distance(connI,i));
6398 mcIdType sz=endCellId-beginCellId;
6399 mcIdType *cells=new mcIdType[sz];
6400 for(mcIdType j=0;j<sz;j++)
6401 cells[j]=beginCellId+j;
6402 MEDCouplingUMesh *m=(MEDCouplingUMesh *)buildPartOfMySelf(cells,cells+sz,true);
6410 * This method performs the opposite operation than those in MEDCoupling1SGTUMesh::buildUnstructured.
6411 * If \a this is a single geometric type unstructured mesh, it will be converted into a more compact data structure,
6412 * MEDCoupling1GTUMesh instance. The returned instance will aggregate the same DataArrayDouble instance of coordinates than \a this.
6414 * \return a newly allocated instance, that the caller must manage.
6415 * \throw If \a this contains more than one geometric type.
6416 * \throw If the nodal connectivity of \a this is not fully defined.
6417 * \throw If the internal data is not coherent.
6419 MEDCoupling1GTUMesh *MEDCouplingUMesh::convertIntoSingleGeoTypeMesh() const
6421 checkConnectivityFullyDefined();
6422 if(_types.size()!=1)
6423 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6424 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6425 MCAuto<MEDCoupling1GTUMesh> ret=MEDCoupling1GTUMesh::New(getName(),typ);
6426 ret->setCoords(getCoords());
6427 MEDCoupling1SGTUMesh *retC=dynamic_cast<MEDCoupling1SGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6430 MCAuto<DataArrayIdType> c=convertNodalConnectivityToStaticGeoTypeMesh();
6431 retC->setNodalConnectivity(c);
6435 MEDCoupling1DGTUMesh *retD=dynamic_cast<MEDCoupling1DGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6437 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : Internal error !");
6438 DataArrayIdType *c=0,*ci=0;
6439 convertNodalConnectivityToDynamicGeoTypeMesh(c,ci);
6440 MCAuto<DataArrayIdType> cs(c),cis(ci);
6441 retD->setNodalConnectivity(cs,cis);
6446 DataArrayIdType *MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh() const
6448 checkConnectivityFullyDefined();
6449 if(_types.size()!=1)
6450 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6451 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6452 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6455 std::ostringstream oss; oss << "MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : this contains a single geo type (" << cm.getRepr() << ") but ";
6456 oss << "this type is dynamic ! Only static geometric type is possible for that type ! call convertNodalConnectivityToDynamicGeoTypeMesh instead !";
6457 throw INTERP_KERNEL::Exception(oss.str());
6459 mcIdType nbCells=getNumberOfCells();
6460 mcIdType typi=ToIdType(typ);
6461 mcIdType nbNodesPerCell=ToIdType(cm.getNumberOfNodes());
6462 MCAuto<DataArrayIdType> connOut=DataArrayIdType::New(); connOut->alloc(nbCells*nbNodesPerCell,1);
6463 mcIdType *outPtr=connOut->getPointer();
6464 const mcIdType *conn=_nodal_connec->begin();
6465 const mcIdType *connI=_nodal_connec_index->begin();
6467 for(mcIdType i=0;i<nbCells;i++,connI++)
6469 if(conn[connI[0]]==typi && connI[1]-connI[0]==nbNodesPerCell)
6470 outPtr=std::copy(conn+connI[0]+1,conn+connI[1],outPtr);
6473 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 << ") !";
6474 throw INTERP_KERNEL::Exception(oss.str());
6477 return connOut.retn();
6481 * Convert the nodal connectivity of the mesh so that all the cells are of dynamic types (polygon or quadratic
6482 * polygon). This returns the corresponding new nodal connectivity in \ref numbering-indirect format.
6483 * \param nodalConn nodal connectivity
6484 * \param nodalConnIndex nodal connectivity indices
6486 void MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh(DataArrayIdType *&nodalConn, DataArrayIdType *&nodalConnIndex) const
6488 static const char msg0[]="MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : nodal connectivity in this are invalid ! Call checkConsistency !";
6489 checkConnectivityFullyDefined();
6490 if(_types.size()!=1)
6491 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6492 mcIdType nbCells=getNumberOfCells(),
6493 lgth=_nodal_connec->getNumberOfTuples();
6495 throw INTERP_KERNEL::Exception(msg0);
6496 MCAuto<DataArrayIdType> c(DataArrayIdType::New()),ci(DataArrayIdType::New());
6497 c->alloc(lgth-nbCells,1); ci->alloc(nbCells+1,1);
6498 mcIdType *cp(c->getPointer()),*cip(ci->getPointer());
6499 const mcIdType *incp(_nodal_connec->begin()),*incip(_nodal_connec_index->begin());
6501 for(mcIdType i=0;i<nbCells;i++,cip++,incip++)
6503 mcIdType strt(incip[0]+1),stop(incip[1]);//+1 to skip geo type
6504 mcIdType delta(stop-strt);
6507 if((strt>=0 && strt<lgth) && (stop>=0 && stop<=lgth))
6508 cp=std::copy(incp+strt,incp+stop,cp);
6510 throw INTERP_KERNEL::Exception(msg0);
6513 throw INTERP_KERNEL::Exception(msg0);
6514 cip[1]=cip[0]+delta;
6516 nodalConn=c.retn(); nodalConnIndex=ci.retn();
6520 * This method takes in input a vector of MEDCouplingUMesh instances lying on the same coordinates with same mesh dimensions.
6521 * Each mesh in \b ms must be sorted by type with the same order (typically using MEDCouplingUMesh::sortCellsInMEDFileFrmt).
6522 * This method is particularly useful for MED file interaction. It allows to aggregate several meshes and keeping the type sorting
6523 * and the track of the permutation by chunk of same geotype cells to retrieve it. The traditional formats old2new and new2old
6524 * are not used here to avoid the build of big permutation array.
6526 * \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
6527 * those specified in MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6528 * \param [out] szOfCellGrpOfSameType is a newly allocated DataArrayIdType instance whose number of tuples is equal to the number of chunks of same geotype
6529 * in all meshes in \b ms. The accumulation of all values of this array is equal to the number of cells of returned mesh.
6530 * \param [out] idInMsOfCellGrpOfSameType is a newly allocated DataArrayIdType instance having the same size than \b szOfCellGrpOfSameType. This
6531 * output array gives for each chunck of same type the corresponding mesh id in \b ms.
6532 * \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
6533 * is sorted by type following the geo cell types order of MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6535 MEDCouplingUMesh *MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& ms,
6536 DataArrayIdType *&szOfCellGrpOfSameType,
6537 DataArrayIdType *&idInMsOfCellGrpOfSameType)
6539 std::vector<const MEDCouplingUMesh *> ms2;
6540 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms.begin();it!=ms.end();it++)
6543 (*it)->checkConnectivityFullyDefined();
6547 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : input vector is empty !");
6548 const DataArrayDouble *refCoo=ms2[0]->getCoords();
6549 int meshDim=ms2[0]->getMeshDimension();
6550 std::vector<const MEDCouplingUMesh *> m1ssm;
6551 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmAuto;
6553 std::vector<const MEDCouplingUMesh *> m1ssmSingle;
6554 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmSingleAuto;
6555 mcIdType fake=0,rk=0;
6556 MCAuto<DataArrayIdType> ret1(DataArrayIdType::New()),ret2(DataArrayIdType::New());
6557 ret1->alloc(0,1); ret2->alloc(0,1);
6558 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms2.begin();it!=ms2.end();it++,rk++)
6560 if(meshDim!=(*it)->getMeshDimension())
6561 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshdims mismatch !");
6562 if(refCoo!=(*it)->getCoords())
6563 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshes are not shared by a single coordinates coords !");
6564 std::vector<MEDCouplingUMesh *> sp=(*it)->splitByType();
6565 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<const MEDCouplingUMesh *> >(m1ssm));
6566 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<MCAuto<MEDCouplingUMesh> > >(m1ssmAuto));
6567 for(std::vector<MEDCouplingUMesh *>::const_iterator it2=sp.begin();it2!=sp.end();it2++)
6569 MEDCouplingUMesh *singleCell=static_cast<MEDCouplingUMesh *>((*it2)->buildPartOfMySelf(&fake,&fake+1,true));
6570 m1ssmSingleAuto.push_back(singleCell);
6571 m1ssmSingle.push_back(singleCell);
6572 ret1->pushBackSilent((*it2)->getNumberOfCells()); ret2->pushBackSilent(rk);
6575 MCAuto<MEDCouplingUMesh> m1ssmSingle2=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmSingle);
6576 MCAuto<DataArrayIdType> renum=m1ssmSingle2->sortCellsInMEDFileFrmt();
6577 std::vector<const MEDCouplingUMesh *> m1ssmfinal(m1ssm.size());
6578 for(mcIdType i=0;i<ToIdType(m1ssm.size());i++)
6579 m1ssmfinal[renum->getIJ(i,0)]=m1ssm[i];
6580 MCAuto<MEDCouplingUMesh> ret0=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmfinal);
6581 szOfCellGrpOfSameType=ret1->renumber(renum->begin());
6582 idInMsOfCellGrpOfSameType=ret2->renumber(renum->begin());
6587 * This method returns a newly created DataArrayIdType instance.
6588 * This method retrieves cell ids in [ \a begin, \a end ) that have the type \a type.
6590 DataArrayIdType *MEDCouplingUMesh::keepCellIdsByType(INTERP_KERNEL::NormalizedCellType type, const mcIdType *begin, const mcIdType *end) const
6592 checkFullyDefined();
6593 const mcIdType *conn=_nodal_connec->begin();
6594 const mcIdType *connIndex=_nodal_connec_index->begin();
6595 MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(0,1);
6596 for(const mcIdType *w=begin;w!=end;w++)
6597 if((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]==type)
6598 ret->pushBackSilent(*w);
6603 * This method makes the assumption that da->getNumberOfTuples()<this->getNumberOfCells(). This method makes the assumption that ids contained in 'da'
6604 * are in [0:getNumberOfCells())
6606 DataArrayIdType *MEDCouplingUMesh::convertCellArrayPerGeoType(const DataArrayIdType *da) const
6608 checkFullyDefined();
6609 const mcIdType *conn=_nodal_connec->begin();
6610 const mcIdType *connI=_nodal_connec_index->begin();
6611 mcIdType nbOfCells=getNumberOfCells();
6612 std::set<INTERP_KERNEL::NormalizedCellType> types(getAllGeoTypes());
6613 mcIdType *tmp=new mcIdType[nbOfCells];
6614 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
6617 for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6618 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
6619 tmp[std::distance(connI,i)]=j++;
6621 DataArrayIdType *ret=DataArrayIdType::New();
6622 ret->alloc(da->getNumberOfTuples(),da->getNumberOfComponents());
6623 ret->copyStringInfoFrom(*da);
6624 mcIdType *retPtr=ret->getPointer();
6625 const mcIdType *daPtr=da->begin();
6626 mcIdType nbOfElems=da->getNbOfElems();
6627 for(mcIdType k=0;k<nbOfElems;k++)
6628 retPtr[k]=tmp[daPtr[k]];
6634 * This method reduced number of cells of this by keeping cells whose type is different from 'type' and if type=='type'
6635 * This method \b works \b for mesh sorted by type.
6636 * cells whose ids is in 'idsPerGeoType' array.
6637 * This method conserves coords and name of mesh.
6639 MEDCouplingUMesh *MEDCouplingUMesh::keepSpecifiedCells(INTERP_KERNEL::NormalizedCellType type, const mcIdType *idsPerGeoTypeBg, const mcIdType *idsPerGeoTypeEnd) const
6641 std::vector<mcIdType> code=getDistributionOfTypes();
6642 std::size_t nOfTypesInThis=code.size()/3;
6643 mcIdType sz=0,szOfType=0;
6644 for(std::size_t i=0;i<nOfTypesInThis;i++)
6649 szOfType=code[3*i+1];
6651 for(const mcIdType *work=idsPerGeoTypeBg;work!=idsPerGeoTypeEnd;work++)
6652 if(*work<0 || *work>=szOfType)
6654 std::ostringstream oss; oss << "MEDCouplingUMesh::keepSpecifiedCells : Request on type " << type << " at place #" << std::distance(idsPerGeoTypeBg,work) << " value " << *work;
6655 oss << ". It should be in [0," << szOfType << ") !";
6656 throw INTERP_KERNEL::Exception(oss.str());
6658 MCAuto<DataArrayIdType> idsTokeep=DataArrayIdType::New(); idsTokeep->alloc(sz+std::distance(idsPerGeoTypeBg,idsPerGeoTypeEnd),1);
6659 mcIdType *idsPtr=idsTokeep->getPointer();
6661 for(std::size_t i=0;i<nOfTypesInThis;i++)
6664 for(mcIdType j=0;j<code[3*i+1];j++)
6667 idsPtr=std::transform(idsPerGeoTypeBg,idsPerGeoTypeEnd,idsPtr,std::bind(std::plus<mcIdType>(),std::placeholders::_1,offset));
6668 offset+=code[3*i+1];
6670 MCAuto<MEDCouplingUMesh> ret=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(idsTokeep->begin(),idsTokeep->end(),true));
6671 ret->copyTinyInfoFrom(this);
6676 * This method returns a vector of size 'this->getNumberOfCells()'.
6677 * This method retrieves for each cell in \a this if it is linear (false) or quadratic(true).
6679 std::vector<bool> MEDCouplingUMesh::getQuadraticStatus() const
6681 mcIdType ncell=getNumberOfCells();
6682 std::vector<bool> ret(ncell);
6683 const mcIdType *cI=getNodalConnectivityIndex()->begin();
6684 const mcIdType *c=getNodalConnectivity()->begin();
6685 for(mcIdType i=0;i<ncell;i++)
6687 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[i]];
6688 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6689 ret[i]=cm.isQuadratic();
6695 * Returns a newly created mesh (with ref count ==1) that contains merge of \a this and \a other.
6697 MEDCouplingMesh *MEDCouplingUMesh::mergeMyselfWith(const MEDCouplingMesh *other) const
6699 if(other->getType()!=UNSTRUCTURED)
6700 throw INTERP_KERNEL::Exception("Merge of umesh only available with umesh each other !");
6701 const MEDCouplingUMesh *otherC=static_cast<const MEDCouplingUMesh *>(other);
6702 return MergeUMeshes(this,otherC);
6706 * Returns a new DataArrayDouble holding barycenters of all cells. The barycenter is
6707 * computed by averaging coordinates of cell nodes, so this method is not a right
6708 * choice for degenerated meshes (not well oriented, cells with measure close to zero).
6709 * Beware also that for quadratic meshes, degenerated arc of circles are turned into linear edges for the computation.
6710 * This happens with a default detection precision of eps=1.0e-14. If you need control over this use computeCellCenterOfMassWithPrecision().
6711 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
6712 * this->getNumberOfCells() tuples per \a this->getSpaceDimension()
6713 * components. The caller is to delete this array using decrRef() as it is
6715 * \throw If the coordinates array is not set.
6716 * \throw If the nodal connectivity of cells is not defined.
6717 * \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
6718 * \sa MEDCouplingUMesh::computeCellCenterOfMassWithPrecision
6720 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMass() const
6722 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6723 int spaceDim=getSpaceDimension();
6724 mcIdType nbOfCells=getNumberOfCells();
6725 ret->alloc(nbOfCells,spaceDim);
6726 ret->copyStringInfoFrom(*getCoords());
6727 double *ptToFill=ret->getPointer();
6728 const mcIdType *nodal=_nodal_connec->begin();
6729 const mcIdType *nodalI=_nodal_connec_index->begin();
6730 const double *coor=_coords->begin();
6731 for(mcIdType i=0;i<nbOfCells;i++)
6733 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6734 INTERP_KERNEL::computeBarycenter2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[i]+1,nodalI[i+1]-nodalI[i]-1,coor,spaceDim,ptToFill);
6742 * See computeCellCenterOfMass().
6743 * \param eps a precision for the detection of degenerated arc of circles.
6744 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
6745 * this->getNumberOfCells() tuples per \a this->getSpaceDimension()
6746 * components. The caller is to delete this array using decrRef() as it is
6748 * \throw If the coordinates array is not set.
6749 * \throw If the nodal connectivity of cells is not defined.
6750 * \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
6751 * \sa MEDCouplingUMesh::computeCellCenterOfMassWithPrecision
6753 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMassWithPrecision(double eps) const
6755 INTERP_KERNEL::QuadraticPlanarPrecision prec(eps);
6756 MCAuto<DataArrayDouble> ret = computeCellCenterOfMass();
6762 * This method computes for each cell in \a this, the location of the iso barycenter of nodes constituting
6763 * the cell. Contrary to badly named MEDCouplingUMesh::computeCellCenterOfMass method that returns the center of inertia of the
6765 * \return a newly allocated DataArrayDouble instance that the caller has to deal with. The returned
6766 * DataArrayDouble instance will have \c this->getNumberOfCells() tuples and \c this->getSpaceDimension() components.
6768 * \sa MEDCouplingUMesh::computeCellCenterOfMass
6769 * \throw If \a this is not fully defined (coordinates and connectivity)
6770 * \throw If there is presence in nodal connectivity in \a this of node ids not in [0, \c this->getNumberOfNodes() )
6772 DataArrayDouble *MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell() const
6774 checkFullyDefined();
6775 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6776 int spaceDim=getSpaceDimension();
6777 mcIdType nbOfCells=getNumberOfCells();
6778 mcIdType nbOfNodes=getNumberOfNodes();
6779 ret->alloc(nbOfCells,spaceDim);
6780 double *ptToFill=ret->getPointer();
6781 const mcIdType *nodal=_nodal_connec->begin();
6782 const mcIdType *nodalI=_nodal_connec_index->begin();
6783 const double *coor=_coords->begin();
6784 for(mcIdType i=0;i<nbOfCells;i++,ptToFill+=spaceDim)
6786 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6787 std::fill(ptToFill,ptToFill+spaceDim,0.);
6788 if(type!=INTERP_KERNEL::NORM_POLYHED)
6790 for(const mcIdType *conn=nodal+nodalI[i]+1;conn!=nodal+nodalI[i+1];conn++)
6792 if(*conn>=0 && *conn<nbOfNodes)
6793 std::transform(coor+spaceDim*conn[0],coor+spaceDim*(conn[0]+1),ptToFill,ptToFill,std::plus<double>());
6796 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of nodeId #" << *conn << " should be in [0," << nbOfNodes << ") !";
6797 throw INTERP_KERNEL::Exception(oss.str());
6800 mcIdType nbOfNodesInCell=nodalI[i+1]-nodalI[i]-1;
6801 if(nbOfNodesInCell>0)
6802 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind(std::multiplies<double>(),std::placeholders::_1,1./(double)nbOfNodesInCell));
6805 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of cell with no nodes !";
6806 throw INTERP_KERNEL::Exception(oss.str());
6811 std::set<mcIdType> s(nodal+nodalI[i]+1,nodal+nodalI[i+1]);
6813 for(std::set<mcIdType>::const_iterator it=s.begin();it!=s.end();it++)
6815 if(*it>=0 && *it<nbOfNodes)
6816 std::transform(coor+spaceDim*(*it),coor+spaceDim*((*it)+1),ptToFill,ptToFill,std::plus<double>());
6819 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell polyhedron cell #" << i << " presence of nodeId #" << *it << " should be in [0," << nbOfNodes << ") !";
6820 throw INTERP_KERNEL::Exception(oss.str());
6824 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind(std::multiplies<double>(),std::placeholders::_1,1./(double)s.size()));
6827 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on polyhedron cell #" << i << " there are no nodes !";
6828 throw INTERP_KERNEL::Exception(oss.str());
6836 * Returns a new DataArrayDouble holding barycenters of specified cells. The
6837 * barycenter is computed by averaging coordinates of cell nodes. The cells to treat
6838 * are specified via an array of cell ids.
6839 * \warning Validity of the specified cell ids is not checked!
6840 * Valid range is [ 0, \a this->getNumberOfCells() ).
6841 * \param [in] begin - an array of cell ids of interest.
6842 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
6843 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size ( \a
6844 * end - \a begin ) tuples per \a this->getSpaceDimension() components. The
6845 * caller is to delete this array using decrRef() as it is no more needed.
6846 * \throw If the coordinates array is not set.
6847 * \throw If the nodal connectivity of cells is not defined.
6849 * \if ENABLE_EXAMPLES
6850 * \ref cpp_mcumesh_getPartBarycenterAndOwner "Here is a C++ example".<br>
6851 * \ref py_mcumesh_getPartBarycenterAndOwner "Here is a Python example".
6854 DataArrayDouble *MEDCouplingUMesh::getPartBarycenterAndOwner(const mcIdType *begin, const mcIdType *end) const
6856 DataArrayDouble *ret=DataArrayDouble::New();
6857 int spaceDim=getSpaceDimension();
6858 std::size_t nbOfTuple=std::distance(begin,end);
6859 ret->alloc(nbOfTuple,spaceDim);
6860 double *ptToFill=ret->getPointer();
6861 double *tmp=new double[spaceDim];
6862 const mcIdType *nodal=_nodal_connec->begin();
6863 const mcIdType *nodalI=_nodal_connec_index->begin();
6864 const double *coor=_coords->begin();
6865 for(const mcIdType *w=begin;w!=end;w++)
6867 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[*w]];
6868 INTERP_KERNEL::computeBarycenter2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[*w]+1,nodalI[*w+1]-nodalI[*w]-1,coor,spaceDim,ptToFill);
6876 * 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".
6877 * So the returned instance will have 4 components and \c this->getNumberOfCells() tuples.
6878 * So this method expects that \a this has a spaceDimension equal to 3 and meshDimension equal to 2.
6879 * The computation of the plane equation is done using each time the 3 first nodes of 2D cells.
6880 * This method is useful to detect 2D cells in 3D space that are not coplanar.
6882 * \return DataArrayDouble * - a new instance of DataArrayDouble having 4 components and a number of tuples equal to number of cells in \a this.
6883 * \throw If spaceDim!=3 or meshDim!=2.
6884 * \throw If connectivity of \a this is invalid.
6885 * \throw If connectivity of a cell in \a this points to an invalid node.
6887 DataArrayDouble *MEDCouplingUMesh::computePlaneEquationOf3DFaces() const
6889 MCAuto<DataArrayDouble> ret(DataArrayDouble::New());
6890 mcIdType nbOfCells=getNumberOfCells();
6891 mcIdType nbOfNodes(getNumberOfNodes());
6892 if(getSpaceDimension()!=3 || getMeshDimension()!=2)
6893 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computePlaneEquationOf3DFaces : This method must be applied on a mesh having meshDimension equal 2 and a spaceDimension equal to 3 !");
6894 ret->alloc(nbOfCells,4);
6895 double *retPtr(ret->getPointer());
6896 const mcIdType *nodal(_nodal_connec->begin()),*nodalI(_nodal_connec_index->begin());
6897 const double *coor(_coords->begin());
6898 for(mcIdType i=0;i<nbOfCells;i++,nodalI++,retPtr+=4)
6900 double matrix[16]={0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,0},matrix2[16];
6901 if(nodalI[1]-nodalI[0]>=4)
6903 double aa[3]={coor[nodal[nodalI[0]+1+1]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6904 coor[nodal[nodalI[0]+1+1]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6905 coor[nodal[nodalI[0]+1+1]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]}
6906 ,bb[3]={coor[nodal[nodalI[0]+1+2]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6907 coor[nodal[nodalI[0]+1+2]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6908 coor[nodal[nodalI[0]+1+2]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]};
6909 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]};
6910 double aa_norm(sqrt(aa[0]*aa[0]+aa[1]*aa[1]+aa[2]*aa[2])),bb_norm(sqrt(bb[0]*bb[0]+bb[1]*bb[1]+bb[2]*bb[2]));
6911 for(int j=0;j<3;j++)
6913 mcIdType nodeId(nodal[nodalI[0]+1+j]);
6914 if(nodeId>=0 && nodeId<nbOfNodes)
6915 std::copy(coor+nodeId*3,coor+(nodeId+1)*3,matrix+4*j);
6918 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! This cell points to an invalid nodeId : " << nodeId << " !";
6919 throw INTERP_KERNEL::Exception(oss.str());
6922 if(sqrt(cc[0]*cc[0]+cc[1]*cc[1]+cc[2]*cc[2])>(1e-3*aa_norm*bb_norm))
6924 INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6925 retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6929 if(nodalI[1]-nodalI[0]==4)
6931 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : cell" << i << " : Presence of The 3 colinear points !";
6932 throw INTERP_KERNEL::Exception(oss.str());
6935 double dd[3]={0.,0.,0.};
6936 for(mcIdType offset=nodalI[0]+1;offset<nodalI[1];offset++)
6937 std::transform(coor+3*nodal[offset],coor+3*(nodal[offset]+1),dd,dd,std::plus<double>());
6938 mcIdType nbOfNodesInCell(nodalI[1]-nodalI[0]-1);
6939 std::transform(dd,dd+3,dd,std::bind(std::multiplies<double>(),std::placeholders::_1,1./(double)nbOfNodesInCell));
6940 std::copy(dd,dd+3,matrix+4*2);
6941 INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6942 retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6947 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! Must be constitued by more than 3 nodes !";
6948 throw INTERP_KERNEL::Exception(oss.str());
6955 * This method expects as input a DataArrayDouble non nul instance 'da' that should be allocated. If not an exception is thrown.
6958 MEDCouplingUMesh *MEDCouplingUMesh::Build0DMeshFromCoords(DataArrayDouble *da)
6961 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build0DMeshFromCoords : instance of DataArrayDouble must be not null !");
6962 da->checkAllocated();
6963 std::string name(da->getName());
6964 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New(name,0));
6966 ret->setName("Mesh");
6968 mcIdType nbOfTuples(da->getNumberOfTuples());
6969 MCAuto<DataArrayIdType> c(DataArrayIdType::New()),cI(DataArrayIdType::New());
6970 c->alloc(2*nbOfTuples,1);
6971 cI->alloc(nbOfTuples+1,1);
6972 mcIdType *cp(c->getPointer()),*cip(cI->getPointer());
6974 for(mcIdType i=0;i<nbOfTuples;i++)
6976 *cp++=INTERP_KERNEL::NORM_POINT1;
6980 ret->setConnectivity(c,cI,true);
6984 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::Build1DMeshFromCoords(DataArrayDouble *da)
6987 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build01MeshFromCoords : instance of DataArrayDouble must be not null !");
6988 da->checkAllocated();
6989 std::string name(da->getName());
6990 MCAuto<MEDCouplingUMesh> ret;
6992 MCAuto<MEDCouplingCMesh> tmp(MEDCouplingCMesh::New());
6993 MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
6994 arr->alloc(da->getNumberOfTuples());
6995 tmp->setCoordsAt(0,arr);
6996 ret=tmp->buildUnstructured();
7000 ret->setName("Mesh");
7007 * Creates a new MEDCouplingUMesh by concatenating two given meshes of the same dimension.
7008 * Cells and nodes of
7009 * the first mesh precede cells and nodes of the second mesh within the result mesh.
7010 * \param [in] mesh1 - the first mesh.
7011 * \param [in] mesh2 - the second mesh.
7012 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7013 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7014 * is no more needed.
7015 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
7016 * \throw If the coordinates array is not set in none of the meshes.
7017 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
7018 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
7020 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
7022 std::vector<const MEDCouplingUMesh *> tmp(2);
7023 tmp[0]=const_cast<MEDCouplingUMesh *>(mesh1); tmp[1]=const_cast<MEDCouplingUMesh *>(mesh2);
7024 return MergeUMeshes(tmp);
7028 * Creates a new MEDCouplingUMesh by concatenating all given meshes of the same dimension.
7029 * Cells and nodes of
7030 * the *i*-th mesh precede cells and nodes of the (*i*+1)-th mesh within the result mesh.
7031 * \param [in] a - a vector of meshes (MEDCouplingUMesh) to concatenate.
7032 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7033 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7034 * is no more needed.
7035 * \throw If \a a.size() == 0.
7036 * \throw If \a a[ *i* ] == NULL.
7037 * \throw If the coordinates array is not set in none of the meshes.
7038 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
7039 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
7041 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const std::vector<const MEDCouplingUMesh *>& a)
7043 std::size_t sz=a.size();
7045 return MergeUMeshesLL(a);
7046 for(std::size_t ii=0;ii<sz;ii++)
7049 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshes : item #" << ii << " in input array of size "<< sz << " is empty !";
7050 throw INTERP_KERNEL::Exception(oss.str());
7052 std::vector< MCAuto<MEDCouplingUMesh> > bb(sz);
7053 std::vector< const MEDCouplingUMesh * > aa(sz);
7055 for(std::size_t i=0;i<sz && spaceDim==-3;i++)
7057 const MEDCouplingUMesh *cur=a[i];
7058 const DataArrayDouble *coo=cur->getCoords();
7060 spaceDim=int(coo->getNumberOfComponents());
7063 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : no spaceDim specified ! unable to perform merge !");
7064 for(std::size_t i=0;i<sz;i++)
7066 bb[i]=a[i]->buildSetInstanceFromThis(spaceDim);
7069 return MergeUMeshesLL(aa);
7073 * Creates a new MEDCouplingUMesh by concatenating cells of two given meshes of same
7074 * dimension and sharing the node coordinates array.
7075 * All cells of the first mesh precede all cells of the second mesh
7076 * within the result mesh.
7077 * \param [in] mesh1 - the first mesh.
7078 * \param [in] mesh2 - the second mesh.
7079 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7080 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7081 * is no more needed.
7082 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
7083 * \throw If the meshes do not share the node coordinates array.
7084 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
7085 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
7087 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
7089 std::vector<const MEDCouplingUMesh *> tmp(2);
7090 tmp[0]=mesh1; tmp[1]=mesh2;
7091 return MergeUMeshesOnSameCoords(tmp);
7095 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
7096 * dimension and sharing the node coordinates array.
7097 * All cells of the *i*-th mesh precede all cells of the
7098 * (*i*+1)-th mesh within the result mesh.
7099 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
7100 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7101 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7102 * is no more needed.
7103 * \throw If \a a.size() == 0.
7104 * \throw If \a a[ *i* ] == NULL.
7105 * \throw If the meshes do not share the node coordinates array.
7106 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
7107 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
7109 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes)
7112 throw INTERP_KERNEL::Exception("meshes input parameter is expected to be non empty.");
7113 for(std::size_t ii=0;ii<meshes.size();ii++)
7116 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshesOnSameCoords : item #" << ii << " in input array of size "<< meshes.size() << " is empty !";
7117 throw INTERP_KERNEL::Exception(oss.str());
7119 const DataArrayDouble *coords=meshes.front()->getCoords();
7120 int meshDim=meshes.front()->getMeshDimension();
7121 std::vector<const MEDCouplingUMesh *>::const_iterator iter=meshes.begin();
7122 mcIdType meshLgth=0;
7123 mcIdType meshIndexLgth=0;
7124 for(;iter!=meshes.end();iter++)
7126 if(coords!=(*iter)->getCoords())
7127 throw INTERP_KERNEL::Exception("meshes does not share the same coords ! Try using tryToShareSameCoords method !");
7128 if(meshDim!=(*iter)->getMeshDimension())
7129 throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, FuseUMeshesOnSameCoords impossible !");
7130 meshLgth+=(*iter)->getNodalConnectivityArrayLen();
7131 meshIndexLgth+=(*iter)->getNumberOfCells();
7133 MCAuto<DataArrayIdType> nodal=DataArrayIdType::New();
7134 nodal->alloc(meshLgth,1);
7135 mcIdType *nodalPtr=nodal->getPointer();
7136 MCAuto<DataArrayIdType> nodalIndex=DataArrayIdType::New();
7137 nodalIndex->alloc(meshIndexLgth+1,1);
7138 mcIdType *nodalIndexPtr=nodalIndex->getPointer();
7140 for(iter=meshes.begin();iter!=meshes.end();iter++)
7142 const mcIdType *nod=(*iter)->getNodalConnectivity()->begin();
7143 const mcIdType *index=(*iter)->getNodalConnectivityIndex()->begin();
7144 mcIdType nbOfCells=(*iter)->getNumberOfCells();
7145 mcIdType meshLgth2=(*iter)->getNodalConnectivityArrayLen();
7146 nodalPtr=std::copy(nod,nod+meshLgth2,nodalPtr);
7147 if(iter!=meshes.begin())
7148 nodalIndexPtr=std::transform(index+1,index+nbOfCells+1,nodalIndexPtr,std::bind(std::plus<mcIdType>(),std::placeholders::_1,offset));
7150 nodalIndexPtr=std::copy(index,index+nbOfCells+1,nodalIndexPtr);
7153 MEDCouplingUMesh *ret=MEDCouplingUMesh::New();
7154 ret->setName("merge");
7155 ret->setMeshDimension(meshDim);
7156 ret->setConnectivity(nodal,nodalIndex,true);
7157 ret->setCoords(coords);
7162 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
7163 * dimension and sharing the node coordinates array. Cells of the *i*-th mesh precede
7164 * cells of the (*i*+1)-th mesh within the result mesh. Duplicates of cells are
7165 * removed from \a this mesh and arrays mapping between new and old cell ids in "Old to
7166 * New" mode are returned for each input mesh.
7167 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
7168 * \param [in] compType - specifies a cell comparison technique. For meaning of its
7169 * valid values [0,1,2], see zipConnectivityTraducer().
7170 * \param [in,out] corr - an array of DataArrayIdType, of the same size as \a
7171 * meshes. The *i*-th array describes cell ids mapping for \a meshes[ *i* ]
7172 * mesh. The caller is to delete each of the arrays using decrRef() as it is
7174 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7175 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7176 * is no more needed.
7177 * \throw If \a meshes.size() == 0.
7178 * \throw If \a meshes[ *i* ] == NULL.
7179 * \throw If the meshes do not share the node coordinates array.
7180 * \throw If \a meshes[ *i* ]->getMeshDimension() < 0.
7181 * \throw If the \a meshes are of different dimension (getMeshDimension()).
7182 * \throw If the nodal connectivity of cells of any of \a meshes is not defined.
7183 * \throw If the nodal connectivity any of \a meshes includes an invalid id.
7185 MEDCouplingUMesh *MEDCouplingUMesh::FuseUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes, int compType, std::vector<DataArrayIdType *>& corr)
7187 //All checks are delegated to MergeUMeshesOnSameCoords
7188 MCAuto<MEDCouplingUMesh> ret=MergeUMeshesOnSameCoords(meshes);
7189 MCAuto<DataArrayIdType> o2n=ret->zipConnectivityTraducer(compType);
7190 corr.resize(meshes.size());
7191 std::size_t nbOfMeshes=meshes.size();
7193 const mcIdType *o2nPtr=o2n->begin();
7194 for(std::size_t i=0;i<nbOfMeshes;i++)
7196 DataArrayIdType *tmp=DataArrayIdType::New();
7197 mcIdType curNbOfCells=meshes[i]->getNumberOfCells();
7198 tmp->alloc(curNbOfCells,1);
7199 std::copy(o2nPtr+offset,o2nPtr+offset+curNbOfCells,tmp->getPointer());
7200 offset+=curNbOfCells;
7201 tmp->setName(meshes[i]->getName());
7208 * Makes all given meshes share the nodal connectivity array. The common connectivity
7209 * array is created by concatenating the connectivity arrays of all given meshes. All
7210 * the given meshes must be of the same space dimension but dimension of cells **can
7211 * differ**. This method is particularly useful in MEDLoader context to build a \ref
7212 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
7213 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
7214 * \param [in,out] meshes - a vector of meshes to update.
7215 * \throw If any of \a meshes is NULL.
7216 * \throw If the coordinates array is not set in any of \a meshes.
7217 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
7218 * \throw If \a meshes are of different space dimension.
7220 void MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords(const std::vector<MEDCouplingUMesh *>& meshes)
7222 std::size_t sz=meshes.size();
7225 std::vector< const DataArrayDouble * > coords(meshes.size());
7226 std::vector< const DataArrayDouble * >::iterator it2=coords.begin();
7227 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++,it2++)
7231 (*it)->checkConnectivityFullyDefined();
7232 const DataArrayDouble *coo=(*it)->getCoords();
7237 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
7238 oss << " has no coordinate array defined !";
7239 throw INTERP_KERNEL::Exception(oss.str());
7244 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
7245 oss << " is null !";
7246 throw INTERP_KERNEL::Exception(oss.str());
7249 MCAuto<DataArrayDouble> res=DataArrayDouble::Aggregate(coords);
7250 std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();
7251 mcIdType offset=(*it)->getNumberOfNodes();
7252 (*it++)->setCoords(res);
7253 for(;it!=meshes.end();it++)
7255 mcIdType oldNumberOfNodes=(*it)->getNumberOfNodes();
7256 (*it)->setCoords(res);
7257 (*it)->shiftNodeNumbersInConn(offset);
7258 offset+=oldNumberOfNodes;
7263 * Merges nodes coincident with a given precision within all given meshes that share
7264 * the nodal connectivity array. The given meshes **can be of different** mesh
7265 * dimension. This method is particularly useful in MEDLoader context to build a \ref
7266 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
7267 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
7268 * \param [in,out] meshes - a vector of meshes to update.
7269 * \param [in] eps - the precision used to detect coincident nodes (infinite norm).
7270 * \throw If any of \a meshes is NULL.
7271 * \throw If the \a meshes do not share the same node coordinates array.
7272 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
7274 void MEDCouplingUMesh::MergeNodesOnUMeshesSharingSameCoords(const std::vector<MEDCouplingUMesh *>& meshes, double eps)
7278 std::set<const DataArrayDouble *> s;
7279 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
7282 s.insert((*it)->getCoords());
7285 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 !";
7286 throw INTERP_KERNEL::Exception(oss.str());
7291 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 !";
7292 throw INTERP_KERNEL::Exception(oss.str());
7294 const DataArrayDouble *coo=*(s.begin());
7298 DataArrayIdType *comm,*commI;
7299 coo->findCommonTuples(eps,-1,comm,commI);
7300 MCAuto<DataArrayIdType> tmp1(comm),tmp2(commI);
7301 mcIdType oldNbOfNodes=coo->getNumberOfTuples();
7302 mcIdType newNbOfNodes;
7303 MCAuto<DataArrayIdType> o2n=DataArrayIdType::ConvertIndexArrayToO2N(oldNbOfNodes,comm->begin(),commI->begin(),commI->end(),newNbOfNodes);
7304 if(oldNbOfNodes==newNbOfNodes)
7306 MCAuto<DataArrayDouble> newCoords=coo->renumberAndReduce(o2n->begin(),newNbOfNodes);
7307 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
7309 (*it)->renumberNodesInConn(o2n->begin());
7310 (*it)->setCoords(newCoords);
7316 * This static operates only for coords in 3D. The polygon is specified by its connectivity nodes in [ \a begin , \a end ).
7318 bool MEDCouplingUMesh::IsPolygonWellOriented(bool isQuadratic, const double *vec, const mcIdType *begin, const mcIdType *end, const double *coords)
7321 double v[3]={0.,0.,0.};
7322 std::size_t sz=std::distance(begin,end);
7326 // Algorithm: sum in v the cross products of (e1, e2) where e_i it the vector between (0,0,0) and point i
7327 // and e2 is linear point directly following e1 in the connectivity. All points are used.
7328 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];
7329 v[1]+=coords[3*begin[i]+2]*coords[3*begin[(i+1)%sz]]-coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+2];
7330 v[2]+=coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+1]-coords[3*begin[i]+1]*coords[3*begin[(i+1)%sz]];
7334 // Same algorithm as above but also using intermediate quadratic points.
7335 // (taking only linear points might lead to issues if the linearized version of the
7336 // polygon is not convex or self-intersecting ... see testCellOrientation4)
7337 std::size_t hsz = sz/2;
7338 for(std::size_t j=0;j<sz;j++)
7340 if (j%2) // current point i is quadratic, next point i+1 is standard
7343 ip1 = ((j-1)/2 + 1)%hsz; // ip1 means "i+1", i.e. next point
7345 else // current point i is standard, next point i+1 is quadratic
7350 v[0]+=coords[3*begin[i]+1]*coords[3*begin[ip1]+2]-coords[3*begin[i]+2]*coords[3*begin[ip1]+1];
7351 v[1]+=coords[3*begin[i]+2]*coords[3*begin[ip1]]-coords[3*begin[i]]*coords[3*begin[ip1]+2];
7352 v[2]+=coords[3*begin[i]]*coords[3*begin[ip1]+1]-coords[3*begin[i]+1]*coords[3*begin[ip1]];
7355 double ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
7360 * The polyhedron is specified by its connectivity nodes in [ \a begin , \a end ).
7362 bool MEDCouplingUMesh::IsPolyhedronWellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7364 std::vector<std::pair<mcIdType,mcIdType> > edges;
7365 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
7366 const mcIdType *bgFace=begin;
7367 for(std::size_t i=0;i<nbOfFaces;i++)
7369 const mcIdType *endFace=std::find(bgFace+1,end,-1);
7370 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
7371 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7373 std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7374 if(std::find(edges.begin(),edges.end(),p1)!=edges.end())
7376 edges.push_back(p1);
7380 return INTERP_KERNEL::calculateVolumeForPolyh2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,ToIdType(std::distance(begin,end)),coords)>-EPS_FOR_POLYH_ORIENTATION;
7384 * The 3D extruded static cell (PENTA6,HEXA8,HEXAGP12...) its connectivity nodes in [ \a begin , \a end ).
7386 bool MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7388 double vec0[3],vec1[3];
7389 std::size_t sz=std::distance(begin,end);
7391 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented : the length of nodal connectivity of extruded cell is not even !");
7392 mcIdType nbOfNodes=ToIdType(sz/2);
7393 INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,nbOfNodes,coords,vec0);
7394 const double *pt0=coords+3*begin[0];
7395 const double *pt1=coords+3*begin[nbOfNodes];
7396 vec1[0]=pt1[0]-pt0[0]; vec1[1]=pt1[1]-pt0[1]; vec1[2]=pt1[2]-pt0[2];
7397 return (vec0[0]*vec1[0]+vec0[1]*vec1[1]+vec0[2]*vec1[2])<0.;
7400 void MEDCouplingUMesh::CorrectExtrudedStaticCell(mcIdType *begin, mcIdType *end)
7402 std::size_t sz=std::distance(begin,end);
7403 INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz];
7404 std::size_t nbOfNodes(sz/2);
7405 std::copy(begin,end,(mcIdType *)tmp);
7406 for(std::size_t j=1;j<nbOfNodes;j++)
7408 begin[j]=tmp[nbOfNodes-j];
7409 begin[j+nbOfNodes]=tmp[nbOfNodes+nbOfNodes-j];
7413 bool MEDCouplingUMesh::IsTetra4WellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7415 std::size_t sz=std::distance(begin,end);
7417 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsTetra4WellOriented : Tetra4 cell with not 4 nodes ! Call checkConsistency !");
7418 double vec0[3],vec1[3];
7419 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[1],*pt2=coords+3*begin[2],*pt3=coords+3*begin[3];
7420 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];
7421 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;
7424 bool MEDCouplingUMesh::IsPyra5WellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7426 std::size_t sz=std::distance(begin,end);
7428 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsPyra5WellOriented : Pyra5 cell with not 5 nodes ! Call checkConsistency !");
7430 INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,4,coords,vec0);
7431 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[4];
7432 return (vec0[0]*(pt1[0]-pt0[0])+vec0[1]*(pt1[1]-pt0[1])+vec0[2]*(pt1[2]-pt0[2]))<0.;
7436 * 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 )
7437 * 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
7440 * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not.
7441 * \param [in] coords the coordinates with nb of components exactly equal to 3
7442 * \param [in] index begin of the nodal connectivity (geometric type included) of a single polyhedron cell
7443 * \param [out] res the result is put at the end of the vector without any alteration of the data.
7445 void MEDCouplingUMesh::SimplifyPolyhedronCell(double eps, const DataArrayDouble *coords, mcIdType index, DataArrayIdType *res, MEDCouplingUMesh *faces,
7446 DataArrayIdType *E_Fi, DataArrayIdType *E_F, DataArrayIdType *F_Ei, DataArrayIdType *F_E)
7448 mcIdType nbFaces = E_Fi->getIJ(index + 1, 0) - E_Fi->getIJ(index, 0);
7449 MCAuto<DataArrayDouble> v=DataArrayDouble::New(); v->alloc(nbFaces,3);
7450 double *vPtr=v->getPointer();
7451 MCAuto<DataArrayDouble> p=DataArrayDouble::New(); p->alloc(nbFaces,2);
7452 double *pPtr=p->getPointer();
7453 mcIdType *e_fi = E_Fi->getPointer(), *e_f = E_F->getPointer(), *f_ei = F_Ei->getPointer(), *f_e = F_E->getPointer();
7454 const mcIdType *f_idx = faces->getNodalConnectivityIndex()->getPointer(), *f_cnn = faces->getNodalConnectivity()->getPointer();
7455 for(mcIdType i=0;i<nbFaces;i++,vPtr+=3,pPtr++)
7457 mcIdType face = e_f[e_fi[index] + i];
7458 ComputeVecAndPtOfFace(eps, coords->begin(), f_cnn + f_idx[face] + 1, f_cnn + f_idx[face + 1], vPtr, pPtr);
7459 // to differentiate faces going to different cells:
7461 for (mcIdType j = f_ei[face]; j < f_ei[face + 1]; j++)
7462 *pPtr += FromIdType<double>(f_e[j]);
7464 pPtr=p->getPointer(); vPtr=v->getPointer();
7465 DataArrayIdType *comm1=0,*commI1=0;
7466 v->findCommonTuples(eps,-1,comm1,commI1);
7467 for (mcIdType i = 0; i < nbFaces; i++)
7468 if (comm1->findIdFirstEqual(i) < 0)
7470 comm1->pushBackSilent(i);
7471 commI1->pushBackSilent(comm1->getNumberOfTuples());
7473 MCAuto<DataArrayIdType> comm1Auto(comm1),commI1Auto(commI1);
7474 const mcIdType *comm1Ptr=comm1->begin();
7475 const mcIdType *commI1Ptr=commI1->begin();
7476 mcIdType nbOfGrps1=commI1Auto->getNumberOfTuples()-1;
7477 res->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYHED));
7479 for(mcIdType i=0;i<nbOfGrps1;i++)
7481 mcIdType vecId=comm1Ptr[commI1Ptr[i]];
7482 MCAuto<DataArrayDouble> tmpgrp2=p->selectByTupleId(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7483 DataArrayIdType *comm2=0,*commI2=0;
7484 tmpgrp2->findCommonTuples(eps,-1,comm2,commI2);
7485 for (mcIdType j = 0; j < commI1Ptr[i+1] - commI1Ptr[i]; j++)
7486 if (comm2->findIdFirstEqual(j) < 0)
7488 comm2->pushBackSilent(j);
7489 commI2->pushBackSilent(comm2->getNumberOfTuples());
7491 MCAuto<DataArrayIdType> comm2Auto(comm2),commI2Auto(commI2);
7492 const mcIdType *comm2Ptr=comm2->begin();
7493 const mcIdType *commI2Ptr=commI2->begin();
7494 mcIdType nbOfGrps2=commI2Auto->getNumberOfTuples()-1;
7495 for(mcIdType j=0;j<nbOfGrps2;j++)
7497 if(commI2Ptr[j+1] == commI2Ptr[j] + 1)
7499 mcIdType face = e_f[e_fi[index] + comm1Ptr[commI1Ptr[i] + comm2Ptr[commI2Ptr[j]]]]; //hmmm
7500 res->insertAtTheEnd(f_cnn + f_idx[face] + 1, f_cnn + f_idx[face + 1]);
7501 res->pushBackSilent(-1);
7505 mcIdType pointId=comm1Ptr[commI1Ptr[i]+comm2Ptr[commI2Ptr[j]]];
7506 MCAuto<DataArrayIdType> ids2=comm2->selectByTupleIdSafeSlice(commI2Ptr[j],commI2Ptr[j+1],1);
7507 ids2->transformWithIndArr(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7508 ids2->transformWithIndArr(e_f + e_fi[index], e_f + e_fi[index + 1]);
7509 MCAuto<MEDCouplingUMesh> mm3=static_cast<MEDCouplingUMesh *>(faces->buildPartOfMySelf(ids2->begin(),ids2->end(),true));
7510 MCAuto<DataArrayIdType> idsNodeTmp=mm3->zipCoordsTraducer();
7511 MCAuto<DataArrayIdType> idsNode=idsNodeTmp->invertArrayO2N2N2O(mm3->getNumberOfNodes());
7512 const mcIdType *idsNodePtr=idsNode->begin();
7513 double center[3]; center[0]=pPtr[2*pointId]*vPtr[3*vecId]; center[1]=pPtr[2*pointId]*vPtr[3*vecId+1]; center[2]=pPtr[2*pointId]*vPtr[3*vecId+2];
7514 double vec[3]; vec[0]=vPtr[3*vecId+1]; vec[1]=-vPtr[3*vecId]; vec[2]=0.;
7515 double norm=vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2];
7516 if(std::abs(norm)>eps)
7518 double angle=INTERP_KERNEL::EdgeArcCircle::SafeAsin(norm);
7519 mm3->rotate(center,vec,angle);
7521 mm3->changeSpaceDimension(2);
7522 MCAuto<MEDCouplingUMesh> mm4=mm3->buildSpreadZonesWithPoly();
7523 const mcIdType *conn4=mm4->getNodalConnectivity()->begin();
7524 const mcIdType *connI4=mm4->getNodalConnectivityIndex()->begin();
7525 mcIdType nbOfCells=mm4->getNumberOfCells();
7526 for(mcIdType k=0;k<nbOfCells;k++)
7529 for(const mcIdType *work=conn4+connI4[k]+1;work!=conn4+connI4[k+1];work++,l++)
7530 res->pushBackSilent(idsNodePtr[*work]);
7531 res->pushBackSilent(-1);
7536 res->popBackSilent();
7540 * 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
7541 * through origin. The plane is defined by its nodal connectivity [ \b begin, \b end ).
7543 * \param [in] eps below that value the dot product of 2 vectors is considered as colinears
7544 * \param [in] coords coordinates expected to have 3 components.
7545 * \param [in] begin start of the nodal connectivity of the face.
7546 * \param [in] end end of the nodal connectivity (excluded) of the face.
7547 * \param [out] v the normalized vector of size 3
7548 * \param [out] p the pos of plane
7550 void MEDCouplingUMesh::ComputeVecAndPtOfFace(double eps, const double *coords, const mcIdType *begin, const mcIdType *end, double *v, double *p)
7552 std::size_t nbPoints=std::distance(begin,end);
7554 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeVecAndPtOfFace : < of 3 points in face ! not able to find a plane on that face !");
7555 double vec[3]={0.,0.,0.};
7557 bool refFound=false;
7558 for(;j<nbPoints-1 && !refFound;j++)
7560 vec[0]=coords[3*begin[j+1]]-coords[3*begin[j]];
7561 vec[1]=coords[3*begin[j+1]+1]-coords[3*begin[j]+1];
7562 vec[2]=coords[3*begin[j+1]+2]-coords[3*begin[j]+2];
7563 double norm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
7567 vec[0]/=norm; vec[1]/=norm; vec[2]/=norm;
7570 for(std::size_t i=j;i<nbPoints-1;i++)
7573 curVec[0]=coords[3*begin[i+1]]-coords[3*begin[i]];
7574 curVec[1]=coords[3*begin[i+1]+1]-coords[3*begin[i]+1];
7575 curVec[2]=coords[3*begin[i+1]+2]-coords[3*begin[i]+2];
7576 double norm=sqrt(curVec[0]*curVec[0]+curVec[1]*curVec[1]+curVec[2]*curVec[2]);
7579 curVec[0]/=norm; curVec[1]/=norm; curVec[2]/=norm;
7580 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];
7581 norm=sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
7584 v[0]/=norm; v[1]/=norm; v[2]/=norm;
7585 *p=v[0]*coords[3*begin[i]]+v[1]*coords[3*begin[i]+1]+v[2]*coords[3*begin[i]+2];
7589 throw INTERP_KERNEL::Exception("Not able to find a normal vector of that 3D face !");
7593 * This method tries to obtain a well oriented polyhedron.
7594 * If the algorithm fails, an exception will be thrown.
7596 void MEDCouplingUMesh::TryToCorrectPolyhedronOrientation(mcIdType *begin, mcIdType *end, const double *coords)
7598 std::list< std::pair<mcIdType,mcIdType> > edgesOK,edgesFinished;
7599 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
7600 std::vector<bool> isPerm(nbOfFaces,false);//field on faces False: I don't know, True : oriented
7602 mcIdType *bgFace=begin,*endFace=std::find(begin+1,end,-1);
7603 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
7604 for(std::size_t l=0;l<nbOfEdgesInFace;l++) { std::pair<mcIdType,mcIdType> p1(bgFace[l],bgFace[(l+1)%nbOfEdgesInFace]); edgesOK.push_back(p1); }
7606 while(std::find(isPerm.begin(),isPerm.end(),false)!=isPerm.end())
7609 std::size_t smthChanged=0;
7610 for(std::size_t i=0;i<nbOfFaces;i++)
7612 endFace=std::find(bgFace+1,end,-1);
7613 nbOfEdgesInFace=std::distance(bgFace,endFace);
7617 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7619 std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7620 std::pair<mcIdType,mcIdType> p2(p1.second,p1.first);
7621 bool b1=std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end();
7622 bool b2=std::find(edgesOK.begin(),edgesOK.end(),p2)!=edgesOK.end();
7623 if(b1 || b2) { b=b2; isPerm[i]=true; smthChanged++; break; }
7628 std::reverse(bgFace+1,endFace);
7629 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7631 std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7632 std::pair<mcIdType,mcIdType> p2(p1.second,p1.first);
7633 if(std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end())
7634 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7635 if(std::find(edgesFinished.begin(),edgesFinished.end(),p1)!=edgesFinished.end() || std::find(edgesFinished.begin(),edgesFinished.end(),p2)!=edgesFinished.end())
7636 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7637 std::list< std::pair<mcIdType,mcIdType> >::iterator it=std::find(edgesOK.begin(),edgesOK.end(),p2);
7638 if(it!=edgesOK.end())
7641 edgesFinished.push_back(p1);
7644 edgesOK.push_back(p1);
7651 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired !"); }
7653 if(!edgesOK.empty())
7654 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired : Some edges are shared only once !"); }
7655 if(INTERP_KERNEL::calculateVolumeForPolyh2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,ToIdType(std::distance(begin,end)),coords)<-EPS_FOR_POLYH_ORIENTATION)
7656 {//not lucky ! The first face was not correctly oriented : reorient all faces...
7658 for(std::size_t i=0;i<nbOfFaces;i++)
7660 endFace=std::find(bgFace+1,end,-1);
7661 std::reverse(bgFace+1,endFace);
7669 * This method makes the assumption spacedimension == meshdimension == 2.
7670 * This method works only for linear cells.
7672 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYGON in pos#0)
7674 DataArrayIdType *MEDCouplingUMesh::buildUnionOf2DMesh() const
7676 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
7677 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : meshdimension, spacedimension must be equal to 2 !");
7678 MCAuto<MEDCouplingUMesh> skin(computeSkin());
7679 mcIdType oldNbOfNodes(skin->getNumberOfNodes());
7680 MCAuto<DataArrayIdType> o2n(skin->zipCoordsTraducer());
7681 mcIdType nbOfNodesExpected(skin->getNumberOfNodes());
7682 MCAuto<DataArrayIdType> n2o(o2n->invertArrayO2N2N2O(oldNbOfNodes));
7683 mcIdType nbCells=skin->getNumberOfCells();
7684 if(nbCells==nbOfNodesExpected)
7685 return buildUnionOf2DMeshLinear(skin,n2o);
7686 else if(2*nbCells==nbOfNodesExpected)
7687 return buildUnionOf2DMeshQuadratic(skin,n2o);
7689 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : the mesh 2D in input appears to be not in a single part of a 2D mesh !");
7693 * This method makes the assumption spacedimension == meshdimension == 3.
7694 * This method works only for linear cells.
7696 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYHED in pos#0)
7698 DataArrayIdType *MEDCouplingUMesh::buildUnionOf3DMesh() const
7700 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
7701 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf3DMesh : meshdimension, spacedimension must be equal to 2 !");
7702 MCAuto<MEDCouplingUMesh> m=computeSkin();
7703 const mcIdType *conn=m->getNodalConnectivity()->begin();
7704 const mcIdType *connI=m->getNodalConnectivityIndex()->begin();
7705 mcIdType nbOfCells=m->getNumberOfCells();
7706 MCAuto<DataArrayIdType> ret=DataArrayIdType::New(); ret->alloc(m->getNodalConnectivity()->getNumberOfTuples(),1);
7707 mcIdType *work=ret->getPointer(); *work++=INTERP_KERNEL::NORM_POLYHED;
7710 work=std::copy(conn+connI[0]+1,conn+connI[1],work);
7711 for(mcIdType i=1;i<nbOfCells;i++)
7714 work=std::copy(conn+connI[i]+1,conn+connI[i+1],work);
7720 * \brief Creates a graph of cell neighbors
7721 * \return MEDCouplingSkyLineArray * - an sky line array the user should delete.
7722 * In the sky line array, graph arcs are stored in terms of (index,value) notation.
7724 * - index: 0 3 5 6 6
7725 * - value: 1 2 3 2 3 3
7726 * means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7727 * Arcs are not doubled but reflexive (1,1) arcs are present for each cell
7729 MEDCouplingSkyLineArray* MEDCouplingUMesh::generateGraph() const
7731 checkConnectivityFullyDefined();
7733 int meshDim = this->getMeshDimension();
7734 MEDCoupling::DataArrayIdType* indexr=MEDCoupling::DataArrayIdType::New();
7735 MEDCoupling::DataArrayIdType* revConn=MEDCoupling::DataArrayIdType::New();
7736 this->getReverseNodalConnectivity(revConn,indexr);
7737 const mcIdType* indexr_ptr=indexr->begin();
7738 const mcIdType* revConn_ptr=revConn->begin();
7740 const MEDCoupling::DataArrayIdType* index;
7741 const MEDCoupling::DataArrayIdType* conn;
7742 conn=this->getNodalConnectivity(); // it includes a type as the 1st element!!!
7743 index=this->getNodalConnectivityIndex();
7744 mcIdType nbCells=this->getNumberOfCells();
7745 const mcIdType* index_ptr=index->begin();
7746 const mcIdType* conn_ptr=conn->begin();
7748 //creating graph arcs (cell to cell relations)
7749 //arcs are stored in terms of (index,value) notation
7752 // means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7753 // in present version arcs are not doubled but reflexive (1,1) arcs are present for each cell
7755 //warning here one node have less than or equal effective number of cell with it
7756 //but cell could have more than effective nodes
7757 //because other equals nodes in other domain (with other global inode)
7758 std::vector <mcIdType> cell2cell_index(nbCells+1,0);
7759 std::vector <mcIdType> cell2cell;
7760 cell2cell.reserve(3*nbCells);
7762 for (mcIdType icell=0; icell<nbCells;icell++)
7764 std::map<mcIdType,mcIdType > counter;
7765 for (mcIdType iconn=index_ptr[icell]+1; iconn<index_ptr[icell+1];iconn++)
7767 mcIdType inode=conn_ptr[iconn];
7768 for (mcIdType iconnr=indexr_ptr[inode]; iconnr<indexr_ptr[inode+1];iconnr++)
7770 mcIdType icell2=revConn_ptr[iconnr];
7771 std::map<mcIdType,mcIdType>::iterator iter=counter.find(icell2);
7772 if (iter!=counter.end()) (iter->second)++;
7773 else counter.insert(std::make_pair(icell2,1));
7776 for (std::map<mcIdType,mcIdType>::const_iterator iter=counter.begin();
7777 iter!=counter.end(); iter++)
7778 if (iter->second >= meshDim)
7780 cell2cell_index[icell+1]++;
7781 cell2cell.push_back(iter->first);
7786 cell2cell_index[0]=0;
7787 for (mcIdType icell=0; icell<nbCells;icell++)
7788 cell2cell_index[icell+1]=cell2cell_index[icell]+cell2cell_index[icell+1];
7790 //filling up index and value to create skylinearray structure
7791 MEDCouplingSkyLineArray * array(MEDCouplingSkyLineArray::New(cell2cell_index,cell2cell));
7796 void MEDCouplingUMesh::writeVTKLL(std::ostream& ofs, const std::string& cellData, const std::string& pointData, DataArrayByte *byteData) const
7798 mcIdType nbOfCells=getNumberOfCells();
7800 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::writeVTK : the unstructured mesh has no cells !");
7801 ofs << " <" << getVTKDataSetType() << ">\n";
7802 ofs << " <Piece NumberOfPoints=\"" << getNumberOfNodes() << "\" NumberOfCells=\"" << nbOfCells << "\">\n";
7803 ofs << " <PointData>\n" << pointData << std::endl;
7804 ofs << " </PointData>\n";
7805 ofs << " <CellData>\n" << cellData << std::endl;
7806 ofs << " </CellData>\n";
7807 ofs << " <Points>\n";
7808 if(getSpaceDimension()==3)
7809 _coords->writeVTK(ofs,8,"Points",byteData);
7812 MCAuto<DataArrayDouble> coo=_coords->changeNbOfComponents(3,0.);
7813 coo->writeVTK(ofs,8,"Points",byteData);
7815 ofs << " </Points>\n";
7816 ofs << " <Cells>\n";
7817 const mcIdType *cPtr=_nodal_connec->begin();
7818 const mcIdType *cIPtr=_nodal_connec_index->begin();
7819 MCAuto<DataArrayIdType> faceoffsets=DataArrayIdType::New(); faceoffsets->alloc(nbOfCells,1);
7820 MCAuto<DataArrayIdType> types=DataArrayIdType::New(); types->alloc(nbOfCells,1);
7821 MCAuto<DataArrayIdType> offsets=DataArrayIdType::New(); offsets->alloc(nbOfCells,1);
7822 MCAuto<DataArrayIdType> connectivity=DataArrayIdType::New(); connectivity->alloc(_nodal_connec->getNumberOfTuples()-nbOfCells,1);
7823 mcIdType *w1=faceoffsets->getPointer(),*w2=types->getPointer(),*w3=offsets->getPointer(),*w4=connectivity->getPointer();
7824 mcIdType szFaceOffsets=0,szConn=0;
7825 for(mcIdType i=0;i<nbOfCells;i++,w1++,w2++,w3++)
7828 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]!=INTERP_KERNEL::NORM_POLYHED)
7831 *w3=szConn+cIPtr[i+1]-cIPtr[i]-1; szConn+=cIPtr[i+1]-cIPtr[i]-1;
7832 w4=std::copy(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],w4);
7836 mcIdType deltaFaceOffset=cIPtr[i+1]-cIPtr[i]+1;
7837 *w1=szFaceOffsets+deltaFaceOffset; szFaceOffsets+=deltaFaceOffset;
7838 std::set<mcIdType> c(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1]); c.erase(-1);
7839 *w3=szConn+ToIdType(c.size()); szConn+=ToIdType(c.size());
7840 w4=std::copy(c.begin(),c.end(),w4);
7843 std::unique_ptr<mcIdType[]> medcoupling2vtkTypeTraducer_mcIdType(new mcIdType[MEDCOUPLING2VTKTYPETRADUCER_LGTH]);
7844 for(auto ii = 0; ii<MEDCOUPLING2VTKTYPETRADUCER_LGTH ; ++ii)
7845 medcoupling2vtkTypeTraducer_mcIdType[ii] = MEDCOUPLING2VTKTYPETRADUCER[ii]!=MEDCOUPLING2VTKTYPETRADUCER_NONE?MEDCOUPLING2VTKTYPETRADUCER[ii] : -1;
7846 types->transformWithIndArr(medcoupling2vtkTypeTraducer_mcIdType.get(),medcoupling2vtkTypeTraducer_mcIdType.get()+MEDCOUPLING2VTKTYPETRADUCER_LGTH);
7847 types->writeVTK(ofs,8,"UInt8","types",byteData);
7848 std::string vtkTypeName = Traits<mcIdType>::VTKReprStr;
7849 offsets->writeVTK(ofs,8,vtkTypeName,"offsets",byteData);
7850 if(szFaceOffsets!=0)
7851 {//presence of Polyhedra
7852 connectivity->reAlloc(szConn);
7853 faceoffsets->writeVTK(ofs,8,vtkTypeName,"faceoffsets",byteData);
7854 MCAuto<DataArrayIdType> faces=DataArrayIdType::New(); faces->alloc(szFaceOffsets,1);
7855 w1=faces->getPointer();
7856 for(mcIdType i=0;i<nbOfCells;i++)
7857 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]==INTERP_KERNEL::NORM_POLYHED)
7859 mcIdType nbFaces=ToIdType(std::count(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],-1))+1;
7861 const mcIdType *w6=cPtr+cIPtr[i]+1,*w5=0;
7862 for(mcIdType j=0;j<nbFaces;j++)
7864 w5=std::find(w6,cPtr+cIPtr[i+1],-1);
7865 *w1++=ToIdType(std::distance(w6,w5));
7866 w1=std::copy(w6,w5,w1);
7870 faces->writeVTK(ofs,8,vtkTypeName,"faces",byteData);
7872 connectivity->writeVTK(ofs,8,vtkTypeName,"connectivity",byteData);
7873 ofs << " </Cells>\n";
7874 ofs << " </Piece>\n";
7875 ofs << " </" << getVTKDataSetType() << ">\n";
7878 void MEDCouplingUMesh::reprQuickOverview(std::ostream& stream) const
7880 stream << "MEDCouplingUMesh C++ instance at " << this << ". Name : \"" << getName() << "\".";
7882 { stream << " Not set !"; return ; }
7883 stream << " Mesh dimension : " << _mesh_dim << ".";
7887 { stream << " No coordinates set !"; return ; }
7888 if(!_coords->isAllocated())
7889 { stream << " Coordinates set but not allocated !"; return ; }
7890 stream << " Space dimension : " << _coords->getNumberOfComponents() << "." << std::endl;
7891 stream << "Number of nodes : " << _coords->getNumberOfTuples() << ".";
7892 if(!_nodal_connec_index)
7893 { stream << std::endl << "Nodal connectivity NOT set !"; return ; }
7894 if(!_nodal_connec_index->isAllocated())
7895 { stream << std::endl << "Nodal connectivity set but not allocated !"; return ; }
7896 mcIdType lgth=_nodal_connec_index->getNumberOfTuples();
7897 std::size_t cpt=_nodal_connec_index->getNumberOfComponents();
7898 if(cpt!=1 || lgth<1)
7900 stream << std::endl << "Number of cells : " << lgth-1 << ".";
7903 std::string MEDCouplingUMesh::getVTKDataSetType() const
7905 return std::string("UnstructuredGrid");
7908 std::string MEDCouplingUMesh::getVTKFileExtension() const
7910 return std::string("vtu");
7916 * Provides a renumbering of the cells of this (which has to be a piecewise connected 1D line), so that
7917 * the segments of the line are indexed in consecutive order (i.e. cells \a i and \a i+1 are neighbors).
7918 * This doesn't modify the mesh. This method only works using nodal connectivity consideration. Coordinates of nodes are ignored here.
7919 * The caller is to deal with the resulting DataArrayIdType.
7920 * \throw If the coordinate array is not set.
7921 * \throw If the nodal connectivity of the cells is not defined.
7922 * \throw If m1 is not a mesh of dimension 2, or m1 is not a mesh of dimension 1
7923 * \throw If m2 is not a (piecewise) line (i.e. if a point has more than 2 adjacent segments)
7925 * \sa DataArrayIdType::sortEachPairToMakeALinkedList
7927 DataArrayIdType *MEDCouplingUMesh::orderConsecutiveCells1D() const
7929 checkFullyDefined();
7930 if(getMeshDimension()!=1)
7931 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D works on unstructured mesh with meshdim = 1 !");
7933 // Check that this is a line (and not a more complex 1D mesh) - each point is used at most by 2 segments:
7934 MCAuto<DataArrayIdType> _d(DataArrayIdType::New()),_dI(DataArrayIdType::New());
7935 MCAuto<DataArrayIdType> _rD(DataArrayIdType::New()),_rDI(DataArrayIdType::New());
7936 MCAuto<MEDCouplingUMesh> m_points(buildDescendingConnectivity(_d, _dI, _rD, _rDI));
7937 const mcIdType *d(_d->begin()), *dI(_dI->begin());
7938 const mcIdType *rD(_rD->begin()), *rDI(_rDI->begin());
7939 MCAuto<DataArrayIdType> _dsi(_rDI->deltaShiftIndex());
7940 const mcIdType * dsi(_dsi->begin());
7941 MCAuto<DataArrayIdType> dsii = _dsi->findIdsNotInRange(0,3);
7943 if (dsii->getNumberOfTuples())
7944 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D only work with a mesh being a (piecewise) connected line!");
7946 mcIdType nc=getNumberOfCells();
7947 MCAuto<DataArrayIdType> result(DataArrayIdType::New());
7948 result->alloc(nc,1);
7950 // set of edges not used so far
7951 std::set<mcIdType> edgeSet;
7952 for (mcIdType i=0; i<nc; edgeSet.insert(i), i++);
7954 mcIdType startSeg=0;
7956 // while we have points with only one neighbor segments
7959 std::list<mcIdType> linePiece;
7960 // fills a list of consecutive segment linked to startSeg. This can go forward or backward.
7961 for (int direction=0;direction<2;direction++) // direction=0 --> forward, direction=1 --> backward
7963 // Fill the list forward (resp. backward) from the start segment:
7964 mcIdType activeSeg = startSeg;
7965 mcIdType prevPointId = -20;
7967 while (!edgeSet.empty())
7969 if (!(direction == 1 && prevPointId==-20)) // prevent adding twice startSeg
7972 linePiece.push_back(activeSeg);
7974 linePiece.push_front(activeSeg);
7975 edgeSet.erase(activeSeg);
7978 mcIdType ptId1 = d[dI[activeSeg]], ptId2 = d[dI[activeSeg]+1];
7979 ptId = direction ? (ptId1 == prevPointId ? ptId2 : ptId1) : (ptId2 == prevPointId ? ptId1 : ptId2);
7980 if (dsi[ptId] == 1) // hitting the end of the line
7984 mcIdType seg1 = rD[rDI[ptId]], seg2 = rD[rDI[ptId]+1];
7985 activeSeg = (seg1 == activeSeg) ? seg2 : seg1;
7987 //for piecewise meshes made up of closed parts
7988 bool segmentAlreadyTreated = (std::find(linePiece.begin(), linePiece.end(), activeSeg) != linePiece.end());
7989 if(segmentAlreadyTreated)
7993 // Done, save final piece into DA:
7994 std::copy(linePiece.begin(), linePiece.end(), result->getPointer()+newIdx);
7995 newIdx += ToIdType(linePiece.size());
7997 // identify next valid start segment (one which is not consumed)
7998 if(!edgeSet.empty())
7999 startSeg = *(edgeSet.begin());
8002 while (!edgeSet.empty());
8003 return result.retn();
8007 * This method split some of edges of 2D cells in \a this. The edges to be split are specified in \a subNodesInSeg
8008 * and in \a subNodesInSegI using \ref numbering-indirect storage mode.
8009 * To do the work this method can optionally needs information about middle of subedges for quadratic cases if
8010 * a minimal creation of new nodes is wanted.
8011 * So this method try to reduce at most the number of new nodes. The only case that can lead this method to add
8012 * nodes if a SEG3 is split without information of middle.
8013 * \b WARNING : is returned value is different from 0 a call to MEDCouplingUMesh::mergeNodes is necessary to
8014 * avoid to have a non conform mesh.
8016 * \return mcIdType - the number of new nodes created (in most of cases 0).
8018 * \throw If \a this is not coherent.
8019 * \throw If \a this has not spaceDim equal to 2.
8020 * \throw If \a this has not meshDim equal to 2.
8021 * \throw If some subcells needed to be split are orphan.
8022 * \sa MEDCouplingUMesh::conformize2D
8024 mcIdType MEDCouplingUMesh::split2DCells(const DataArrayIdType *desc, const DataArrayIdType *descI, const DataArrayIdType *subNodesInSeg, const DataArrayIdType *subNodesInSegI, const DataArrayIdType *midOpt, const DataArrayIdType *midOptI)
8026 if(!desc || !descI || !subNodesInSeg || !subNodesInSegI)
8027 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : the 4 first arrays must be not null !");
8028 desc->checkAllocated(); descI->checkAllocated(); subNodesInSeg->checkAllocated(); subNodesInSegI->checkAllocated();
8029 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
8030 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : This method only works for meshes with spaceDim=2 and meshDim=2 !");
8031 if(midOpt==0 && midOptI==0)
8033 split2DCellsLinear(desc,descI,subNodesInSeg,subNodesInSegI);
8036 else if(midOpt!=0 && midOptI!=0)
8037 return split2DCellsQuadratic(desc,descI,subNodesInSeg,subNodesInSegI,midOpt,midOptI);
8039 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : middle parameters must be set to null for all or not null for all.");
8043 * 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
8044 * 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
8045 * the geometric cell type set to INTERP_KERNEL::NORM_POLYGON.
8046 * 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
8047 * 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.
8049 * \return false if the input connectivity represents already the convex hull, true if the input cell needs to be reordered.
8051 bool MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis(const double *coords, const mcIdType *nodalConnBg, const mcIdType *nodalConnEnd, DataArrayIdType *nodalConnecOut)
8053 std::size_t sz=std::distance(nodalConnBg,nodalConnEnd);
8056 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)*nodalConnBg);
8057 if(cm.getDimension()==2)
8059 const mcIdType *node=nodalConnBg+1;
8060 mcIdType startNode=*node++;
8061 double refX=coords[2*startNode];
8062 for(;node!=nodalConnEnd;node++)
8064 if(coords[2*(*node)]<refX)
8067 refX=coords[2*startNode];
8070 std::vector<mcIdType> tmpOut; tmpOut.reserve(sz); tmpOut.push_back(startNode);
8074 double angle0=-M_PI/2;
8076 mcIdType nextNode=-1;
8077 mcIdType prevNode=-1;
8079 double angleNext=0.;
8080 while(nextNode!=startNode)
8084 for(node=nodalConnBg+1;node!=nodalConnEnd;node++)
8086 if(*node!=tmpOut.back() && *node!=prevNode)
8088 tmp2[0]=coords[2*(*node)]-coords[2*tmpOut.back()]; tmp2[1]=coords[2*(*node)+1]-coords[2*tmpOut.back()+1];
8089 double angleM=INTERP_KERNEL::EdgeArcCircle::GetAbsoluteAngle(tmp2,tmp1);
8094 res=angle0-angleM+2.*M_PI;
8103 if(nextNode!=startNode)
8105 angle0=angleNext-M_PI;
8108 prevNode=tmpOut.back();
8109 tmpOut.push_back(nextNode);
8112 std::vector<mcIdType> tmp3(2*(sz-1));
8113 std::vector<mcIdType>::iterator it=std::copy(nodalConnBg+1,nodalConnEnd,tmp3.begin());
8114 std::copy(nodalConnBg+1,nodalConnEnd,it);
8115 if(std::search(tmp3.begin(),tmp3.end(),tmpOut.begin(),tmpOut.end())!=tmp3.end())
8117 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
8120 if(std::search(tmp3.rbegin(),tmp3.rend(),tmpOut.begin(),tmpOut.end())!=tmp3.rend())
8122 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
8127 nodalConnecOut->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYGON));
8128 nodalConnecOut->insertAtTheEnd(tmpOut.begin(),tmpOut.end());
8133 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
8136 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
8140 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
8141 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
8142 * This method start from id 0 that will be contained in output DataArrayIdType. It searches then all neighbors of id0 looking at arrIn[arrIndxIn[0]:arrIndxIn[0+1]].
8143 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
8144 * A negative value in \b arrIn means that it is ignored.
8145 * 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.
8147 * \param [in] arrIn arr origin array from which the extraction will be done.
8148 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
8149 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
8150 * \sa MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed, MEDCouplingUMesh::partitionBySpreadZone
8152 DataArrayIdType *MEDCouplingUMesh::ComputeSpreadZoneGradually(const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn)
8154 mcIdType seed=0,nbOfDepthPeelingPerformed=0;
8155 return ComputeSpreadZoneGraduallyFromSeed(&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfDepthPeelingPerformed);
8159 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
8160 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
8161 * This method start from id 0 that will be contained in output DataArrayIdType. It searches then all neighbors of id0 regarding arrIn[arrIndxIn[0]:arrIndxIn[0+1]].
8162 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
8163 * A negative value in \b arrIn means that it is ignored.
8164 * 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.
8165 * \param [in] seedBg the begin pointer (included) of an array containing the seed of the search zone
8166 * \param [in] seedEnd the end pointer (not included) of an array containing the seed of the search zone
8167 * \param [in] arrIn arr origin array from which the extraction will be done.
8168 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
8169 * \param [in] nbOfDepthPeeling the max number of peels requested in search. By default -1, that is to say, no limit.
8170 * \param [out] nbOfDepthPeelingPerformed the number of peels effectively performed. May be different from \a nbOfDepthPeeling
8171 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
8172 * \sa MEDCouplingUMesh::partitionBySpreadZone
8174 DataArrayIdType *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(const mcIdType *seedBg, const mcIdType *seedEnd, const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn, mcIdType nbOfDepthPeeling, mcIdType& nbOfDepthPeelingPerformed)
8176 nbOfDepthPeelingPerformed=0;
8178 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed : arrIndxIn input pointer is NULL !");
8179 mcIdType nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
8182 DataArrayIdType *ret=DataArrayIdType::New(); ret->alloc(0,1);
8186 std::vector<bool> fetched(nbOfTuples,false);
8187 return ComputeSpreadZoneGraduallyFromSeedAlg(fetched,seedBg,seedEnd,arrIn,arrIndxIn,nbOfDepthPeeling,nbOfDepthPeelingPerformed);
8193 * \b this is expected to be a mesh fully defined whose spaceDim==meshDim.
8194 * It returns a new allocated mesh having the same mesh dimension and lying on same coordinates.
8195 * The returned mesh contains as poly cells as number of contiguous zone (regarding connectivity).
8196 * A spread contiguous zone is built using poly cells (polyhedra in 3D, polygons in 2D and polyline in 1D).
8197 * The sum of measure field of returned mesh is equal to the sum of measure field of this.
8199 * \return a newly allocated mesh lying on the same coords than \b this with same meshdimension than \b this.
8201 MEDCouplingUMesh *MEDCouplingUMesh::buildSpreadZonesWithPoly() const
8203 checkFullyDefined();
8204 int mdim=getMeshDimension();
8205 int spaceDim=getSpaceDimension();
8207 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension and spacedimension do not match !");
8208 std::vector<DataArrayIdType *> partition=partitionBySpreadZone();
8209 std::vector< MCAuto<DataArrayIdType> > partitionAuto; partitionAuto.reserve(partition.size());
8210 std::copy(partition.begin(),partition.end(),std::back_insert_iterator<std::vector< MCAuto<DataArrayIdType> > >(partitionAuto));
8211 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
8212 ret->setCoords(getCoords());
8213 ret->allocateCells(ToIdType(partition.size()));
8215 for(std::vector<DataArrayIdType *>::const_iterator it=partition.begin();it!=partition.end();it++)
8217 MCAuto<MEDCouplingUMesh> tmp=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf((*it)->begin(),(*it)->end(),true));
8218 MCAuto<DataArrayIdType> cell;
8222 cell=tmp->buildUnionOf2DMesh();
8225 cell=tmp->buildUnionOf3DMesh();
8228 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension supported are [2,3] ! Not implemented yet for others !");
8231 ret->insertNextCell((INTERP_KERNEL::NormalizedCellType)cell->getIJSafe(0,0),cell->getNumberOfTuples()-1,cell->begin()+1);
8234 ret->finishInsertingCells();
8239 * This method partitions \b this into contiguous zone.
8240 * This method only needs a well defined connectivity. Coordinates are not considered here.
8241 * This method returns a vector of \b newly allocated arrays that the caller has to deal with.
8243 std::vector<DataArrayIdType *> MEDCouplingUMesh::partitionBySpreadZone() const
8245 DataArrayIdType *neigh=0,*neighI=0;
8246 computeNeighborsOfCells(neigh,neighI);
8247 MCAuto<DataArrayIdType> neighAuto(neigh),neighIAuto(neighI);
8248 return PartitionBySpreadZone(neighAuto,neighIAuto);
8251 std::vector<DataArrayIdType *> MEDCouplingUMesh::PartitionBySpreadZone(const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn)
8253 if(!arrIn || !arrIndxIn)
8254 throw INTERP_KERNEL::Exception("PartitionBySpreadZone : null input pointers !");
8255 arrIn->checkAllocated(); arrIndxIn->checkAllocated();
8256 mcIdType nbOfTuples(arrIndxIn->getNumberOfTuples());
8257 if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1 || nbOfTuples<1)
8258 throw INTERP_KERNEL::Exception("PartitionBySpreadZone : invalid arrays in input !");
8259 mcIdType nbOfCellsCur(nbOfTuples-1);
8260 std::vector<DataArrayIdType *> ret;
8263 std::vector<bool> fetchedCells(nbOfCellsCur,false);
8264 std::vector< MCAuto<DataArrayIdType> > ret2;
8266 while(seed<nbOfCellsCur)
8268 mcIdType nbOfPeelPerformed=0;
8269 ret2.push_back(ComputeSpreadZoneGraduallyFromSeedAlg(fetchedCells,&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfPeelPerformed));
8270 seed=ToIdType(std::distance(fetchedCells.begin(),std::find(fetchedCells.begin()+seed,fetchedCells.end(),false)));
8272 for(std::vector< MCAuto<DataArrayIdType> >::iterator it=ret2.begin();it!=ret2.end();it++)
8273 ret.push_back((*it).retn());
8278 * This method returns given a distribution of cell type (returned for example by MEDCouplingUMesh::getDistributionOfTypes method and customized after) a
8279 * newly allocated DataArrayIdType instance with 2 components ready to be interpreted as input of DataArrayIdType::findRangeIdForEachTuple method.
8281 * \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.
8282 * \return a newly allocated DataArrayIdType to be managed by the caller.
8283 * \throw In case of \a code has not the right format (typically of size 3*n)
8285 DataArrayIdType *MEDCouplingUMesh::ComputeRangesFromTypeDistribution(const std::vector<mcIdType>& code)
8287 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
8288 std::size_t nb=code.size()/3;
8289 if(code.size()%3!=0)
8290 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeRangesFromTypeDistribution : invalid input code !");
8292 mcIdType *retPtr=ret->getPointer();
8293 for(std::size_t i=0;i<nb;i++,retPtr+=2)
8295 retPtr[0]=code[3*i+2];
8296 retPtr[1]=code[3*i+2]+code[3*i+1];
8302 * This method expects that \a this a 3D mesh (spaceDim=3 and meshDim=3) with all coordinates and connectivities set.
8303 * All cells in \a this are expected to be linear 3D cells.
8304 * This method will split **all** 3D cells in \a this into INTERP_KERNEL::NORM_TETRA4 cells and put them in the returned mesh.
8305 * It leads to an increase to number of cells.
8306 * This method contrary to MEDCouplingUMesh::simplexize can append coordinates in \a this to perform its work.
8307 * The \a nbOfAdditionalPoints returned value informs about it. If > 0, the coordinates array in returned mesh will have \a nbOfAdditionalPoints
8308 * more tuples (nodes) than in \a this. Anyway, all the nodes in \a this (with the same order) will be in the returned mesh.
8310 * \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.
8311 * For all other cells, the splitting policy will be ignored. See INTERP_KERNEL::SplittingPolicy for the images.
8312 * \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.
8313 * \param [out] n2oCells - A new instance of DataArrayIdType holding, for each new cell,
8314 * an id of old cell producing it. The caller is to delete this array using
8315 * decrRef() as it is no more needed.
8316 * \return MEDCoupling1SGTUMesh * - the mesh containing only INTERP_KERNEL::NORM_TETRA4 cells.
8318 * \warning This method operates on each cells in this independently ! So it can leads to non conform mesh in returned value ! If you expect to have a conform mesh in output
8319 * the policy PLANAR_FACE_6 should be used on a mesh sorted with MEDCoupling1SGTUMesh::sortHexa8EachOther.
8321 * \throw If \a this is not a 3D mesh (spaceDim==3 and meshDim==3).
8322 * \throw If \a this is not fully constituted with linear 3D cells.
8323 * \sa MEDCouplingUMesh::simplexize, MEDCoupling1SGTUMesh::sortHexa8EachOther
8325 MEDCoupling1SGTUMesh *MEDCouplingUMesh::tetrahedrize(int policy, DataArrayIdType *& n2oCells, mcIdType& nbOfAdditionalPoints) const
8327 INTERP_KERNEL::SplittingPolicy pol((INTERP_KERNEL::SplittingPolicy)policy);
8328 checkConnectivityFullyDefined();
8329 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
8330 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tetrahedrize : only available for mesh with meshdim == 3 and spacedim == 3 !");
8331 mcIdType nbOfCells=getNumberOfCells();
8332 mcIdType nbNodes(getNumberOfNodes());
8333 MCAuto<MEDCoupling1SGTUMesh> ret0(MEDCoupling1SGTUMesh::New(getName(),INTERP_KERNEL::NORM_TETRA4));
8334 MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(nbOfCells,1);
8335 mcIdType *retPt(ret->getPointer());
8336 MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()); newConn->alloc(0,1);
8337 MCAuto<DataArrayDouble> addPts(DataArrayDouble::New()); addPts->alloc(0,1);
8338 const mcIdType *oldc(_nodal_connec->begin());
8339 const mcIdType *oldci(_nodal_connec_index->begin());
8340 const double *coords(_coords->begin());
8341 for(mcIdType i=0;i<nbOfCells;i++,oldci++,retPt++)
8343 std::vector<mcIdType> a; std::vector<double> b;
8344 INTERP_KERNEL::SplitIntoTetras(pol,(INTERP_KERNEL::NormalizedCellType)oldc[oldci[0]],oldc+oldci[0]+1,oldc+oldci[1],coords,a,b);
8345 std::size_t nbOfTet(a.size()/4); *retPt=ToIdType(nbOfTet);
8346 const mcIdType *aa(&a[0]);
8349 for(std::vector<mcIdType>::iterator it=a.begin();it!=a.end();it++)
8351 *it=(-(*(it))-1+nbNodes);
8352 addPts->insertAtTheEnd(b.begin(),b.end());
8353 nbNodes+=ToIdType(b.size()/3);
8355 for(std::size_t j=0;j<nbOfTet;j++,aa+=4)
8356 newConn->insertAtTheEnd(aa,aa+4);
8358 if(!addPts->empty())
8360 addPts->rearrange(3);
8361 nbOfAdditionalPoints=addPts->getNumberOfTuples();
8362 addPts=DataArrayDouble::Aggregate(getCoords(),addPts);
8363 ret0->setCoords(addPts);
8367 nbOfAdditionalPoints=0;
8368 ret0->setCoords(getCoords());
8370 ret0->setNodalConnectivity(newConn);
8372 ret->computeOffsetsFull();
8373 n2oCells=ret->buildExplicitArrOfSliceOnScaledArr(0,nbOfCells,1);
8377 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),
8378 _own_cell(true),_cell_id(-1),_nb_cell(0)
8383 _nb_cell=mesh->getNumberOfCells();
8387 MEDCouplingUMeshCellIterator::~MEDCouplingUMeshCellIterator()
8395 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh, MEDCouplingUMeshCell *itc, mcIdType bg, mcIdType end):_mesh(mesh),_cell(itc),
8396 _own_cell(false),_cell_id(bg-1),
8403 MEDCouplingUMeshCell *MEDCouplingUMeshCellIterator::nextt()
8406 if(_cell_id<_nb_cell)
8415 MEDCouplingUMeshCellByTypeEntry::MEDCouplingUMeshCellByTypeEntry(MEDCouplingUMesh *mesh):_mesh(mesh)
8421 MEDCouplingUMeshCellByTypeIterator *MEDCouplingUMeshCellByTypeEntry::iterator()
8423 return new MEDCouplingUMeshCellByTypeIterator(_mesh);
8426 MEDCouplingUMeshCellByTypeEntry::~MEDCouplingUMeshCellByTypeEntry()
8432 MEDCouplingUMeshCellEntry::MEDCouplingUMeshCellEntry(MEDCouplingUMesh *mesh, INTERP_KERNEL::NormalizedCellType type, MEDCouplingUMeshCell *itc, mcIdType bg, mcIdType end):_mesh(mesh),_type(type),
8440 MEDCouplingUMeshCellEntry::~MEDCouplingUMeshCellEntry()
8446 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCellEntry::getType() const
8451 mcIdType MEDCouplingUMeshCellEntry::getNumberOfElems() const
8456 MEDCouplingUMeshCellIterator *MEDCouplingUMeshCellEntry::iterator()
8458 return new MEDCouplingUMeshCellIterator(_mesh,_itc,_bg,_end);
8461 MEDCouplingUMeshCellByTypeIterator::MEDCouplingUMeshCellByTypeIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),_cell_id(0),_nb_cell(0)
8466 _nb_cell=mesh->getNumberOfCells();
8470 MEDCouplingUMeshCellByTypeIterator::~MEDCouplingUMeshCellByTypeIterator()
8477 MEDCouplingUMeshCellEntry *MEDCouplingUMeshCellByTypeIterator::nextt()
8479 const mcIdType *c=_mesh->getNodalConnectivity()->begin();
8480 const mcIdType *ci=_mesh->getNodalConnectivityIndex()->begin();
8481 if(_cell_id<_nb_cell)
8483 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[_cell_id]];
8484 mcIdType nbOfElems=ToIdType(std::distance(ci+_cell_id,std::find_if(ci+_cell_id,ci+_nb_cell,MEDCouplingImpl::ConnReader(c,type))));
8485 mcIdType startId=_cell_id;
8486 _cell_id+=nbOfElems;
8487 return new MEDCouplingUMeshCellEntry(_mesh,type,_cell,startId,_cell_id);
8493 MEDCouplingUMeshCell::MEDCouplingUMeshCell(MEDCouplingUMesh *mesh):_conn(0),_conn_indx(0),_conn_lgth(NOTICABLE_FIRST_VAL)
8497 _conn=mesh->getNodalConnectivity()->getPointer();
8498 _conn_indx=mesh->getNodalConnectivityIndex()->getPointer();
8502 void MEDCouplingUMeshCell::next()
8504 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8509 _conn_lgth=_conn_indx[1]-_conn_indx[0];
8512 std::string MEDCouplingUMeshCell::repr() const
8514 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8516 std::ostringstream oss; oss << "Cell Type " << INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)_conn[0]).getRepr();
8518 std::copy(_conn+1,_conn+_conn_lgth,std::ostream_iterator<mcIdType>(oss," "));
8522 return std::string("MEDCouplingUMeshCell::repr : Invalid pos");
8525 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCell::getType() const
8527 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8528 return (INTERP_KERNEL::NormalizedCellType)_conn[0];
8530 return INTERP_KERNEL::NORM_ERROR;
8533 const mcIdType *MEDCouplingUMeshCell::getAllConn(mcIdType& lgth) const
8536 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8544 namespace MEDCouplingImpl
8546 const mcIdType theUndefID = std::numeric_limits< mcIdType >::max(); //!< undefined cell id
8548 //================================================================================
8550 * \brief Encode a cell id and a mesh index into a code
8551 * \param [in] id - cell id
8552 * \param [in] iMesh - mesh index [0,1]
8553 * \return mcIdType - code
8555 //================================================================================
8557 mcIdType encodeID( mcIdType id, int iMesh )
8559 return ( id + 1 ) * ( iMesh ? -1 : 1 );
8561 //================================================================================
8563 * \brief Return cell id and mesh index by a given id
8564 * \param [in] id - code of a cell in a mesh
8565 * \param [out] iMesh - returned mesh index
8566 * \return mcIdType - cell id
8568 //================================================================================
8570 mcIdType decodeID( mcIdType id, int& iMesh )
8573 return std::abs( id ) - 1;
8576 //================================================================================
8578 * \brief return another face sharing two given nodes of a face edge
8579 * \param [in] n0 - 1st node of the edge
8580 * \param [in] n1 - 2nd node of the edge
8581 * \param [in] inputFaceID - face including \a n0 andf \a n2
8582 * \param [in] mesh - object and reference meshes
8583 * \param [in] revNodal - reverse nodal connectivity of the two meshes
8584 * \param [in] revNodalIndx - index of reverse nodal connectivity of the two meshes
8585 * \param [out] facesByEdge - return another face including \a n0 andf \a n2
8586 * \param [out] equalFaces - return faces equal to facesByEdge
8588 //================================================================================
8590 void getFacesOfEdge( mcIdType n0,
8592 mcIdType inputFaceID,
8593 MEDCouplingUMesh* mesh[],
8594 MCAuto<DataArrayIdType> revNodal[],
8595 MCAuto<DataArrayIdType> revNodalIndx[],
8596 std::vector< mcIdType >& facesByEdge,
8597 std::vector< mcIdType >& equalFaces)
8599 // find faces sharing the both nodes of edge
8601 facesByEdge.clear();
8602 size_t prevNbF; // nb faces found in 0-th mesh
8603 for ( int iM = 0; iM < 2; ++iM )
8605 const mcIdType * revInd = revNodalIndx[ iM ]->begin();
8606 const mcIdType * rev = revNodal [ iM ]->begin();
8608 mcIdType nbRevFaces0 = revInd[ n0 + 1 ] - revInd[ n0 ];
8609 mcIdType nbRevFaces1 = revInd[ n1 + 1 ] - revInd[ n1 ];
8611 prevNbF = facesByEdge.size();
8612 facesByEdge.resize( prevNbF + std::max( nbRevFaces0, nbRevFaces1 ));
8614 auto it = std::set_intersection( rev + revInd[ n0 ],
8615 rev + revInd[ n0 ] + nbRevFaces0,
8617 rev + revInd[ n1 ] + nbRevFaces1,
8618 facesByEdge.begin() + prevNbF );
8619 facesByEdge.resize( it - facesByEdge.begin() );
8622 // facesByEdge now contains at least the 'inputFaceID'
8623 // check if there are other faces
8625 size_t nbF = facesByEdge.size();
8628 if ( prevNbF > 0 && prevNbF < nbF ) // faces found in both meshes
8630 // remove from facesByEdge equal faces in different meshes
8631 const mcIdType *conn [2] = { mesh[0]->getNodalConnectivity()->getConstPointer(),
8632 mesh[1]->getNodalConnectivity()->getConstPointer() };
8633 const mcIdType *connI[2] = { mesh[0]->getNodalConnectivityIndex()->getConstPointer(),
8634 mesh[1]->getNodalConnectivityIndex()->getConstPointer() };
8635 for ( size_t i0 = 0; i0 < prevNbF; ++i0 )
8637 if ( facesByEdge[ i0 ] == theUndefID )
8639 mcIdType objFaceID = MEDCouplingImpl::encodeID( facesByEdge[ i0 ], 0 );
8640 bool isInputFace = ( objFaceID == inputFaceID );
8642 for ( size_t i1 = prevNbF; i1 < facesByEdge.size(); ++i1 )
8644 if ( facesByEdge[ i1 ] == theUndefID )
8647 mcIdType f0 = facesByEdge[ i0 ];
8648 mcIdType f1 = facesByEdge[ i1 ];
8649 size_t nbNodes0 = connI[0][ f0 + 1 ] - connI[0][ f0 ] - 1;
8650 size_t nbNodes1 = connI[1][ f1 + 1 ] - connI[1][ f1 ] - 1;
8651 if ( nbNodes0 != nbNodes1 )
8654 const mcIdType * fConn0 = conn[0] + connI[0][ f0 ] + 1;
8655 const mcIdType * fConn1 = conn[1] + connI[1][ f1 ] + 1;
8656 if ( std::equal( fConn0, fConn0 + nbNodes0, fConn1 ))
8658 // equal faces; remove an object one
8659 mcIdType refFaceID = MEDCouplingImpl::encodeID( facesByEdge[ i1 ], 1 );
8660 if ( refFaceID == inputFaceID )
8663 if ( std::find( equalFaces.begin(),
8664 equalFaces.end(), objFaceID ) == equalFaces.end() )
8665 equalFaces.push_back( objFaceID );
8667 facesByEdge[ i0 ] = theUndefID;
8669 facesByEdge[ i1 ] = theUndefID;
8674 facesByEdge[ i0 ] = theUndefID;
8679 nbF = facesByEdge.size();
8680 for ( size_t i = 0; i < facesByEdge.size(); ++i )
8682 if ( facesByEdge[ i ] != theUndefID )
8684 facesByEdge[ i ] = MEDCouplingImpl::encodeID( facesByEdge[ i ], i >= prevNbF );
8685 if ( facesByEdge[ i ] == inputFaceID )
8686 facesByEdge[ i ] = theUndefID;
8688 nbF -= ( facesByEdge[ i ] == theUndefID );
8692 return; // non-manifold
8696 facesByEdge.clear();
8698 else // nbF == 1, set a found face first
8700 if ( facesByEdge[ 0 ] == theUndefID )
8702 for ( size_t i = 1; i < facesByEdge.size(); ++i )
8703 if ( facesByEdge[ i ] != theUndefID )
8705 facesByEdge[ 0 ] = facesByEdge[ i ];
8709 facesByEdge.resize( 1 );
8714 //================================================================================
8716 * \brief Remove a face from nodal reversed connectivity
8717 * \param [in] node - a node of the face
8718 * \param [in] face - the face
8719 * \param [in.out] revNodal - reverse nodal connectivity
8720 * \param [in,out] revNodalIndx - reverse nodal connectivity index
8722 //================================================================================
8724 void removeFromRevNodal( mcIdType node,
8726 MCAuto<DataArrayIdType>& revNodal,
8727 MCAuto<DataArrayIdType>& revNodalIndx)
8729 mcIdType* fBeg = revNodal->getPointer() + revNodalIndx->getIJ( node, 0 );
8730 mcIdType* fEnd = revNodal->getPointer() + revNodalIndx->getIJ( node + 1, 0);
8731 auto it = std::find( fBeg, fEnd, face );
8734 for ( auto it2 = it + 1; it2 < fEnd; ++it2 ) // keep faces sorted
8735 *( it2 - 1 ) = *it2;
8737 *( fEnd - 1 ) = theUndefID;
8741 //================================================================================
8743 * \brief Check order of two nodes in a given face
8744 * \param [inout] n0 - node 1
8745 * \param [inout] n1 - node 2
8746 * \param [inout] iFEnc - face
8747 * \param [inout] mesh - mesh
8748 * \return bool - true if the nodes are in [ .., n1, n0, ..] order in face
8750 //================================================================================
8752 bool isReverseOrder( mcIdType n0,
8755 MEDCouplingUMesh* mesh[] )
8758 mcIdType iF = decodeID( iFEnc, iMesh );
8760 const mcIdType *conn = mesh[ iMesh ]->getNodalConnectivity()->getConstPointer();
8761 const mcIdType *connI = mesh[ iMesh ]->getNodalConnectivityIndex()->getConstPointer();
8763 auto it0 = std::find( conn + connI[ iF ] + 1,
8764 conn + connI[ iF + 1 ],
8766 auto it1 = std::find( conn + connI[ iF ] + 1,
8767 conn + connI[ iF + 1 ],
8769 long i0 = it0 - conn;
8770 long i1 = it1 - conn;
8772 bool isRev = ( std::abs( i1 - i0 ) == 1 ) ? i1 < i0 : i0 < i1;
8776 //================================================================================
8778 * \brief Change orientation of a face in one of given meshes
8779 * \param [in] iFEnc - face ID also encoding a mesh index
8780 * \param [in,out] mesh - object and reference meshes
8782 //================================================================================
8784 void reverseFace( mcIdType iFEnc, MEDCouplingUMesh* mesh[] )
8787 mcIdType face = decodeID( iFEnc, iMesh );
8789 mcIdType *conn = mesh[ iMesh ]->getNodalConnectivity()->getPointer();
8790 mcIdType *connI = mesh[ iMesh ]->getNodalConnectivityIndex()->getPointer();
8792 const INTERP_KERNEL::CellModel& cm =
8793 INTERP_KERNEL::CellModel::GetCellModel( mesh[iMesh]->getTypeOfCell( face ));
8795 cm.changeOrientationOf2D( conn + connI[ face ] + 1,
8796 (unsigned int)( connI[ face + 1 ] - connI[ face ] - 1 ));
8803 //================================================================================
8805 * \brief Orient cells of \a this 2D mesh equally to \a refFaces
8806 * \param [in] refFaces - 2D mesh containing correctly oriented faces. It is optional.
8807 * If there are no cells in \a refFaces or it is nullptr, then any face
8808 * in \a this mesh is used as a reference
8809 * \throw If \a this mesh is not well defined.
8810 * \throw If \a this mesh or \refFaces are not 2D.
8811 * \throw If \a this mesh and \refFaces do not share nodes.
8812 * \throw If \a refFaces are not equally oriented.
8813 * \throw If \a this mesh plus \a refFaces together form a non-manifold mesh.
8815 * \if ENABLE_EXAMPLES
8816 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
8817 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
8820 //================================================================================
8822 void MEDCouplingUMesh::orientCorrectly2DCells(const MEDCouplingUMesh* refFaces)
8824 checkConsistencyLight();
8825 if ( getMeshDimension() != 2 )
8826 throw INTERP_KERNEL::Exception("The mesh dimension must be 2");
8829 refFaces->checkConsistencyLight();
8830 if ( refFaces->getMeshDimension() != 2 )
8831 throw INTERP_KERNEL::Exception("The reference mesh dimension must be 2");
8832 if ( getCoords() != refFaces->getCoords() )
8833 throw INTERP_KERNEL::Exception("Object and reference meshes must share nodes ");
8834 if ( refFaces->getNumberOfCells() == 0 )
8837 if ( getNumberOfCells() == 0 )
8840 enum { _OBJ, _REF };
8841 MEDCouplingUMesh* mesh[2] = { this, const_cast< MEDCouplingUMesh* >( refFaces ) };
8842 MCAuto<MEDCouplingUMesh> meshPtr;
8845 meshPtr = mesh[_REF] = MEDCouplingUMesh::New();
8846 mesh[_REF]->setCoords( mesh[_OBJ]->getCoords() );
8847 mesh[_REF]->allocateCells(0);
8848 mesh[_REF]->finishInsertingCells();
8850 mcIdType nbFacesToCheck[2] = { mesh[_OBJ]->getNumberOfCells(),
8851 mesh[_REF]->getNumberOfCells() };
8852 std::vector< bool > isFaceQueued[ 2 ]; // enqueued faces of 2 meshes
8853 isFaceQueued[_OBJ].resize( nbFacesToCheck[_OBJ] );
8854 isFaceQueued[_REF].resize( nbFacesToCheck[_REF] );
8856 MCAuto<DataArrayIdType> revNodal [2] = { DataArrayIdType::New(), DataArrayIdType::New() };
8857 MCAuto<DataArrayIdType> revNodalIndx[2] = { DataArrayIdType::New(), DataArrayIdType::New() };
8858 mesh[_OBJ]->getReverseNodalConnectivity( revNodal[_OBJ], revNodalIndx[_OBJ] );
8859 mesh[_REF]->getReverseNodalConnectivity( revNodal[_REF], revNodalIndx[_REF] );
8861 std::vector< mcIdType > faceNodes(4);
8862 std::vector< mcIdType > facesByEdge(4), equalFaces;
8863 std::vector< mcIdType > faceQueue; // starting faces with IDs counted from 1; negative ID mean a face in ref mesh
8865 while ( nbFacesToCheck[_OBJ] + nbFacesToCheck[_REF] > 0 ) // until all faces checked
8867 if ( faceQueue.empty() ) // all neighbors checked, find more faces to check
8869 for ( int iMesh = 1; iMesh >= 0; --iMesh ) // on [ _REF, _OBJ ]
8870 if ( nbFacesToCheck[iMesh] > 0 )
8871 for ( mcIdType f = 0, nbF = mesh[iMesh]->getNumberOfCells(); f < nbF; ++f )
8872 if ( !isFaceQueued[iMesh][f] )
8874 faceQueue.push_back( MEDCouplingImpl::encodeID( f, iMesh ));
8875 isFaceQueued[ iMesh ][ f ] = true;
8879 if ( faceQueue.empty() )
8883 mcIdType fID = faceQueue.back();
8884 faceQueue.pop_back();
8887 mcIdType refFace = MEDCouplingImpl::decodeID( fID, iMesh );
8889 nbFacesToCheck[iMesh]--;
8893 mesh[iMesh]->getNodeIdsOfCell( refFace, faceNodes );
8894 const INTERP_KERNEL::CellModel& cm = INTERP_KERNEL::CellModel::GetCellModel( mesh[iMesh]->getTypeOfCell( refFace ));
8895 const int nbEdges = cm.getNumberOfSons();
8897 // loop on edges of the refFace
8898 mcIdType n0 = faceNodes[ nbEdges - 1 ]; // 1st node of edge
8899 for ( int edge = 0; edge < nbEdges; ++edge )
8901 mcIdType n1 = faceNodes[ edge ]; // 2nd node of edge
8903 // get faces sharing the edge
8904 MEDCouplingImpl::getFacesOfEdge( n0, n1, fID, mesh, revNodal, revNodalIndx,
8905 facesByEdge, equalFaces );
8907 if ( facesByEdge.size() > 1 )
8908 THROW_IK_EXCEPTION("Non-manifold mesh at edge " << n0+1 << " - " << n1+1);
8910 if ( facesByEdge.size() == 1 )
8912 // compare orientation of two faces
8914 if ( !MEDCouplingImpl::isReverseOrder( n0, n1, facesByEdge[0], mesh ))
8916 if ( facesByEdge[0] < 0 ) // in the ref mesh
8917 throw INTERP_KERNEL::Exception("Different orientation of reference faces");
8919 MEDCouplingImpl::reverseFace( facesByEdge[0], mesh );
8921 mcIdType face2 = MEDCouplingImpl::decodeID( facesByEdge[0], iMesh2 );
8922 if ( !isFaceQueued[iMesh2][face2] )
8924 isFaceQueued[iMesh2][face2] = true;
8925 faceQueue.push_back( facesByEdge[0] );
8931 // remove face and equalFaces from revNodal in order not to treat them again
8932 equalFaces.push_back( fID );
8933 for ( mcIdType face : equalFaces )
8935 mcIdType f = MEDCouplingImpl::decodeID( face, iMesh2 );
8936 const mcIdType *conn = mesh[iMesh2]->getNodalConnectivity()->getConstPointer();
8937 const mcIdType *connI = mesh[iMesh2]->getNodalConnectivityIndex()->getConstPointer();
8938 mcIdType nbNodes = connI[ f + 1 ] - connI[ f ] - 1;
8939 for ( const mcIdType* n = conn + connI[ f ] + 1, *nEnd = n + nbNodes; n < nEnd; ++n )
8941 MEDCouplingImpl::removeFromRevNodal( *n, f, // not to treat f again
8942 revNodal[ iMesh2 ], revNodalIndx[ iMesh2 ] );
8945 } // while() until all faces checked