1 // Copyright (C) 2007-2023 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 * \b WARNING: this method will not modify edges connectivity! Take a look at colinearizeEdges for that.
1345 * \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
1348 void MEDCouplingUMesh::simplifyPolyhedra(double eps)
1350 checkFullyDefined();
1351 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1352 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplifyPolyhedra : works on meshdimension 3 and spaceDimension 3 !");
1353 MCAuto<DataArrayDouble> coords=getCoords()->deepCopy();
1354 coords->recenterForMaxPrecision(eps);
1356 mcIdType nbOfCells=getNumberOfCells();
1357 const mcIdType *conn=_nodal_connec->getConstPointer();
1358 const mcIdType *index=_nodal_connec_index->getConstPointer();
1359 MCAuto<DataArrayIdType> connINew=DataArrayIdType::New();
1360 connINew->alloc(nbOfCells+1,1);
1361 mcIdType *connINewPtr=connINew->getPointer(); *connINewPtr++=0;
1362 MCAuto<DataArrayIdType> connNew=DataArrayIdType::New(); connNew->alloc(0,1);
1363 MCAuto<DataArrayIdType> E_Fi(DataArrayIdType::New()), E_F(DataArrayIdType::New()), F_Ei(DataArrayIdType::New()), F_E(DataArrayIdType::New());
1364 MCAuto<MEDCouplingUMesh> m_faces(buildDescendingConnectivity(E_F, E_Fi, F_E, F_Ei));
1366 for(mcIdType i=0;i<nbOfCells;i++,connINewPtr++)
1368 if(conn[index[i]]==ToIdType(INTERP_KERNEL::NORM_POLYHED))
1370 SimplifyPolyhedronCell(eps,coords, i,connNew, m_faces, E_Fi, E_F, F_Ei, F_E);
1374 connNew->insertAtTheEnd(conn+index[i],conn+index[i+1]);
1375 *connINewPtr=connNew->getNumberOfTuples();
1378 setConnectivity(connNew,connINew,false);
1382 * This method expects that spaceDimension is equal to 3 and meshDimension equal to 3.
1383 * This method performs operation only on polyhedrons in \b this. If no polyhedrons exists in \b this, \b this remains unchanged.
1384 * This method allows to simplify edges of polyhedron cells so that consecutive colinear segments (with intermediate points
1385 * not used by any other cell) are merged together.
1387 * \param [in] eps is a relative precision that allows to establish if two consecutive 3D segments are colinear or not.
1389 * \sa simplifyPolyhedra
1391 void MEDCouplingUMesh::colinearizeEdges(double eps)
1394 // Thanks to Antoine Gerschenfeld (CEA) for contributing this method!
1396 using DAI = MCAuto<DataArrayIdType>;
1397 checkFullyDefined();
1398 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1399 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::colinearizeEdges() : works with meshdim=3 and spaceDim=3!");
1400 double seps = sqrt(1-eps);
1401 // Computing connectivities and correspondances : elements -> segments -> points
1402 DAI E_Fi(DataArrayIdType::New()), E_F(DataArrayIdType::New()), F_Ei(DataArrayIdType::New()), F_E(DataArrayIdType::New()),
1403 F_Si(DataArrayIdType::New()), F_S(DataArrayIdType::New()), S_Fi(DataArrayIdType::New()), S_F(DataArrayIdType::New()),
1404 S_Pi(DataArrayIdType::New()), S_P(DataArrayIdType::New()), P_Si(DataArrayIdType::New()), P_S(DataArrayIdType::New());
1405 MCAuto<MEDCouplingUMesh> m_f(buildDescendingConnectivity(E_F, E_Fi, F_E, F_Ei)),
1406 m_s(m_f->buildDescendingConnectivity(F_S, F_Si, S_F, S_Fi)),
1407 m_p(m_s->buildDescendingConnectivity(S_P, S_Pi, P_S, P_Si)); // E: elem, F: faces, S: segments (edges), P: points (vertices)
1408 const mcIdType *S_Pp(S_P->begin()), *S_Pip(S_Pi->begin()), *P_Sp(P_S->begin()), *P_Sip(P_Si->begin());
1409 std::set<mcIdType> pt_rem;
1410 const mcIdType *m_pi = m_p->getNodalConnectivityIndex()->begin(),
1411 *m_pc = m_p->getNodalConnectivity()->begin();
1412 double (*coord)[3] = (double (*)[3]) getCoords()->begin();
1413 // Find all points only connected to exaclty 2 segments - they are the candidates for elimination
1414 // Note that in 3D this can only happen for polyhedrons (when this happens at all)
1415 DAI dsi = P_Si->deltaShiftIndex();
1416 DAI cand = dsi->findIdsEqual(2);
1417 for (const mcIdType& i: *cand) // i is a point to be potentially eliminated, shared by 2 segs only
1419 double n2[2] = {0., 0.}, scal = 0.; // n2 is a squared norm, scal is a scalar product
1420 mcIdType p[2][2]; // p[j][k] is the ID (in the coord array) of the k-th point of the j-th segment
1421 for (mcIdType j = 0; j < 2; j++)
1422 for (mcIdType k = 0; k < 2; k++)
1424 mcIdType off1 = P_Sip[i] + j; // offset to get ID of the j-th seg (around the i-th point) in the point->seg correspondance
1425 mcIdType pt_id = P_Sp[off1] + k; // ID of the k-th point of the j-th seg in the point->seg correspondance
1426 mcIdType pt_id2 = S_Pp[S_Pip[pt_id]]; // ID of the point in the point mesh
1427 p[j][k] = m_pc[m_pi[pt_id2] + 1]; // Absolute ID, as read from the connectvity (+1 to skip type: NORM_POINT1)
1428 // Just for fun, as initially written by Antoine :-)
1429 // p[j][k] = m_pc[m_pi[S_P->getIJ(S_Pi->getIJ(P_S->getIJ(P_Si->getIJ(i, 0) + j, 0), 0) + k, 0)] + 1];
1431 // Geometric test on scalar product
1432 for (int d = 0; d < 3; d++) // dimension
1434 for (int j = 0; j < 2; j++)
1435 n2[j] += std::pow(coord[p[j][1]][d] - coord[p[j][0]][d], 2);
1436 scal += (coord[p[1][1]][d] - coord[p[1][0]][d]) * (coord[p[0][1]][d] - coord[p[0][0]][d]);
1438 if (scal * scal > seps * n2[0] * n2[1]) // seps is a sqrt for homogeneity
1439 pt_rem.insert(m_pc[m_pi[i] + 1]); // point should be removed
1441 // Clean connectivity by filtering points to be removed:
1442 DataArrayIdType *old_index = getNodalConnectivityIndex(), *old_conn = getNodalConnectivity();
1443 DAI new_index(DataArrayIdType::New()), new_conn(DataArrayIdType::New());
1444 const mcIdType *old_index_p(old_index->begin()), *old_conn_p(old_conn->begin());
1445 for (mcIdType i = 0; i < getNumberOfCells(); i++)
1447 new_index->pushBackSilent(new_conn->getNbOfElems());
1448 for (mcIdType j = old_index_p[i]; j < old_index_p[i + 1]; j++)
1450 // Keep point if it is not to be removed, or if is first in connectivity (TODO this last check could be removed?)
1451 if (std::find(pt_rem.begin(), pt_rem.end(), old_conn_p[j]) == pt_rem.end() || j == old_index_p[i])
1452 new_conn->pushBackSilent(old_conn_p[j]);
1455 new_index->pushBackSilent(new_conn->getNbOfElems());
1456 setConnectivity(new_conn, new_index);
1460 * This method returns all node ids used in the connectivity of \b this. The data array returned has to be dealt by the caller.
1461 * The returned node ids are sorted ascendingly. This method is close to MEDCouplingUMesh::getNodeIdsInUse except
1462 * the format of the returned DataArrayIdType instance.
1464 * \return a newly allocated DataArrayIdType sorted ascendingly of fetched node ids.
1465 * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1467 DataArrayIdType *MEDCouplingUMesh::computeFetchedNodeIds() const
1469 checkConnectivityFullyDefined();
1470 const mcIdType *maxEltPt(std::max_element(_nodal_connec->begin(),_nodal_connec->end()));
1471 mcIdType maxElt(maxEltPt==_nodal_connec->end()?0:std::abs(*maxEltPt)+1);
1472 std::vector<bool> retS(maxElt,false);
1473 computeNodeIdsAlg(retS);
1474 return DataArrayIdType::BuildListOfSwitchedOn(retS);
1478 * \param [in,out] nodeIdsInUse an array of size typically equal to nbOfNodes.
1479 * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1481 void MEDCouplingUMesh::computeNodeIdsAlg(std::vector<bool>& nodeIdsInUse) const
1483 mcIdType nbOfNodes=ToIdType(nodeIdsInUse.size()),
1484 nbOfCells=getNumberOfCells();
1485 const mcIdType *connIndex(_nodal_connec_index->getConstPointer()),*conn(_nodal_connec->getConstPointer());
1486 for(mcIdType i=0;i<nbOfCells;i++)
1487 for(mcIdType j=connIndex[i]+1;j<connIndex[i+1];j++)
1490 if(conn[j]<nbOfNodes)
1491 nodeIdsInUse[conn[j]]=true;
1494 std::ostringstream oss; oss << "MEDCouplingUMesh::computeNodeIdsAlg : In cell #" << i << " presence of node id " << conn[j] << " not in [0," << nbOfNodes << ") !";
1495 throw INTERP_KERNEL::Exception(oss.str());
1502 struct MEDCouplingAccVisit
1504 MEDCouplingAccVisit():_new_nb_of_nodes(0) { }
1505 mcIdType operator()(mcIdType val) { if(val!=-1) return _new_nb_of_nodes++; else return -1; }
1506 mcIdType _new_nb_of_nodes;
1512 * Finds nodes not used in any cell and returns an array giving a new id to every node
1513 * by excluding the unused nodes, for which the array holds -1. The result array is
1514 * a mapping in "Old to New" mode.
1515 * \param [out] nbrOfNodesInUse - number of node ids present in the nodal connectivity.
1516 * \return DataArrayIdType * - a new instance of DataArrayIdType. Its length is \a
1517 * this->getNumberOfNodes(). It holds for each node of \a this mesh either -1
1518 * if the node is unused or a new id else. The caller is to delete this
1519 * array using decrRef() as it is no more needed.
1520 * \throw If the coordinates array is not set.
1521 * \throw If the nodal connectivity of cells is not defined.
1522 * \throw If the nodal connectivity includes an invalid id.
1524 * \if ENABLE_EXAMPLES
1525 * \ref cpp_mcumesh_getNodeIdsInUse "Here is a C++ example".<br>
1526 * \ref py_mcumesh_getNodeIdsInUse "Here is a Python example".
1528 * \sa computeFetchedNodeIds, computeNodeIdsAlg()
1530 DataArrayIdType *MEDCouplingUMesh::getNodeIdsInUse(mcIdType& nbrOfNodesInUse) const
1533 mcIdType nbOfNodes(getNumberOfNodes());
1534 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1535 ret->alloc(nbOfNodes,1);
1536 mcIdType *traducer=ret->getPointer();
1537 std::fill(traducer,traducer+nbOfNodes,-1);
1538 mcIdType nbOfCells=getNumberOfCells();
1539 const mcIdType *connIndex=_nodal_connec_index->getConstPointer();
1540 const mcIdType *conn=_nodal_connec->getConstPointer();
1541 for(mcIdType i=0;i<nbOfCells;i++)
1542 for(mcIdType j=connIndex[i]+1;j<connIndex[i+1];j++)
1545 if(conn[j]<nbOfNodes)
1546 traducer[conn[j]]=1;
1549 std::ostringstream oss; oss << "MEDCouplingUMesh::getNodeIdsInUse : In cell #" << i << " presence of node id " << conn[j] << " not in [0," << nbOfNodes << ") !";
1550 throw INTERP_KERNEL::Exception(oss.str());
1553 nbrOfNodesInUse=ToIdType(std::count(traducer,traducer+nbOfNodes,1));
1554 std::transform(traducer,traducer+nbOfNodes,traducer,MEDCouplingAccVisit());
1559 * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1560 * For each cell in \b this the number of nodes constituting cell is computed.
1561 * For each polyhedron cell, the sum of the number of nodes of each face constituting polyhedron cell is returned.
1562 * So for pohyhedrons some nodes can be counted several times in the returned result.
1564 * \return a newly allocated array
1565 * \sa MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell
1567 DataArrayIdType *MEDCouplingUMesh::computeNbOfNodesPerCell() const
1569 checkConnectivityFullyDefined();
1570 mcIdType nbOfCells=getNumberOfCells();
1571 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1572 ret->alloc(nbOfCells,1);
1573 mcIdType *retPtr=ret->getPointer();
1574 const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1575 const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1576 for(mcIdType i=0;i<nbOfCells;i++,retPtr++)
1578 if(conn[connI[i]]!=ToIdType(INTERP_KERNEL::NORM_POLYHED))
1579 *retPtr=connI[i+1]-connI[i]-1;
1581 *retPtr=connI[i+1]-connI[i]-1-ToIdType(std::count(conn+connI[i]+1,conn+connI[i+1],-1));
1587 * This method computes effective number of nodes per cell. That is to say nodes appearing several times in nodal connectivity of a cell,
1588 * will be counted only once here whereas it will be counted several times in MEDCouplingUMesh::computeNbOfNodesPerCell method.
1590 * \return DataArrayIdType * - new object to be deallocated by the caller.
1591 * \sa MEDCouplingUMesh::computeNbOfNodesPerCell
1593 DataArrayIdType *MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell() const
1595 checkConnectivityFullyDefined();
1596 mcIdType nbOfCells=getNumberOfCells();
1597 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1598 ret->alloc(nbOfCells,1);
1599 mcIdType *retPtr=ret->getPointer();
1600 const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1601 const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1602 for(mcIdType i=0;i<nbOfCells;i++,retPtr++)
1604 std::set<mcIdType> s(conn+connI[i]+1,conn+connI[i+1]);
1605 if(conn[connI[i]]!=ToIdType(INTERP_KERNEL::NORM_POLYHED))
1606 *retPtr=ToIdType(s.size());
1610 *retPtr=ToIdType(s.size());
1617 * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1618 * For each cell in \b this the number of faces constituting (entity of dimension this->getMeshDimension()-1) cell is computed.
1620 * \return a newly allocated array
1622 DataArrayIdType *MEDCouplingUMesh::computeNbOfFacesPerCell() const
1624 checkConnectivityFullyDefined();
1625 mcIdType nbOfCells=getNumberOfCells();
1626 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1627 ret->alloc(nbOfCells,1);
1628 mcIdType *retPtr=ret->getPointer();
1629 const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1630 const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1631 for(mcIdType i=0;i<nbOfCells;i++,retPtr++,connI++)
1633 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]);
1634 *retPtr=cm.getNumberOfSons2(conn+connI[0]+1,connI[1]-connI[0]-1);
1640 * Removes unused nodes (the node coordinates array is shorten) and returns an array
1641 * mapping between new and old node ids in "Old to New" mode. -1 values in the returned
1642 * array mean that the corresponding old node is no more used.
1643 * \return DataArrayIdType * - a new instance of DataArrayIdType of length \a
1644 * this->getNumberOfNodes() before call of this method. The caller is to
1645 * delete this array using decrRef() as it is no more needed.
1646 * \throw If the coordinates array is not set.
1647 * \throw If the nodal connectivity of cells is not defined.
1648 * \throw If the nodal connectivity includes an invalid id.
1649 * \sa areAllNodesFetched
1651 * \if ENABLE_EXAMPLES
1652 * \ref cpp_mcumesh_zipCoordsTraducer "Here is a C++ example".<br>
1653 * \ref py_mcumesh_zipCoordsTraducer "Here is a Python example".
1656 DataArrayIdType *MEDCouplingUMesh::zipCoordsTraducer()
1658 return MEDCouplingPointSet::zipCoordsTraducer();
1662 * This method stands if 'cell1' and 'cell2' are equals regarding 'compType' policy.
1663 * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1665 int MEDCouplingUMesh::AreCellsEqual(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2, int compType)
1670 return AreCellsEqualPolicy0(conn,connI,cell1,cell2);
1672 return AreCellsEqualPolicy1(conn,connI,cell1,cell2);
1674 return AreCellsEqualPolicy2(conn,connI,cell1,cell2);
1676 return AreCellsEqualPolicy2NoType(conn,connI,cell1,cell2);
1678 return AreCellsEqualPolicy7(conn,connI,cell1,cell2);
1680 throw INTERP_KERNEL::Exception("Unknown comparison asked ! Must be in 0,1,2,3 or 7.");
1684 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 0.
1686 int MEDCouplingUMesh::AreCellsEqualPolicy0(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1688 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1689 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;
1694 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 1.
1696 int MEDCouplingUMesh::AreCellsEqualPolicy1(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1698 mcIdType sz=connI[cell1+1]-connI[cell1];
1699 if(sz==connI[cell2+1]-connI[cell2])
1701 if(conn[connI[cell1]]==conn[connI[cell2]])
1703 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1704 unsigned dim=cm.getDimension();
1709 mcIdType sz1=2*(sz-1);
1710 INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz1];
1711 mcIdType *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(mcIdType *)tmp);
1712 std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1713 work=std::search((mcIdType *)tmp,(mcIdType *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1714 return work!=tmp+sz1?1:0;
1717 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;//case of SEG2 and SEG3
1720 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy1 : not implemented yet for meshdim == 3 !");
1727 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 2.
1729 int MEDCouplingUMesh::AreCellsEqualPolicy2(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1731 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1733 if(conn[connI[cell1]]==conn[connI[cell2]])
1735 std::set<mcIdType> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1736 std::set<mcIdType> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1744 * This method is less restrictive than AreCellsEqualPolicy2. Here the geometric type is absolutely not taken into account !
1746 int MEDCouplingUMesh::AreCellsEqualPolicy2NoType(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1748 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1750 std::set<mcIdType> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1751 std::set<mcIdType> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1758 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 7.
1760 int MEDCouplingUMesh::AreCellsEqualPolicy7(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1762 mcIdType sz=connI[cell1+1]-connI[cell1];
1763 if(sz==connI[cell2+1]-connI[cell2])
1765 if(conn[connI[cell1]]==conn[connI[cell2]])
1767 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1768 unsigned dim=cm.getDimension();
1773 mcIdType sz1=2*(sz-1);
1774 INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz1];
1775 mcIdType *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(mcIdType *)tmp);
1776 std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1777 work=std::search((mcIdType *)tmp,(mcIdType *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1782 std::reverse_iterator<mcIdType *> it1((mcIdType *)tmp+sz1);
1783 std::reverse_iterator<mcIdType *> it2((mcIdType *)tmp);
1784 if(std::search(it1,it2,conn+connI[cell2]+1,conn+connI[cell2+1])!=it2)
1791 {//case of SEG2 and SEG3
1792 if(std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1))
1794 if(!cm.isQuadratic())
1796 std::reverse_iterator<const mcIdType *> it1(conn+connI[cell1+1]);
1797 std::reverse_iterator<const mcIdType *> it2(conn+connI[cell1]+1);
1798 if(std::equal(it1,it2,conn+connI[cell2]+1))
1804 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])
1811 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy7 : not implemented yet for meshdim == 3 !");
1819 * This method find cells that are equal (regarding \a compType) in \a this. The comparison is specified by \a compType (see zipConnectivityTraducer).
1820 * This method keeps the coordinates of \a this. The comparison starts at rank \a startCellId cell id (included).
1821 * 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.
1822 * If \a startCellId is greater than 0 algorithm starts at cell #startCellId but for each cell all candidates are considered.
1823 * This method is time consuming.
1825 * \param [in] compType input specifying the technique used to compare cells each other.
1826 * - 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.
1827 * - 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)
1828 * and their type equal. For 1D mesh the policy 1 is equivalent to 0.
1829 * - 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
1830 * can be used for users not sensitive to orientation of cell
1831 * \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.
1832 * \param [out] commonCellsArr common cells ids (\ref numbering-indirect)
1833 * \param [out] commonCellsIArr common cells ids (\ref numbering-indirect)
1836 void MEDCouplingUMesh::findCommonCells(int compType, mcIdType startCellId, DataArrayIdType *& commonCellsArr, DataArrayIdType *& commonCellsIArr) const
1838 MCAuto<DataArrayIdType> revNodal=DataArrayIdType::New(),revNodalI=DataArrayIdType::New();
1839 getReverseNodalConnectivity(revNodal,revNodalI);
1840 FindCommonCellsAlg(compType,startCellId,_nodal_connec,_nodal_connec_index,revNodal,revNodalI,commonCellsArr,commonCellsIArr);
1843 void MEDCouplingUMesh::FindCommonCellsAlg(int compType, mcIdType startCellId, const DataArrayIdType *nodal, const DataArrayIdType *nodalI, const DataArrayIdType *revNodal, const DataArrayIdType *revNodalI,
1844 DataArrayIdType *& commonCellsArr, DataArrayIdType *& commonCellsIArr)
1846 MCAuto<DataArrayIdType> commonCells=DataArrayIdType::New(),commonCellsI=DataArrayIdType::New(); commonCells->alloc(0,1);
1847 mcIdType nbOfCells=nodalI->getNumberOfTuples()-1;
1848 commonCellsI->reserve(1); commonCellsI->pushBackSilent(0);
1849 const mcIdType *revNodalPtr=revNodal->getConstPointer(),*revNodalIPtr=revNodalI->getConstPointer();
1850 const mcIdType *connPtr=nodal->getConstPointer(),*connIPtr=nodalI->getConstPointer();
1851 std::vector<bool> isFetched(nbOfCells,false);
1854 for(mcIdType i=startCellId;i<nbOfCells;i++)
1858 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));
1859 std::vector<mcIdType> v,v2;
1860 if(connOfNode!=connPtr+connIPtr[i+1])
1862 const mcIdType *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1863 v2.insert(v2.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1]);
1866 for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1870 const mcIdType *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1871 std::vector<mcIdType>::iterator it=std::set_intersection(v.begin(),v.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1872 v2.resize(std::distance(v2.begin(),it));
1876 if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1878 mcIdType pos=commonCellsI->back();
1879 commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1880 for(const mcIdType *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1881 isFetched[*it]=true;
1889 for(mcIdType i=startCellId;i<nbOfCells;i++)
1893 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));
1894 // v2 contains the result of successive intersections using rev nodal on on each node of cell #i
1895 std::vector<mcIdType> v,v2;
1896 if(connOfNode!=connPtr+connIPtr[i+1])
1898 v2.insert(v2.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1]);
1901 for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1905 std::vector<mcIdType>::iterator it=std::set_intersection(v.begin(),v.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1906 v2.resize(std::distance(v2.begin(),it));
1908 // v2 contains now candidates. Problem candidates are sorted using id rank.
1913 auto it(std::find(v2.begin(),v2.end(),i));
1914 std::swap(*v2.begin(),*it);
1916 if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1918 mcIdType newPos(commonCells->getNumberOfTuples());
1919 mcIdType pos(commonCellsI->back());
1920 std::sort(commonCells->getPointerSilent()+pos,commonCells->getPointerSilent()+newPos);
1921 commonCellsI->pushBackSilent(newPos);
1922 for(const mcIdType *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1923 isFetched[*it]=true;
1929 commonCellsArr=commonCells.retn();
1930 commonCellsIArr=commonCellsI.retn();
1934 * Checks if \a this mesh includes all cells of an \a other mesh, and returns an array
1935 * giving for each cell of the \a other an id of a cell in \a this mesh. A value larger
1936 * than \a this->getNumberOfCells() in the returned array means that there is no
1937 * corresponding cell in \a this mesh.
1938 * It is expected that \a this and \a other meshes share the same node coordinates
1939 * array, if it is not so an exception is thrown.
1940 * \param [in] other - the mesh to compare with.
1941 * \param [in] compType - specifies a cell comparison technique. For meaning of its
1942 * valid values [0,1,2], see zipConnectivityTraducer().
1943 * \param [out] arr - a new instance of DataArrayIdType returning correspondence
1944 * between cells of the two meshes. It contains \a other->getNumberOfCells()
1945 * values. The caller is to delete this array using
1946 * decrRef() as it is no more needed.
1947 * \return bool - \c true if all cells of \a other mesh are present in the \a this
1950 * \if ENABLE_EXAMPLES
1951 * \ref cpp_mcumesh_areCellsIncludedIn "Here is a C++ example".<br>
1952 * \ref py_mcumesh_areCellsIncludedIn "Here is a Python example".
1954 * \sa checkDeepEquivalOnSameNodesWith()
1955 * \sa checkGeoEquivalWith()
1957 bool MEDCouplingUMesh::areCellsIncludedIn(const MEDCouplingUMesh *other, int compType, DataArrayIdType *& arr) const
1959 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1960 mcIdType nbOfCells=getNumberOfCells();
1961 static const int possibleCompType[]={0,1,2};
1962 if(std::find(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),compType)==possibleCompType+sizeof(possibleCompType)/sizeof(int))
1964 std::ostringstream oss; oss << "MEDCouplingUMesh::areCellsIncludedIn : only following policies are possible : ";
1965 std::copy(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),std::ostream_iterator<int>(oss," "));
1967 throw INTERP_KERNEL::Exception(oss.str());
1970 if(other->getNumberOfCells()==0)
1972 MCAuto<DataArrayIdType> dftRet(DataArrayIdType::New()); dftRet->alloc(0,1); arr=dftRet.retn(); arr->setName(other->getName());
1975 DataArrayIdType *commonCells(nullptr),*commonCellsI(nullptr);
1976 mesh->findCommonCells(compType,nbOfCells,commonCells,commonCellsI);
1977 MCAuto<DataArrayIdType> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1978 mcIdType newNbOfCells=-1;
1979 MCAuto<DataArrayIdType> o2n = DataArrayIdType::ConvertIndexArrayToO2N(ToIdType(mesh->getNumberOfCells()),commonCells->begin(),commonCellsI->begin(),commonCellsI->end(),newNbOfCells);
1980 MCAuto<DataArrayIdType> p0(o2n->selectByTupleIdSafeSlice(0,nbOfCells,1));
1981 mcIdType maxPart(p0->getMaxValueInArray());
1982 bool ret(maxPart==newNbOfCells-1);
1983 MCAuto<DataArrayIdType> p1(p0->invertArrayO2N2N2O(newNbOfCells));
1984 // fill p1 array in case of presence of cells in other not in this
1985 mcIdType *pt(p1->getPointer());
1986 for(mcIdType i = maxPart ; i < newNbOfCells-1 ; ++i )
1989 MCAuto<DataArrayIdType> p2(o2n->subArray(nbOfCells));
1990 p2->transformWithIndArr(p1->begin(),p1->end()); p2->setName(other->getName());
1996 * This method makes the assumption that \a this and \a other share the same coords. If not an exception will be thrown !
1997 * This method tries to determine if \b other is fully included in \b this.
1998 * The main difference is that this method is not expected to throw exception.
1999 * This method has two outputs :
2001 * \param other other mesh
2002 * \param arr is an output parameter that returns a \b newly created instance. This array is of size 'other->getNumberOfCells()'.
2003 * \return If \a other is fully included in 'this 'true is returned. If not false is returned.
2005 bool MEDCouplingUMesh::areCellsIncludedInPolicy7(const MEDCouplingUMesh *other, DataArrayIdType *& arr) const
2007 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
2008 DataArrayIdType *commonCells=0,*commonCellsI=0;
2009 mcIdType thisNbCells=getNumberOfCells();
2010 mesh->findCommonCells(7,thisNbCells,commonCells,commonCellsI);
2011 MCAuto<DataArrayIdType> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
2012 const mcIdType *commonCellsPtr=commonCells->getConstPointer(),*commonCellsIPtr=commonCellsI->getConstPointer();
2013 mcIdType otherNbCells=other->getNumberOfCells();
2014 MCAuto<DataArrayIdType> arr2=DataArrayIdType::New();
2015 arr2->alloc(otherNbCells,1);
2016 arr2->fillWithZero();
2017 mcIdType *arr2Ptr=arr2->getPointer();
2018 mcIdType nbOfCommon=commonCellsI->getNumberOfTuples()-1;
2019 for(mcIdType i=0;i<nbOfCommon;i++)
2021 mcIdType start=commonCellsPtr[commonCellsIPtr[i]];
2022 if(start<thisNbCells)
2024 for(mcIdType j=commonCellsIPtr[i]+1;j!=commonCellsIPtr[i+1];j++)
2026 mcIdType sig=commonCellsPtr[j]>0?1:-1;
2027 mcIdType val=std::abs(commonCellsPtr[j])-1;
2028 if(val>=thisNbCells)
2029 arr2Ptr[val-thisNbCells]=sig*(start+1);
2033 arr2->setName(other->getName());
2034 if(arr2->presenceOfValue(0))
2040 MEDCouplingUMesh *MEDCouplingUMesh::mergeMyselfWithOnSameCoords(const MEDCouplingPointSet *other) const
2043 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : input other is null !");
2044 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
2046 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : the input other mesh is not of type unstructured !");
2047 std::vector<const MEDCouplingUMesh *> ms(2);
2050 return MergeUMeshesOnSameCoords(ms);
2054 * Build a sub part of \b this lying or not on the same coordinates than \b this (regarding value of \b keepCoords).
2055 * By default coordinates are kept. This method is close to MEDCouplingUMesh::buildPartOfMySelf except that here input
2056 * cellIds is not given explicitly but by a range python like.
2058 * \param start starting ID
2059 * \param end end ID (excluded)
2060 * \param step step size
2061 * \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.
2062 * \return a newly allocated
2064 * \warning This method modifies can generate an unstructured mesh whose cells are not sorted by geometric type order.
2065 * In view of the MED file writing, a renumbering of cells of returned unstructured mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
2067 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfSlice(mcIdType start, mcIdType end, mcIdType step, bool keepCoords) const
2069 if(getMeshDimension()!=-1)
2070 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelfSlice(start,end,step,keepCoords));
2073 mcIdType newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfSlice for -1 dimension mesh ");
2075 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
2077 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
2079 return const_cast<MEDCouplingUMesh *>(this);
2084 * Creates a new MEDCouplingUMesh containing specified cells of \a this mesh.
2085 * The result mesh shares or not the node coordinates array with \a this mesh depending
2086 * on \a keepCoords parameter.
2087 * \warning Cells of the result mesh can be \b not sorted by geometric type, hence,
2088 * to write this mesh to the MED file, its cells must be sorted using
2089 * sortCellsInMEDFileFrmt().
2090 * \param [in] begin - an array of cell ids to include to the new mesh.
2091 * \param [in] end - a pointer to last-plus-one-th element of \a begin.
2092 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2093 * array of \a this mesh, else "free" nodes are removed from the result mesh
2094 * by calling zipCoords().
2095 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2096 * to delete this mesh using decrRef() as it is no more needed.
2097 * \throw If the coordinates array is not set.
2098 * \throw If the nodal connectivity of cells is not defined.
2099 * \throw If any cell id in the array \a begin is not valid.
2101 * \if ENABLE_EXAMPLES
2102 * \ref cpp_mcumesh_buildPartOfMySelf "Here is a C++ example".<br>
2103 * \ref py_mcumesh_buildPartOfMySelf "Here is a Python example".
2106 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelf(const mcIdType *begin, const mcIdType *end, bool keepCoords) const
2108 if(getMeshDimension()!=-1)
2109 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelf(begin,end,keepCoords));
2113 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
2115 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
2117 return const_cast<MEDCouplingUMesh *>(this);
2122 * This method operates only on nodal connectivity on \b this. Coordinates of \b this is completely ignored here.
2124 * 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.
2125 * Size of [ \b cellIdsBg, \b cellIdsEnd ) ) must be equal to the number of cells of otherOnSameCoordsThanThis.
2126 * The number of cells of \b this will remain the same with this method.
2128 * \param [in] cellIdsBg begin of cell ids (included) of cells in this to assign
2129 * \param [in] cellIdsEnd end of cell ids (excluded) of cells in this to assign
2130 * \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 ).
2131 * Coordinate pointer of \b this and those of \b otherOnSameCoordsThanThis must be the same
2133 void MEDCouplingUMesh::setPartOfMySelf(const mcIdType *cellIdsBg, const mcIdType *cellIdsEnd, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2135 checkConnectivityFullyDefined();
2136 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2137 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2138 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelf : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2139 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2141 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2142 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2143 throw INTERP_KERNEL::Exception(oss.str());
2145 mcIdType nbOfCellsToModify( ToIdType((std::distance(cellIdsBg,cellIdsEnd))));
2146 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2148 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2149 throw INTERP_KERNEL::Exception(oss.str());
2151 mcIdType nbOfCells(getNumberOfCells());
2152 bool easyAssign(true);
2153 const mcIdType *connI(_nodal_connec_index->begin());
2154 const mcIdType *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->begin();
2155 for(const mcIdType *it=cellIdsBg;it!=cellIdsEnd && easyAssign;it++,connIOther++)
2157 if(*it>=0 && *it<nbOfCells)
2159 easyAssign=(connIOther[1]-connIOther[0])==(connI[*it+1]-connI[*it]);
2163 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : On pos #" << std::distance(cellIdsBg,it) << " id is equal to " << *it << " which is not in [0," << nbOfCells << ") !";
2164 throw INTERP_KERNEL::Exception(oss.str());
2169 DataArrayIdType::SetPartOfIndexedArraysSameIdx(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2174 DataArrayIdType *arrOut=0,*arrIOut=0;
2175 DataArrayIdType::SetPartOfIndexedArrays(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2177 MCAuto<DataArrayIdType> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2178 setConnectivity(arrOut,arrIOut,true);
2182 void MEDCouplingUMesh::setPartOfMySelfSlice(mcIdType start, mcIdType end, mcIdType step, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2184 checkConnectivityFullyDefined();
2185 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2186 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2187 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelfSlice : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2188 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2190 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2191 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2192 throw INTERP_KERNEL::Exception(oss.str());
2194 mcIdType nbOfCellsToModify=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::setPartOfMySelfSlice : ");
2195 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2197 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2198 throw INTERP_KERNEL::Exception(oss.str());
2200 mcIdType nbOfCells=getNumberOfCells();
2201 bool easyAssign=true;
2202 const mcIdType *connI=_nodal_connec_index->getConstPointer();
2203 const mcIdType *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2205 for(mcIdType i=0;i<nbOfCellsToModify && easyAssign;i++,it+=step,connIOther++)
2207 if(it>=0 && it<nbOfCells)
2209 easyAssign=(connIOther[1]-connIOther[0])==(connI[it+1]-connI[it]);
2213 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : On pos #" << i << " id is equal to " << it << " which is not in [0," << nbOfCells << ") !";
2214 throw INTERP_KERNEL::Exception(oss.str());
2219 DataArrayIdType::SetPartOfIndexedArraysSameIdxSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2224 DataArrayIdType *arrOut=0,*arrIOut=0;
2225 DataArrayIdType::SetPartOfIndexedArraysSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2227 MCAuto<DataArrayIdType> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2228 setConnectivity(arrOut,arrIOut,true);
2234 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2235 * this->getMeshDimension(), that bound some cells of \a this mesh.
2236 * The cells of lower dimension to include to the result mesh are selected basing on
2237 * specified node ids and the value of \a fullyIn parameter. If \a fullyIn ==\c true, a
2238 * cell is copied if its all nodes are in the array \a begin of node ids. If \a fullyIn
2239 * ==\c false, a cell is copied if any its node is in the array of node ids. The
2240 * created mesh shares the node coordinates array with \a this mesh.
2241 * \param [in] begin - the array of node ids.
2242 * \param [in] end - a pointer to the (last+1)-th element of \a begin.
2243 * \param [in] fullyIn - if \c true, then cells whose all nodes are in the
2244 * array \a begin are added, else cells whose any node is in the
2245 * array \a begin are added.
2246 * \return MEDCouplingUMesh * - new instance of MEDCouplingUMesh. The caller is
2247 * to delete this mesh using decrRef() as it is no more needed.
2248 * \throw If the coordinates array is not set.
2249 * \throw If the nodal connectivity of cells is not defined.
2250 * \throw If any node id in \a begin is not valid.
2252 * \if ENABLE_EXAMPLES
2253 * \ref cpp_mcumesh_buildFacePartOfMySelfNode "Here is a C++ example".<br>
2254 * \ref py_mcumesh_buildFacePartOfMySelfNode "Here is a Python example".
2257 MEDCouplingUMesh *MEDCouplingUMesh::buildFacePartOfMySelfNode(const mcIdType *begin, const mcIdType *end, bool fullyIn) const
2259 MCAuto<DataArrayIdType> desc,descIndx,revDesc,revDescIndx;
2260 desc=DataArrayIdType::New(); descIndx=DataArrayIdType::New(); revDesc=DataArrayIdType::New(); revDescIndx=DataArrayIdType::New();
2261 MCAuto<MEDCouplingUMesh> subMesh=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2262 desc=0; descIndx=0; revDesc=0; revDescIndx=0;
2263 return static_cast<MEDCouplingUMesh*>(subMesh->buildPartOfMySelfNode(begin,end,fullyIn));
2267 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2268 * this->getMeshDimension(), which bound only one cell of \a this mesh.
2269 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2270 * array of \a this mesh, else "free" nodes are removed from the result mesh
2271 * by calling zipCoords().
2272 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2273 * to delete this mesh using decrRef() as it is no more needed.
2274 * \throw If the coordinates array is not set.
2275 * \throw If the nodal connectivity of cells is not defined.
2277 * \if ENABLE_EXAMPLES
2278 * \ref cpp_mcumesh_buildBoundaryMesh "Here is a C++ example".<br>
2279 * \ref py_mcumesh_buildBoundaryMesh "Here is a Python example".
2282 MEDCouplingUMesh *MEDCouplingUMesh::buildBoundaryMesh(bool keepCoords) const
2284 DataArrayIdType *desc=DataArrayIdType::New();
2285 DataArrayIdType *descIndx=DataArrayIdType::New();
2286 DataArrayIdType *revDesc=DataArrayIdType::New();
2287 DataArrayIdType *revDescIndx=DataArrayIdType::New();
2289 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2292 descIndx->decrRef();
2293 mcIdType nbOfCells=meshDM1->getNumberOfCells();
2294 const mcIdType *revDescIndxC=revDescIndx->getConstPointer();
2295 std::vector<mcIdType> boundaryCells;
2296 for(mcIdType i=0;i<nbOfCells;i++)
2297 if(revDescIndxC[i+1]-revDescIndxC[i]==1)
2298 boundaryCells.push_back(i);
2299 revDescIndx->decrRef();
2300 MEDCouplingUMesh *ret=meshDM1->buildPartOfMySelf(&boundaryCells[0],&boundaryCells[0]+boundaryCells.size(),keepCoords);
2305 * This method returns a newly created DataArrayIdType instance containing ids of cells located in boundary.
2306 * A cell is detected to be on boundary if it contains one or more than one face having only one father.
2307 * This method makes the assumption that \a this is fully defined (coords,connectivity). If not an exception will be thrown.
2309 DataArrayIdType *MEDCouplingUMesh::findCellIdsOnBoundary() const
2311 checkFullyDefined();
2312 MCAuto<DataArrayIdType> ret2(DataArrayIdType::New());
2314 if (getNumberOfCells() == 0)
2320 MCAuto<DataArrayIdType> desc(DataArrayIdType::New()), descIndx(DataArrayIdType::New()), revDesc(DataArrayIdType::New()), revDescIndx(DataArrayIdType::New());
2322 buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx)->decrRef();
2323 desc=(DataArrayIdType*)0; descIndx=(DataArrayIdType*)0;
2325 MCAuto<DataArrayIdType> tmp=revDescIndx->deltaShiftIndex();
2326 MCAuto<DataArrayIdType> faceIds=tmp->findIdsEqual(1); tmp=(DataArrayIdType*)0;
2327 const mcIdType *revDescPtr=revDesc->getConstPointer();
2328 const mcIdType *revDescIndxPtr=revDescIndx->getConstPointer();
2329 mcIdType nbOfCells=getNumberOfCells();
2330 std::vector<bool> ret1(nbOfCells,false);
2332 for(const mcIdType *pt=faceIds->begin();pt!=faceIds->end();pt++)
2333 if(!ret1[revDescPtr[revDescIndxPtr[*pt]]])
2334 { ret1[revDescPtr[revDescIndxPtr[*pt]]]=true; sz++; }
2337 mcIdType *ret2Ptr=ret2->getPointer();
2339 for(std::vector<bool>::const_iterator it=ret1.begin();it!=ret1.end();it++,sz++)
2342 ret2->setName("BoundaryCells");
2347 * This method finds in \b this the cell ids that lie on mesh \b otherDimM1OnSameCoords.
2348 * \b this and \b otherDimM1OnSameCoords have to lie on the same coordinate array pointer. The coherency of that coords array with connectivity
2349 * of \b this and \b otherDimM1OnSameCoords is not important here because this method works only on connectivity.
2350 * this->getMeshDimension() - 1 must be equal to otherDimM1OnSameCoords.getMeshDimension()
2352 * s0 is the cell ids set in \b this lying on at least one node in the fetched nodes in \b otherDimM1OnSameCoords.
2353 * 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
2354 * equals a cell in \b otherDimM1OnSameCoords.
2356 * \throw if \b otherDimM1OnSameCoords is not part of constituent of \b this, or if coordinate pointer of \b this and \b otherDimM1OnSameCoords
2357 * are not same, or if this->getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension()
2359 * \param [in] otherDimM1OnSameCoords other mesh
2360 * \param [out] cellIdsRk0 a newly allocated array containing the cell ids of s0 (which are cell ids of \b this) in the above algorithm.
2361 * \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
2362 * cellIdsRk1->transformWithIndArr(cellIdsRk0->begin(),cellIdsRk0->end());
2364 void MEDCouplingUMesh::findCellIdsLyingOn(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayIdType *&cellIdsRk0, DataArrayIdType *&cellIdsRk1) const
2366 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2367 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : coordinates pointer are not the same ! Use tryToShareSameCoords method !");
2368 checkConnectivityFullyDefined();
2369 otherDimM1OnSameCoords.checkConnectivityFullyDefined();
2370 if(getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension())
2371 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : invalid mesh dimension of input mesh regarding meshdimesion of this !");
2372 MCAuto<DataArrayIdType> fetchedNodeIds1=otherDimM1OnSameCoords.computeFetchedNodeIds();
2373 MCAuto<DataArrayIdType> s0arr=getCellIdsLyingOnNodes(fetchedNodeIds1->begin(),fetchedNodeIds1->end(),false);
2374 MCAuto<MEDCouplingUMesh> thisPart=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(s0arr->begin(),s0arr->end(),true));
2375 MCAuto<DataArrayIdType> descThisPart=DataArrayIdType::New(),descIThisPart=DataArrayIdType::New(),revDescThisPart=DataArrayIdType::New(),revDescIThisPart=DataArrayIdType::New();
2376 MCAuto<MEDCouplingUMesh> thisPartConsti=thisPart->buildDescendingConnectivity(descThisPart,descIThisPart,revDescThisPart,revDescIThisPart);
2377 const mcIdType *revDescThisPartPtr=revDescThisPart->getConstPointer(),*revDescIThisPartPtr=revDescIThisPart->getConstPointer();
2378 DataArrayIdType *idsOtherInConsti=0;
2379 bool b=thisPartConsti->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsOtherInConsti);
2380 MCAuto<DataArrayIdType> idsOtherInConstiAuto(idsOtherInConsti);
2382 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : the given mdim-1 mesh in other is not a constituent of this !");
2383 std::set<mcIdType> s1;
2384 for(const mcIdType *idOther=idsOtherInConsti->begin();idOther!=idsOtherInConsti->end();idOther++)
2385 s1.insert(revDescThisPartPtr+revDescIThisPartPtr[*idOther],revDescThisPartPtr+revDescIThisPartPtr[*idOther+1]);
2386 MCAuto<DataArrayIdType> s1arr_renum1=DataArrayIdType::New(); s1arr_renum1->alloc(s1.size(),1); std::copy(s1.begin(),s1.end(),s1arr_renum1->getPointer());
2387 s1arr_renum1->sort();
2388 cellIdsRk0=s0arr.retn();
2389 //cellIdsRk1=s_renum1.retn();
2390 cellIdsRk1=s1arr_renum1.retn();
2394 * 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
2395 * returned. This subpart of meshdim-1 mesh is built using meshdim-1 cells in it shared only one cell in \b this.
2397 * \return a newly allocated mesh lying on the same coordinates than \b this. The caller has to deal with returned mesh.
2399 MEDCouplingUMesh *MEDCouplingUMesh::computeSkin() const
2401 MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
2402 MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
2403 MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
2404 MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
2406 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2407 revDesc=0; desc=0; descIndx=0;
2408 MCAuto<DataArrayIdType> revDescIndx2=revDescIndx->deltaShiftIndex();
2409 MCAuto<DataArrayIdType> part=revDescIndx2->findIdsEqual(1);
2410 return static_cast<MEDCouplingUMesh *>(meshDM1->buildPartOfMySelf(part->begin(),part->end(),true));
2414 * Finds nodes lying on the boundary of \a this mesh.
2415 * \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of found
2416 * nodes. The caller is to delete this array using decrRef() as it is no
2418 * \throw If the coordinates array is not set.
2419 * \throw If the nodal connectivity of cells is node defined.
2421 * \if ENABLE_EXAMPLES
2422 * \ref cpp_mcumesh_findBoundaryNodes "Here is a C++ example".<br>
2423 * \ref py_mcumesh_findBoundaryNodes "Here is a Python example".
2426 DataArrayIdType *MEDCouplingUMesh::findBoundaryNodes() const
2428 MCAuto<MEDCouplingUMesh> skin=computeSkin();
2429 return skin->computeFetchedNodeIds();
2432 MEDCouplingUMesh *MEDCouplingUMesh::buildUnstructured() const
2435 return const_cast<MEDCouplingUMesh *>(this);
2439 * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2440 * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2441 * This method searches for nodes needed to be duplicated. Those are the nodes fetched by \b otherDimM1OnSameCoords which are not part of the boundary of \b otherDimM1OnSameCoords.
2442 * If a node is in the boundary of \b this \b and in the boundary of \b otherDimM1OnSameCoords, it will be duplicated.
2443 * 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.
2445 * \param [in] crackingMesh 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
2446 * parameter is altered during the call.
2447 * \return node ids which need to be duplicated following the algorithm explained above.
2450 DataArrayIdType* MEDCouplingUMesh::findNodesToDuplicate(const MEDCouplingUMesh& crackingMesh) const
2452 // DEBUG NOTE: in case of issue with the algorithm in this method, see Python script in resources/dev
2453 // which mimicks the C++
2454 using DAInt = MCAuto<DataArrayIdType>;
2455 using MCUMesh = MCAuto<MEDCouplingUMesh>;
2457 checkFullyDefined();
2458 crackingMesh.checkFullyDefined();
2459 if(getCoords()!=crackingMesh.getCoords())
2460 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : meshes do not share the same coords array !");
2461 if(crackingMesh.getMeshDimension()!=getMeshDimension()-1)
2462 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the mesh given in other parameter must have this->getMeshDimension()-1 !");
2464 // Clean the M1 group (cracking mesh): the M1 cells which are part of M0 boundary are irrelevant (we can't create a crack on the boundary of M0!)
2465 MCUMesh m0skin = computeSkin();
2466 DataArrayIdType *idsToKeepP;
2467 m0skin->areCellsIncludedIn(&crackingMesh,2, idsToKeepP);
2468 DAInt idsToKeep(idsToKeepP);
2469 DAInt ids2 = idsToKeep->findIdsNotInRange(0, m0skin->getNumberOfCells()); // discard cells on the skin of M0
2470 MCUMesh otherDimM1OnSameCoords =static_cast<MEDCouplingUMesh *>(crackingMesh.buildPartOfMySelf(ids2->begin(), ids2->end(), true));
2472 if (!otherDimM1OnSameCoords->getNumberOfCells())
2473 return MCAuto<DataArrayIdType>(DataArrayIdType::New()).retn();
2475 // Checking star-shaped M1 group:
2476 DAInt dt0=DataArrayIdType::New(),dit0=DataArrayIdType::New(),rdt0=DataArrayIdType::New(),rdit0=DataArrayIdType::New();
2477 MCUMesh meshM2 = otherDimM1OnSameCoords->buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); // 2D: a mesh of points, 3D: a mesh of segs
2478 DAInt dsi = rdit0->deltaShiftIndex();
2479 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.
2480 if(idsTmp0->getNumberOfTuples())
2481 throw INTERP_KERNEL::Exception("MEDFileUMesh::buildInnerBoundaryAlongM1Group: group is too complex: some points (or edges) have more than two connected segments (or faces)!");
2482 dt0=0; dit0=0; rdt0=0; rdit0=0; idsTmp0=0;
2484 // Get extreme nodes from the group (they won't be duplicated except if they also lie on bound of M0 -- see below),
2485 // ie nodes belonging to the boundary "cells" (might be points) of M1
2486 DAInt xtremIdsM2 = dsi->findIdsEqual(1); dsi = 0;
2487 MCUMesh meshM2Part = static_cast<MEDCouplingUMesh *>(meshM2->buildPartOfMySelf(xtremIdsM2->begin(), xtremIdsM2->end(),true));
2488 DAInt xtrem = meshM2Part->computeFetchedNodeIds();
2489 // Remove from the list points on the boundary of the M0 mesh (those need duplication!).
2490 // 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)
2491 // 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
2492 // although they are technically on the skin of the cube.
2493 DAInt fNodes = m0skin->computeFetchedNodeIds();
2495 if (getMeshDimension() == 3)
2497 DAInt dnu1=DataArrayIdType::New(), dnu2=DataArrayIdType::New(), dnu3=DataArrayIdType::New(), dnu4=DataArrayIdType::New();
2498 MCUMesh m0skinDesc = m0skin->buildDescendingConnectivity(dnu1, dnu2, dnu3, dnu4); // all segments of the skin of the 3D (M0) mesh
2499 dnu1=0;dnu2=0;dnu3=0;dnu4=0;
2500 DataArrayIdType * corresp=0;
2501 meshM2->areCellsIncludedIn(m0skinDesc,2,corresp);
2502 // validIds is the list of segments which are on both the skin of *this*, and in the segments of the M1 group
2503 // In the cube example above, this is a U-shaped polyline.
2504 DAInt validIds = corresp->findIdsInRange(0, meshM2->getNumberOfCells());
2506 if (validIds->getNumberOfTuples())
2508 // 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:
2509 // (the U-shaped polyline described above)
2510 MCUMesh m1IntersecSkin = static_cast<MEDCouplingUMesh *>(m0skinDesc->buildPartOfMySelf(validIds->begin(), validIds->end(), true));
2511 // Its boundary nodes should no be duplicated (this is for example the tip of the crack inside the cube described above)
2512 DAInt notDuplSkin = m1IntersecSkin->findBoundaryNodes();
2513 DAInt fNodes1 = fNodes->buildSubstraction(notDuplSkin);
2515 // Specific logic to handle singular points :
2516 // - a point on this U-shape line used in a cell which has no face in common with M1 is deemed singular.
2517 // - indeed, if duplicated, such a point would lead to the duplication of a cell which has no face touching M1 ! The
2518 // algorithm would be duplicating too much ...
2519 // 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:
2520 dnu1=DataArrayIdType::New(), dnu2=DataArrayIdType::New(), dnu3=DataArrayIdType::New(), rdit0=DataArrayIdType::New();
2521 MCUMesh meshM2Desc = meshM2->buildDescendingConnectivity(dnu1, dnu2, dnu3, rdit0); // a mesh made of node cells
2522 dnu1=0;dnu2=0;dnu3=0;
2523 dsi = rdit0->deltaShiftIndex(); rdit0=0;
2524 DAInt singPoints = dsi->findIdsNotInRange(-1,4) ; dsi=0;// points connected to (strictly) more than 3 segments
2525 if (singPoints->getNumberOfTuples())
2527 DAInt boundNodes = m1IntersecSkin->computeFetchedNodeIds();
2528 // If a point on this U-shape line is connected to cells which do not share any face with M1, then it
2529 // should not be duplicated
2530 // 1. Extract N D cells touching U-shape line:
2531 DAInt cellsAroundBN = getCellIdsLyingOnNodes(boundNodes->begin(), boundNodes->end(), false); // false= take cell in, even if not all nodes are in dupl
2532 MCUMesh mAroundBN = static_cast<MEDCouplingUMesh *>(this->buildPartOfMySelf(cellsAroundBN->begin(), cellsAroundBN->end(), true));
2533 DAInt descBN=DataArrayIdType::New(), descIBN=DataArrayIdType::New(), revDescBN=DataArrayIdType::New(), revDescIBN=DataArrayIdType::New();
2534 MCUMesh mAroundBNDesc = mAroundBN->buildDescendingConnectivity(descBN,descIBN,revDescBN,revDescIBN);
2535 // 2. Identify cells in sub-mesh mAroundBN which have a face in common with M1
2536 DataArrayIdType *idsOfM1BNt;
2537 mAroundBNDesc->areCellsIncludedIn(otherDimM1OnSameCoords,2, idsOfM1BNt);
2538 DAInt idsOfM1BN(idsOfM1BNt);
2539 mcIdType nCells=mAroundBN->getNumberOfCells(), nCellsDesc=mAroundBNDesc->getNumberOfCells();
2540 DAInt idsTouch=DataArrayIdType::New(); idsTouch->alloc(0,1);
2541 const mcIdType *revDescIBNP=revDescIBN->begin(), *revDescBNP=revDescBN->begin();
2542 for(const auto& v: *idsOfM1BN)
2544 if (v >= nCellsDesc) // Keep valid match only
2546 mcIdType idx0 = revDescIBNP[v];
2547 // Keep the two cells on either side of the face v of M1:
2548 mcIdType c1=revDescBNP[idx0], c2=revDescBNP[idx0+1];
2549 idsTouch->pushBackSilent(c1); idsTouch->pushBackSilent(c2);
2551 // 3. Build complement
2552 DAInt idsTouchCompl = idsTouch->buildComplement(nCells);
2553 MCUMesh mAroundBNStrict = static_cast<MEDCouplingUMesh *>(mAroundBN->buildPartOfMySelf(idsTouchCompl->begin(), idsTouchCompl->end(), true));
2554 DAInt nod3 = mAroundBNStrict->computeFetchedNodeIds();
2555 DAInt inters = boundNodes->buildIntersection(nod3);
2556 fNodes1 = fNodes1->buildSubstraction(inters); // reminder: fNodes1 represent nodes that need dupl.
2558 notDup = xtrem->buildSubstraction(fNodes1);
2560 else // if (validIds-> ...)
2561 notDup = xtrem->buildSubstraction(fNodes);
2564 notDup = xtrem->buildSubstraction(fNodes);
2566 DAInt m1Nodes = otherDimM1OnSameCoords->computeFetchedNodeIds();
2567 DAInt dupl = m1Nodes->buildSubstraction(notDup);
2573 * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2574 * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2575 * This method is part of the MEDFileUMesh::buildInnerBoundaryAlongM1Group() algorithm.
2576 * Given a set of nodes to duplicate, this method identifies which cells should have their connectivity modified
2577 * to produce the inner boundary. It is typically called after findNodesToDuplicate().
2579 * \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.
2580 * \param [in] nodeIdsToDuplicateBg node ids needed to be duplicated, as returned by findNodesToDuplicate.
2581 * \param [in] nodeIdsToDuplicateEnd node ids needed to be duplicated, as returned by findNodesToDuplicate.
2582 * \param [out] cellIdsNeededToBeRenum cell ids in \b this in which the renumber of nodes should be performed.
2583 * \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.
2586 void MEDCouplingUMesh::findCellsToRenumber(const MEDCouplingUMesh& otherDimM1OnSameCoords, const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd,
2587 DataArrayIdType *& cellIdsNeededToBeRenum, DataArrayIdType *& cellIdsNotModified) const
2589 using DAInt = MCAuto<DataArrayIdType>;
2590 using MCUMesh = MCAuto<MEDCouplingUMesh>;
2592 checkFullyDefined();
2593 otherDimM1OnSameCoords.checkFullyDefined();
2594 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2595 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellsToRenumber: meshes do not share the same coords array !");
2596 if(otherDimM1OnSameCoords.getMeshDimension()!=getMeshDimension()-1)
2597 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellsToRenumber: the mesh given in other parameter must have this->getMeshDimension()-1 !");
2599 // Degenerated case - no nodes to duplicate
2600 if (nodeIdsToDuplicateBg == nodeIdsToDuplicateEnd)
2602 cellIdsNeededToBeRenum = DataArrayIdType::New(); cellIdsNeededToBeRenum->alloc(0,1);
2603 cellIdsNotModified = DataArrayIdType::New(); cellIdsNotModified->alloc(0,1);
2607 // Compute cell IDs of the mesh with cells that touch the M1 group with a least one node:
2608 DAInt cellsAroundGroupLarge = getCellIdsLyingOnNodes(nodeIdsToDuplicateBg, nodeIdsToDuplicateEnd, false); // false= take cell in, even if not all nodes are in dupl
2609 MCUMesh mAroundGrpLarge=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(cellsAroundGroupLarge->begin(),cellsAroundGroupLarge->end(),true));
2610 mcIdType nCellsLarge=cellsAroundGroupLarge->getNumberOfTuples();
2611 DAInt descL=DataArrayIdType::New(),descIL=DataArrayIdType::New(),revDescL=DataArrayIdType::New(),revDescIL=DataArrayIdType::New();
2612 MCUMesh mArGrpLargeDesc=mAroundGrpLarge->buildDescendingConnectivity(descL,descIL,revDescL,revDescIL);
2613 const mcIdType *descILP=descIL->begin(), *descLP=descL->begin();
2614 DataArrayIdType *idsOfM1t;
2615 mArGrpLargeDesc->areCellsIncludedIn(&otherDimM1OnSameCoords,2, idsOfM1t);
2616 DAInt idsOfM1Large(idsOfM1t);
2617 mcIdType nL = mArGrpLargeDesc->getNumberOfCells();
2619 // Computation of the neighbor information of the mesh WITH the crack (some neighbor links are removed):
2620 // In the neighbor information remove the connection between high dimension cells and its low level constituents which are part
2621 // of the frontier given in parameter (i.e. the cells of low dimension from the group delimiting the crack):
2622 DAInt descLTrunc = descL->deepCopy(), descILTrunc = descIL->deepCopy();
2623 DataArrayIdType::RemoveIdsFromIndexedArrays(idsOfM1Large->begin(), idsOfM1Large->end(),descLTrunc,descILTrunc);
2624 DataArrayIdType *neight=0, *neighIt=0;
2625 MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(descLTrunc,descILTrunc,revDescL,revDescIL, neight, neighIt);
2626 DAInt neighL(neight), neighIL(neighIt);
2628 DAInt hitCellsLarge = DataArrayIdType::New(); hitCellsLarge->alloc(nCellsLarge,1);
2629 hitCellsLarge->fillWithValue(0); // 0 : not hit, +1: one side of the crack, -1: other side of the crack,
2630 mcIdType* hitCellsLargeP = hitCellsLarge->rwBegin();
2632 // Now loop on the faces of the M1 group and fill spread zones on either side of the crack:
2633 const mcIdType *revDescILP=revDescIL->begin(), *revDescLP=revDescL->begin();
2634 for(const auto& v: *idsOfM1Large)
2636 if (v >= nL) continue; // Keep valid match only - see doc of areCellsIncludedIn()
2637 mcIdType idx0 = revDescILP[v];
2638 // Retrieve the two cells on either side of the face v of M1:
2639 mcIdType c1=revDescLP[idx0], c2=revDescLP[idx0+1];
2640 std::map<mcIdType, mcIdType> toOther = {{c1, c2}, {c2, c1}};
2641 // Handle the spread zones on the two sides of the crack:
2642 for (const auto c: {c1, c2})
2644 if (hitCellsLargeP[c]) continue;
2645 // Identify connex zone around this cell - if we find a value already assigned there, use it.
2647 DAInt spreadZone = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&c, &c+1, neighL,neighIL, -1, dnu);
2648 std::set<mcIdType> sv;
2649 for (const mcIdType& s: *spreadZone)
2650 if (hitCellsLargeP[s]) sv.insert(hitCellsLargeP[s]);
2652 // Strange: we find in the same spread zone a +1 and -1 !
2653 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellsToRenumber: internal error #0 - conflicting values - should not happen!");
2654 // If a valid value was found, use it:
2655 mcIdType val = sv.size()==1 ? *sv.begin() : 0;
2656 // Hopefully this does not conflict with an potential value on the other side:
2657 mcIdType other = toOther[c];
2658 if (hitCellsLargeP[other])
2660 if(val && hitCellsLargeP[other] != -val)
2661 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellsToRenumber: internal error #1 - conflicting values - should not happen!");;
2662 // We do not yet have a value, but other side has one. Use it!
2663 if(!val) val = -hitCellsLargeP[other];
2665 // Cover first initialisation:
2667 // And finally, fill the current spread zone:
2668 for(const mcIdType& s: *spreadZone) hitCellsLargeP[s] = val;
2672 DAInt cellsRet1 = hitCellsLarge->findIdsEqual(1);
2673 DAInt cellsRet2 = hitCellsLarge->findIdsEqual(-1);
2675 if (cellsRet1->getNumberOfTuples() + cellsRet2->getNumberOfTuples() != cellsAroundGroupLarge->getNumberOfTuples())
2677 DAInt nonHitCells = hitCellsLarge->findIdsEqual(0); // variable kept for debug ...
2678 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellsToRenumber: Some cells not hit - Internal error should not happen");
2680 cellsRet1->transformWithIndArr(cellsAroundGroupLarge->begin(),cellsAroundGroupLarge->end());
2681 cellsRet2->transformWithIndArr(cellsAroundGroupLarge->begin(),cellsAroundGroupLarge->end());
2683 cellIdsNeededToBeRenum=cellsRet1.retn();
2684 cellIdsNotModified=cellsRet2.retn();
2688 * This method operates a modification of the connectivity and coords in \b this.
2689 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2690 * its ids will be modified to id this->getNumberOfNodes()+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2691 * 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
2692 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id this->getNumberOfNodes()+0, node id nodeIdsToDuplicateBg[1] will have id this->getNumberOfNodes()+1,
2693 * node id nodeIdsToDuplicateBg[2] will have id this->getNumberOfNodes()+2...
2695 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2697 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2698 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2700 void MEDCouplingUMesh::duplicateNodes(const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd)
2702 mcIdType nbOfNodes=getNumberOfNodes();
2703 duplicateNodesInCoords(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd);
2704 duplicateNodesInConn(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,nbOfNodes);
2708 * This method renumbers only nodal connectivity in \a this. The renumbering is only an offset applied. So this method is a specialization of
2709 * \a renumberNodesInConn. \b WARNING, this method does not check that the resulting node ids in the nodal connectivity is in a valid range !
2711 * \param [in] offset - specifies the offset to be applied on each element of connectivity.
2713 * \sa renumberNodesInConn
2715 void MEDCouplingUMesh::renumberNodesWithOffsetInConn(mcIdType offset)
2717 checkConnectivityFullyDefined();
2718 mcIdType *conn(getNodalConnectivity()->getPointer());
2719 const mcIdType *connIndex(getNodalConnectivityIndex()->getConstPointer());
2720 mcIdType nbOfCells=getNumberOfCells();
2721 for(mcIdType i=0;i<nbOfCells;i++)
2722 for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2724 mcIdType& node=conn[iconn];
2725 if(node>=0)//avoid polyhedron separator
2730 _nodal_connec->declareAsNew();
2735 * Same than renumberNodesInConn(const mcIdType *) except that here the format of old-to-new traducer is using map instead
2736 * 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
2739 void MEDCouplingUMesh::renumberNodesInConn(const INTERP_KERNEL::HashMap<mcIdType,mcIdType>& newNodeNumbersO2N)
2741 this->renumberNodesInConnT< INTERP_KERNEL::HashMap<mcIdType,mcIdType> >(newNodeNumbersO2N);
2745 * Same than renumberNodesInConn(const mcIdType *) except that here the format of old-to-new traducer is using map instead
2746 * 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
2749 void MEDCouplingUMesh::renumberNodesInConn(const std::map<mcIdType,mcIdType>& newNodeNumbersO2N)
2751 this->renumberNodesInConnT< std::map<mcIdType,mcIdType> >(newNodeNumbersO2N);
2755 * Changes ids of nodes within the nodal connectivity arrays according to a permutation
2756 * array in "Old to New" mode. The node coordinates array is \b not changed by this method.
2757 * This method is a generalization of shiftNodeNumbersInConn().
2758 * \warning This method performs no check of validity of new ids. **Use it with care !**
2759 * \param [in] newNodeNumbersO2N - a permutation array, of length \a
2760 * this->getNumberOfNodes(), in "Old to New" mode.
2761 * See \ref numbering for more info on renumbering modes.
2762 * \throw If the nodal connectivity of cells is not defined.
2764 * \if ENABLE_EXAMPLES
2765 * \ref cpp_mcumesh_renumberNodesInConn "Here is a C++ example".<br>
2766 * \ref py_mcumesh_renumberNodesInConn "Here is a Python example".
2769 void MEDCouplingUMesh::renumberNodesInConn(const mcIdType *newNodeNumbersO2N)
2771 checkConnectivityFullyDefined();
2772 mcIdType *conn=getNodalConnectivity()->getPointer();
2773 const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2774 mcIdType nbOfCells=getNumberOfCells();
2775 for(mcIdType i=0;i<nbOfCells;i++)
2776 for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2778 mcIdType& node=conn[iconn];
2779 if(node>=0)//avoid polyhedron separator
2781 node=newNodeNumbersO2N[node];
2784 _nodal_connec->declareAsNew();
2789 * This method renumbers nodes \b in \b connectivity \b only \b without \b any \b reference \b to \b coords.
2790 * This method performs no check on the fact that new coordinate ids are valid. \b Use \b it \b with \b care !
2791 * This method is an specialization of \ref MEDCoupling::MEDCouplingUMesh::renumberNodesInConn "renumberNodesInConn method".
2793 * \param [in] delta specifies the shift size applied to nodeId in nodal connectivity in \b this.
2795 void MEDCouplingUMesh::shiftNodeNumbersInConn(mcIdType delta)
2797 checkConnectivityFullyDefined();
2798 mcIdType *conn=getNodalConnectivity()->getPointer();
2799 const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2800 mcIdType nbOfCells=getNumberOfCells();
2801 for(mcIdType i=0;i<nbOfCells;i++)
2802 for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2804 mcIdType& node=conn[iconn];
2805 if(node>=0)//avoid polyhedron separator
2810 _nodal_connec->declareAsNew();
2815 * This method operates a modification of the connectivity in \b this.
2816 * 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.
2817 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2818 * its ids will be modified to id offset+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2819 * 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
2820 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id offset+0, node id nodeIdsToDuplicateBg[1] will have id offset+1,
2821 * node id nodeIdsToDuplicateBg[2] will have id offset+2...
2823 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2824 * As an another consequense after the call of this method \b this can be transiently non cohrent.
2826 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2827 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2828 * \param [in] offset the offset applied to all node ids in connectivity that are in [ \a nodeIdsToDuplicateBg, \a nodeIdsToDuplicateEnd ).
2830 void MEDCouplingUMesh::duplicateNodesInConn(const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd, mcIdType offset)
2832 checkConnectivityFullyDefined();
2833 std::map<mcIdType,mcIdType> m;
2834 mcIdType val=offset;
2835 for(const mcIdType *work=nodeIdsToDuplicateBg;work!=nodeIdsToDuplicateEnd;work++,val++)
2837 mcIdType *conn=getNodalConnectivity()->getPointer();
2838 const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2839 mcIdType nbOfCells=getNumberOfCells();
2840 for(mcIdType i=0;i<nbOfCells;i++)
2841 for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2843 mcIdType& node=conn[iconn];
2844 if(node>=0)//avoid polyhedron separator
2846 std::map<mcIdType,mcIdType>::iterator it=m.find(node);
2855 * This method renumbers cells of \a this using the array specified by [old2NewBg;old2NewBg+getNumberOfCells())
2857 * Contrary to MEDCouplingPointSet::renumberNodes, this method makes a permutation without any fuse of cell.
2858 * After the call of this method the number of cells remains the same as before.
2860 * If 'check' equals true the method will check that any elements in [ \a old2NewBg; \a old2NewEnd ) is unique ; if not
2861 * an INTERP_KERNEL::Exception will be thrown. When 'check' equals true [ \a old2NewBg ; \a old2NewEnd ) is not expected to
2862 * be strictly in [0;this->getNumberOfCells()).
2864 * If 'check' equals false the method will not check the content of [ \a old2NewBg ; \a old2NewEnd ).
2865 * To avoid any throw of SIGSEGV when 'check' equals false, the elements in [ \a old2NewBg ; \a old2NewEnd ) should be unique and
2866 * should be contained in[0;this->getNumberOfCells()).
2868 * \param [in] old2NewBg is expected to be a dynamically allocated pointer of size at least equal to this->getNumberOfCells()
2869 * \param check whether to check content of old2NewBg
2871 void MEDCouplingUMesh::renumberCells(const mcIdType *old2NewBg, bool check)
2873 checkConnectivityFullyDefined();
2874 mcIdType nbCells=getNumberOfCells();
2875 const mcIdType *array=old2NewBg;
2877 array=DataArrayIdType::CheckAndPreparePermutation(old2NewBg,old2NewBg+nbCells);
2879 const mcIdType *conn=_nodal_connec->getConstPointer();
2880 const mcIdType *connI=_nodal_connec_index->getConstPointer();
2881 MCAuto<DataArrayIdType> o2n=DataArrayIdType::New(); o2n->useArray(array,false,DeallocType::C_DEALLOC,nbCells,1);
2882 MCAuto<DataArrayIdType> n2o=o2n->invertArrayO2N2N2O(nbCells);
2883 const mcIdType *n2oPtr=n2o->begin();
2884 MCAuto<DataArrayIdType> newConn=DataArrayIdType::New();
2885 newConn->alloc(_nodal_connec->getNumberOfTuples(),_nodal_connec->getNumberOfComponents());
2886 newConn->copyStringInfoFrom(*_nodal_connec);
2887 MCAuto<DataArrayIdType> newConnI=DataArrayIdType::New();
2888 newConnI->alloc(_nodal_connec_index->getNumberOfTuples(),_nodal_connec_index->getNumberOfComponents());
2889 newConnI->copyStringInfoFrom(*_nodal_connec_index);
2891 mcIdType *newC=newConn->getPointer();
2892 mcIdType *newCI=newConnI->getPointer();
2895 for(mcIdType i=0;i<nbCells;i++)
2897 mcIdType pos=n2oPtr[i];
2898 mcIdType nbOfElts=connI[pos+1]-connI[pos];
2899 newC=std::copy(conn+connI[pos],conn+connI[pos+1],newC);
2904 setConnectivity(newConn,newConnI);
2906 free(const_cast<mcIdType *>(array));
2910 * Finds cells whose bounding boxes intersect a given bounding box.
2911 * \param [in] bbox - an array defining the bounding box via coordinates of its
2912 * extremum points in "no interlace" mode, i.e. xMin, xMax, yMin, yMax, zMin,
2914 * \param [in] eps - a factor used to increase size of the bounding box of cell
2915 * before comparing it with \a bbox. This factor is multiplied by the maximal
2916 * extent of the bounding box of cell to produce an addition to this bounding box.
2917 * \return DataArrayIdType * - a new instance of DataArrayIdType holding ids for found
2918 * cells. The caller is to delete this array using decrRef() as it is no more
2920 * \throw If the coordinates array is not set.
2921 * \throw If the nodal connectivity of cells is not defined.
2923 * \if ENABLE_EXAMPLES
2924 * \ref cpp_mcumesh_getCellsInBoundingBox "Here is a C++ example".<br>
2925 * \ref py_mcumesh_getCellsInBoundingBox "Here is a Python example".
2928 DataArrayIdType *MEDCouplingUMesh::getCellsInBoundingBox(const double *bbox, double eps) const
2930 MCAuto<DataArrayIdType> elems=DataArrayIdType::New(); elems->alloc(0,1);
2931 if(getMeshDimension()==-1)
2933 elems->pushBackSilent(0);
2934 return elems.retn();
2936 int dim=getSpaceDimension();
2937 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2938 const mcIdType* conn = getNodalConnectivity()->getConstPointer();
2939 const mcIdType* conn_index= getNodalConnectivityIndex()->getConstPointer();
2940 const double* coords = getCoords()->getConstPointer();
2941 mcIdType nbOfCells=getNumberOfCells();
2942 for ( mcIdType ielem=0; ielem<nbOfCells;ielem++ )
2944 for (int i=0; i<dim; i++)
2946 elem_bb[i*2]=std::numeric_limits<double>::max();
2947 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2950 for (mcIdType inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2952 mcIdType node= conn[inode];
2953 if(node>=0)//avoid polyhedron separator
2955 for (int idim=0; idim<dim; idim++)
2957 if ( coords[node*dim+idim] < elem_bb[idim*2] )
2959 elem_bb[idim*2] = coords[node*dim+idim] ;
2961 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2963 elem_bb[idim*2+1] = coords[node*dim+idim] ;
2968 if (intersectsBoundingBox(elem_bb, bbox, dim, eps))
2969 elems->pushBackSilent(ielem);
2971 return elems.retn();
2975 * Given a boundary box 'bbox' returns elements 'elems' contained in this 'bbox' or touching 'bbox' (within 'eps' distance).
2976 * Warning 'elems' is incremented during the call so if elems is not empty before call returned elements will be
2977 * added in 'elems' parameter.
2979 DataArrayIdType *MEDCouplingUMesh::getCellsInBoundingBox(const INTERP_KERNEL::DirectedBoundingBox& bbox, double eps)
2981 MCAuto<DataArrayIdType> elems=DataArrayIdType::New(); elems->alloc(0,1);
2982 if(getMeshDimension()==-1)
2984 elems->pushBackSilent(0);
2985 return elems.retn();
2987 int dim=getSpaceDimension();
2988 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2989 const mcIdType* conn = getNodalConnectivity()->getConstPointer();
2990 const mcIdType* conn_index= getNodalConnectivityIndex()->getConstPointer();
2991 const double* coords = getCoords()->getConstPointer();
2992 mcIdType nbOfCells=getNumberOfCells();
2993 for ( mcIdType ielem=0; ielem<nbOfCells;ielem++ )
2995 for (int i=0; i<dim; i++)
2997 elem_bb[i*2]=std::numeric_limits<double>::max();
2998 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
3001 for (mcIdType inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
3003 mcIdType node= conn[inode];
3004 if(node>=0)//avoid polyhedron separator
3006 for (int idim=0; idim<dim; idim++)
3008 if ( coords[node*dim+idim] < elem_bb[idim*2] )
3010 elem_bb[idim*2] = coords[node*dim+idim] ;
3012 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
3014 elem_bb[idim*2+1] = coords[node*dim+idim] ;
3019 if(intersectsBoundingBox(bbox, elem_bb, dim, eps))
3020 elems->pushBackSilent(ielem);
3022 return elems.retn();
3026 * Returns a type of a cell by its id.
3027 * \param [in] cellId - the id of the cell of interest.
3028 * \return INTERP_KERNEL::NormalizedCellType - enumeration item describing the cell type.
3029 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
3031 INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::getTypeOfCell(mcIdType cellId) const
3033 const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
3034 if(cellId<_nodal_connec_index->getNbOfElems()-1)
3035 return (INTERP_KERNEL::NormalizedCellType) pt[ptI[cellId]];
3038 std::ostringstream oss; oss << "MEDCouplingUMesh::getTypeOfCell : Requesting type of cell #" << cellId << " but it should be in [0," << _nodal_connec_index->getNbOfElems()-1 << ") !";
3039 throw INTERP_KERNEL::Exception(oss.str());
3044 * This method returns a newly allocated array containing cell ids (ascendingly sorted) whose geometric type are equal to type.
3045 * This method does not throw exception if geometric type \a type is not in \a this.
3046 * This method throws an INTERP_KERNEL::Exception if meshdimension of \b this is not equal to those of \b type.
3047 * The coordinates array is not considered here.
3049 * \param [in] type the geometric type
3050 * \return cell ids in this having geometric type \a type.
3052 DataArrayIdType *MEDCouplingUMesh::giveCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
3055 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
3057 checkConnectivityFullyDefined();
3058 mcIdType nbCells=getNumberOfCells();
3059 int mdim=getMeshDimension();
3060 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
3061 if(mdim!=ToIdType(cm.getDimension()))
3062 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::giveCellsWithType : Mismatch between mesh dimension and dimension of the cell !");
3063 const mcIdType *ptI=_nodal_connec_index->getConstPointer();
3064 const mcIdType *pt=_nodal_connec->getConstPointer();
3065 for(mcIdType i=0;i<nbCells;i++)
3067 if((INTERP_KERNEL::NormalizedCellType)pt[ptI[i]]==type)
3068 ret->pushBackSilent(i);
3074 * Returns nb of cells having the geometric type \a type. No throw if no cells in \a this has the geometric type \a type.
3076 mcIdType MEDCouplingUMesh::getNumberOfCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
3078 const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
3079 mcIdType nbOfCells(getNumberOfCells()),ret(0);
3080 for(mcIdType i=0;i<nbOfCells;i++)
3081 if((INTERP_KERNEL::NormalizedCellType) pt[ptI[i]]==type)
3087 * Returns the nodal connectivity of a given cell.
3088 * The separator of faces within polyhedron connectivity (-1) is not returned, thus
3089 * all returned node ids can be used in getCoordinatesOfNode().
3090 * \param [in] cellId - an id of the cell of interest.
3091 * \param [in,out] conn - a vector where the node ids are appended. It is not
3092 * cleared before the appending.
3093 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
3095 void MEDCouplingUMesh::getNodeIdsOfCell(mcIdType cellId, std::vector<mcIdType>& conn) const
3097 const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
3098 for(const mcIdType *w=pt+ptI[cellId]+1;w!=pt+ptI[cellId+1];w++)
3103 std::string MEDCouplingUMesh::simpleRepr() const
3105 static const char msg0[]="No coordinates specified !";
3106 std::ostringstream ret;
3107 ret << "Unstructured mesh with name : \"" << getName() << "\"\n";
3108 ret << "Description of mesh : \"" << getDescription() << "\"\n";
3110 double tt=getTime(tmpp1,tmpp2);
3111 ret << "Time attached to the mesh [unit] : " << tt << " [" << getTimeUnit() << "]\n";
3112 ret << "Iteration : " << tmpp1 << " Order : " << tmpp2 << "\n";
3114 { ret << "Mesh dimension : " << _mesh_dim << "\nSpace dimension : "; }
3116 { ret << " Mesh dimension has not been set or is invalid !"; }
3119 const int spaceDim=getSpaceDimension();
3120 ret << spaceDim << "\nInfo attached on space dimension : ";
3121 for(int i=0;i<spaceDim;i++)
3122 ret << "\"" << _coords->getInfoOnComponent(i) << "\" ";
3126 ret << msg0 << "\n";
3127 ret << "Number of nodes : ";
3129 ret << getNumberOfNodes() << "\n";
3131 ret << msg0 << "\n";
3132 ret << "Number of cells : ";
3133 if(_nodal_connec!=0 && _nodal_connec_index!=0)
3134 ret << getNumberOfCells() << "\n";
3136 ret << "No connectivity specified !" << "\n";
3137 ret << "Cell types present : ";
3138 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
3140 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter);
3141 ret << cm.getRepr() << " ";
3147 std::string MEDCouplingUMesh::advancedRepr() const
3149 std::ostringstream ret;
3150 ret << simpleRepr();
3151 ret << "\nCoordinates array : \n___________________\n\n";
3153 _coords->reprWithoutNameStream(ret);
3155 ret << "No array set !\n";
3156 ret << "\n\nConnectivity arrays : \n_____________________\n\n";
3157 reprConnectivityOfThisLL(ret);
3162 * This method returns a C++ code that is a dump of \a this.
3163 * This method will throw if this is not fully defined.
3165 std::string MEDCouplingUMesh::cppRepr() const
3167 static const char coordsName[]="coords";
3168 static const char connName[]="conn";
3169 static const char connIName[]="connI";
3170 checkFullyDefined();
3171 std::ostringstream ret; ret << "// coordinates" << std::endl;
3172 _coords->reprCppStream(coordsName,ret); ret << std::endl << "// connectivity" << std::endl;
3173 _nodal_connec->reprCppStream(connName,ret); ret << std::endl;
3174 _nodal_connec_index->reprCppStream(connIName,ret); ret << std::endl;
3175 ret << "MEDCouplingUMesh *mesh=MEDCouplingUMesh::New(\"" << getName() << "\"," << getMeshDimension() << ");" << std::endl;
3176 ret << "mesh->setCoords(" << coordsName << ");" << std::endl;
3177 ret << "mesh->setConnectivity(" << connName << "," << connIName << ",true);" << std::endl;
3178 ret << coordsName << "->decrRef(); " << connName << "->decrRef(); " << connIName << "->decrRef();" << std::endl;
3182 std::string MEDCouplingUMesh::reprConnectivityOfThis() const
3184 std::ostringstream ret;
3185 reprConnectivityOfThisLL(ret);
3190 * This method builds a newly allocated instance (with the same name than \a this) that the caller has the responsibility to deal with.
3191 * This method returns an instance with all arrays allocated (connectivity, connectivity index, coordinates)
3192 * but with length of these arrays set to 0. It allows to define an "empty" mesh (with nor cells nor nodes but compliant with
3195 * This method expects that \a this has a mesh dimension set and higher or equal to 0. If not an exception will be thrown.
3196 * 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
3197 * with number of tuples set to 0, if not the array is taken as this in the returned instance.
3199 MEDCouplingUMesh *MEDCouplingUMesh::buildSetInstanceFromThis(std::size_t spaceDim) const
3201 int mdim=getMeshDimension();
3203 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSetInstanceFromThis : invalid mesh dimension ! Should be >= 0 !");
3204 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
3205 MCAuto<DataArrayIdType> tmp1,tmp2;
3206 bool needToCpyCT=true;
3209 tmp1=DataArrayIdType::New(); tmp1->alloc(0,1);
3217 if(!_nodal_connec_index)
3219 tmp2=DataArrayIdType::New(); tmp2->alloc(1,1); tmp2->setIJ(0,0,0);
3224 tmp2=_nodal_connec_index;
3227 ret->setConnectivity(tmp1,tmp2,false);
3232 MCAuto<DataArrayDouble> coords=DataArrayDouble::New(); coords->alloc(0,spaceDim);
3233 ret->setCoords(coords);
3236 ret->setCoords(_coords);
3240 mcIdType MEDCouplingUMesh::getNumberOfNodesInCell(mcIdType cellId) const
3242 const mcIdType *ptI=_nodal_connec_index->getConstPointer();
3243 const mcIdType *pt=_nodal_connec->getConstPointer();
3244 if(pt[ptI[cellId]]!=INTERP_KERNEL::NORM_POLYHED)
3245 return ptI[cellId+1]-ptI[cellId]-1;
3247 return ToIdType(std::count_if(pt+ptI[cellId]+1,pt+ptI[cellId+1],std::bind(std::not_equal_to<mcIdType>(),std::placeholders::_1,-1)));
3251 * Returns types of cells of the specified part of \a this mesh.
3252 * This method avoids computing sub-mesh explicitly to get its types.
3253 * \param [in] begin - an array of cell ids of interest.
3254 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3255 * \return std::set<INTERP_KERNEL::NormalizedCellType> - a set of enumeration items
3256 * describing the cell types.
3257 * \throw If the coordinates array is not set.
3258 * \throw If the nodal connectivity of cells is not defined.
3259 * \sa getAllGeoTypes()
3261 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getTypesOfPart(const mcIdType *begin, const mcIdType *end) const
3263 checkFullyDefined();
3264 std::set<INTERP_KERNEL::NormalizedCellType> ret;
3265 const mcIdType *conn=_nodal_connec->getConstPointer();
3266 const mcIdType *connIndex=_nodal_connec_index->getConstPointer();
3267 for(const mcIdType *w=begin;w!=end;w++)
3268 ret.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]);
3273 * Defines the nodal connectivity using given connectivity arrays in \ref numbering-indirect format.
3274 * Optionally updates
3275 * a set of types of cells constituting \a this mesh.
3276 * This method is for advanced users having prepared their connectivity before. For
3277 * more info on using this method see \ref MEDCouplingUMeshAdvBuild.
3278 * \param [in] conn - the nodal connectivity array.
3279 * \param [in] connIndex - the nodal connectivity index array.
3280 * \param [in] isComputingTypes - if \c true, the set of types constituting \a this
3283 void MEDCouplingUMesh::setConnectivity(DataArrayIdType *conn, DataArrayIdType *connIndex, bool isComputingTypes)
3285 DataArrayIdType::SetArrayIn(conn,_nodal_connec);
3286 DataArrayIdType::SetArrayIn(connIndex,_nodal_connec_index);
3287 if(isComputingTypes)
3293 * Copy constructor. If 'deepCopy' is false \a this is a shallow copy of other.
3294 * If 'deeCpy' is true all arrays (coordinates and connectivities) are deeply copied.
3296 MEDCouplingUMesh::MEDCouplingUMesh(const MEDCouplingUMesh& other, bool deepCpy):MEDCouplingPointSet(other,deepCpy),_mesh_dim(other._mesh_dim),
3297 _nodal_connec(0),_nodal_connec_index(0),
3298 _types(other._types)
3300 if(other._nodal_connec)
3301 _nodal_connec=other._nodal_connec->performCopyOrIncrRef(deepCpy);
3302 if(other._nodal_connec_index)
3303 _nodal_connec_index=other._nodal_connec_index->performCopyOrIncrRef(deepCpy);
3306 MEDCouplingUMesh::~MEDCouplingUMesh()
3309 _nodal_connec->decrRef();
3310 if(_nodal_connec_index)
3311 _nodal_connec_index->decrRef();
3315 * Recomputes a set of cell types of \a this mesh. For more info see
3316 * \ref MEDCouplingUMeshNodalConnectivity.
3318 void MEDCouplingUMesh::computeTypes()
3320 ComputeAllTypesInternal(_types,_nodal_connec,_nodal_connec_index);
3325 * Returns a number of cells constituting \a this mesh.
3326 * \return mcIdType - the number of cells in \a this mesh.
3327 * \throw If the nodal connectivity of cells is not defined.
3329 mcIdType MEDCouplingUMesh::getNumberOfCells() const
3331 if(_nodal_connec_index)
3332 return _nodal_connec_index->getNumberOfTuples()-1;
3337 throw INTERP_KERNEL::Exception("Unable to get number of cells because no connectivity specified !");
3341 * Returns a dimension of \a this mesh, i.e. a dimension of cells constituting \a this
3342 * mesh. For more info see \ref meshes.
3343 * \return int - the dimension of \a this mesh.
3344 * \throw If the mesh dimension is not defined using setMeshDimension().
3346 int MEDCouplingUMesh::getMeshDimension() const
3349 throw INTERP_KERNEL::Exception("No mesh dimension specified !");
3354 * Returns a length of the nodal connectivity array.
3355 * This method is for test reason. Normally the integer returned is not useable by
3356 * user. For more info see \ref MEDCouplingUMeshNodalConnectivity.
3357 * \return mcIdType - the length of the nodal connectivity array.
3359 mcIdType MEDCouplingUMesh::getNodalConnectivityArrayLen() const
3361 return _nodal_connec->getNbOfElems();
3365 * First step of serialization process. Used by ParaMEDMEM and MEDCouplingCorba to transfert data between process.
3367 void MEDCouplingUMesh::getTinySerializationInformation(std::vector<double>& tinyInfoD, std::vector<mcIdType>& tinyInfo, std::vector<std::string>& littleStrings) const
3369 MEDCouplingPointSet::getTinySerializationInformation(tinyInfoD,tinyInfo,littleStrings);
3370 tinyInfo.push_back(ToIdType(getMeshDimension()));
3371 tinyInfo.push_back(getNumberOfCells());
3373 tinyInfo.push_back(getNodalConnectivityArrayLen());
3375 tinyInfo.push_back(-1);
3379 * First step of unserialization process.
3381 bool MEDCouplingUMesh::isEmptyMesh(const std::vector<mcIdType>& tinyInfo) const
3383 return tinyInfo[6]<=0;
3387 * Second step of serialization process.
3388 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3389 * \param a1 DataArrayDouble
3390 * \param a2 DataArrayDouble
3391 * \param littleStrings string vector
3393 void MEDCouplingUMesh::resizeForUnserialization(const std::vector<mcIdType>& tinyInfo, DataArrayIdType *a1, DataArrayDouble *a2, std::vector<std::string>& littleStrings) const
3395 MEDCouplingPointSet::resizeForUnserialization(tinyInfo,a1,a2,littleStrings);
3397 a1->alloc(tinyInfo[7]+tinyInfo[6]+1,1);
3401 * Third and final step of serialization process.
3403 void MEDCouplingUMesh::serialize(DataArrayIdType *&a1, DataArrayDouble *&a2) const
3405 MEDCouplingPointSet::serialize(a1,a2);
3406 if(getMeshDimension()>-1)
3408 a1=DataArrayIdType::New();
3409 a1->alloc(getNodalConnectivityArrayLen()+getNumberOfCells()+1,1);
3410 mcIdType *ptA1=a1->getPointer();
3411 const mcIdType *conn=getNodalConnectivity()->getConstPointer();
3412 const mcIdType *index=getNodalConnectivityIndex()->getConstPointer();
3413 ptA1=std::copy(index,index+getNumberOfCells()+1,ptA1);
3414 std::copy(conn,conn+getNodalConnectivityArrayLen(),ptA1);
3421 * Second and final unserialization process.
3422 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3424 void MEDCouplingUMesh::unserialization(const std::vector<double>& tinyInfoD, const std::vector<mcIdType>& tinyInfo, const DataArrayIdType *a1, DataArrayDouble *a2, const std::vector<std::string>& littleStrings)
3426 MEDCouplingPointSet::unserialization(tinyInfoD,tinyInfo,a1,a2,littleStrings);
3427 setMeshDimension(FromIdType<int>(tinyInfo[5]));
3431 const mcIdType *recvBuffer=a1->getConstPointer();
3432 MCAuto<DataArrayIdType> myConnecIndex=DataArrayIdType::New();
3433 myConnecIndex->alloc(tinyInfo[6]+1,1);
3434 std::copy(recvBuffer,recvBuffer+tinyInfo[6]+1,myConnecIndex->getPointer());
3435 MCAuto<DataArrayIdType> myConnec=DataArrayIdType::New();
3436 myConnec->alloc(tinyInfo[7],1);
3437 std::copy(recvBuffer+tinyInfo[6]+1,recvBuffer+tinyInfo[6]+1+tinyInfo[7],myConnec->getPointer());
3438 setConnectivity(myConnec, myConnecIndex);
3445 * Returns a new MEDCouplingFieldDouble containing volumes of cells constituting \a this
3447 * For 1D cells, the returned field contains lengths.<br>
3448 * For 2D cells, the returned field contains areas.<br>
3449 * For 3D cells, the returned field contains volumes.
3450 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3451 * orientation, i.e. the volume is always positive.
3452 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on cells
3453 * and one time . The caller is to delete this field using decrRef() as it is no
3456 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureField(bool isAbs) const
3458 std::string name="MeasureOfMesh_";
3460 mcIdType nbelem=getNumberOfCells();
3461 MCAuto<MEDCouplingFieldDouble> field=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3462 field->setName(name);
3463 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3464 array->alloc(nbelem,1);
3465 double *area_vol=array->getPointer();
3466 field->setArray(array) ; array=0;
3467 field->setMesh(const_cast<MEDCouplingUMesh *>(this));
3468 field->synchronizeTimeWithMesh();
3469 if(getMeshDimension()!=-1)
3472 INTERP_KERNEL::NormalizedCellType type;
3473 int dim_space=getSpaceDimension();
3474 const double *coords=getCoords()->getConstPointer();
3475 const mcIdType *connec=getNodalConnectivity()->getConstPointer();
3476 const mcIdType *connec_index=getNodalConnectivityIndex()->getConstPointer();
3477 for(mcIdType iel=0;iel<nbelem;iel++)
3479 ipt=connec_index[iel];
3480 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3481 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);
3484 std::transform(area_vol,area_vol+nbelem,area_vol,[](double c){return fabs(c);});
3488 area_vol[0]=std::numeric_limits<double>::max();
3490 return field.retn();
3494 * Returns a new DataArrayDouble containing volumes of specified cells of \a this
3496 * For 1D cells, the returned array contains lengths.<br>
3497 * For 2D cells, the returned array contains areas.<br>
3498 * For 3D cells, the returned array contains volumes.
3499 * This method avoids building explicitly a part of \a this mesh to perform the work.
3500 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3501 * orientation, i.e. the volume is always positive.
3502 * \param [in] begin - an array of cell ids of interest.
3503 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3504 * \return DataArrayDouble * - a new instance of DataArrayDouble. The caller is to
3505 * delete this array using decrRef() as it is no more needed.
3507 * \if ENABLE_EXAMPLES
3508 * \ref cpp_mcumesh_getPartMeasureField "Here is a C++ example".<br>
3509 * \ref py_mcumesh_getPartMeasureField "Here is a Python example".
3511 * \sa getMeasureField()
3513 DataArrayDouble *MEDCouplingUMesh::getPartMeasureField(bool isAbs, const mcIdType *begin, const mcIdType *end) const
3515 std::string name="PartMeasureOfMesh_";
3517 std::size_t nbelem=std::distance(begin,end);
3518 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3519 array->setName(name);
3520 array->alloc(nbelem,1);
3521 double *area_vol=array->getPointer();
3522 if(getMeshDimension()!=-1)
3525 INTERP_KERNEL::NormalizedCellType type;
3526 int dim_space=getSpaceDimension();
3527 const double *coords=getCoords()->getConstPointer();
3528 const mcIdType *connec=getNodalConnectivity()->getConstPointer();
3529 const mcIdType *connec_index=getNodalConnectivityIndex()->getConstPointer();
3530 for(const mcIdType *iel=begin;iel!=end;iel++)
3532 ipt=connec_index[*iel];
3533 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3534 *area_vol++=INTERP_KERNEL::computeVolSurfOfCell2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,connec+ipt+1,connec_index[*iel+1]-ipt-1,coords,dim_space);
3537 std::transform(array->getPointer(),area_vol,array->getPointer(),[](double c){return fabs(c);});
3541 area_vol[0]=std::numeric_limits<double>::max();
3543 return array.retn();
3547 * Returns a new MEDCouplingFieldDouble containing volumes of cells of a dual mesh of
3548 * \a this one. The returned field contains the dual cell volume for each corresponding
3549 * node in \a this mesh. In other words, the field returns the getMeasureField() of
3550 * the dual mesh in P1 sens of \a this.<br>
3551 * For 1D cells, the returned field contains lengths.<br>
3552 * For 2D cells, the returned field contains areas.<br>
3553 * For 3D cells, the returned field contains volumes.
3554 * This method is useful to check "P1*" conservative interpolators.
3555 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3556 * orientation, i.e. the volume is always positive.
3557 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3558 * nodes and one time. The caller is to delete this array using decrRef() as
3559 * it is no more needed.
3561 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureFieldOnNode(bool isAbs) const
3563 MCAuto<MEDCouplingFieldDouble> tmp=getMeasureField(isAbs);
3564 std::string name="MeasureOnNodeOfMesh_";
3566 mcIdType nbNodes=getNumberOfNodes();
3567 MCAuto<DataArrayDouble> nnpc;
3569 MCAuto<DataArrayIdType> tmp2(computeNbOfNodesPerCell());
3570 nnpc=tmp2->convertToDblArr();
3572 std::for_each(nnpc->rwBegin(),nnpc->rwEnd(),[](double& v) { v=1./v; });
3573 const double *nnpcPtr(nnpc->begin());
3574 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_NODES);
3575 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3576 array->alloc(nbNodes,1);
3577 double *valsToFill=array->getPointer();
3578 std::fill(valsToFill,valsToFill+nbNodes,0.);
3579 const double *values=tmp->getArray()->getConstPointer();
3580 MCAuto<DataArrayIdType> da=DataArrayIdType::New();
3581 MCAuto<DataArrayIdType> daInd=DataArrayIdType::New();
3582 getReverseNodalConnectivity(da,daInd);
3583 const mcIdType *daPtr=da->getConstPointer();
3584 const mcIdType *daIPtr=daInd->getConstPointer();
3585 for(mcIdType i=0;i<nbNodes;i++)
3586 for(const mcIdType *cell=daPtr+daIPtr[i];cell!=daPtr+daIPtr[i+1];cell++)
3587 valsToFill[i]+=nnpcPtr[*cell]*values[*cell];
3589 ret->setArray(array);
3594 * Returns a new MEDCouplingFieldDouble holding normal vectors to cells of \a this
3595 * mesh. The returned normal vectors to each cell have a norm2 equal to 1.
3596 * The computed vectors have <em> this->getMeshDimension()+1 </em> components
3597 * and are normalized.
3598 * <br> \a this can be either
3599 * - a 2D mesh in 2D or 3D space or
3600 * - an 1D mesh in 2D space.
3602 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3603 * cells and one time. The caller is to delete this field using decrRef() as
3604 * it is no more needed.
3605 * \throw If the nodal connectivity of cells is not defined.
3606 * \throw If the coordinates array is not set.
3607 * \throw If the mesh dimension is not set.
3608 * \throw If the mesh and space dimension is not as specified above.
3610 MEDCouplingFieldDouble *MEDCouplingUMesh::buildOrthogonalField() const
3612 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3613 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3614 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3615 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3616 mcIdType nbOfCells=getNumberOfCells();
3617 int nbComp=getMeshDimension()+1;
3618 array->alloc(nbOfCells,nbComp);
3619 double *vals=array->getPointer();
3620 const mcIdType *connI=_nodal_connec_index->getConstPointer();
3621 const mcIdType *conn=_nodal_connec->getConstPointer();
3622 const double *coords=_coords->getConstPointer();
3623 if(getMeshDimension()==2)
3625 if(getSpaceDimension()==3)
3627 MCAuto<DataArrayDouble> loc=computeCellCenterOfMass();
3628 const double *locPtr=loc->getConstPointer();
3629 for(mcIdType i=0;i<nbOfCells;i++,vals+=3)
3631 mcIdType offset=connI[i];
3632 INTERP_KERNEL::crossprod<3>(locPtr+3*i,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3633 double n=INTERP_KERNEL::norm<3>(vals);
3634 std::transform(vals,vals+3,vals,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3639 MCAuto<MEDCouplingFieldDouble> isAbs=getMeasureField(false);
3640 const double *isAbsPtr=isAbs->getArray()->begin();
3641 for(mcIdType i=0;i<nbOfCells;i++,isAbsPtr++)
3642 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=*isAbsPtr>0.?1.:-1.; }
3645 else//meshdimension==1
3648 for(mcIdType i=0;i<nbOfCells;i++)
3650 mcIdType offset=connI[i];
3651 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3652 double n=INTERP_KERNEL::norm<2>(tmp);
3653 std::transform(tmp,tmp+2,tmp,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3658 ret->setArray(array);
3660 ret->synchronizeTimeWithSupport();
3665 * Returns a new MEDCouplingFieldDouble holding normal vectors to specified cells of
3666 * \a this mesh. The computed vectors have <em> this->getMeshDimension()+1 </em> components
3667 * and are normalized.
3668 * <br> \a this can be either
3669 * - a 2D mesh in 2D or 3D space or
3670 * - an 1D mesh in 2D space.
3672 * This method avoids building explicitly a part of \a this mesh to perform the work.
3673 * \param [in] begin - an array of cell ids of interest.
3674 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3675 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3676 * cells and one time. The caller is to delete this field using decrRef() as
3677 * it is no more needed.
3678 * \throw If the nodal connectivity of cells is not defined.
3679 * \throw If the coordinates array is not set.
3680 * \throw If the mesh dimension is not set.
3681 * \throw If the mesh and space dimension is not as specified above.
3682 * \sa buildOrthogonalField()
3684 * \if ENABLE_EXAMPLES
3685 * \ref cpp_mcumesh_buildPartOrthogonalField "Here is a C++ example".<br>
3686 * \ref py_mcumesh_buildPartOrthogonalField "Here is a Python example".
3689 MEDCouplingFieldDouble *MEDCouplingUMesh::buildPartOrthogonalField(const mcIdType *begin, const mcIdType *end) const
3691 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3692 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3693 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3694 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3695 std::size_t nbelems=std::distance(begin,end);
3696 int nbComp=getMeshDimension()+1;
3697 array->alloc(nbelems,nbComp);
3698 double *vals=array->getPointer();
3699 const mcIdType *connI=_nodal_connec_index->getConstPointer();
3700 const mcIdType *conn=_nodal_connec->getConstPointer();
3701 const double *coords=_coords->getConstPointer();
3702 if(getMeshDimension()==2)
3704 if(getSpaceDimension()==3)
3706 MCAuto<DataArrayDouble> loc=getPartBarycenterAndOwner(begin,end);
3707 const double *locPtr=loc->getConstPointer();
3708 for(const mcIdType *i=begin;i!=end;i++,vals+=3,locPtr+=3)
3710 mcIdType offset=connI[*i];
3711 INTERP_KERNEL::crossprod<3>(locPtr,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3712 double n=INTERP_KERNEL::norm<3>(vals);
3713 std::transform(vals,vals+3,vals,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3718 for(std::size_t i=0;i<nbelems;i++)
3719 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=1.; }
3722 else//meshdimension==1
3725 for(const mcIdType *i=begin;i!=end;i++)
3727 mcIdType offset=connI[*i];
3728 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3729 double n=INTERP_KERNEL::norm<2>(tmp);
3730 std::transform(tmp,tmp+2,tmp,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3735 ret->setArray(array);
3737 ret->synchronizeTimeWithSupport();
3742 * Returns a new MEDCouplingFieldDouble holding a direction vector for each SEG2 in \a
3743 * this 1D mesh. The computed vectors have <em> this->getSpaceDimension() </em> components
3744 * and are \b not normalized.
3745 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3746 * cells and one time. The caller is to delete this field using decrRef() as
3747 * it is no more needed.
3748 * \throw If the nodal connectivity of cells is not defined.
3749 * \throw If the coordinates array is not set.
3750 * \throw If \a this->getMeshDimension() != 1.
3751 * \throw If \a this mesh includes cells of type other than SEG2.
3753 MEDCouplingFieldDouble *MEDCouplingUMesh::buildDirectionVectorField() const
3755 if(getMeshDimension()!=1)
3756 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for buildDirectionVectorField !");
3757 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3758 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for buildDirectionVectorField !");
3759 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3760 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3761 mcIdType nbOfCells=getNumberOfCells();
3762 int spaceDim=getSpaceDimension();
3763 array->alloc(nbOfCells,spaceDim);
3764 double *pt=array->getPointer();
3765 const double *coo=getCoords()->getConstPointer();
3766 std::vector<mcIdType> conn;
3768 for(mcIdType i=0;i<nbOfCells;i++)
3771 getNodeIdsOfCell(i,conn);
3772 pt=std::transform(coo+conn[1]*spaceDim,coo+(conn[1]+1)*spaceDim,coo+conn[0]*spaceDim,pt,std::minus<double>());
3774 ret->setArray(array);
3776 ret->synchronizeTimeWithSupport();
3781 * Creates a 2D mesh by cutting \a this 3D mesh with a plane. In addition to the mesh,
3782 * returns a new DataArrayIdType, of length equal to the number of 2D cells in the result
3783 * mesh, holding, for each cell in the result mesh, an id of a 3D cell it comes
3784 * from. If a result face is shared by two 3D cells, then the face in included twice in
3786 * \param [in] origin - 3 components of a point defining location of the plane.
3787 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3788 * must be greater than 1e-6.
3789 * \param [in] eps - half-thickness of the plane.
3790 * \param [out] cellIds - a new instance of DataArrayIdType holding ids of 3D cells
3791 * producing correspondent 2D cells. The caller is to delete this array
3792 * using decrRef() as it is no more needed.
3793 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This mesh does
3794 * not share the node coordinates array with \a this mesh. The caller is to
3795 * delete this mesh using decrRef() as it is no more needed.
3796 * \throw If the coordinates array is not set.
3797 * \throw If the nodal connectivity of cells is not defined.
3798 * \throw If \a this->getMeshDimension() != 3 or \a this->getSpaceDimension() != 3.
3799 * \throw If magnitude of \a vec is less than 1e-6.
3800 * \throw If the plane does not intersect any 3D cell of \a this mesh.
3801 * \throw If \a this includes quadratic cells.
3803 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3D(const double *origin, const double *vec, double eps, DataArrayIdType *&cellIds) const
3805 checkFullyDefined();
3806 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3807 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3808 MCAuto<DataArrayIdType> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3809 if(candidates->empty())
3810 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane considering bounding boxes !");
3811 std::vector<mcIdType> nodes;
3812 DataArrayIdType *cellIds1D=0;
3813 MCAuto<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3814 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3815 MCAuto<DataArrayIdType> desc1=DataArrayIdType::New(),desc2=DataArrayIdType::New();
3816 MCAuto<DataArrayIdType> descIndx1=DataArrayIdType::New(),descIndx2=DataArrayIdType::New();
3817 MCAuto<DataArrayIdType> revDesc1=DataArrayIdType::New(),revDesc2=DataArrayIdType::New();
3818 MCAuto<DataArrayIdType> revDescIndx1=DataArrayIdType::New(),revDescIndx2=DataArrayIdType::New();
3819 MCAuto<MEDCouplingUMesh> mDesc2=subMesh->buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2);//meshDim==2 spaceDim==3
3820 revDesc2=0; revDescIndx2=0;
3821 MCAuto<MEDCouplingUMesh> mDesc1=mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3822 revDesc1=0; revDescIndx1=0;
3823 //Marking all 1D cells that contained at least one node located on the plane
3824 //the intersection between those cells and the plane, which consist of the nodes previously tagged, thus don't need to be computed afterwards
3825 //(if said intersection is computed in MEDCouplingUMesh::split3DCurveWithPlane, then we might create additional nodes
3826 //due to accuracy errors when the needed nodes already exist)
3827 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),false,cellIds1D);
3828 MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3830 std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3831 for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3833 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3834 std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(mDesc2->getNumberOfCells());
3835 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->getConstPointer(),mDesc2->getNodalConnectivityIndex()->getConstPointer(),
3836 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3837 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3838 MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New()),cellIds2(DataArrayIdType::New());
3839 connI->pushBackSilent(0); conn->alloc(0,1); cellIds2->alloc(0,1);
3840 subMesh->assemblyForSplitFrom3DSurf(cut3DSurf,desc2->getConstPointer(),descIndx2->getConstPointer(),conn,connI,cellIds2);
3841 if(cellIds2->empty())
3842 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3843 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3D",2);
3844 ret->setCoords(mDesc1->getCoords());
3845 ret->setConnectivity(conn,connI,true);
3846 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3851 * Creates an 1D mesh by cutting \a this 2D mesh in 3D space with a plane. In
3852 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
3853 from. If a result segment is shared by two 2D cells, then the segment in included twice in
3855 * \param [in] origin - 3 components of a point defining location of the plane.
3856 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3857 * must be greater than 1e-6.
3858 * \param [in] eps - half-thickness of the plane.
3859 * \param [out] cellIds - a new instance of DataArrayIdType holding ids of faces
3860 * producing correspondent segments. The caller is to delete this array
3861 * using decrRef() as it is no more needed.
3862 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This is an 1D
3863 * mesh in 3D space. This mesh does not share the node coordinates array with
3864 * \a this mesh. The caller is to delete this mesh using decrRef() as it is
3866 * \throw If the coordinates array is not set.
3867 * \throw If the nodal connectivity of cells is not defined.
3868 * \throw If \a this->getMeshDimension() != 2 or \a this->getSpaceDimension() != 3.
3869 * \throw If magnitude of \a vec is less than 1e-6.
3870 * \throw If the plane does not intersect any 2D cell of \a this mesh.
3871 * \throw If \a this includes quadratic cells.
3873 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3DSurf(const double *origin, const double *vec, double eps, DataArrayIdType *&cellIds) const
3875 checkFullyDefined();
3876 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
3877 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf works on umeshes with meshdim equal to 2 and spaceDim equal to 3 !");
3878 MCAuto<DataArrayIdType> candidates(getCellIdsCrossingPlane(origin,vec,eps));
3879 if(candidates->empty())
3880 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3D surf cells in this intercepts the specified plane considering bounding boxes !");
3881 std::vector<mcIdType> nodes;
3882 DataArrayIdType *cellIds1D(0);
3883 MCAuto<MEDCouplingUMesh> subMesh(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3884 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3885 MCAuto<DataArrayIdType> desc1(DataArrayIdType::New()),descIndx1(DataArrayIdType::New()),revDesc1(DataArrayIdType::New()),revDescIndx1(DataArrayIdType::New());
3886 MCAuto<MEDCouplingUMesh> mDesc1(subMesh->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3887 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3888 MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3890 std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3891 for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3893 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3894 mcIdType ncellsSub=subMesh->getNumberOfCells();
3895 std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(ncellsSub);
3896 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,subMesh->getNodalConnectivity()->getConstPointer(),subMesh->getNodalConnectivityIndex()->getConstPointer(),
3897 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3898 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3899 MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New()),cellIds2(DataArrayIdType::New()); connI->pushBackSilent(0);
3901 const mcIdType *nodal=subMesh->getNodalConnectivity()->getConstPointer();
3902 const mcIdType *nodalI=subMesh->getNodalConnectivityIndex()->getConstPointer();
3903 for(mcIdType i=0;i<ncellsSub;i++)
3905 if(cut3DSurf[i].first!=-1 && cut3DSurf[i].second!=-1)
3907 if(cut3DSurf[i].first!=-2)
3909 conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_SEG2)); conn->pushBackSilent(cut3DSurf[i].first); conn->pushBackSilent(cut3DSurf[i].second);
3910 connI->pushBackSilent(conn->getNumberOfTuples());
3911 cellIds2->pushBackSilent(i);
3915 mcIdType cellId3DSurf=cut3DSurf[i].second;
3916 mcIdType offset=nodalI[cellId3DSurf]+1;
3917 mcIdType nbOfEdges=nodalI[cellId3DSurf+1]-offset;
3918 for(mcIdType j=0;j<nbOfEdges;j++)
3920 conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_SEG2)); conn->pushBackSilent(nodal[offset+j]); conn->pushBackSilent(nodal[offset+(j+1)%nbOfEdges]);
3921 connI->pushBackSilent(conn->getNumberOfTuples());
3922 cellIds2->pushBackSilent(cellId3DSurf);
3927 if(cellIds2->empty())
3928 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3DSurf cells in this intercepts the specified plane !");
3929 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3DSurf",1);
3930 ret->setCoords(mDesc1->getCoords());
3931 ret->setConnectivity(conn,connI,true);
3932 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3936 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::clipSingle3DCellByPlane(const double origin[3], const double vec[3], double eps) const
3938 checkFullyDefined();
3939 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3940 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3941 if(getNumberOfCells()!=1)
3942 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works only on mesh containing exactly one cell !");
3944 std::vector<mcIdType> nodes;
3945 findNodesOnPlane(origin,vec,eps,nodes);
3946 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());
3947 MCAuto<MEDCouplingUMesh> mDesc2(buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2));//meshDim==2 spaceDim==3
3948 revDesc2=0; revDescIndx2=0;
3949 MCAuto<MEDCouplingUMesh> mDesc1(mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3950 revDesc1=0; revDescIndx1=0;
3951 DataArrayIdType *cellIds1D(0);
3952 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3953 MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3954 std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3955 for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3959 mcIdType oldNbNodes(mDesc1->getNumberOfNodes());
3960 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3961 sameNbNodes=(mDesc1->getNumberOfNodes()==oldNbNodes);
3963 std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(mDesc2->getNumberOfCells());
3964 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->begin(),mDesc2->getNodalConnectivityIndex()->begin(),
3965 mDesc1->getNodalConnectivity()->begin(),mDesc1->getNodalConnectivityIndex()->begin(),
3966 desc1->begin(),descIndx1->begin(),cut3DSurf);
3967 MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New());
3968 connI->pushBackSilent(0); conn->alloc(0,1);
3970 MCAuto<DataArrayIdType> cellIds2(DataArrayIdType::New()); cellIds2->alloc(0,1);
3971 assemblyForSplitFrom3DSurf(cut3DSurf,desc2->begin(),descIndx2->begin(),conn,connI,cellIds2);
3972 if(cellIds2->empty())
3973 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3975 std::vector<std::vector<mcIdType> > res;
3976 buildSubCellsFromCut(cut3DSurf,desc2->begin(),descIndx2->begin(),mDesc1->getCoords()->begin(),eps,res);
3977 std::size_t sz(res.size());
3978 if(ToIdType(res.size())==mDesc1->getNumberOfCells() && sameNbNodes)
3979 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane : cell is not clipped !");
3980 for(std::size_t i=0;i<sz;i++)
3982 conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYGON));
3983 conn->insertAtTheEnd(res[i].begin(),res[i].end());
3984 connI->pushBackSilent(conn->getNumberOfTuples());
3986 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
3987 ret->setCoords(mDesc1->getCoords());
3988 ret->setConnectivity(conn,connI,true);
3989 mcIdType nbCellsRet(ret->getNumberOfCells());
3991 MCAuto<DataArrayDouble> vec2(DataArrayDouble::New()); vec2->alloc(1,3); std::copy(vec,vec+3,vec2->getPointer());
3992 MCAuto<MEDCouplingFieldDouble> ortho(ret->buildOrthogonalField());
3993 MCAuto<DataArrayDouble> ortho2(ortho->getArray()->selectByTupleIdSafeSlice(0,1,1));
3994 MCAuto<DataArrayDouble> dott(DataArrayDouble::Dot(ortho2,vec2));
3995 MCAuto<DataArrayDouble> ccm(ret->computeCellCenterOfMass());
3996 MCAuto<DataArrayDouble> occm;
3998 MCAuto<DataArrayDouble> pt(DataArrayDouble::New()); pt->alloc(1,3); std::copy(origin,origin+3,pt->getPointer());
3999 occm=DataArrayDouble::Substract(ccm,pt);
4001 vec2=DataArrayDouble::New(); vec2->alloc(nbCellsRet,3);
4002 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);
4003 MCAuto<DataArrayDouble> dott2(DataArrayDouble::Dot(occm,vec2));
4005 const mcIdType *cPtr(ret->getNodalConnectivity()->begin()),*ciPtr(ret->getNodalConnectivityIndex()->begin());
4006 MCAuto<MEDCouplingUMesh> ret2(MEDCouplingUMesh::New("Clip3D",3));
4007 ret2->setCoords(mDesc1->getCoords());
4008 MCAuto<DataArrayIdType> conn2(DataArrayIdType::New()),conn2I(DataArrayIdType::New());
4009 conn2I->pushBackSilent(0); conn2->alloc(0,1);
4010 std::vector<mcIdType> cell0(1,ToIdType(INTERP_KERNEL::NORM_POLYHED));
4011 std::vector<mcIdType> cell1(1,ToIdType(INTERP_KERNEL::NORM_POLYHED));
4012 if(dott->getIJ(0,0)>0)
4014 cell0.insert(cell0.end(),cPtr+1,cPtr+ciPtr[1]);
4015 std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell1,cell1.end()));
4019 cell1.insert(cell1.end(),cPtr+1,cPtr+ciPtr[1]);
4020 std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell0,cell0.end()));
4022 for(mcIdType i=1;i<nbCellsRet;i++)
4024 if(dott2->getIJ(i,0)<0)
4026 if(ciPtr[i+1]-ciPtr[i]>=4)
4028 cell0.push_back(-1);
4029 cell0.insert(cell0.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
4034 if(ciPtr[i+1]-ciPtr[i]>=4)
4036 cell1.push_back(-1);
4037 cell1.insert(cell1.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
4041 conn2->insertAtTheEnd(cell0.begin(),cell0.end());
4042 conn2I->pushBackSilent(conn2->getNumberOfTuples());
4043 conn2->insertAtTheEnd(cell1.begin(),cell1.end());
4044 conn2I->pushBackSilent(conn2->getNumberOfTuples());
4045 ret2->setConnectivity(conn2,conn2I,true);
4046 ret2->checkConsistencyLight();
4047 ret2->orientCorrectlyPolyhedrons();
4052 * Finds cells whose bounding boxes intersect a given plane.
4053 * \param [in] origin - 3 components of a point defining location of the plane.
4054 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
4055 * must be greater than 1e-6.
4056 * \param [in] eps - half-thickness of the plane.
4057 * \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of the found
4058 * cells. The caller is to delete this array using decrRef() as it is no more
4060 * \throw If the coordinates array is not set.
4061 * \throw If the nodal connectivity of cells is not defined.
4062 * \throw If \a this->getSpaceDimension() != 3.
4063 * \throw If magnitude of \a vec is less than 1e-6.
4064 * \sa buildSlice3D()
4066 DataArrayIdType *MEDCouplingUMesh::getCellIdsCrossingPlane(const double *origin, const double *vec, double eps) const
4068 checkFullyDefined();
4069 if(getSpaceDimension()!=3)
4070 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with spaceDim equal to 3 !");
4071 double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
4073 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellIdsCrossingPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
4075 vec2[0]=vec[1]; vec2[1]=-vec[0]; vec2[2]=0.;//vec2 is the result of cross product of vec with (0,0,1)
4076 double angle=acos(vec[2]/normm);
4077 MCAuto<DataArrayIdType> cellIds;
4081 MCAuto<DataArrayDouble> coo=_coords->deepCopy();
4082 double normm2(sqrt(vec2[0]*vec2[0]+vec2[1]*vec2[1]+vec2[2]*vec2[2]));
4083 if(normm2/normm>1e-6)
4084 DataArrayDouble::Rotate3DAlg(origin,vec2,angle,coo->getNumberOfTuples(),coo->getPointer(),coo->getPointer());
4085 MCAuto<MEDCouplingUMesh> mw=clone(false);//false -> shallow copy
4087 mw->getBoundingBox(bbox);
4088 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
4089 cellIds=mw->getCellsInBoundingBox(bbox,eps);
4093 getBoundingBox(bbox);
4094 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
4095 cellIds=getCellsInBoundingBox(bbox,eps);
4097 return cellIds.retn();
4101 * This method checks that \a this is a contiguous mesh. The user is expected to call this method on a mesh with meshdim==1.
4102 * If not an exception will thrown. If this is an empty mesh with no cell an exception will be thrown too.
4103 * No consideration of coordinate is done by this method.
4104 * 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)
4105 * If not false is returned. In case that false is returned a call to MEDCoupling::MEDCouplingUMesh::mergeNodes could be useful.
4107 bool MEDCouplingUMesh::isContiguous1D() const
4109 if(getMeshDimension()!=1)
4110 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense only for 1D mesh !");
4111 mcIdType nbCells=getNumberOfCells();
4113 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense for non empty mesh !");
4114 const mcIdType *connI(_nodal_connec_index->begin()),*conn(_nodal_connec->begin());
4115 mcIdType ref=conn[connI[0]+2];
4116 for(mcIdType i=1;i<nbCells;i++)
4118 if(conn[connI[i]+1]!=ref)
4120 ref=conn[connI[i]+2];
4126 * This method is only callable on mesh with meshdim == 1 containing only SEG2 and spaceDim==3.
4127 * This method projects this on the 3D line defined by (pt,v). This methods first checks that all SEG2 are along v vector.
4128 * \param pt reference point of the line
4129 * \param v normalized director vector of the line
4130 * \param eps max precision before throwing an exception
4131 * \param res output of size this->getNumberOfCells
4133 void MEDCouplingUMesh::project1D(const double *pt, const double *v, double eps, double *res) const
4135 if(getMeshDimension()!=1)
4136 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for project1D !");
4137 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
4138 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for project1D !");
4139 if(getSpaceDimension()!=3)
4140 throw INTERP_KERNEL::Exception("Expected a umesh with spaceDim==3 for project1D !");
4141 MCAuto<MEDCouplingFieldDouble> f=buildDirectionVectorField();
4142 const double *fPtr=f->getArray()->getConstPointer();
4144 for(mcIdType i=0;i<getNumberOfCells();i++)
4146 const double *tmp1=fPtr+3*i;
4147 tmp[0]=tmp1[1]*v[2]-tmp1[2]*v[1];
4148 tmp[1]=tmp1[2]*v[0]-tmp1[0]*v[2];
4149 tmp[2]=tmp1[0]*v[1]-tmp1[1]*v[0];
4150 double n1=INTERP_KERNEL::norm<3>(tmp);
4151 n1/=INTERP_KERNEL::norm<3>(tmp1);
4153 throw INTERP_KERNEL::Exception("UMesh::Projection 1D failed !");
4155 const double *coo=getCoords()->getConstPointer();
4156 for(mcIdType i=0;i<getNumberOfNodes();i++)
4158 std::transform(coo+i*3,coo+i*3+3,pt,tmp,std::minus<double>());
4159 std::transform(tmp,tmp+3,v,tmp,std::multiplies<double>());
4160 res[i]=std::accumulate(tmp,tmp+3,0.);
4165 * 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.
4166 * \a this is expected to be a mesh so that its space dimension is equal to its
4167 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4168 * 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).
4170 * 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
4171 * 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).
4172 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4174 * So this method is more accurate (so, more costly) than simply searching for the closest point in \a this.
4175 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4177 * \param [in] ptBg the start pointer (included) of the coordinates of the point
4178 * \param [in] ptEnd the end pointer (not included) of the coordinates of the point
4179 * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4180 * \return the positive value of the distance.
4181 * \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
4183 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoints
4185 double MEDCouplingUMesh::distanceToPoint(const double *ptBg, const double *ptEnd, mcIdType& cellId) const
4187 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4188 if(meshDim!=spaceDim-1)
4189 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint works only for spaceDim=meshDim+1 !");
4190 if(meshDim!=2 && meshDim!=1)
4191 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint : only mesh dimension 2 and 1 are implemented !");
4192 checkFullyDefined();
4193 if(ToIdType(std::distance(ptBg,ptEnd))!=spaceDim)
4194 { 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()); }
4195 DataArrayIdType *ret1=0;
4196 MCAuto<DataArrayDouble> pts=DataArrayDouble::New(); pts->useArray(ptBg,false,DeallocType::C_DEALLOC,1,spaceDim);
4197 MCAuto<DataArrayDouble> ret0=distanceToPoints(pts,ret1);
4198 MCAuto<DataArrayIdType> ret1Safe(ret1);
4199 cellId=*ret1Safe->begin();
4200 return *ret0->begin();
4204 * This method computes the distance from each point of points serie \a pts (stored in a DataArrayDouble in which each tuple represents a point)
4205 * to \a this and the first \a cellId in \a this corresponding to the returned distance.
4206 * 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
4207 * 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).
4208 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4210 * \a this is expected to be a mesh so that its space dimension is equal to its
4211 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4212 * 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).
4214 * So this method is more accurate (so, more costly) than simply searching for each point in \a pts the closest point in \a this.
4215 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4217 * \param [in] pts the list of points in which each tuple represents a point
4218 * \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.
4219 * \return a newly allocated object to be dealed by the caller that tells for each point in \a pts the distance to \a this.
4220 * \throw if number of components of \a pts is not equal to the space dimension.
4221 * \throw if mesh dimension of \a this is not equal to space dimension - 1.
4222 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoint
4224 DataArrayDouble *MEDCouplingUMesh::distanceToPoints(const DataArrayDouble *pts, DataArrayIdType *& cellIds) const
4227 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : input points pointer is NULL !");
4228 pts->checkAllocated();
4229 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4230 if(meshDim!=spaceDim-1)
4231 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints works only for spaceDim=meshDim+1 !");
4232 if(meshDim!=2 && meshDim!=1)
4233 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only mesh dimension 2 and 1 are implemented !");
4234 if(ToIdType(pts->getNumberOfComponents())!=spaceDim)
4236 std::ostringstream oss; oss << "MEDCouplingUMesh::distanceToPoints : input pts DataArrayDouble has " << pts->getNumberOfComponents() << " components whereas it should be equal to " << spaceDim << " (mesh spaceDimension) !";
4237 throw INTERP_KERNEL::Exception(oss.str());
4239 checkFullyDefined();
4240 mcIdType nbCells=getNumberOfCells();
4242 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : no cells in this !");
4243 mcIdType nbOfPts=pts->getNumberOfTuples();
4244 MCAuto<DataArrayDouble> ret0=DataArrayDouble::New(); ret0->alloc(nbOfPts,1);
4245 MCAuto<DataArrayIdType> ret1=DataArrayIdType::New(); ret1->alloc(nbOfPts,1);
4246 const mcIdType *nc=_nodal_connec->begin(),*ncI=_nodal_connec_index->begin(); const double *coords=_coords->begin();
4247 double *ret0Ptr=ret0->getPointer(); mcIdType *ret1Ptr=ret1->getPointer(); const double *ptsPtr=pts->begin();
4248 MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree());
4249 const double *bbox(bboxArr->begin());
4254 BBTreeDst<3> myTree(bbox,0,0,nbCells);
4255 for(mcIdType i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=3)
4257 double x=std::numeric_limits<double>::max();
4258 std::vector<mcIdType> elems;
4259 myTree.getMinDistanceOfMax(ptsPtr,x);
4260 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4261 DistanceToPoint3DSurfAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4267 BBTreeDst<2> myTree(bbox,0,0,nbCells);
4268 for(mcIdType i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=2)
4270 double x=std::numeric_limits<double>::max();
4271 std::vector<mcIdType> elems;
4272 myTree.getMinDistanceOfMax(ptsPtr,x);
4273 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4274 DistanceToPoint2DCurveAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4279 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only spacedim 2 and 3 supported !");
4281 cellIds=ret1.retn();
4290 * Finds cells in contact with a ball (i.e. a point with precision).
4291 * 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.
4292 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4294 * \warning This method is suitable if the caller intends to evaluate only one
4295 * point, for more points getCellsContainingPoints() is recommended as it is
4297 * \param [in] pos - array of coordinates of the ball central point.
4298 * \param [in] eps - ball radius.
4299 * \return mcIdType - a smallest id of cells being in contact with the ball, -1 in case
4300 * if there are no such cells.
4301 * \throw If the coordinates array is not set.
4302 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4304 mcIdType MEDCouplingUMesh::getCellContainingPoint(const double *pos, double eps) const
4306 std::vector<mcIdType> elts;
4307 getCellsContainingPoint(pos,eps,elts);
4310 return elts.front();
4314 * Finds cells in contact with a ball (i.e. a point with precision).
4315 * 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.
4316 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4317 * \warning This method is suitable if the caller intends to evaluate only one
4318 * point, for more points getCellsContainingPoints() is recommended as it is
4320 * \param [in] pos - array of coordinates of the ball central point.
4321 * \param [in] eps - ball radius.
4322 * \param [out] elts - vector returning ids of the found cells. It is cleared
4323 * before inserting ids.
4324 * \throw If the coordinates array is not set.
4325 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4327 * \if ENABLE_EXAMPLES
4328 * \ref cpp_mcumesh_getCellsContainingPoint "Here is a C++ example".<br>
4329 * \ref py_mcumesh_getCellsContainingPoint "Here is a Python example".
4332 void MEDCouplingUMesh::getCellsContainingPoint(const double *pos, double eps, std::vector<mcIdType>& elts) const
4334 MCAuto<DataArrayIdType> eltsUg,eltsIndexUg;
4335 getCellsContainingPoints(pos,1,eps,eltsUg,eltsIndexUg);
4336 elts.clear(); elts.insert(elts.end(),eltsUg->begin(),eltsUg->end());
4339 void MEDCouplingUMesh::getCellsContainingPointsZeAlg(const double *pos, mcIdType nbOfPoints, double eps,
4340 MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex,
4341 std::function<bool(INTERP_KERNEL::NormalizedCellType,mcIdType)> sensibilityTo2DQuadraticLinearCellsFunc) const
4343 int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
4348 const double *coords=_coords->getConstPointer();
4349 getCellsContainingPointsAlg<3>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4352 throw INTERP_KERNEL::Exception("For spaceDim==3 only meshDim==3 implemented for getelementscontainingpoints !");
4354 else if(spaceDim==2)
4358 const double *coords=_coords->getConstPointer();
4359 getCellsContainingPointsAlg<2>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4362 throw INTERP_KERNEL::Exception("For spaceDim==2 only meshDim==2 implemented for getelementscontainingpoints !");
4364 else if(spaceDim==1)
4368 const double *coords=_coords->getConstPointer();
4369 getCellsContainingPointsAlg<1>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4372 throw INTERP_KERNEL::Exception("For spaceDim==1 only meshDim==1 implemented for getelementscontainingpoints !");
4375 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPoints : not managed for mdim not in [1,2,3] !");
4379 * Finds cells in contact with several balls (i.e. points with precision).
4380 * This method is an extension of getCellContainingPoint() and
4381 * getCellsContainingPoint() for the case of multiple points.
4382 * 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.
4383 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4384 * \param [in] pos - an array of coordinates of points in full interlace mode :
4385 * X0,Y0,Z0,X1,Y1,Z1,... Size of the array must be \a
4386 * this->getSpaceDimension() * \a nbOfPoints
4387 * \param [in] nbOfPoints - number of points to locate within \a this mesh.
4388 * \param [in] eps - radius of balls (i.e. the precision).
4389 * \param [out] elts - vector returning ids of found cells.
4390 * \param [out] eltsIndex - an array, of length \a nbOfPoints + 1,
4391 * dividing cell ids in \a elts into groups each referring to one
4392 * point. Its every element (except the last one) is an index pointing to the
4393 * first id of a group of cells. For example cells in contact with the *i*-th
4394 * point are described by following range of indices:
4395 * [ \a eltsIndex[ *i* ], \a eltsIndex[ *i*+1 ] ) and the cell ids are
4396 * \a elts[ \a eltsIndex[ *i* ]], \a elts[ \a eltsIndex[ *i* ] + 1 ], ...
4397 * Number of cells in contact with the *i*-th point is
4398 * \a eltsIndex[ *i*+1 ] - \a eltsIndex[ *i* ].
4399 * \throw If the coordinates array is not set.
4400 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4402 * \if ENABLE_EXAMPLES
4403 * \ref cpp_mcumesh_getCellsContainingPoints "Here is a C++ example".<br>
4404 * \ref py_mcumesh_getCellsContainingPoints "Here is a Python example".
4407 void MEDCouplingUMesh::getCellsContainingPoints(const double *pos, mcIdType nbOfPoints, double eps,
4408 MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex) const
4410 auto yesImSensibleTo2DQuadraticLinearCellsFunc([](INTERP_KERNEL::NormalizedCellType ct, int mdim) { return INTERP_KERNEL::CellModel::GetCellModel(ct).isQuadratic() && mdim == 2; } );
4411 this->getCellsContainingPointsZeAlg(pos,nbOfPoints,eps,elts,eltsIndex,yesImSensibleTo2DQuadraticLinearCellsFunc);
4415 * Behaves like MEDCouplingMesh::getCellsContainingPoints for cells in \a this that are linear.
4416 * For quadratic cells in \a this, this method behaves by just considering linear part of cells.
4417 * This method is here only for backward compatibility (interpolation GaussPoints to GaussPoints).
4419 * \sa MEDCouplingUMesh::getCellsContainingPoints, MEDCouplingRemapper::prepareNotInterpKernelOnlyGaussGauss
4421 void MEDCouplingUMesh::getCellsContainingPointsLinearPartOnlyOnNonDynType(const double *pos, mcIdType nbOfPoints, double eps, MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex) const
4423 auto noImNotSensibleTo2DQuadraticLinearCellsFunc([](INTERP_KERNEL::NormalizedCellType,mcIdType) { return false; } );
4424 this->getCellsContainingPointsZeAlg(pos,nbOfPoints,eps,elts,eltsIndex,noImNotSensibleTo2DQuadraticLinearCellsFunc);
4428 * Finds butterfly cells in \a this mesh. A 2D cell is considered to be butterfly if at
4429 * least two its edges intersect each other anywhere except their extremities. An
4430 * INTERP_KERNEL::NORM_NORI3 cell can \b not be butterfly.
4431 * \param [in,out] cells - a vector returning ids of the found cells. It is not
4432 * cleared before filling in.
4433 * \param [in] eps - precision.
4434 * \throw If \a this->getMeshDimension() != 2.
4435 * \throw If \a this->getSpaceDimension() != 2 && \a this->getSpaceDimension() != 3.
4437 void MEDCouplingUMesh::checkButterflyCells(std::vector<mcIdType>& cells, double eps) const
4439 const char msg[]="Butterfly detection work only for 2D cells with spaceDim==2 or 3!";
4440 if(getMeshDimension()!=2)
4441 throw INTERP_KERNEL::Exception(msg);
4442 int spaceDim=getSpaceDimension();
4443 if(spaceDim!=2 && spaceDim!=3)
4444 throw INTERP_KERNEL::Exception(msg);
4445 const mcIdType *conn=_nodal_connec->getConstPointer();
4446 const mcIdType *connI=_nodal_connec_index->getConstPointer();
4447 mcIdType nbOfCells=getNumberOfCells();
4448 std::vector<double> cell2DinS2;
4449 for(mcIdType i=0;i<nbOfCells;i++)
4451 mcIdType offset=connI[i];
4452 mcIdType nbOfNodesForCell=connI[i+1]-offset-1;
4453 if(nbOfNodesForCell<=3)
4455 bool isQuad=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[offset]).isQuadratic();
4456 project2DCellOnXY(conn+offset+1,conn+connI[i+1],cell2DinS2);
4457 if(isButterfly2DCell(cell2DinS2,isQuad,eps))
4464 * This method is typically requested to unbutterfly 2D linear cells in \b this.
4466 * 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.
4467 * 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.
4469 * For each 2D linear cell in \b this, this method builds the convex envelop (or the convex hull) of the current cell.
4470 * This convex envelop is computed using Jarvis march algorithm.
4471 * The coordinates and the number of cells of \b this remain unchanged on invocation of this method.
4472 * 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)
4473 * 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.
4475 * \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.
4476 * \sa MEDCouplingUMesh::colinearize2D
4478 DataArrayIdType *MEDCouplingUMesh::convexEnvelop2D()
4480 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
4481 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convexEnvelop2D works only for meshDim=2 and spaceDim=2 !");
4482 checkFullyDefined();
4483 const double *coords=getCoords()->getConstPointer();
4484 mcIdType nbOfCells=getNumberOfCells();
4485 MCAuto<DataArrayIdType> nodalConnecIndexOut=DataArrayIdType::New();
4486 nodalConnecIndexOut->alloc(nbOfCells+1,1);
4487 MCAuto<DataArrayIdType> nodalConnecOut(DataArrayIdType::New());
4488 mcIdType *workIndexOut=nodalConnecIndexOut->getPointer();
4490 const mcIdType *nodalConnecIn=_nodal_connec->getConstPointer();
4491 const mcIdType *nodalConnecIndexIn=_nodal_connec_index->getConstPointer();
4492 std::set<INTERP_KERNEL::NormalizedCellType> types;
4493 MCAuto<DataArrayIdType> isChanged(DataArrayIdType::New());
4494 isChanged->alloc(0,1);
4495 for(mcIdType i=0;i<nbOfCells;i++,workIndexOut++)
4497 mcIdType pos=nodalConnecOut->getNumberOfTuples();
4498 if(BuildConvexEnvelopOf2DCellJarvis(coords,nodalConnecIn+nodalConnecIndexIn[i],nodalConnecIn+nodalConnecIndexIn[i+1],nodalConnecOut))
4499 isChanged->pushBackSilent(i);
4500 types.insert((INTERP_KERNEL::NormalizedCellType)nodalConnecOut->getIJ(pos,0));
4501 workIndexOut[1]=nodalConnecOut->getNumberOfTuples();
4503 if(isChanged->empty())
4505 setConnectivity(nodalConnecOut,nodalConnecIndexOut,false);
4507 return isChanged.retn();
4511 * This method is \b NOT const because it can modify \a this.
4512 * \a this is expected to be an unstructured mesh with meshDim==2 and spaceDim==3. If not an exception will be thrown.
4513 * \param mesh1D is an unstructured mesh with MeshDim==1 and spaceDim==3. If not an exception will be thrown.
4514 * \param policy specifies the type of extrusion chosen:
4515 * - \b 0 for translation only (most simple): the cells of the 1D mesh represent the vectors along which the 2D mesh
4516 * will be repeated to build each level
4517 * - \b 1 for translation and rotation: the translation is done as above. For each level, an arc of circle is fitted on
4518 * 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
4519 * 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
4521 * \return an unstructured mesh with meshDim==3 and spaceDim==3. The returned mesh has the same coords than \a this.
4523 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMesh(const MEDCouplingUMesh *mesh1D, int policy)
4525 checkFullyDefined();
4526 mesh1D->checkFullyDefined();
4527 if(!mesh1D->isContiguous1D())
4528 throw INTERP_KERNEL::Exception("buildExtrudedMesh : 1D mesh passed in parameter is not contiguous !");
4529 if(getSpaceDimension()!=mesh1D->getSpaceDimension())
4530 throw INTERP_KERNEL::Exception("Invalid call to buildExtrudedMesh this and mesh1D must have same space dimension !");
4531 if((getMeshDimension()!=2 || getSpaceDimension()!=3) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
4532 throw INTERP_KERNEL::Exception("Invalid 'this' for buildExtrudedMesh method : must be (meshDim==2 and spaceDim==3) or (meshDim==1 and spaceDim==2) !");
4533 if(mesh1D->getMeshDimension()!=1)
4534 throw INTERP_KERNEL::Exception("Invalid 'mesh1D' for buildExtrudedMesh method : must be meshDim==1 !");
4536 if(isPresenceOfQuadratic())
4538 if(mesh1D->isFullyQuadratic())
4541 throw INTERP_KERNEL::Exception("Invalid 2D mesh and 1D mesh because 2D mesh has quadratic cells and 1D is not fully quadratic !");
4543 mcIdType oldNbOfNodes(getNumberOfNodes());
4544 MCAuto<DataArrayDouble> newCoords;
4549 newCoords=fillExtCoordsUsingTranslation(mesh1D,isQuad);
4554 newCoords=fillExtCoordsUsingTranslAndAutoRotation(mesh1D,isQuad);
4558 throw INTERP_KERNEL::Exception("Not implemented extrusion policy : must be in (0) !");
4560 setCoords(newCoords);
4561 MCAuto<MEDCouplingUMesh> ret(buildExtrudedMeshFromThisLowLev(oldNbOfNodes,isQuad));
4568 * Checks if \a this mesh is constituted by only quadratic cells.
4569 * \return bool - \c true if there are only quadratic cells in \a this mesh.
4570 * \throw If the coordinates array is not set.
4571 * \throw If the nodal connectivity of cells is not defined.
4573 bool MEDCouplingUMesh::isFullyQuadratic() const
4575 checkFullyDefined();
4577 mcIdType nbOfCells=getNumberOfCells();
4578 for(mcIdType i=0;i<nbOfCells && ret;i++)
4580 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4581 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4582 ret=cm.isQuadratic();
4588 * Checks if \a this mesh includes any quadratic cell.
4589 * \return bool - \c true if there is at least one quadratic cells in \a this mesh.
4590 * \throw If the coordinates array is not set.
4591 * \throw If the nodal connectivity of cells is not defined.
4593 bool MEDCouplingUMesh::isPresenceOfQuadratic() const
4595 checkFullyDefined();
4597 mcIdType nbOfCells=getNumberOfCells();
4598 for(mcIdType i=0;i<nbOfCells && !ret;i++)
4600 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4601 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4602 ret=cm.isQuadratic();
4608 * Converts all quadratic cells to linear ones. If there are no quadratic cells in \a
4609 * this mesh, it remains unchanged.
4610 * \throw If the coordinates array is not set.
4611 * \throw If the nodal connectivity of cells is not defined.
4613 void MEDCouplingUMesh::convertQuadraticCellsToLinear()
4615 checkFullyDefined();
4616 mcIdType nbOfCells=getNumberOfCells();
4618 const mcIdType *iciptr=_nodal_connec_index->begin();
4619 for(mcIdType i=0;i<nbOfCells;i++)
4621 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4622 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4623 if(cm.isQuadratic())
4625 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4626 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4627 if(!cml.isDynamic())
4628 delta+=cm.getNumberOfNodes()-cml.getNumberOfNodes();
4630 delta+=(iciptr[i+1]-iciptr[i]-1)/2;
4635 MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()),newConnI(DataArrayIdType::New());
4636 const mcIdType *icptr(_nodal_connec->begin());
4637 newConn->alloc(getNodalConnectivityArrayLen()-delta,1);
4638 newConnI->alloc(nbOfCells+1,1);
4639 mcIdType *ocptr(newConn->getPointer()),*ociptr(newConnI->getPointer());
4642 for(mcIdType i=0;i<nbOfCells;i++,ociptr++)
4644 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)icptr[iciptr[i]];
4645 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4646 if(!cm.isQuadratic())
4648 _types.insert(type);
4649 ocptr=std::copy(icptr+iciptr[i],icptr+iciptr[i+1],ocptr);
4650 ociptr[1]=ociptr[0]+iciptr[i+1]-iciptr[i];
4654 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4655 _types.insert(typel);
4656 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4657 mcIdType newNbOfNodes=cml.getNumberOfNodes();
4659 newNbOfNodes=(iciptr[i+1]-iciptr[i]-1)/2;
4660 *ocptr++=ToIdType(typel);
4661 ocptr=std::copy(icptr+iciptr[i]+1,icptr+iciptr[i]+newNbOfNodes+1,ocptr);
4662 ociptr[1]=ociptr[0]+newNbOfNodes+1;
4665 setConnectivity(newConn,newConnI,false);
4669 * This method converts all linear cell in \a this to quadratic one.
4670 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, here it is needed to specify the target
4671 * 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)
4672 * 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.
4673 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, the coordinates in \a this can be become bigger. All created nodes will be put at the
4674 * end of the existing coordinates.
4676 * \param [in] conversionType specifies the type of conversion expected. Only 0 (default) and 1 are supported presently. 0 those that creates the 'most' simple
4677 * corresponding quadratic cells. 1 is those creating the 'most' complex.
4678 * \return a newly created DataArrayIdType instance that the caller should deal with containing cell ids of converted cells.
4680 * \throw if \a this is not fully defined. It throws too if \a conversionType is not in [0,1].
4682 * \sa MEDCouplingUMesh::convertQuadraticCellsToLinear
4684 DataArrayIdType *MEDCouplingUMesh::convertLinearCellsToQuadratic(int conversionType)
4686 DataArrayIdType *conn=0,*connI=0;
4687 DataArrayDouble *coords=0;
4688 std::set<INTERP_KERNEL::NormalizedCellType> types;
4689 checkFullyDefined();
4690 MCAuto<DataArrayIdType> ret,connSafe,connISafe;
4691 MCAuto<DataArrayDouble> coordsSafe;
4692 int meshDim=getMeshDimension();
4693 switch(conversionType)
4699 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);
4700 connSafe=conn; connISafe=connI; coordsSafe=coords;
4703 ret=convertLinearCellsToQuadratic2D0(conn,connI,coords,types);
4704 connSafe=conn; connISafe=connI; coordsSafe=coords;
4707 ret=convertLinearCellsToQuadratic3D0(conn,connI,coords,types);
4708 connSafe=conn; connISafe=connI; coordsSafe=coords;
4711 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 0 mesh dimensions available are [1,2,3] !");
4719 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);//it is not a bug. In 1D policy 0 and 1 are equals
4720 connSafe=conn; connISafe=connI; coordsSafe=coords;
4723 ret=convertLinearCellsToQuadratic2D1(conn,connI,coords,types);
4724 connSafe=conn; connISafe=connI; coordsSafe=coords;
4727 ret=convertLinearCellsToQuadratic3D1(conn,connI,coords,types);
4728 connSafe=conn; connISafe=connI; coordsSafe=coords;
4731 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 1 mesh dimensions available are [1,2,3] !");
4736 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion type available are 0 (default, the simplest) and 1 (the most complex) !");
4738 setConnectivity(connSafe,connISafe,false);
4740 setCoords(coordsSafe);
4745 * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
4746 * so that the number of cells remains the same. Quadratic faces are converted to
4747 * polygons. This method works only for 2D meshes in
4748 * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
4749 * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
4750 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
4751 * \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
4752 * a polylinized edge constituting the input polygon.
4753 * \throw If the coordinates array is not set.
4754 * \throw If the nodal connectivity of cells is not defined.
4755 * \throw If \a this->getMeshDimension() != 2.
4756 * \throw If \a this->getSpaceDimension() != 2.
4758 void MEDCouplingUMesh::tessellate2D(double eps)
4760 int meshDim(getMeshDimension()),spaceDim(getSpaceDimension());
4762 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : works only with space dimension equal to 2 !");
4766 return tessellate2DCurveInternal(eps);
4768 return tessellate2DInternal(eps);
4770 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : mesh dimension must be in [1,2] !");
4776 * This method only works if \a this has spaceDimension equal to 2 and meshDimension also equal to 2.
4777 * This method allows to modify connectivity of cells in \a this that shares some edges in \a edgeIdsToBeSplit.
4778 * The nodes to be added in those 2D cells are defined by the pair of \a nodeIdsToAdd and \a nodeIdsIndexToAdd.
4779 * Length of \a nodeIdsIndexToAdd is expected to equal to length of \a edgeIdsToBeSplit + 1.
4780 * The node ids in \a nodeIdsToAdd should be valid. Those nodes have to be sorted exactly following exactly the direction of the edge.
4781 * This method can be seen as the opposite method of colinearize2D.
4782 * 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
4783 * to avoid to modify the numbering of existing nodes.
4785 * \param [in] nodeIdsToAdd - the list of node ids to be added (\a nodeIdsIndexToAdd array allows to walk on this array)
4786 * \param [in] nodeIdsIndexToAdd - the entry point of \a nodeIdsToAdd to point to the corresponding nodes to be added.
4787 * \param [in] mesh1Desc - 1st output of buildDescendingConnectivity2 on \a this.
4788 * \param [in] desc - 2nd output of buildDescendingConnectivity2 on \a this.
4789 * \param [in] descI - 3rd output of buildDescendingConnectivity2 on \a this.
4790 * \param [in] revDesc - 4th output of buildDescendingConnectivity2 on \a this.
4791 * \param [in] revDescI - 5th output of buildDescendingConnectivity2 on \a this.
4793 * \sa buildDescendingConnectivity2
4795 void MEDCouplingUMesh::splitSomeEdgesOf2DMesh(const DataArrayIdType *nodeIdsToAdd, const DataArrayIdType *nodeIdsIndexToAdd, const DataArrayIdType *edgeIdsToBeSplit,
4796 const MEDCouplingUMesh *mesh1Desc, const DataArrayIdType *desc, const DataArrayIdType *descI, const DataArrayIdType *revDesc, const DataArrayIdType *revDescI)
4798 if(!nodeIdsToAdd || !nodeIdsIndexToAdd || !edgeIdsToBeSplit || !mesh1Desc || !desc || !descI || !revDesc || !revDescI)
4799 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : input pointers must be not NULL !");
4800 nodeIdsToAdd->checkAllocated(); nodeIdsIndexToAdd->checkAllocated(); edgeIdsToBeSplit->checkAllocated(); desc->checkAllocated(); descI->checkAllocated(); revDesc->checkAllocated(); revDescI->checkAllocated();
4801 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
4802 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : this must have spacedim=meshdim=2 !");
4803 if(mesh1Desc->getSpaceDimension()!=2 || mesh1Desc->getMeshDimension()!=1)
4804 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : mesh1Desc must be the explosion of this with spaceDim=2 and meshDim = 1 !");
4805 //DataArrayIdType *out0(0),*outi0(0);
4806 //MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
4807 //MCAuto<DataArrayIdType> out0s(out0),outi0s(outi0);
4808 //out0s=out0s->buildUnique(); out0s->sort(true);
4814 * Divides every cell of \a this mesh into simplices (triangles in 2D and tetrahedra in 3D).
4815 * In addition, returns an array mapping new cells to old ones. <br>
4816 * This method typically increases the number of cells in \a this mesh
4817 * but the number of nodes remains \b unchanged.
4818 * That's why the 3D splitting policies
4819 * INTERP_KERNEL::GENERAL_24 and INTERP_KERNEL::GENERAL_48 are not available here.
4820 * \param [in] policy - specifies a pattern used for splitting.
4821 * The semantic of \a policy is:
4822 * - 0 - to split QUAD4 by cutting it along 0-2 diagonal (for 2D mesh only).
4823 * - 1 - to split QUAD4 by cutting it along 1-3 diagonal (for 2D mesh only).
4824 * - INTERP_KERNEL::PLANAR_FACE_5 - to split HEXA8 into 5 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4825 * - INTERP_KERNEL::PLANAR_FACE_6 - to split HEXA8 into 6 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4828 * \return DataArrayIdType * - a new instance of DataArrayIdType holding, for each new cell,
4829 * an id of old cell producing it. The caller is to delete this array using
4830 * decrRef() as it is no more needed.
4832 * \throw If \a policy is 0 or 1 and \a this->getMeshDimension() != 2.
4833 * \throw If \a policy is INTERP_KERNEL::PLANAR_FACE_5 or INTERP_KERNEL::PLANAR_FACE_6
4834 * and \a this->getMeshDimension() != 3.
4835 * \throw If \a policy is not one of the four discussed above.
4836 * \throw If the nodal connectivity of cells is not defined.
4837 * \sa MEDCouplingUMesh::tetrahedrize, MEDCoupling1SGTUMesh::sortHexa8EachOther
4839 DataArrayIdType *MEDCouplingUMesh::simplexize(int policy)
4844 return simplexizePol0();
4846 return simplexizePol1();
4847 case INTERP_KERNEL::PLANAR_FACE_5:
4848 return simplexizePlanarFace5();
4849 case INTERP_KERNEL::PLANAR_FACE_6:
4850 return simplexizePlanarFace6();
4852 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)");
4857 * Checks if \a this mesh is constituted by simplex cells only. Simplex cells are:
4858 * - 1D: INTERP_KERNEL::NORM_SEG2
4859 * - 2D: INTERP_KERNEL::NORM_TRI3
4860 * - 3D: INTERP_KERNEL::NORM_TETRA4.
4862 * This method is useful for users that need to use P1 field services as
4863 * MEDCouplingFieldDouble::getValueOn(), MEDCouplingField::buildMeasureField() etc.
4864 * All these methods need mesh support containing only simplex cells.
4865 * \return bool - \c true if there are only simplex cells in \a this mesh.
4866 * \throw If the coordinates array is not set.
4867 * \throw If the nodal connectivity of cells is not defined.
4868 * \throw If \a this->getMeshDimension() < 1.
4870 bool MEDCouplingUMesh::areOnlySimplexCells() const
4872 checkFullyDefined();
4873 int mdim=getMeshDimension();
4874 if(mdim<1 || mdim>3)
4875 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::areOnlySimplexCells : only available with meshes having a meshdim 1, 2 or 3 !");
4876 mcIdType nbCells=getNumberOfCells();
4877 const mcIdType *conn=_nodal_connec->begin();
4878 const mcIdType *connI=_nodal_connec_index->begin();
4879 for(mcIdType i=0;i<nbCells;i++)
4881 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4891 * Converts degenerated 2D or 3D linear cells of \a this mesh into cells of simpler
4892 * type. For example an INTERP_KERNEL::NORM_QUAD4 cell having only three unique nodes in
4893 * its connectivity is transformed into an INTERP_KERNEL::NORM_TRI3 cell.
4894 * Quadratic cells in 2D are also handled. In those cells edges where start=end=midpoint are removed.
4895 * This method does \b not perform geometrical checks and checks only nodal connectivity of cells,
4896 * so it can be useful to call mergeNodes() before calling this method.
4897 * \throw If \a this->getMeshDimension() <= 1.
4898 * \throw If the coordinates array is not set.
4899 * \throw If the nodal connectivity of cells is not defined.
4901 void MEDCouplingUMesh::convertDegeneratedCells()
4903 checkFullyDefined();
4904 if(getMeshDimension()<=1)
4905 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4906 mcIdType nbOfCells=getNumberOfCells();
4909 mcIdType initMeshLgth=getNodalConnectivityArrayLen();
4910 mcIdType *conn=_nodal_connec->getPointer();
4911 mcIdType *index=_nodal_connec_index->getPointer();
4912 mcIdType posOfCurCell=0;
4914 mcIdType lgthOfCurCell;
4915 for(mcIdType i=0;i<nbOfCells;i++)
4917 lgthOfCurCell=index[i+1]-posOfCurCell;
4918 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4920 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
4921 conn+newPos+1,newLgth);
4922 conn[newPos]=newType;
4924 posOfCurCell=index[i+1];
4927 if(newPos!=initMeshLgth)
4928 _nodal_connec->reAlloc(newPos);
4933 * Same as MEDCouplingUMesh::convertDegeneratedCells() plus deletion of the flat cells.
4934 * A cell is flat in the following cases:
4935 * - for a linear cell, all points in the connectivity are equal
4936 * - for a quadratic cell, either the above, or a quadratic polygon with two (linear) points and two
4937 * identical quadratic points
4938 * \return a new instance of DataArrayIdType holding ids of removed cells. The caller is to delete
4939 * this array using decrRef() as it is no more needed.
4941 DataArrayIdType *MEDCouplingUMesh::convertDegeneratedCellsAndRemoveFlatOnes()
4943 checkFullyDefined();
4944 if(getMeshDimension()<=1)
4945 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4946 mcIdType nbOfCells=getNumberOfCells();
4947 MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(0,1);
4950 mcIdType initMeshLgth=getNodalConnectivityArrayLen();
4951 mcIdType *conn=_nodal_connec->getPointer();
4952 mcIdType *index=_nodal_connec_index->getPointer();
4953 mcIdType posOfCurCell=0;
4955 mcIdType lgthOfCurCell, nbDelCells(0);
4956 for(mcIdType i=0;i<nbOfCells;i++)
4958 lgthOfCurCell=index[i+1]-posOfCurCell;
4959 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4961 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
4962 conn+newPos+1,newLgth);
4963 // Shall we delete the cell if it is completely degenerated:
4964 bool delCell=INTERP_KERNEL::CellSimplify::isFlatCell(conn, newPos, newLgth, newType);
4968 ret->pushBackSilent(i);
4970 else //if the cell is to be deleted, simply stay at the same place
4972 conn[newPos]=newType;
4975 posOfCurCell=index[i+1];
4976 index[i+1-nbDelCells]=newPos;
4978 if(newPos!=initMeshLgth)
4979 _nodal_connec->reAlloc(newPos);
4980 const mcIdType nCellDel=ret->getNumberOfTuples();
4982 _nodal_connec_index->reAlloc(nbOfCells-nCellDel+1);
4988 * This method remove null 1D cells from \a this. A 1D cell is considered null if start node is equal to end node.
4989 * Only connectivity is considered here.
4991 bool MEDCouplingUMesh::removeDegenerated1DCells()
4993 checkConnectivityFullyDefined();
4994 if(getMeshDimension()!=1)
4995 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::removeDegenerated1DCells works on umeshes with meshdim equals to 1 !");
4996 std::size_t nbCells(getNumberOfCells()),newSize(0),newSize2(0);
4997 const mcIdType *conn(getNodalConnectivity()->begin()),*conni(getNodalConnectivityIndex()->begin());
4999 for(std::size_t i=0;i<nbCells;i++)
5001 INTERP_KERNEL::NormalizedCellType ct((INTERP_KERNEL::NormalizedCellType)conn[conni[i]]);
5002 if(ct==INTERP_KERNEL::NORM_SEG2 || ct==INTERP_KERNEL::NORM_SEG3)
5004 if(conn[conni[i]+1]!=conn[conni[i]+2])
5007 newSize2+=conni[i+1]-conni[i];
5012 std::ostringstream oss; oss << "MEDCouplingUMesh::removeDegenerated1DCells : cell #" << i << " in this is not of type SEG2/SEG3 !";
5013 throw INTERP_KERNEL::Exception(oss.str());
5017 if(newSize==nbCells)//no cells has been removed -> do nothing
5019 MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()),newConnI(DataArrayIdType::New()); newConnI->alloc(newSize+1,1); newConn->alloc(newSize2,1);
5020 mcIdType *newConnPtr(newConn->getPointer()),*newConnIPtr(newConnI->getPointer()); newConnIPtr[0]=0;
5021 for(std::size_t i=0;i<nbCells;i++)
5023 if(conn[conni[i]+1]!=conn[conni[i]+2])
5025 newConnIPtr[1]=newConnIPtr[0]+conni[i+1]-conni[i];
5026 newConnPtr=std::copy(conn+conni[i],conn+conni[i+1],newConnPtr);
5030 setConnectivity(newConn,newConnI,true);
5035 * Finds incorrectly oriented cells of this 2D mesh in 3D space.
5036 * A cell is considered to be oriented correctly if an angle between its
5037 * normal vector and a given vector is less than \c PI / \c 2.
5038 * \param [in] vec - 3 components of the vector specifying the correct orientation of
5040 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
5042 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
5043 * is not cleared before filling in.
5044 * \throw If \a this->getMeshDimension() != 2.
5045 * \throw If \a this->getSpaceDimension() != 3.
5047 * \if ENABLE_EXAMPLES
5048 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
5049 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
5052 void MEDCouplingUMesh::are2DCellsNotCorrectlyOriented(const double *vec, bool polyOnly, std::vector<mcIdType>& cells) const
5054 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
5055 throw INTERP_KERNEL::Exception("Invalid mesh to apply are2DCellsNotCorrectlyOriented on it : must be meshDim==2 and spaceDim==3 !");
5056 mcIdType nbOfCells=getNumberOfCells();
5057 const mcIdType *conn=_nodal_connec->begin();
5058 const mcIdType *connI=_nodal_connec_index->begin();
5059 const double *coordsPtr=_coords->begin();
5060 for(mcIdType i=0;i<nbOfCells;i++)
5062 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5063 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
5065 bool isQuadratic=INTERP_KERNEL::CellModel::GetCellModel(type).isQuadratic();
5066 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5073 * Reverse connectivity of 2D cells whose orientation is not correct. A cell is
5074 * considered to be oriented correctly if an angle between its normal vector and a
5075 * given vector is less than \c PI / \c 2.
5076 * \param [in] vec - 3 components of the vector specifying the correct orientation of
5078 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
5080 * \throw If \a this->getMeshDimension() != 2.
5081 * \throw If \a this->getSpaceDimension() != 3.
5083 * \if ENABLE_EXAMPLES
5084 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
5085 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
5088 * \sa changeOrientationOfCells
5090 void MEDCouplingUMesh::orientCorrectly2DCells(const double *vec, bool polyOnly)
5092 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
5093 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectly2DCells on it : must be meshDim==2 and spaceDim==3 !");
5094 mcIdType nbOfCells=getNumberOfCells();
5095 mcIdType *conn(_nodal_connec->getPointer());
5096 const mcIdType *connI(_nodal_connec_index->begin());
5097 const double *coordsPtr(_coords->begin());
5098 bool isModified(false);
5099 for(mcIdType i=0;i<nbOfCells;i++)
5101 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5102 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
5104 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
5105 bool isQuadratic(cm.isQuadratic());
5106 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5109 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
5114 _nodal_connec->declareAsNew();
5119 * This method change the orientation of cells in \a this without any consideration of coordinates. Only connectivity is impacted.
5121 * \sa orientCorrectly2DCells
5123 void MEDCouplingUMesh::changeOrientationOfCells()
5125 int mdim(getMeshDimension());
5126 if(mdim!=2 && mdim!=1)
5127 throw INTERP_KERNEL::Exception("Invalid mesh to apply changeOrientationOfCells on it : must be meshDim==2 or meshDim==1 !");
5128 mcIdType nbOfCells=getNumberOfCells();
5129 mcIdType *conn(_nodal_connec->getPointer());
5130 const mcIdType *connI(_nodal_connec_index->begin());
5133 for(mcIdType i=0;i<nbOfCells;i++)
5135 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5136 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
5137 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
5142 for(mcIdType i=0;i<nbOfCells;i++)
5144 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5145 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
5146 cm.changeOrientationOf1D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
5152 * Finds incorrectly oriented polyhedral cells, i.e. polyhedrons having correctly
5153 * oriented facets. The normal vector of the facet should point out of the cell.
5154 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
5155 * is not cleared before filling in.
5156 * \throw If \a this->getMeshDimension() != 3.
5157 * \throw If \a this->getSpaceDimension() != 3.
5158 * \throw If the coordinates array is not set.
5159 * \throw If the nodal connectivity of cells is not defined.
5161 * \if ENABLE_EXAMPLES
5162 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
5163 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
5166 void MEDCouplingUMesh::arePolyhedronsNotCorrectlyOriented(std::vector<mcIdType>& cells) const
5168 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
5169 throw INTERP_KERNEL::Exception("Invalid mesh to apply arePolyhedronsNotCorrectlyOriented on it : must be meshDim==3 and spaceDim==3 !");
5170 mcIdType nbOfCells=getNumberOfCells();
5171 const mcIdType *conn=_nodal_connec->begin();
5172 const mcIdType *connI=_nodal_connec_index->begin();
5173 const double *coordsPtr=_coords->begin();
5174 for(mcIdType i=0;i<nbOfCells;i++)
5176 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5177 if(type==INTERP_KERNEL::NORM_POLYHED)
5179 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5186 * Tries to fix connectivity of polyhedra, so that normal vector of all facets to point
5188 * \throw If \a this->getMeshDimension() != 3.
5189 * \throw If \a this->getSpaceDimension() != 3.
5190 * \throw If the coordinates array is not set.
5191 * \throw If the nodal connectivity of cells is not defined.
5192 * \throw If the reparation fails.
5194 * \if ENABLE_EXAMPLES
5195 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
5196 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
5198 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
5200 void MEDCouplingUMesh::orientCorrectlyPolyhedrons()
5202 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
5203 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectlyPolyhedrons on it : must be meshDim==3 and spaceDim==3 !");
5204 mcIdType nbOfCells=getNumberOfCells();
5205 mcIdType *conn=_nodal_connec->getPointer();
5206 const mcIdType *connI=_nodal_connec_index->begin();
5207 const double *coordsPtr=_coords->begin();
5208 for(mcIdType i=0;i<nbOfCells;i++)
5210 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5211 if(type==INTERP_KERNEL::NORM_POLYHED)
5215 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5216 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
5218 catch(INTERP_KERNEL::Exception& e)
5220 std::ostringstream oss; oss << "Something wrong in polyhedron #" << i << " : " << e.what();
5221 throw INTERP_KERNEL::Exception(oss.str());
5229 * This method invert orientation of all cells in \a this.
5230 * After calling this method the absolute value of measure of cells in \a this are the same than before calling.
5231 * This method only operates on the connectivity so coordinates are not touched at all.
5233 void MEDCouplingUMesh::invertOrientationOfAllCells()
5235 checkConnectivityFullyDefined();
5236 std::set<INTERP_KERNEL::NormalizedCellType> gts(getAllGeoTypes());
5237 mcIdType *conn(_nodal_connec->getPointer());
5238 const mcIdType *conni(_nodal_connec_index->begin());
5239 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator gt=gts.begin();gt!=gts.end();gt++)
5241 INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::OrientationInverter> oi(INTERP_KERNEL::OrientationInverter::BuildInstanceFrom(*gt));
5242 MCAuto<DataArrayIdType> cwt(giveCellsWithType(*gt));
5243 for(const mcIdType *it=cwt->begin();it!=cwt->end();it++)
5244 oi->operate(conn+conni[*it]+1,conn+conni[*it+1]);
5250 * Finds and fixes incorrectly oriented linear extruded volumes (INTERP_KERNEL::NORM_HEXA8,
5251 * INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXGP12 etc) to respect the MED convention
5252 * according to which the first facet of the cell should be oriented to have the normal vector
5253 * pointing out of cell.
5254 * \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of fixed
5255 * cells. The caller is to delete this array using decrRef() as it is no more
5257 * \throw If \a this->getMeshDimension() != 3.
5258 * \throw If \a this->getSpaceDimension() != 3.
5259 * \throw If the coordinates array is not set.
5260 * \throw If the nodal connectivity of cells is not defined.
5262 * \if ENABLE_EXAMPLES
5263 * \ref cpp_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a C++ example".<br>
5264 * \ref py_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a Python example".
5266 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
5268 DataArrayIdType *MEDCouplingUMesh::findAndCorrectBadOriented3DExtrudedCells()
5270 const char msg[]="check3DCellsWellOriented detection works only for 3D cells !";
5271 if(getMeshDimension()!=3)
5272 throw INTERP_KERNEL::Exception(msg);
5273 int spaceDim=getSpaceDimension();
5275 throw INTERP_KERNEL::Exception(msg);
5277 mcIdType nbOfCells=getNumberOfCells();
5278 mcIdType *conn=_nodal_connec->getPointer();
5279 const mcIdType *connI=_nodal_connec_index->begin();
5280 const double *coo=getCoords()->begin();
5281 MCAuto<DataArrayIdType> cells(DataArrayIdType::New()); cells->alloc(0,1);
5282 for(mcIdType i=0;i<nbOfCells;i++)
5284 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5285 if(cm.isExtruded() && !cm.isDynamic() && !cm.isQuadratic())
5287 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coo))
5289 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
5290 cells->pushBackSilent(i);
5294 return cells.retn();
5298 * This method is a faster method to correct orientation of all 3D cells in \a this.
5299 * 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.
5300 * This method makes the hypothesis that \a this a coherent that is to say MEDCouplingUMesh::checkConsistency should throw no exception.
5302 * \return a newly allocated mcIdType array with one components containing cell ids renumbered to fit the convention of MED (MED file and MEDCoupling)
5303 * \sa MEDCouplingUMesh::orientCorrectlyPolyhedrons,
5305 DataArrayIdType *MEDCouplingUMesh::findAndCorrectBadOriented3DCells()
5307 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
5308 throw INTERP_KERNEL::Exception("Invalid mesh to apply findAndCorrectBadOriented3DCells on it : must be meshDim==3 and spaceDim==3 !");
5309 mcIdType nbOfCells=getNumberOfCells();
5310 mcIdType *conn=_nodal_connec->getPointer();
5311 const mcIdType *connI=_nodal_connec_index->begin();
5312 const double *coordsPtr=_coords->begin();
5313 MCAuto<DataArrayIdType> ret=DataArrayIdType::New(); ret->alloc(0,1);
5314 for(mcIdType i=0;i<nbOfCells;i++)
5316 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5319 case INTERP_KERNEL::NORM_TETRA4:
5321 if(!IsTetra4WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5323 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+3));
5324 ret->pushBackSilent(i);
5328 case INTERP_KERNEL::NORM_PYRA5:
5330 if(!IsPyra5WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5332 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+4));
5333 ret->pushBackSilent(i);
5337 case INTERP_KERNEL::NORM_PENTA6:
5338 case INTERP_KERNEL::NORM_HEXA8:
5339 case INTERP_KERNEL::NORM_HEXGP12:
5341 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5343 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
5344 ret->pushBackSilent(i);
5348 case INTERP_KERNEL::NORM_POLYHED:
5350 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5352 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
5353 ret->pushBackSilent(i);
5358 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 !");
5366 * This method has a sense for meshes with spaceDim==3 and meshDim==2.
5367 * If it is not the case an exception will be thrown.
5368 * This method is fast because the first cell of \a this is used to compute the plane.
5369 * \param vec output of size at least 3 used to store the normal vector (with norm equal to Area ) of searched plane.
5370 * \param pos output of size at least 3 used to store a point owned of searched plane.
5372 void MEDCouplingUMesh::getFastAveragePlaneOfThis(double *vec, double *pos) const
5374 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
5375 throw INTERP_KERNEL::Exception("Invalid mesh to apply getFastAveragePlaneOfThis on it : must be meshDim==2 and spaceDim==3 !");
5376 const mcIdType *conn=_nodal_connec->begin();
5377 const mcIdType *connI=_nodal_connec_index->begin();
5378 const double *coordsPtr=_coords->begin();
5379 INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(conn+1,connI[1]-connI[0]-1,coordsPtr,vec);
5380 std::copy(coordsPtr+3*conn[1],coordsPtr+3*conn[1]+3,pos);
5384 * Creates a new MEDCouplingFieldDouble holding Edge Ratio values of all
5385 * cells. Currently cells of the following types are treated:
5386 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5387 * For a cell of other type an exception is thrown.
5388 * Space dimension of a 2D mesh can be either 2 or 3.
5389 * The Edge Ratio of a cell \f$t\f$ is:
5390 * \f$\frac{|t|_\infty}{|t|_0}\f$,
5391 * where \f$|t|_\infty\f$ and \f$|t|_0\f$ respectively denote the greatest and
5392 * the smallest edge lengths of \f$t\f$.
5393 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5394 * cells and one time, lying on \a this mesh. The caller is to delete this
5395 * field using decrRef() as it is no more needed.
5396 * \throw If the coordinates array is not set.
5397 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5398 * \throw If the connectivity data array has more than one component.
5399 * \throw If the connectivity data array has a named component.
5400 * \throw If the connectivity index data array has more than one component.
5401 * \throw If the connectivity index data array has a named component.
5402 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
5403 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5404 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5406 MEDCouplingFieldDouble *MEDCouplingUMesh::getEdgeRatioField() const
5408 checkConsistencyLight();
5409 int spaceDim=getSpaceDimension();
5410 int meshDim=getMeshDimension();
5411 if(spaceDim!=2 && spaceDim!=3)
5412 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : SpaceDimension must be equal to 2 or 3 !");
5413 if(meshDim!=2 && meshDim!=3)
5414 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : MeshDimension must be equal to 2 or 3 !");
5415 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5417 mcIdType nbOfCells=getNumberOfCells();
5418 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5419 arr->alloc(nbOfCells,1);
5420 double *pt=arr->getPointer();
5421 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5422 const mcIdType *conn=_nodal_connec->begin();
5423 const mcIdType *connI=_nodal_connec_index->begin();
5424 const double *coo=_coords->begin();
5426 for(mcIdType i=0;i<nbOfCells;i++,pt++)
5428 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5431 case INTERP_KERNEL::NORM_TRI3:
5433 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5434 *pt=INTERP_KERNEL::triEdgeRatio(tmp);
5437 case INTERP_KERNEL::NORM_QUAD4:
5439 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5440 *pt=INTERP_KERNEL::quadEdgeRatio(tmp);
5443 case INTERP_KERNEL::NORM_TETRA4:
5445 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5446 *pt=INTERP_KERNEL::tetraEdgeRatio(tmp);
5450 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5452 conn+=connI[i+1]-connI[i];
5454 ret->setName("EdgeRatio");
5455 ret->synchronizeTimeWithSupport();
5460 * Creates a new MEDCouplingFieldDouble holding Aspect Ratio values of all
5461 * cells. Currently cells of the following types are treated:
5462 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5463 * For a cell of other type an exception is thrown.
5464 * Space dimension of a 2D mesh can be either 2 or 3.
5465 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5466 * cells and one time, lying on \a this mesh. The caller is to delete this
5467 * field using decrRef() as it is no more needed.
5468 * \throw If the coordinates array is not set.
5469 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5470 * \throw If the connectivity data array has more than one component.
5471 * \throw If the connectivity data array has a named component.
5472 * \throw If the connectivity index data array has more than one component.
5473 * \throw If the connectivity index data array has a named component.
5474 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
5475 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5476 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5478 MEDCouplingFieldDouble *MEDCouplingUMesh::getAspectRatioField() const
5480 checkConsistencyLight();
5481 int spaceDim=getSpaceDimension();
5482 int meshDim=getMeshDimension();
5483 if(spaceDim!=2 && spaceDim!=3)
5484 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : SpaceDimension must be equal to 2 or 3 !");
5485 if(meshDim!=2 && meshDim!=3)
5486 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : MeshDimension must be equal to 2 or 3 !");
5487 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5489 mcIdType nbOfCells=getNumberOfCells();
5490 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5491 arr->alloc(nbOfCells,1);
5492 double *pt=arr->getPointer();
5493 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5494 const mcIdType *conn=_nodal_connec->begin();
5495 const mcIdType *connI=_nodal_connec_index->begin();
5496 const double *coo=_coords->begin();
5498 for(mcIdType i=0;i<nbOfCells;i++,pt++)
5500 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5503 case INTERP_KERNEL::NORM_TRI3:
5505 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5506 *pt=INTERP_KERNEL::triAspectRatio(tmp);
5509 case INTERP_KERNEL::NORM_QUAD4:
5511 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5512 *pt=INTERP_KERNEL::quadAspectRatio(tmp);
5515 case INTERP_KERNEL::NORM_TETRA4:
5517 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5518 *pt=INTERP_KERNEL::tetraAspectRatio(tmp);
5522 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5524 conn+=connI[i+1]-connI[i];
5526 ret->setName("AspectRatio");
5527 ret->synchronizeTimeWithSupport();
5532 * Creates a new MEDCouplingFieldDouble holding Warping factor values of all
5533 * cells of \a this 2D mesh in 3D space. It is a measure of the "planarity" of 2D cell
5534 * in 3D space. Currently only cells of the following types are
5535 * treated: INTERP_KERNEL::NORM_QUAD4.
5536 * For a cell of other type an exception is thrown.
5537 * The warp field is computed as follows: let (a,b,c,d) be the points of the quad.
5539 * \f$t=\vec{da}\times\vec{ab}\f$,
5540 * \f$u=\vec{ab}\times\vec{bc}\f$
5541 * \f$v=\vec{bc}\times\vec{cd}\f$
5542 * \f$w=\vec{cd}\times\vec{da}\f$, the warp is defined as \f$W^3\f$ with
5544 * W=min(\frac{t}{|t|}\cdot\frac{v}{|v|}, \frac{u}{|u|}\cdot\frac{w}{|w|})
5546 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5547 * cells and one time, lying on \a this mesh. The caller is to delete this
5548 * field using decrRef() as it is no more needed.
5549 * \throw If the coordinates array is not set.
5550 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5551 * \throw If the connectivity data array has more than one component.
5552 * \throw If the connectivity data array has a named component.
5553 * \throw If the connectivity index data array has more than one component.
5554 * \throw If the connectivity index data array has a named component.
5555 * \throw If \a this->getMeshDimension() != 2.
5556 * \throw If \a this->getSpaceDimension() != 3.
5557 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5559 MEDCouplingFieldDouble *MEDCouplingUMesh::getWarpField() const
5561 checkConsistencyLight();
5562 int spaceDim=getSpaceDimension();
5563 int meshDim=getMeshDimension();
5565 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : SpaceDimension must be equal to 3 !");
5567 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : MeshDimension must be equal to 2 !");
5568 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5570 mcIdType nbOfCells=getNumberOfCells();
5571 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5572 arr->alloc(nbOfCells,1);
5573 double *pt=arr->getPointer();
5574 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5575 const mcIdType *conn=_nodal_connec->begin();
5576 const mcIdType *connI=_nodal_connec_index->begin();
5577 const double *coo=_coords->begin();
5579 for(mcIdType i=0;i<nbOfCells;i++,pt++)
5581 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5584 case INTERP_KERNEL::NORM_QUAD4:
5586 FillInCompact3DMode(3,4,conn+1,coo,tmp);
5587 *pt=INTERP_KERNEL::quadWarp(tmp);
5591 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : A cell with not manged type (NORM_QUAD4) has been detected !");
5593 conn+=connI[i+1]-connI[i];
5595 ret->setName("Warp");
5596 ret->synchronizeTimeWithSupport();
5602 * Creates a new MEDCouplingFieldDouble holding Skew factor values of all
5603 * cells of \a this 2D mesh in 3D space. Currently cells of the following types are
5604 * treated: INTERP_KERNEL::NORM_QUAD4.
5605 * The skew is computed as follow for a quad with points (a,b,c,d): let
5606 * \f$u=\vec{ab}+\vec{dc}\f$ and \f$v=\vec{ac}+\vec{bd}\f$
5607 * then the skew is computed as:
5609 * s=\frac{u}{|u|}\cdot\frac{v}{|v|}
5612 * For a cell of other type an exception is thrown.
5613 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5614 * cells and one time, lying on \a this mesh. The caller is to delete this
5615 * field using decrRef() as it is no more needed.
5616 * \throw If the coordinates array is not set.
5617 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5618 * \throw If the connectivity data array has more than one component.
5619 * \throw If the connectivity data array has a named component.
5620 * \throw If the connectivity index data array has more than one component.
5621 * \throw If the connectivity index data array has a named component.
5622 * \throw If \a this->getMeshDimension() != 2.
5623 * \throw If \a this->getSpaceDimension() != 3.
5624 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5626 MEDCouplingFieldDouble *MEDCouplingUMesh::getSkewField() const
5628 checkConsistencyLight();
5629 int spaceDim=getSpaceDimension();
5630 int meshDim=getMeshDimension();
5632 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : SpaceDimension must be equal to 3 !");
5634 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : MeshDimension must be equal to 2 !");
5635 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5637 mcIdType nbOfCells=getNumberOfCells();
5638 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5639 arr->alloc(nbOfCells,1);
5640 double *pt=arr->getPointer();
5641 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5642 const mcIdType *conn=_nodal_connec->begin();
5643 const mcIdType *connI=_nodal_connec_index->begin();
5644 const double *coo=_coords->begin();
5646 for(mcIdType i=0;i<nbOfCells;i++,pt++)
5648 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5651 case INTERP_KERNEL::NORM_QUAD4:
5653 FillInCompact3DMode(3,4,conn+1,coo,tmp);
5654 *pt=INTERP_KERNEL::quadSkew(tmp);
5658 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : A cell with not manged type (NORM_QUAD4) has been detected !");
5660 conn+=connI[i+1]-connI[i];
5662 ret->setName("Skew");
5663 ret->synchronizeTimeWithSupport();
5668 * 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.
5670 * \return a new instance of field containing the result. The returned instance has to be deallocated by the caller.
5672 * \sa getSkewField, getWarpField, getAspectRatioField, getEdgeRatioField
5674 MEDCouplingFieldDouble *MEDCouplingUMesh::computeDiameterField() const
5676 checkConsistencyLight();
5677 MCAuto<MEDCouplingFieldDouble> ret(MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME));
5679 std::set<INTERP_KERNEL::NormalizedCellType> types;
5680 ComputeAllTypesInternal(types,_nodal_connec,_nodal_connec_index);
5681 int spaceDim(getSpaceDimension());
5682 mcIdType nbCells(getNumberOfCells());
5683 MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
5684 arr->alloc(nbCells,1);
5685 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++)
5687 INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::DiameterCalculator> dc(INTERP_KERNEL::CellModel::GetCellModel(*it).buildInstanceOfDiameterCalulator(spaceDim));
5688 MCAuto<DataArrayIdType> cellIds(giveCellsWithType(*it));
5689 dc->computeForListOfCellIdsUMeshFrmt(cellIds->begin(),cellIds->end(),_nodal_connec_index->begin(),_nodal_connec->begin(),getCoords()->begin(),arr->getPointer());
5692 ret->setName("Diameter");
5697 * This method aggregate the bbox of each cell and put it into bbox parameter (xmin,xmax,ymin,ymax,zmin,zmax).
5699 * \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)
5700 * For all other cases this input parameter is ignored.
5701 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5703 * \throw If \a this is not fully set (coordinates and connectivity).
5704 * \throw If a cell in \a this has no valid nodeId.
5705 * \sa MEDCouplingUMesh::getBoundingBoxForBBTreeFast, MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5707 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree(double arcDetEps) const
5709 int mDim(getMeshDimension()),sDim(getSpaceDimension());
5710 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.
5711 return getBoundingBoxForBBTreeFast();
5712 if((mDim==2 && sDim==2) || (mDim==1 && sDim==2))
5714 bool presenceOfQuadratic(false);
5715 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=_types.begin();it!=_types.end();it++)
5717 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(*it));
5718 if(cm.isQuadratic())
5719 presenceOfQuadratic=true;
5721 if(!presenceOfQuadratic)
5722 return getBoundingBoxForBBTreeFast();
5723 if(mDim==2 && sDim==2)
5724 return getBoundingBoxForBBTree2DQuadratic(arcDetEps);
5726 return getBoundingBoxForBBTree1DQuadratic(arcDetEps);
5728 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) !");
5732 * This method aggregate the bbox of each cell only considering the nodes constituting each cell and put it into bbox parameter.
5733 * So meshes having quadratic cells the computed bounding boxes can be invalid !
5735 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5737 * \throw If \a this is not fully set (coordinates and connectivity).
5738 * \throw If a cell in \a this has no valid nodeId.
5740 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTreeFast() const
5742 checkFullyDefined();
5743 int spaceDim(getSpaceDimension());
5744 mcIdType nbOfCells(getNumberOfCells()), nbOfNodes(getNumberOfNodes());
5745 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5746 double *bbox(ret->getPointer());
5747 for(mcIdType i=0;i<nbOfCells*spaceDim;i++)
5749 bbox[2*i]=std::numeric_limits<double>::max();
5750 bbox[2*i+1]=-std::numeric_limits<double>::max();
5752 const double *coordsPtr(_coords->begin());
5753 const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5754 for(mcIdType i=0;i<nbOfCells;i++)
5756 mcIdType offset=connI[i]+1;
5757 mcIdType nbOfNodesForCell(connI[i+1]-offset),kk(0);
5758 for(mcIdType j=0;j<nbOfNodesForCell;j++)
5760 mcIdType nodeId=conn[offset+j];
5761 if(nodeId>=0 && nodeId<nbOfNodes)
5763 for(int k=0;k<spaceDim;k++)
5765 bbox[2*spaceDim*i+2*k]=std::min(bbox[2*spaceDim*i+2*k],coordsPtr[spaceDim*nodeId+k]);
5766 bbox[2*spaceDim*i+2*k+1]=std::max(bbox[2*spaceDim*i+2*k+1],coordsPtr[spaceDim*nodeId+k]);
5773 std::ostringstream oss; oss << "MEDCouplingUMesh::getBoundingBoxForBBTree : cell #" << i << " contains no valid nodeId !";
5774 throw INTERP_KERNEL::Exception(oss.str());
5781 * This method aggregates the bbox of each 2D cell in \a this considering the whole shape. This method is particularly
5782 * useful for 2D meshes having quadratic cells
5783 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5784 * the two extremities of the arc of circle).
5786 * \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)
5787 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5788 * \throw If \a this is not fully defined.
5789 * \throw If \a this is not a mesh with meshDimension equal to 2.
5790 * \throw If \a this is not a mesh with spaceDimension equal to 2.
5791 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic
5793 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic(double arcDetEps) const
5795 checkFullyDefined();
5796 INTERP_KERNEL::QuadraticPlanarPrecision arcPrec(arcDetEps);
5798 int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
5799 mcIdType nbOfCells=getNumberOfCells();
5800 if(spaceDim!=2 || mDim!=2)
5801 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!");
5802 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5803 double *bbox(ret->getPointer());
5804 const double *coords(_coords->begin());
5805 const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5806 for(mcIdType i=0;i<nbOfCells;i++,bbox+=4,connI++)
5808 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5809 mcIdType sz(connI[1]-connI[0]-1);
5810 std::vector<INTERP_KERNEL::Node *> nodes(sz);
5811 INTERP_KERNEL::QuadraticPolygon *pol(0);
5812 for(mcIdType j=0;j<sz;j++)
5814 mcIdType nodeId(conn[*connI+1+j]);
5815 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5817 if(!cm.isQuadratic())
5818 pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
5820 pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
5821 INTERP_KERNEL::Bounds b; b.prepareForAggregation(); pol->fillBounds(b); delete pol;
5822 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax();
5828 * This method aggregates the bbox of each 1D cell in \a this considering the whole shape. This method is particularly
5829 * useful for 2D meshes having quadratic cells
5830 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5831 * the two extremities of the arc of circle).
5833 * \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)
5834 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5835 * \throw If \a this is not fully defined.
5836 * \throw If \a this is not a mesh with meshDimension equal to 1.
5837 * \throw If \a this is not a mesh with spaceDimension equal to 2.
5838 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5840 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic(double arcDetEps) const
5842 checkFullyDefined();
5843 int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
5844 mcIdType nbOfCells=getNumberOfCells();
5845 if(spaceDim!=2 || mDim!=1)
5846 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!");
5847 INTERP_KERNEL::QuadraticPlanarPrecision arcPrec(arcDetEps);
5848 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5849 double *bbox(ret->getPointer());
5850 const double *coords(_coords->begin());
5851 const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5852 for(mcIdType i=0;i<nbOfCells;i++,bbox+=4,connI++)
5854 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5855 mcIdType sz(connI[1]-connI[0]-1);
5856 std::vector<INTERP_KERNEL::Node *> nodes(sz);
5857 INTERP_KERNEL::Edge *edge(0);
5858 for(mcIdType j=0;j<sz;j++)
5860 mcIdType nodeId(conn[*connI+1+j]);
5861 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5863 if(!cm.isQuadratic())
5864 edge=INTERP_KERNEL::QuadraticPolygon::BuildLinearEdge(nodes);
5866 edge=INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(nodes);
5867 const INTERP_KERNEL::Bounds& b(edge->getBounds());
5868 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax(); edge->decrRef();
5875 namespace MEDCouplingImpl
5880 ConnReader(const mcIdType *c, mcIdType val):_conn(c),_val(val) { }
5881 bool operator() (const mcIdType& pos) { return _conn[pos]!=_val; }
5883 const mcIdType *_conn;
5890 ConnReader2(const mcIdType *c, mcIdType val):_conn(c),_val(val) { }
5891 bool operator() (const mcIdType& pos) { return _conn[pos]==_val; }
5893 const mcIdType *_conn;
5901 * This method expects that \a this is sorted by types. If not an exception will be thrown.
5902 * This method returns in the same format as code (see MEDCouplingUMesh::checkTypeConsistencyAndContig or MEDCouplingUMesh::splitProfilePerType) how
5903 * \a this is composed in cell types.
5904 * The returned array is of size 3*n where n is the number of different types present in \a this.
5905 * For every k in [0,n] ret[3*k+2]==-1 because it has no sense here.
5906 * This parameter is kept only for compatibility with other method listed above.
5908 std::vector<mcIdType> MEDCouplingUMesh::getDistributionOfTypes() const
5910 checkConnectivityFullyDefined();
5911 const mcIdType *conn=_nodal_connec->begin();
5912 const mcIdType *connI=_nodal_connec_index->begin();
5913 const mcIdType *work=connI;
5914 mcIdType nbOfCells=getNumberOfCells();
5915 std::size_t n=getAllGeoTypes().size();
5916 std::vector<mcIdType> ret(3*n,-1); //ret[3*k+2]==-1 because it has no sense here
5917 std::set<INTERP_KERNEL::NormalizedCellType> types;
5918 for(std::size_t i=0;work!=connI+nbOfCells;i++)
5920 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn[*work];
5921 if(types.find(typ)!=types.end())
5923 std::ostringstream oss; oss << "MEDCouplingUMesh::getDistributionOfTypes : Type " << INTERP_KERNEL::CellModel::GetCellModel(typ).getRepr();
5924 oss << " is not contiguous !";
5925 throw INTERP_KERNEL::Exception(oss.str());
5929 const mcIdType *work2=std::find_if(work+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,typ));
5930 ret[3*i+1]=ToIdType(std::distance(work,work2));
5937 * This method is used to check that this has contiguous cell type in same order than described in \a code.
5938 * only for types cell, type node is not managed.
5939 * Format of \a code is the following. \a code should be of size 3*n and non empty. If not an exception is thrown.
5940 * foreach k in [0,n) on 3*k pos represent the geometric type and 3*k+1 number of elements of type 3*k.
5941 * 3*k+2 refers if different from -1 the pos in 'idsPerType' to get the corresponding array.
5942 * If 2 or more same geometric type is in \a code and exception is thrown too.
5944 * This method firstly checks
5945 * If it exists k so that 3*k geometric type is not in geometric types of this an exception will be thrown.
5946 * If it exists k so that 3*k geometric type exists but the number of consecutive cell types does not match,
5947 * an exception is thrown too.
5949 * If all geometric types in \a code are exactly those in \a this null pointer is returned.
5950 * If it exists a geometric type in \a this \b not in \a code \b no exception is thrown
5951 * and a DataArrayIdType instance is returned that the user has the responsibility to deallocate.
5953 DataArrayIdType *MEDCouplingUMesh::checkTypeConsistencyAndContig(const std::vector<mcIdType>& code, const std::vector<const DataArrayIdType *>& idsPerType) const
5956 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code is empty, should not !");
5957 std::size_t sz=code.size();
5960 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code size is NOT %3 !");
5961 std::vector<INTERP_KERNEL::NormalizedCellType> types;
5963 bool isNoPflUsed=true;
5964 for(std::size_t i=0;i<n;i++)
5965 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)code[3*i])==types.end())
5967 types.push_back((INTERP_KERNEL::NormalizedCellType)code[3*i]);
5969 if(_types.find((INTERP_KERNEL::NormalizedCellType)code[3*i])==_types.end())
5970 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : expected geo types not in this !");
5971 isNoPflUsed=isNoPflUsed && (code[3*i+2]==-1);
5974 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code contains duplication of types in unstructured mesh !");
5977 if(!checkConsecutiveCellTypesAndOrder(&types[0],&types[0]+types.size()))
5978 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : non contiguous type !");
5979 if(types.size()==_types.size())
5982 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
5984 mcIdType *retPtr=ret->getPointer();
5985 const mcIdType *connI=_nodal_connec_index->begin();
5986 const mcIdType *conn=_nodal_connec->begin();
5987 mcIdType nbOfCells=getNumberOfCells();
5988 const mcIdType *i=connI;
5990 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++,kk++)
5992 i=std::find_if(i,connI+nbOfCells,MEDCouplingImpl::ConnReader2(conn,ToIdType((*it))));
5993 mcIdType offset=ToIdType(std::distance(connI,i));
5994 const mcIdType *j=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType((*it))));
5995 mcIdType nbOfCellsOfCurType=ToIdType(std::distance(i,j));
5996 if(code[3*kk+2]==-1)
5997 for(mcIdType k=0;k<nbOfCellsOfCurType;k++)
6001 mcIdType idInIdsPerType=code[3*kk+2];
6002 if(idInIdsPerType>=0 && idInIdsPerType<ToIdType(idsPerType.size()))
6004 const DataArrayIdType *zePfl=idsPerType[idInIdsPerType];
6007 zePfl->checkAllocated();
6008 if(zePfl->getNumberOfComponents()==1)
6010 for(const mcIdType *k=zePfl->begin();k!=zePfl->end();k++,retPtr++)
6012 if(*k>=0 && *k<nbOfCellsOfCurType)
6013 *retPtr=(*k)+offset;
6016 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : the section " << kk << " points to the profile #" << idInIdsPerType;
6017 oss << ", and this profile contains a value " << *k << " should be in [0," << nbOfCellsOfCurType << ") !";
6018 throw INTERP_KERNEL::Exception(oss.str());
6023 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of a profile with nb of compo != 1 !");
6026 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of null profile !");
6030 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : at section " << kk << " of code it points to the array #" << idInIdsPerType;
6031 oss << " should be in [0," << idsPerType.size() << ") !";
6032 throw INTERP_KERNEL::Exception(oss.str());
6041 * This method makes the hypothesis that \a this is sorted by type. If not an exception will be thrown.
6042 * 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.
6043 * 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.
6044 * This method has 1 input \a profile and 3 outputs \a code \a idsInPflPerType and \a idsPerType.
6046 * \param [in] profile list of IDs constituing the profile
6047 * \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.
6048 * \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,
6049 * \a idsInPflPerType[i] stores the tuple ids in \a profile that correspond to the geometric type code[3*i+0]
6050 * \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.
6051 * This vector can be empty in case of all geometric type cells are fully covered in ascending in the given input \a profile.
6052 * \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
6054 void MEDCouplingUMesh::splitProfilePerType(const DataArrayIdType *profile, std::vector<mcIdType>& code, std::vector<DataArrayIdType *>& idsInPflPerType, std::vector<DataArrayIdType *>& idsPerType, bool smartPflKiller) const
6057 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile is NULL !");
6058 if(profile->getNumberOfComponents()!=1)
6059 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile should have exactly one component !");
6060 checkConnectivityFullyDefined();
6061 const mcIdType *conn=_nodal_connec->begin();
6062 const mcIdType *connI=_nodal_connec_index->begin();
6063 mcIdType nbOfCells=getNumberOfCells();
6064 std::vector<INTERP_KERNEL::NormalizedCellType> types;
6065 std::vector<mcIdType> typeRangeVals(1);
6066 for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6068 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6069 if(std::find(types.begin(),types.end(),curType)!=types.end())
6071 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : current mesh is not sorted by type !");
6073 types.push_back(curType);
6074 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6075 typeRangeVals.push_back(ToIdType(std::distance(connI,i)));
6078 DataArrayIdType *castArr=0,*rankInsideCast=0,*castsPresent=0;
6079 profile->splitByValueRange(&typeRangeVals[0],&typeRangeVals[0]+typeRangeVals.size(),castArr,rankInsideCast,castsPresent);
6080 MCAuto<DataArrayIdType> tmp0=castArr;
6081 MCAuto<DataArrayIdType> tmp1=rankInsideCast;
6082 MCAuto<DataArrayIdType> tmp2=castsPresent;
6084 mcIdType nbOfCastsFinal=castsPresent->getNumberOfTuples();
6085 code.resize(3*nbOfCastsFinal);
6086 std::vector< MCAuto<DataArrayIdType> > idsInPflPerType2;
6087 std::vector< MCAuto<DataArrayIdType> > idsPerType2;
6088 for(mcIdType i=0;i<nbOfCastsFinal;i++)
6090 mcIdType castId=castsPresent->getIJ(i,0);
6091 MCAuto<DataArrayIdType> tmp3=castArr->findIdsEqual(castId);
6092 idsInPflPerType2.push_back(tmp3);
6093 code[3*i]=ToIdType(types[castId]);
6094 code[3*i+1]=tmp3->getNumberOfTuples();
6095 MCAuto<DataArrayIdType> tmp4=rankInsideCast->selectByTupleId(tmp3->begin(),tmp3->begin()+tmp3->getNumberOfTuples());
6096 if(!smartPflKiller || !tmp4->isIota(typeRangeVals[castId+1]-typeRangeVals[castId]))
6098 tmp4->copyStringInfoFrom(*profile);
6099 idsPerType2.push_back(tmp4);
6100 code[3*i+2]=ToIdType(idsPerType2.size())-1;
6107 std::size_t sz2=idsInPflPerType2.size();
6108 idsInPflPerType.resize(sz2);
6109 for(std::size_t i=0;i<sz2;i++)
6111 DataArrayIdType *locDa=idsInPflPerType2[i];
6113 idsInPflPerType[i]=locDa;
6115 std::size_t sz=idsPerType2.size();
6116 idsPerType.resize(sz);
6117 for(std::size_t i=0;i<sz;i++)
6119 DataArrayIdType *locDa=idsPerType2[i];
6121 idsPerType[i]=locDa;
6126 * This method is here too emulate the MEDMEM behaviour on BDC (buildDescendingConnectivity). Hoping this method becomes deprecated very soon.
6127 * This method make the assumption that \a this and 'nM1LevMesh' mesh lyies on same coords (same pointer) as MED and MEDMEM does.
6128 * The following equality should be verified 'nM1LevMesh->getMeshDimension()==this->getMeshDimension()-1'
6129 * 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.
6131 MEDCouplingUMesh *MEDCouplingUMesh::emulateMEDMEMBDC(const MEDCouplingUMesh *nM1LevMesh, DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *&revDesc, DataArrayIdType *&revDescIndx, DataArrayIdType *& nM1LevMeshIds, DataArrayIdType *&meshnM1Old2New) const
6133 checkFullyDefined();
6134 nM1LevMesh->checkFullyDefined();
6135 if(getMeshDimension()-1!=nM1LevMesh->getMeshDimension())
6136 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : The mesh passed as first argument should have a meshDim equal to this->getMeshDimension()-1 !" );
6137 if(_coords!=nM1LevMesh->getCoords())
6138 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : 'this' and mesh in first argument should share the same coords : Use tryToShareSameCoords method !");
6139 MCAuto<DataArrayIdType> tmp0=DataArrayIdType::New();
6140 MCAuto<DataArrayIdType> tmp1=DataArrayIdType::New();
6141 MCAuto<MEDCouplingUMesh> ret1=buildDescendingConnectivity(desc,descIndx,tmp0,tmp1);
6142 MCAuto<DataArrayIdType> ret0=ret1->sortCellsInMEDFileFrmt();
6143 desc->transformWithIndArr(ret0->begin(),ret0->begin()+ret0->getNbOfElems());
6144 MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
6145 tmp->setConnectivity(tmp0,tmp1);
6146 tmp->renumberCells(ret0->begin(),false);
6147 revDesc=tmp->getNodalConnectivity();
6148 revDescIndx=tmp->getNodalConnectivityIndex();
6149 DataArrayIdType *ret=0;
6150 if(!ret1->areCellsIncludedIn(nM1LevMesh,2,ret))
6153 ret->getMaxValue(tmp2);
6155 std::ostringstream oss; oss << "MEDCouplingUMesh::emulateMEDMEMBDC : input N-1 mesh present a cell not in descending mesh ... Id of cell is " << tmp2 << " !";
6156 throw INTERP_KERNEL::Exception(oss.str());
6161 revDescIndx->incrRef();
6164 meshnM1Old2New=ret0;
6169 * Permutes the nodal connectivity arrays so that the cells are sorted by type, which is
6170 * necessary for writing the mesh to MED file. Additionally returns a permutation array
6171 * in "Old to New" mode.
6172 * \return DataArrayIdType * - a new instance of DataArrayIdType. The caller is to delete
6173 * this array using decrRef() as it is no more needed.
6174 * \throw If the nodal connectivity of cells is not defined.
6176 DataArrayIdType *MEDCouplingUMesh::sortCellsInMEDFileFrmt()
6178 checkConnectivityFullyDefined();
6179 MCAuto<DataArrayIdType> ret=getRenumArrForMEDFileFrmt();
6180 renumberCells(ret->begin(),false);
6185 * This methods checks that cells are sorted by their types.
6186 * This method makes asumption (no check) that connectivity is correctly set before calling.
6188 bool MEDCouplingUMesh::checkConsecutiveCellTypes() const
6190 checkFullyDefined();
6191 const mcIdType *conn=_nodal_connec->begin();
6192 const mcIdType *connI=_nodal_connec_index->begin();
6193 mcIdType nbOfCells=getNumberOfCells();
6194 std::set<INTERP_KERNEL::NormalizedCellType> types;
6195 for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6197 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6198 if(types.find(curType)!=types.end())
6200 types.insert(curType);
6201 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6207 * This method is a specialization of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method that is called here.
6208 * The geometric type order is specified by MED file.
6210 * \sa MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder
6212 bool MEDCouplingUMesh::checkConsecutiveCellTypesForMEDFileFrmt() const
6214 return checkConsecutiveCellTypesAndOrder(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
6218 * This method performs the same job as checkConsecutiveCellTypes except that the order of types sequence is analyzed to check
6219 * that the order is specified in array defined by [ \a orderBg , \a orderEnd ).
6220 * If there is some geo types in \a this \b NOT in [ \a orderBg, \a orderEnd ) it is OK (return true) if contiguous.
6221 * If there is some geo types in [ \a orderBg, \a orderEnd ) \b NOT in \a this it is OK too (return true) if contiguous.
6223 bool MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
6225 checkFullyDefined();
6226 const mcIdType *conn=_nodal_connec->begin();
6227 const mcIdType *connI=_nodal_connec_index->begin();
6228 mcIdType nbOfCells=getNumberOfCells();
6231 mcIdType lastPos=-1;
6232 std::set<INTERP_KERNEL::NormalizedCellType> sg;
6233 for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6235 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6236 const INTERP_KERNEL::NormalizedCellType *isTypeExists=std::find(orderBg,orderEnd,curType);
6237 if(isTypeExists!=orderEnd)
6239 mcIdType pos=ToIdType(std::distance(orderBg,isTypeExists));
6243 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6247 if(sg.find(curType)==sg.end())
6249 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6260 * This method returns 2 newly allocated DataArrayIdType instances. The first is an array of size 'this->getNumberOfCells()' with one component,
6261 * 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
6262 * 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'.
6264 DataArrayIdType *MEDCouplingUMesh::getLevArrPerCellTypes(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd, DataArrayIdType *&nbPerType) const
6266 checkConnectivityFullyDefined();
6267 mcIdType nbOfCells=getNumberOfCells();
6268 const mcIdType *conn=_nodal_connec->begin();
6269 const mcIdType *connI=_nodal_connec_index->begin();
6270 MCAuto<DataArrayIdType> tmpa=DataArrayIdType::New();
6271 MCAuto<DataArrayIdType> tmpb=DataArrayIdType::New();
6272 tmpa->alloc(nbOfCells,1);
6273 tmpb->alloc(std::distance(orderBg,orderEnd),1);
6274 tmpb->fillWithZero();
6275 mcIdType *tmp=tmpa->getPointer();
6276 mcIdType *tmp2=tmpb->getPointer();
6277 for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6279 const INTERP_KERNEL::NormalizedCellType *where=std::find(orderBg,orderEnd,(INTERP_KERNEL::NormalizedCellType)conn[*i]);
6282 mcIdType pos=ToIdType(std::distance(orderBg,where));
6284 tmp[std::distance(connI,i)]=pos;
6288 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*i]);
6289 std::ostringstream oss; oss << "MEDCouplingUMesh::getLevArrPerCellTypes : Cell #" << std::distance(connI,i);
6290 oss << " has a type " << cm.getRepr() << " not in input array of type !";
6291 throw INTERP_KERNEL::Exception(oss.str());
6294 nbPerType=tmpb.retn();
6299 * This method behaves exactly as MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec but the order is those defined in MED file spec.
6301 * \return a new object containing the old to new correspondence.
6303 * \sa MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec, MEDCouplingUMesh::sortCellsInMEDFileFrmt.
6305 DataArrayIdType *MEDCouplingUMesh::getRenumArrForMEDFileFrmt() const
6307 return getRenumArrForConsecutiveCellTypesSpec(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
6311 * 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.
6312 * This method returns an array of size getNumberOfCells() that gives a renumber array old2New that can be used as input of MEDCouplingMesh::renumberCells.
6313 * The mesh after this call to MEDCouplingMesh::renumberCells will pass the test of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder with the same inputs.
6314 * The returned array minimizes the permutations that is to say the order of cells inside same geometric type remains the same.
6316 DataArrayIdType *MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
6318 DataArrayIdType *nbPerType=0;
6319 MCAuto<DataArrayIdType> tmpa=getLevArrPerCellTypes(orderBg,orderEnd,nbPerType);
6320 nbPerType->decrRef();
6321 return tmpa->buildPermArrPerLevel();
6325 * This method reorganize the cells of \a this so that the cells with same geometric types are put together.
6326 * The number of cells remains unchanged after the call of this method.
6327 * This method tries to minimizes the number of needed permutations. So, this method behaves not exactly as
6328 * MEDCouplingUMesh::sortCellsInMEDFileFrmt.
6330 * \return the array giving the correspondence old to new.
6332 DataArrayIdType *MEDCouplingUMesh::rearrange2ConsecutiveCellTypes()
6334 checkFullyDefined();
6336 const mcIdType *conn=_nodal_connec->begin();
6337 const mcIdType *connI=_nodal_connec_index->begin();
6338 mcIdType nbOfCells=getNumberOfCells();
6339 std::vector<INTERP_KERNEL::NormalizedCellType> types;
6340 for(const mcIdType *i=connI;i!=connI+nbOfCells && (types.size()!=_types.size());)
6341 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)conn[*i])==types.end())
6343 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6344 types.push_back(curType);
6345 for(i++;i!=connI+nbOfCells && (INTERP_KERNEL::NormalizedCellType)conn[*i]==curType;i++);
6347 DataArrayIdType *ret=DataArrayIdType::New();
6348 ret->alloc(nbOfCells,1);
6349 mcIdType *retPtr=ret->getPointer();
6350 std::fill(retPtr,retPtr+nbOfCells,-1);
6351 mcIdType newCellId=0;
6352 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
6354 for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6355 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
6356 retPtr[std::distance(connI,i)]=newCellId++;
6358 renumberCells(retPtr,false);
6363 * This method splits \a this into as mush as untructured meshes that consecutive set of same type cells.
6364 * So this method has typically a sense if MEDCouplingUMesh::checkConsecutiveCellTypes has a sense.
6365 * This method makes asumption that connectivity is correctly set before calling.
6367 std::vector<MEDCouplingUMesh *> MEDCouplingUMesh::splitByType() const
6369 checkConnectivityFullyDefined();
6370 const mcIdType *conn=_nodal_connec->begin();
6371 const mcIdType *connI=_nodal_connec_index->begin();
6372 mcIdType nbOfCells=getNumberOfCells();
6373 std::vector<MEDCouplingUMesh *> ret;
6374 for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6376 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6377 mcIdType beginCellId=ToIdType(std::distance(connI,i));
6378 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6379 mcIdType endCellId=ToIdType(std::distance(connI,i));
6380 mcIdType sz=endCellId-beginCellId;
6381 mcIdType *cells=new mcIdType[sz];
6382 for(mcIdType j=0;j<sz;j++)
6383 cells[j]=beginCellId+j;
6384 MEDCouplingUMesh *m=(MEDCouplingUMesh *)buildPartOfMySelf(cells,cells+sz,true);
6392 * This method performs the opposite operation than those in MEDCoupling1SGTUMesh::buildUnstructured.
6393 * If \a this is a single geometric type unstructured mesh, it will be converted into a more compact data structure,
6394 * MEDCoupling1GTUMesh instance. The returned instance will aggregate the same DataArrayDouble instance of coordinates than \a this.
6396 * \return a newly allocated instance, that the caller must manage.
6397 * \throw If \a this contains more than one geometric type.
6398 * \throw If the nodal connectivity of \a this is not fully defined.
6399 * \throw If the internal data is not coherent.
6401 MEDCoupling1GTUMesh *MEDCouplingUMesh::convertIntoSingleGeoTypeMesh() const
6403 checkConnectivityFullyDefined();
6404 if(_types.size()!=1)
6405 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6406 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6407 MCAuto<MEDCoupling1GTUMesh> ret=MEDCoupling1GTUMesh::New(getName(),typ);
6408 ret->setCoords(getCoords());
6409 MEDCoupling1SGTUMesh *retC=dynamic_cast<MEDCoupling1SGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6412 MCAuto<DataArrayIdType> c=convertNodalConnectivityToStaticGeoTypeMesh();
6413 retC->setNodalConnectivity(c);
6417 MEDCoupling1DGTUMesh *retD=dynamic_cast<MEDCoupling1DGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6419 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : Internal error !");
6420 DataArrayIdType *c=0,*ci=0;
6421 convertNodalConnectivityToDynamicGeoTypeMesh(c,ci);
6422 MCAuto<DataArrayIdType> cs(c),cis(ci);
6423 retD->setNodalConnectivity(cs,cis);
6428 DataArrayIdType *MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh() const
6430 checkConnectivityFullyDefined();
6431 if(_types.size()!=1)
6432 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6433 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6434 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6437 std::ostringstream oss; oss << "MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : this contains a single geo type (" << cm.getRepr() << ") but ";
6438 oss << "this type is dynamic ! Only static geometric type is possible for that type ! call convertNodalConnectivityToDynamicGeoTypeMesh instead !";
6439 throw INTERP_KERNEL::Exception(oss.str());
6441 mcIdType nbCells=getNumberOfCells();
6442 mcIdType typi=ToIdType(typ);
6443 mcIdType nbNodesPerCell=ToIdType(cm.getNumberOfNodes());
6444 MCAuto<DataArrayIdType> connOut=DataArrayIdType::New(); connOut->alloc(nbCells*nbNodesPerCell,1);
6445 mcIdType *outPtr=connOut->getPointer();
6446 const mcIdType *conn=_nodal_connec->begin();
6447 const mcIdType *connI=_nodal_connec_index->begin();
6449 for(mcIdType i=0;i<nbCells;i++,connI++)
6451 if(conn[connI[0]]==typi && connI[1]-connI[0]==nbNodesPerCell)
6452 outPtr=std::copy(conn+connI[0]+1,conn+connI[1],outPtr);
6455 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 << ") !";
6456 throw INTERP_KERNEL::Exception(oss.str());
6459 return connOut.retn();
6463 * Convert the nodal connectivity of the mesh so that all the cells are of dynamic types (polygon or quadratic
6464 * polygon). This returns the corresponding new nodal connectivity in \ref numbering-indirect format.
6465 * \param nodalConn nodal connectivity
6466 * \param nodalConnIndex nodal connectivity indices
6468 void MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh(DataArrayIdType *&nodalConn, DataArrayIdType *&nodalConnIndex) const
6470 static const char msg0[]="MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : nodal connectivity in this are invalid ! Call checkConsistency !";
6471 checkConnectivityFullyDefined();
6472 if(_types.size()!=1)
6473 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6474 mcIdType nbCells=getNumberOfCells(),
6475 lgth=_nodal_connec->getNumberOfTuples();
6477 throw INTERP_KERNEL::Exception(msg0);
6478 MCAuto<DataArrayIdType> c(DataArrayIdType::New()),ci(DataArrayIdType::New());
6479 c->alloc(lgth-nbCells,1); ci->alloc(nbCells+1,1);
6480 mcIdType *cp(c->getPointer()),*cip(ci->getPointer());
6481 const mcIdType *incp(_nodal_connec->begin()),*incip(_nodal_connec_index->begin());
6483 for(mcIdType i=0;i<nbCells;i++,cip++,incip++)
6485 mcIdType strt(incip[0]+1),stop(incip[1]);//+1 to skip geo type
6486 mcIdType delta(stop-strt);
6489 if((strt>=0 && strt<lgth) && (stop>=0 && stop<=lgth))
6490 cp=std::copy(incp+strt,incp+stop,cp);
6492 throw INTERP_KERNEL::Exception(msg0);
6495 throw INTERP_KERNEL::Exception(msg0);
6496 cip[1]=cip[0]+delta;
6498 nodalConn=c.retn(); nodalConnIndex=ci.retn();
6502 * This method takes in input a vector of MEDCouplingUMesh instances lying on the same coordinates with same mesh dimensions.
6503 * Each mesh in \b ms must be sorted by type with the same order (typically using MEDCouplingUMesh::sortCellsInMEDFileFrmt).
6504 * This method is particularly useful for MED file interaction. It allows to aggregate several meshes and keeping the type sorting
6505 * and the track of the permutation by chunk of same geotype cells to retrieve it. The traditional formats old2new and new2old
6506 * are not used here to avoid the build of big permutation array.
6508 * \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
6509 * those specified in MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6510 * \param [out] szOfCellGrpOfSameType is a newly allocated DataArrayIdType instance whose number of tuples is equal to the number of chunks of same geotype
6511 * in all meshes in \b ms. The accumulation of all values of this array is equal to the number of cells of returned mesh.
6512 * \param [out] idInMsOfCellGrpOfSameType is a newly allocated DataArrayIdType instance having the same size than \b szOfCellGrpOfSameType. This
6513 * output array gives for each chunck of same type the corresponding mesh id in \b ms.
6514 * \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
6515 * is sorted by type following the geo cell types order of MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6517 MEDCouplingUMesh *MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& ms,
6518 DataArrayIdType *&szOfCellGrpOfSameType,
6519 DataArrayIdType *&idInMsOfCellGrpOfSameType)
6521 std::vector<const MEDCouplingUMesh *> ms2;
6522 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms.begin();it!=ms.end();it++)
6525 (*it)->checkConnectivityFullyDefined();
6529 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : input vector is empty !");
6530 const DataArrayDouble *refCoo=ms2[0]->getCoords();
6531 int meshDim=ms2[0]->getMeshDimension();
6532 std::vector<const MEDCouplingUMesh *> m1ssm;
6533 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmAuto;
6535 std::vector<const MEDCouplingUMesh *> m1ssmSingle;
6536 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmSingleAuto;
6537 mcIdType fake=0,rk=0;
6538 MCAuto<DataArrayIdType> ret1(DataArrayIdType::New()),ret2(DataArrayIdType::New());
6539 ret1->alloc(0,1); ret2->alloc(0,1);
6540 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms2.begin();it!=ms2.end();it++,rk++)
6542 if(meshDim!=(*it)->getMeshDimension())
6543 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshdims mismatch !");
6544 if(refCoo!=(*it)->getCoords())
6545 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshes are not shared by a single coordinates coords !");
6546 std::vector<MEDCouplingUMesh *> sp=(*it)->splitByType();
6547 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<const MEDCouplingUMesh *> >(m1ssm));
6548 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<MCAuto<MEDCouplingUMesh> > >(m1ssmAuto));
6549 for(std::vector<MEDCouplingUMesh *>::const_iterator it2=sp.begin();it2!=sp.end();it2++)
6551 MEDCouplingUMesh *singleCell=static_cast<MEDCouplingUMesh *>((*it2)->buildPartOfMySelf(&fake,&fake+1,true));
6552 m1ssmSingleAuto.push_back(singleCell);
6553 m1ssmSingle.push_back(singleCell);
6554 ret1->pushBackSilent((*it2)->getNumberOfCells()); ret2->pushBackSilent(rk);
6557 MCAuto<MEDCouplingUMesh> m1ssmSingle2=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmSingle);
6558 MCAuto<DataArrayIdType> renum=m1ssmSingle2->sortCellsInMEDFileFrmt();
6559 std::vector<const MEDCouplingUMesh *> m1ssmfinal(m1ssm.size());
6560 for(mcIdType i=0;i<ToIdType(m1ssm.size());i++)
6561 m1ssmfinal[renum->getIJ(i,0)]=m1ssm[i];
6562 MCAuto<MEDCouplingUMesh> ret0=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmfinal);
6563 szOfCellGrpOfSameType=ret1->renumber(renum->begin());
6564 idInMsOfCellGrpOfSameType=ret2->renumber(renum->begin());
6569 * This method returns a newly created DataArrayIdType instance.
6570 * This method retrieves cell ids in [ \a begin, \a end ) that have the type \a type.
6572 DataArrayIdType *MEDCouplingUMesh::keepCellIdsByType(INTERP_KERNEL::NormalizedCellType type, const mcIdType *begin, const mcIdType *end) const
6574 checkFullyDefined();
6575 const mcIdType *conn=_nodal_connec->begin();
6576 const mcIdType *connIndex=_nodal_connec_index->begin();
6577 MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(0,1);
6578 for(const mcIdType *w=begin;w!=end;w++)
6579 if((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]==type)
6580 ret->pushBackSilent(*w);
6585 * This method makes the assumption that da->getNumberOfTuples()<this->getNumberOfCells(). This method makes the assumption that ids contained in 'da'
6586 * are in [0:getNumberOfCells())
6588 DataArrayIdType *MEDCouplingUMesh::convertCellArrayPerGeoType(const DataArrayIdType *da) const
6590 checkFullyDefined();
6591 const mcIdType *conn=_nodal_connec->begin();
6592 const mcIdType *connI=_nodal_connec_index->begin();
6593 mcIdType nbOfCells=getNumberOfCells();
6594 std::set<INTERP_KERNEL::NormalizedCellType> types(getAllGeoTypes());
6595 mcIdType *tmp=new mcIdType[nbOfCells];
6596 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
6599 for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6600 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
6601 tmp[std::distance(connI,i)]=j++;
6603 DataArrayIdType *ret=DataArrayIdType::New();
6604 ret->alloc(da->getNumberOfTuples(),da->getNumberOfComponents());
6605 ret->copyStringInfoFrom(*da);
6606 mcIdType *retPtr=ret->getPointer();
6607 const mcIdType *daPtr=da->begin();
6608 mcIdType nbOfElems=da->getNbOfElems();
6609 for(mcIdType k=0;k<nbOfElems;k++)
6610 retPtr[k]=tmp[daPtr[k]];
6616 * This method reduced number of cells of this by keeping cells whose type is different from 'type' and if type=='type'
6617 * This method \b works \b for mesh sorted by type.
6618 * cells whose ids is in 'idsPerGeoType' array.
6619 * This method conserves coords and name of mesh.
6621 MEDCouplingUMesh *MEDCouplingUMesh::keepSpecifiedCells(INTERP_KERNEL::NormalizedCellType type, const mcIdType *idsPerGeoTypeBg, const mcIdType *idsPerGeoTypeEnd) const
6623 std::vector<mcIdType> code=getDistributionOfTypes();
6624 std::size_t nOfTypesInThis=code.size()/3;
6625 mcIdType sz=0,szOfType=0;
6626 for(std::size_t i=0;i<nOfTypesInThis;i++)
6631 szOfType=code[3*i+1];
6633 for(const mcIdType *work=idsPerGeoTypeBg;work!=idsPerGeoTypeEnd;work++)
6634 if(*work<0 || *work>=szOfType)
6636 std::ostringstream oss; oss << "MEDCouplingUMesh::keepSpecifiedCells : Request on type " << type << " at place #" << std::distance(idsPerGeoTypeBg,work) << " value " << *work;
6637 oss << ". It should be in [0," << szOfType << ") !";
6638 throw INTERP_KERNEL::Exception(oss.str());
6640 MCAuto<DataArrayIdType> idsTokeep=DataArrayIdType::New(); idsTokeep->alloc(sz+std::distance(idsPerGeoTypeBg,idsPerGeoTypeEnd),1);
6641 mcIdType *idsPtr=idsTokeep->getPointer();
6643 for(std::size_t i=0;i<nOfTypesInThis;i++)
6646 for(mcIdType j=0;j<code[3*i+1];j++)
6649 idsPtr=std::transform(idsPerGeoTypeBg,idsPerGeoTypeEnd,idsPtr,std::bind(std::plus<mcIdType>(),std::placeholders::_1,offset));
6650 offset+=code[3*i+1];
6652 MCAuto<MEDCouplingUMesh> ret=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(idsTokeep->begin(),idsTokeep->end(),true));
6653 ret->copyTinyInfoFrom(this);
6658 * This method returns a vector of size 'this->getNumberOfCells()'.
6659 * This method retrieves for each cell in \a this if it is linear (false) or quadratic(true).
6661 std::vector<bool> MEDCouplingUMesh::getQuadraticStatus() const
6663 mcIdType ncell=getNumberOfCells();
6664 std::vector<bool> ret(ncell);
6665 const mcIdType *cI=getNodalConnectivityIndex()->begin();
6666 const mcIdType *c=getNodalConnectivity()->begin();
6667 for(mcIdType i=0;i<ncell;i++)
6669 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[i]];
6670 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6671 ret[i]=cm.isQuadratic();
6677 * Returns a newly created mesh (with ref count ==1) that contains merge of \a this and \a other.
6679 MEDCouplingMesh *MEDCouplingUMesh::mergeMyselfWith(const MEDCouplingMesh *other) const
6681 if(other->getType()!=UNSTRUCTURED)
6682 throw INTERP_KERNEL::Exception("Merge of umesh only available with umesh each other !");
6683 const MEDCouplingUMesh *otherC=static_cast<const MEDCouplingUMesh *>(other);
6684 return MergeUMeshes(this,otherC);
6688 * Returns a new DataArrayDouble holding barycenters of all cells. The barycenter is
6689 * computed by averaging coordinates of cell nodes, so this method is not a right
6690 * choice for degenerated meshes (not well oriented, cells with measure close to zero).
6691 * Beware also that for quadratic meshes, degenerated arc of circles are turned into linear edges for the computation.
6692 * This happens with a default detection precision of eps=1.0e-14. If you need control over this use computeCellCenterOfMassWithPrecision().
6693 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
6694 * this->getNumberOfCells() tuples per \a this->getSpaceDimension()
6695 * components. The caller is to delete this array using decrRef() as it is
6697 * \throw If the coordinates array is not set.
6698 * \throw If the nodal connectivity of cells is not defined.
6699 * \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
6700 * \sa MEDCouplingUMesh::computeCellCenterOfMassWithPrecision
6702 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMass() const
6704 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6705 int spaceDim=getSpaceDimension();
6706 mcIdType nbOfCells=getNumberOfCells();
6707 ret->alloc(nbOfCells,spaceDim);
6708 ret->copyStringInfoFrom(*getCoords());
6709 double *ptToFill=ret->getPointer();
6710 const mcIdType *nodal=_nodal_connec->begin();
6711 const mcIdType *nodalI=_nodal_connec_index->begin();
6712 const double *coor=_coords->begin();
6713 for(mcIdType i=0;i<nbOfCells;i++)
6715 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6716 INTERP_KERNEL::computeBarycenter2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[i]+1,nodalI[i+1]-nodalI[i]-1,coor,spaceDim,ptToFill);
6724 * See computeCellCenterOfMass().
6725 * \param eps a precision for the detection of degenerated arc of circles.
6726 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
6727 * this->getNumberOfCells() tuples per \a this->getSpaceDimension()
6728 * components. The caller is to delete this array using decrRef() as it is
6730 * \throw If the coordinates array is not set.
6731 * \throw If the nodal connectivity of cells is not defined.
6732 * \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
6733 * \sa MEDCouplingUMesh::computeCellCenterOfMassWithPrecision
6735 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMassWithPrecision(double eps) const
6737 INTERP_KERNEL::QuadraticPlanarPrecision prec(eps);
6738 MCAuto<DataArrayDouble> ret = computeCellCenterOfMass();
6744 * This method computes for each cell in \a this, the location of the iso barycenter of nodes constituting
6745 * the cell. Contrary to badly named MEDCouplingUMesh::computeCellCenterOfMass method that returns the center of inertia of the
6747 * \return a newly allocated DataArrayDouble instance that the caller has to deal with. The returned
6748 * DataArrayDouble instance will have \c this->getNumberOfCells() tuples and \c this->getSpaceDimension() components.
6750 * \sa MEDCouplingUMesh::computeCellCenterOfMass
6751 * \throw If \a this is not fully defined (coordinates and connectivity)
6752 * \throw If there is presence in nodal connectivity in \a this of node ids not in [0, \c this->getNumberOfNodes() )
6754 DataArrayDouble *MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell() const
6756 checkFullyDefined();
6757 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6758 int spaceDim=getSpaceDimension();
6759 mcIdType nbOfCells=getNumberOfCells();
6760 mcIdType nbOfNodes=getNumberOfNodes();
6761 ret->alloc(nbOfCells,spaceDim);
6762 double *ptToFill=ret->getPointer();
6763 const mcIdType *nodal=_nodal_connec->begin();
6764 const mcIdType *nodalI=_nodal_connec_index->begin();
6765 const double *coor=_coords->begin();
6766 for(mcIdType i=0;i<nbOfCells;i++,ptToFill+=spaceDim)
6768 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6769 std::fill(ptToFill,ptToFill+spaceDim,0.);
6770 if(type!=INTERP_KERNEL::NORM_POLYHED)
6772 for(const mcIdType *conn=nodal+nodalI[i]+1;conn!=nodal+nodalI[i+1];conn++)
6774 if(*conn>=0 && *conn<nbOfNodes)
6775 std::transform(coor+spaceDim*conn[0],coor+spaceDim*(conn[0]+1),ptToFill,ptToFill,std::plus<double>());
6778 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of nodeId #" << *conn << " should be in [0," << nbOfNodes << ") !";
6779 throw INTERP_KERNEL::Exception(oss.str());
6782 mcIdType nbOfNodesInCell=nodalI[i+1]-nodalI[i]-1;
6783 if(nbOfNodesInCell>0)
6784 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind(std::multiplies<double>(),std::placeholders::_1,1./(double)nbOfNodesInCell));
6787 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of cell with no nodes !";
6788 throw INTERP_KERNEL::Exception(oss.str());
6793 std::set<mcIdType> s(nodal+nodalI[i]+1,nodal+nodalI[i+1]);
6795 for(std::set<mcIdType>::const_iterator it=s.begin();it!=s.end();it++)
6797 if(*it>=0 && *it<nbOfNodes)
6798 std::transform(coor+spaceDim*(*it),coor+spaceDim*((*it)+1),ptToFill,ptToFill,std::plus<double>());
6801 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell polyhedron cell #" << i << " presence of nodeId #" << *it << " should be in [0," << nbOfNodes << ") !";
6802 throw INTERP_KERNEL::Exception(oss.str());
6806 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind(std::multiplies<double>(),std::placeholders::_1,1./(double)s.size()));
6809 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on polyhedron cell #" << i << " there are no nodes !";
6810 throw INTERP_KERNEL::Exception(oss.str());
6818 * Returns a new DataArrayDouble holding barycenters of specified cells. The
6819 * barycenter is computed by averaging coordinates of cell nodes. The cells to treat
6820 * are specified via an array of cell ids.
6821 * \warning Validity of the specified cell ids is not checked!
6822 * Valid range is [ 0, \a this->getNumberOfCells() ).
6823 * \param [in] begin - an array of cell ids of interest.
6824 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
6825 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size ( \a
6826 * end - \a begin ) tuples per \a this->getSpaceDimension() components. The
6827 * caller is to delete this array using decrRef() as it is no more needed.
6828 * \throw If the coordinates array is not set.
6829 * \throw If the nodal connectivity of cells is not defined.
6831 * \if ENABLE_EXAMPLES
6832 * \ref cpp_mcumesh_getPartBarycenterAndOwner "Here is a C++ example".<br>
6833 * \ref py_mcumesh_getPartBarycenterAndOwner "Here is a Python example".
6836 DataArrayDouble *MEDCouplingUMesh::getPartBarycenterAndOwner(const mcIdType *begin, const mcIdType *end) const
6838 DataArrayDouble *ret=DataArrayDouble::New();
6839 int spaceDim=getSpaceDimension();
6840 std::size_t nbOfTuple=std::distance(begin,end);
6841 ret->alloc(nbOfTuple,spaceDim);
6842 double *ptToFill=ret->getPointer();
6843 double *tmp=new double[spaceDim];
6844 const mcIdType *nodal=_nodal_connec->begin();
6845 const mcIdType *nodalI=_nodal_connec_index->begin();
6846 const double *coor=_coords->begin();
6847 for(const mcIdType *w=begin;w!=end;w++)
6849 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[*w]];
6850 INTERP_KERNEL::computeBarycenter2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[*w]+1,nodalI[*w+1]-nodalI[*w]-1,coor,spaceDim,ptToFill);
6858 * 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".
6859 * So the returned instance will have 4 components and \c this->getNumberOfCells() tuples.
6860 * So this method expects that \a this has a spaceDimension equal to 3 and meshDimension equal to 2.
6861 * The computation of the plane equation is done using each time the 3 first nodes of 2D cells.
6862 * This method is useful to detect 2D cells in 3D space that are not coplanar.
6864 * \return DataArrayDouble * - a new instance of DataArrayDouble having 4 components and a number of tuples equal to number of cells in \a this.
6865 * \throw If spaceDim!=3 or meshDim!=2.
6866 * \throw If connectivity of \a this is invalid.
6867 * \throw If connectivity of a cell in \a this points to an invalid node.
6869 DataArrayDouble *MEDCouplingUMesh::computePlaneEquationOf3DFaces() const
6871 MCAuto<DataArrayDouble> ret(DataArrayDouble::New());
6872 mcIdType nbOfCells=getNumberOfCells();
6873 mcIdType nbOfNodes(getNumberOfNodes());
6874 if(getSpaceDimension()!=3 || getMeshDimension()!=2)
6875 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computePlaneEquationOf3DFaces : This method must be applied on a mesh having meshDimension equal 2 and a spaceDimension equal to 3 !");
6876 ret->alloc(nbOfCells,4);
6877 double *retPtr(ret->getPointer());
6878 const mcIdType *nodal(_nodal_connec->begin()),*nodalI(_nodal_connec_index->begin());
6879 const double *coor(_coords->begin());
6880 for(mcIdType i=0;i<nbOfCells;i++,nodalI++,retPtr+=4)
6882 double matrix[16]={0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,0},matrix2[16];
6883 if(nodalI[1]-nodalI[0]>=4)
6885 double aa[3]={coor[nodal[nodalI[0]+1+1]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6886 coor[nodal[nodalI[0]+1+1]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6887 coor[nodal[nodalI[0]+1+1]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]}
6888 ,bb[3]={coor[nodal[nodalI[0]+1+2]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6889 coor[nodal[nodalI[0]+1+2]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6890 coor[nodal[nodalI[0]+1+2]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]};
6891 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]};
6892 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]));
6893 for(int j=0;j<3;j++)
6895 mcIdType nodeId(nodal[nodalI[0]+1+j]);
6896 if(nodeId>=0 && nodeId<nbOfNodes)
6897 std::copy(coor+nodeId*3,coor+(nodeId+1)*3,matrix+4*j);
6900 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! This cell points to an invalid nodeId : " << nodeId << " !";
6901 throw INTERP_KERNEL::Exception(oss.str());
6904 if(sqrt(cc[0]*cc[0]+cc[1]*cc[1]+cc[2]*cc[2])>(1e-3*aa_norm*bb_norm))
6906 INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6907 retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6911 if(nodalI[1]-nodalI[0]==4)
6913 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : cell" << i << " : Presence of The 3 colinear points !";
6914 throw INTERP_KERNEL::Exception(oss.str());
6917 double dd[3]={0.,0.,0.};
6918 for(mcIdType offset=nodalI[0]+1;offset<nodalI[1];offset++)
6919 std::transform(coor+3*nodal[offset],coor+3*(nodal[offset]+1),dd,dd,std::plus<double>());
6920 mcIdType nbOfNodesInCell(nodalI[1]-nodalI[0]-1);
6921 std::transform(dd,dd+3,dd,std::bind(std::multiplies<double>(),std::placeholders::_1,1./(double)nbOfNodesInCell));
6922 std::copy(dd,dd+3,matrix+4*2);
6923 INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6924 retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6929 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! Must be constitued by more than 3 nodes !";
6930 throw INTERP_KERNEL::Exception(oss.str());
6937 * This method expects as input a DataArrayDouble non nul instance 'da' that should be allocated. If not an exception is thrown.
6940 MEDCouplingUMesh *MEDCouplingUMesh::Build0DMeshFromCoords(DataArrayDouble *da)
6943 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build0DMeshFromCoords : instance of DataArrayDouble must be not null !");
6944 da->checkAllocated();
6945 std::string name(da->getName());
6946 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New(name,0));
6948 ret->setName("Mesh");
6950 mcIdType nbOfTuples(da->getNumberOfTuples());
6951 MCAuto<DataArrayIdType> c(DataArrayIdType::New()),cI(DataArrayIdType::New());
6952 c->alloc(2*nbOfTuples,1);
6953 cI->alloc(nbOfTuples+1,1);
6954 mcIdType *cp(c->getPointer()),*cip(cI->getPointer());
6956 for(mcIdType i=0;i<nbOfTuples;i++)
6958 *cp++=INTERP_KERNEL::NORM_POINT1;
6962 ret->setConnectivity(c,cI,true);
6966 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::Build1DMeshFromCoords(DataArrayDouble *da)
6969 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build01MeshFromCoords : instance of DataArrayDouble must be not null !");
6970 da->checkAllocated();
6971 std::string name(da->getName());
6972 MCAuto<MEDCouplingUMesh> ret;
6974 MCAuto<MEDCouplingCMesh> tmp(MEDCouplingCMesh::New());
6975 MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
6976 arr->alloc(da->getNumberOfTuples());
6977 tmp->setCoordsAt(0,arr);
6978 ret=tmp->buildUnstructured();
6982 ret->setName("Mesh");
6989 * Creates a new MEDCouplingUMesh by concatenating two given meshes of the same dimension.
6990 * Cells and nodes of
6991 * the first mesh precede cells and nodes of the second mesh within the result mesh.
6992 * \param [in] mesh1 - the first mesh.
6993 * \param [in] mesh2 - the second mesh.
6994 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6995 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6996 * is no more needed.
6997 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
6998 * \throw If the coordinates array is not set in none of the meshes.
6999 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
7000 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
7002 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
7004 std::vector<const MEDCouplingUMesh *> tmp(2);
7005 tmp[0]=const_cast<MEDCouplingUMesh *>(mesh1); tmp[1]=const_cast<MEDCouplingUMesh *>(mesh2);
7006 return MergeUMeshes(tmp);
7010 * Creates a new MEDCouplingUMesh by concatenating all given meshes of the same dimension.
7011 * Cells and nodes of
7012 * the *i*-th mesh precede cells and nodes of the (*i*+1)-th mesh within the result mesh.
7013 * \param [in] a - a vector of meshes (MEDCouplingUMesh) to concatenate.
7014 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7015 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7016 * is no more needed.
7017 * \throw If \a a.size() == 0.
7018 * \throw If \a a[ *i* ] == NULL.
7019 * \throw If the coordinates array is not set in none of the meshes.
7020 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
7021 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
7023 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const std::vector<const MEDCouplingUMesh *>& a)
7025 std::size_t sz=a.size();
7027 return MergeUMeshesLL(a);
7028 for(std::size_t ii=0;ii<sz;ii++)
7031 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshes : item #" << ii << " in input array of size "<< sz << " is empty !";
7032 throw INTERP_KERNEL::Exception(oss.str());
7034 std::vector< MCAuto<MEDCouplingUMesh> > bb(sz);
7035 std::vector< const MEDCouplingUMesh * > aa(sz);
7037 for(std::size_t i=0;i<sz && spaceDim==-3;i++)
7039 const MEDCouplingUMesh *cur=a[i];
7040 const DataArrayDouble *coo=cur->getCoords();
7042 spaceDim=int(coo->getNumberOfComponents());
7045 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : no spaceDim specified ! unable to perform merge !");
7046 for(std::size_t i=0;i<sz;i++)
7048 bb[i]=a[i]->buildSetInstanceFromThis(spaceDim);
7051 return MergeUMeshesLL(aa);
7055 * Creates a new MEDCouplingUMesh by concatenating cells of two given meshes of same
7056 * dimension and sharing the node coordinates array.
7057 * All cells of the first mesh precede all cells of the second mesh
7058 * within the result mesh.
7059 * \param [in] mesh1 - the first mesh.
7060 * \param [in] mesh2 - the second mesh.
7061 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7062 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7063 * is no more needed.
7064 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
7065 * \throw If the meshes do not share the node coordinates array.
7066 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
7067 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
7069 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
7071 std::vector<const MEDCouplingUMesh *> tmp(2);
7072 tmp[0]=mesh1; tmp[1]=mesh2;
7073 return MergeUMeshesOnSameCoords(tmp);
7077 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
7078 * dimension and sharing the node coordinates array.
7079 * All cells of the *i*-th mesh precede all cells of the
7080 * (*i*+1)-th mesh within the result mesh.
7081 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
7082 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7083 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7084 * is no more needed.
7085 * \throw If \a a.size() == 0.
7086 * \throw If \a a[ *i* ] == NULL.
7087 * \throw If the meshes do not share the node coordinates array.
7088 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
7089 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
7091 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes)
7094 throw INTERP_KERNEL::Exception("meshes input parameter is expected to be non empty.");
7095 for(std::size_t ii=0;ii<meshes.size();ii++)
7098 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshesOnSameCoords : item #" << ii << " in input array of size "<< meshes.size() << " is empty !";
7099 throw INTERP_KERNEL::Exception(oss.str());
7101 const DataArrayDouble *coords=meshes.front()->getCoords();
7102 int meshDim=meshes.front()->getMeshDimension();
7103 std::vector<const MEDCouplingUMesh *>::const_iterator iter=meshes.begin();
7104 mcIdType meshLgth=0;
7105 mcIdType meshIndexLgth=0;
7106 for(;iter!=meshes.end();iter++)
7108 if(coords!=(*iter)->getCoords())
7109 throw INTERP_KERNEL::Exception("meshes does not share the same coords ! Try using tryToShareSameCoords method !");
7110 if(meshDim!=(*iter)->getMeshDimension())
7111 throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, FuseUMeshesOnSameCoords impossible !");
7112 meshLgth+=(*iter)->getNodalConnectivityArrayLen();
7113 meshIndexLgth+=(*iter)->getNumberOfCells();
7115 MCAuto<DataArrayIdType> nodal=DataArrayIdType::New();
7116 nodal->alloc(meshLgth,1);
7117 mcIdType *nodalPtr=nodal->getPointer();
7118 MCAuto<DataArrayIdType> nodalIndex=DataArrayIdType::New();
7119 nodalIndex->alloc(meshIndexLgth+1,1);
7120 mcIdType *nodalIndexPtr=nodalIndex->getPointer();
7122 for(iter=meshes.begin();iter!=meshes.end();iter++)
7124 const mcIdType *nod=(*iter)->getNodalConnectivity()->begin();
7125 const mcIdType *index=(*iter)->getNodalConnectivityIndex()->begin();
7126 mcIdType nbOfCells=(*iter)->getNumberOfCells();
7127 mcIdType meshLgth2=(*iter)->getNodalConnectivityArrayLen();
7128 nodalPtr=std::copy(nod,nod+meshLgth2,nodalPtr);
7129 if(iter!=meshes.begin())
7130 nodalIndexPtr=std::transform(index+1,index+nbOfCells+1,nodalIndexPtr,std::bind(std::plus<mcIdType>(),std::placeholders::_1,offset));
7132 nodalIndexPtr=std::copy(index,index+nbOfCells+1,nodalIndexPtr);
7135 MEDCouplingUMesh *ret=MEDCouplingUMesh::New();
7136 ret->setName("merge");
7137 ret->setMeshDimension(meshDim);
7138 ret->setConnectivity(nodal,nodalIndex,true);
7139 ret->setCoords(coords);
7144 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
7145 * dimension and sharing the node coordinates array. Cells of the *i*-th mesh precede
7146 * cells of the (*i*+1)-th mesh within the result mesh. Duplicates of cells are
7147 * removed from \a this mesh and arrays mapping between new and old cell ids in "Old to
7148 * New" mode are returned for each input mesh.
7149 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
7150 * \param [in] compType - specifies a cell comparison technique. For meaning of its
7151 * valid values [0,1,2], see zipConnectivityTraducer().
7152 * \param [in,out] corr - an array of DataArrayIdType, of the same size as \a
7153 * meshes. The *i*-th array describes cell ids mapping for \a meshes[ *i* ]
7154 * mesh. The caller is to delete each of the arrays using decrRef() as it is
7156 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7157 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7158 * is no more needed.
7159 * \throw If \a meshes.size() == 0.
7160 * \throw If \a meshes[ *i* ] == NULL.
7161 * \throw If the meshes do not share the node coordinates array.
7162 * \throw If \a meshes[ *i* ]->getMeshDimension() < 0.
7163 * \throw If the \a meshes are of different dimension (getMeshDimension()).
7164 * \throw If the nodal connectivity of cells of any of \a meshes is not defined.
7165 * \throw If the nodal connectivity any of \a meshes includes an invalid id.
7167 MEDCouplingUMesh *MEDCouplingUMesh::FuseUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes, int compType, std::vector<DataArrayIdType *>& corr)
7169 //All checks are delegated to MergeUMeshesOnSameCoords
7170 MCAuto<MEDCouplingUMesh> ret=MergeUMeshesOnSameCoords(meshes);
7171 MCAuto<DataArrayIdType> o2n=ret->zipConnectivityTraducer(compType);
7172 corr.resize(meshes.size());
7173 std::size_t nbOfMeshes=meshes.size();
7175 const mcIdType *o2nPtr=o2n->begin();
7176 for(std::size_t i=0;i<nbOfMeshes;i++)
7178 DataArrayIdType *tmp=DataArrayIdType::New();
7179 mcIdType curNbOfCells=meshes[i]->getNumberOfCells();
7180 tmp->alloc(curNbOfCells,1);
7181 std::copy(o2nPtr+offset,o2nPtr+offset+curNbOfCells,tmp->getPointer());
7182 offset+=curNbOfCells;
7183 tmp->setName(meshes[i]->getName());
7190 * Makes all given meshes share the nodal connectivity array. The common connectivity
7191 * array is created by concatenating the connectivity arrays of all given meshes. All
7192 * the given meshes must be of the same space dimension but dimension of cells **can
7193 * differ**. This method is particularly useful in MEDLoader context to build a \ref
7194 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
7195 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
7196 * \param [in,out] meshes - a vector of meshes to update.
7197 * \throw If any of \a meshes is NULL.
7198 * \throw If the coordinates array is not set in any of \a meshes.
7199 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
7200 * \throw If \a meshes are of different space dimension.
7202 void MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords(const std::vector<MEDCouplingUMesh *>& meshes)
7204 std::size_t sz=meshes.size();
7207 std::vector< const DataArrayDouble * > coords(meshes.size());
7208 std::vector< const DataArrayDouble * >::iterator it2=coords.begin();
7209 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++,it2++)
7213 (*it)->checkConnectivityFullyDefined();
7214 const DataArrayDouble *coo=(*it)->getCoords();
7219 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
7220 oss << " has no coordinate array defined !";
7221 throw INTERP_KERNEL::Exception(oss.str());
7226 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
7227 oss << " is null !";
7228 throw INTERP_KERNEL::Exception(oss.str());
7231 MCAuto<DataArrayDouble> res=DataArrayDouble::Aggregate(coords);
7232 std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();
7233 mcIdType offset=(*it)->getNumberOfNodes();
7234 (*it++)->setCoords(res);
7235 for(;it!=meshes.end();it++)
7237 mcIdType oldNumberOfNodes=(*it)->getNumberOfNodes();
7238 (*it)->setCoords(res);
7239 (*it)->shiftNodeNumbersInConn(offset);
7240 offset+=oldNumberOfNodes;
7245 * Merges nodes coincident with a given precision within all given meshes that share
7246 * the nodal connectivity array. The given meshes **can be of different** mesh
7247 * dimension. This method is particularly useful in MEDLoader context to build a \ref
7248 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
7249 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
7250 * \param [in,out] meshes - a vector of meshes to update.
7251 * \param [in] eps - the precision used to detect coincident nodes (infinite norm).
7252 * \throw If any of \a meshes is NULL.
7253 * \throw If the \a meshes do not share the same node coordinates array.
7254 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
7256 void MEDCouplingUMesh::MergeNodesOnUMeshesSharingSameCoords(const std::vector<MEDCouplingUMesh *>& meshes, double eps)
7260 std::set<const DataArrayDouble *> s;
7261 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
7264 s.insert((*it)->getCoords());
7267 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 !";
7268 throw INTERP_KERNEL::Exception(oss.str());
7273 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 !";
7274 throw INTERP_KERNEL::Exception(oss.str());
7276 const DataArrayDouble *coo=*(s.begin());
7280 DataArrayIdType *comm,*commI;
7281 coo->findCommonTuples(eps,-1,comm,commI);
7282 MCAuto<DataArrayIdType> tmp1(comm),tmp2(commI);
7283 mcIdType oldNbOfNodes=coo->getNumberOfTuples();
7284 mcIdType newNbOfNodes;
7285 MCAuto<DataArrayIdType> o2n=DataArrayIdType::ConvertIndexArrayToO2N(oldNbOfNodes,comm->begin(),commI->begin(),commI->end(),newNbOfNodes);
7286 if(oldNbOfNodes==newNbOfNodes)
7288 MCAuto<DataArrayDouble> newCoords=coo->renumberAndReduce(o2n->begin(),newNbOfNodes);
7289 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
7291 (*it)->renumberNodesInConn(o2n->begin());
7292 (*it)->setCoords(newCoords);
7298 * This static operates only for coords in 3D. The polygon is specified by its connectivity nodes in [ \a begin , \a end ).
7300 bool MEDCouplingUMesh::IsPolygonWellOriented(bool isQuadratic, const double *vec, const mcIdType *begin, const mcIdType *end, const double *coords)
7303 double v[3]={0.,0.,0.};
7304 std::size_t sz=std::distance(begin,end);
7308 // Algorithm: sum in v the cross products of (e1, e2) where e_i it the vector between (0,0,0) and point i
7309 // and e2 is linear point directly following e1 in the connectivity. All points are used.
7310 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];
7311 v[1]+=coords[3*begin[i]+2]*coords[3*begin[(i+1)%sz]]-coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+2];
7312 v[2]+=coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+1]-coords[3*begin[i]+1]*coords[3*begin[(i+1)%sz]];
7316 // Same algorithm as above but also using intermediate quadratic points.
7317 // (taking only linear points might lead to issues if the linearized version of the
7318 // polygon is not convex or self-intersecting ... see testCellOrientation4)
7319 std::size_t hsz = sz/2;
7320 for(std::size_t j=0;j<sz;j++)
7322 if (j%2) // current point i is quadratic, next point i+1 is standard
7325 ip1 = ((j-1)/2 + 1)%hsz; // ip1 means "i+1", i.e. next point
7327 else // current point i is standard, next point i+1 is quadratic
7332 v[0]+=coords[3*begin[i]+1]*coords[3*begin[ip1]+2]-coords[3*begin[i]+2]*coords[3*begin[ip1]+1];
7333 v[1]+=coords[3*begin[i]+2]*coords[3*begin[ip1]]-coords[3*begin[i]]*coords[3*begin[ip1]+2];
7334 v[2]+=coords[3*begin[i]]*coords[3*begin[ip1]+1]-coords[3*begin[i]+1]*coords[3*begin[ip1]];
7337 double ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
7342 * The polyhedron is specified by its connectivity nodes in [ \a begin , \a end ).
7344 bool MEDCouplingUMesh::IsPolyhedronWellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7346 std::vector<std::pair<mcIdType,mcIdType> > edges;
7347 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
7348 const mcIdType *bgFace=begin;
7349 for(std::size_t i=0;i<nbOfFaces;i++)
7351 const mcIdType *endFace=std::find(bgFace+1,end,-1);
7352 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
7353 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7355 std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7356 if(std::find(edges.begin(),edges.end(),p1)!=edges.end())
7358 edges.push_back(p1);
7362 return INTERP_KERNEL::calculateVolumeForPolyh2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,ToIdType(std::distance(begin,end)),coords)>-EPS_FOR_POLYH_ORIENTATION;
7366 * The 3D extruded static cell (PENTA6,HEXA8,HEXAGP12...) its connectivity nodes in [ \a begin , \a end ).
7368 bool MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7370 double vec0[3],vec1[3];
7371 std::size_t sz=std::distance(begin,end);
7373 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented : the length of nodal connectivity of extruded cell is not even !");
7374 mcIdType nbOfNodes=ToIdType(sz/2);
7375 INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,nbOfNodes,coords,vec0);
7376 const double *pt0=coords+3*begin[0];
7377 const double *pt1=coords+3*begin[nbOfNodes];
7378 vec1[0]=pt1[0]-pt0[0]; vec1[1]=pt1[1]-pt0[1]; vec1[2]=pt1[2]-pt0[2];
7379 return (vec0[0]*vec1[0]+vec0[1]*vec1[1]+vec0[2]*vec1[2])<0.;
7382 void MEDCouplingUMesh::CorrectExtrudedStaticCell(mcIdType *begin, mcIdType *end)
7384 std::size_t sz=std::distance(begin,end);
7385 INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz];
7386 std::size_t nbOfNodes(sz/2);
7387 std::copy(begin,end,(mcIdType *)tmp);
7388 for(std::size_t j=1;j<nbOfNodes;j++)
7390 begin[j]=tmp[nbOfNodes-j];
7391 begin[j+nbOfNodes]=tmp[nbOfNodes+nbOfNodes-j];
7395 bool MEDCouplingUMesh::IsTetra4WellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7397 std::size_t sz=std::distance(begin,end);
7399 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsTetra4WellOriented : Tetra4 cell with not 4 nodes ! Call checkConsistency !");
7400 double vec0[3],vec1[3];
7401 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[1],*pt2=coords+3*begin[2],*pt3=coords+3*begin[3];
7402 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];
7403 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;
7406 bool MEDCouplingUMesh::IsPyra5WellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7408 std::size_t sz=std::distance(begin,end);
7410 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsPyra5WellOriented : Pyra5 cell with not 5 nodes ! Call checkConsistency !");
7412 INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,4,coords,vec0);
7413 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[4];
7414 return (vec0[0]*(pt1[0]-pt0[0])+vec0[1]*(pt1[1]-pt0[1])+vec0[2]*(pt1[2]-pt0[2]))<0.;
7418 * 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 )
7419 * 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
7422 * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not.
7423 * \param [in] coords the coordinates with nb of components exactly equal to 3
7424 * \param [in] index begin of the nodal connectivity (geometric type included) of a single polyhedron cell
7425 * \param [out] res the result is put at the end of the vector without any alteration of the data.
7427 void MEDCouplingUMesh::SimplifyPolyhedronCell(double eps, const DataArrayDouble *coords, mcIdType index, DataArrayIdType *res, MEDCouplingUMesh *faces,
7428 DataArrayIdType *E_Fi, DataArrayIdType *E_F, DataArrayIdType *F_Ei, DataArrayIdType *F_E)
7430 mcIdType nbFaces = E_Fi->getIJ(index + 1, 0) - E_Fi->getIJ(index, 0);
7431 MCAuto<DataArrayDouble> v=DataArrayDouble::New(); v->alloc(nbFaces,3);
7432 double *vPtr=v->getPointer();
7433 MCAuto<DataArrayDouble> p=DataArrayDouble::New(); p->alloc(nbFaces,2);
7434 double *pPtr=p->getPointer();
7435 mcIdType *e_fi = E_Fi->getPointer(), *e_f = E_F->getPointer(), *f_ei = F_Ei->getPointer(), *f_e = F_E->getPointer();
7436 const mcIdType *f_idx = faces->getNodalConnectivityIndex()->getPointer(), *f_cnn = faces->getNodalConnectivity()->getPointer();
7437 for(mcIdType i=0;i<nbFaces;i++,vPtr+=3,pPtr++)
7439 mcIdType face = e_f[e_fi[index] + i];
7440 ComputeVecAndPtOfFace(eps, coords->begin(), f_cnn + f_idx[face] + 1, f_cnn + f_idx[face + 1], vPtr, pPtr);
7441 // to differentiate faces going to different cells:
7443 for (mcIdType j = f_ei[face]; j < f_ei[face + 1]; j++)
7444 *pPtr += FromIdType<double>(f_e[j]);
7446 pPtr=p->getPointer(); vPtr=v->getPointer();
7447 DataArrayIdType *comm1=0,*commI1=0;
7448 v->findCommonTuples(eps,-1,comm1,commI1);
7449 for (mcIdType i = 0; i < nbFaces; i++)
7450 if (comm1->findIdFirstEqual(i) < 0)
7452 comm1->pushBackSilent(i);
7453 commI1->pushBackSilent(comm1->getNumberOfTuples());
7455 MCAuto<DataArrayIdType> comm1Auto(comm1),commI1Auto(commI1);
7456 const mcIdType *comm1Ptr=comm1->begin();
7457 const mcIdType *commI1Ptr=commI1->begin();
7458 mcIdType nbOfGrps1=commI1Auto->getNumberOfTuples()-1;
7459 res->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYHED));
7461 for(mcIdType i=0;i<nbOfGrps1;i++)
7463 mcIdType vecId=comm1Ptr[commI1Ptr[i]];
7464 MCAuto<DataArrayDouble> tmpgrp2=p->selectByTupleId(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7465 DataArrayIdType *comm2=0,*commI2=0;
7466 tmpgrp2->findCommonTuples(eps,-1,comm2,commI2);
7467 for (mcIdType j = 0; j < commI1Ptr[i+1] - commI1Ptr[i]; j++)
7468 if (comm2->findIdFirstEqual(j) < 0)
7470 comm2->pushBackSilent(j);
7471 commI2->pushBackSilent(comm2->getNumberOfTuples());
7473 MCAuto<DataArrayIdType> comm2Auto(comm2),commI2Auto(commI2);
7474 const mcIdType *comm2Ptr=comm2->begin();
7475 const mcIdType *commI2Ptr=commI2->begin();
7476 mcIdType nbOfGrps2=commI2Auto->getNumberOfTuples()-1;
7477 for(mcIdType j=0;j<nbOfGrps2;j++)
7479 if(commI2Ptr[j+1] == commI2Ptr[j] + 1)
7481 mcIdType face = e_f[e_fi[index] + comm1Ptr[commI1Ptr[i] + comm2Ptr[commI2Ptr[j]]]]; //hmmm
7482 res->insertAtTheEnd(f_cnn + f_idx[face] + 1, f_cnn + f_idx[face + 1]);
7483 res->pushBackSilent(-1);
7487 mcIdType pointId=comm1Ptr[commI1Ptr[i]+comm2Ptr[commI2Ptr[j]]];
7488 MCAuto<DataArrayIdType> ids2=comm2->selectByTupleIdSafeSlice(commI2Ptr[j],commI2Ptr[j+1],1);
7489 ids2->transformWithIndArr(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7490 ids2->transformWithIndArr(e_f + e_fi[index], e_f + e_fi[index + 1]);
7491 MCAuto<MEDCouplingUMesh> mm3=static_cast<MEDCouplingUMesh *>(faces->buildPartOfMySelf(ids2->begin(),ids2->end(),true));
7492 MCAuto<DataArrayIdType> idsNodeTmp=mm3->zipCoordsTraducer();
7493 MCAuto<DataArrayIdType> idsNode=idsNodeTmp->invertArrayO2N2N2O(mm3->getNumberOfNodes());
7494 const mcIdType *idsNodePtr=idsNode->begin();
7495 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];
7496 double vec[3]; vec[0]=vPtr[3*vecId+1]; vec[1]=-vPtr[3*vecId]; vec[2]=0.;
7497 double norm=vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2];
7498 if(std::abs(norm)>eps)
7500 double angle=INTERP_KERNEL::EdgeArcCircle::SafeAsin(norm);
7501 mm3->rotate(center,vec,angle);
7503 mm3->changeSpaceDimension(2);
7504 MCAuto<MEDCouplingUMesh> mm4=mm3->buildSpreadZonesWithPoly();
7505 const mcIdType *conn4=mm4->getNodalConnectivity()->begin();
7506 const mcIdType *connI4=mm4->getNodalConnectivityIndex()->begin();
7507 mcIdType nbOfCells=mm4->getNumberOfCells();
7508 for(mcIdType k=0;k<nbOfCells;k++)
7511 for(const mcIdType *work=conn4+connI4[k]+1;work!=conn4+connI4[k+1];work++,l++)
7512 res->pushBackSilent(idsNodePtr[*work]);
7513 res->pushBackSilent(-1);
7518 res->popBackSilent();
7522 * 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
7523 * through origin. The plane is defined by its nodal connectivity [ \b begin, \b end ).
7525 * \param [in] eps below that value the dot product of 2 vectors is considered as colinears
7526 * \param [in] coords coordinates expected to have 3 components.
7527 * \param [in] begin start of the nodal connectivity of the face.
7528 * \param [in] end end of the nodal connectivity (excluded) of the face.
7529 * \param [out] v the normalized vector of size 3
7530 * \param [out] p the pos of plane
7532 void MEDCouplingUMesh::ComputeVecAndPtOfFace(double eps, const double *coords, const mcIdType *begin, const mcIdType *end, double *v, double *p)
7534 std::size_t nbPoints=std::distance(begin,end);
7536 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeVecAndPtOfFace : < of 3 points in face ! not able to find a plane on that face !");
7537 double vec[3]={0.,0.,0.};
7539 bool refFound=false;
7540 for(;j<nbPoints-1 && !refFound;j++)
7542 vec[0]=coords[3*begin[j+1]]-coords[3*begin[j]];
7543 vec[1]=coords[3*begin[j+1]+1]-coords[3*begin[j]+1];
7544 vec[2]=coords[3*begin[j+1]+2]-coords[3*begin[j]+2];
7545 double norm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
7549 vec[0]/=norm; vec[1]/=norm; vec[2]/=norm;
7552 for(std::size_t i=j;i<nbPoints-1;i++)
7555 curVec[0]=coords[3*begin[i+1]]-coords[3*begin[i]];
7556 curVec[1]=coords[3*begin[i+1]+1]-coords[3*begin[i]+1];
7557 curVec[2]=coords[3*begin[i+1]+2]-coords[3*begin[i]+2];
7558 double norm=sqrt(curVec[0]*curVec[0]+curVec[1]*curVec[1]+curVec[2]*curVec[2]);
7561 curVec[0]/=norm; curVec[1]/=norm; curVec[2]/=norm;
7562 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];
7563 norm=sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
7566 v[0]/=norm; v[1]/=norm; v[2]/=norm;
7567 *p=v[0]*coords[3*begin[i]]+v[1]*coords[3*begin[i]+1]+v[2]*coords[3*begin[i]+2];
7571 throw INTERP_KERNEL::Exception("Not able to find a normal vector of that 3D face !");
7575 * This method tries to obtain a well oriented polyhedron.
7576 * If the algorithm fails, an exception will be thrown.
7578 void MEDCouplingUMesh::TryToCorrectPolyhedronOrientation(mcIdType *begin, mcIdType *end, const double *coords)
7580 std::list< std::pair<mcIdType,mcIdType> > edgesOK,edgesFinished;
7581 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
7582 std::vector<bool> isPerm(nbOfFaces,false);//field on faces False: I don't know, True : oriented
7584 mcIdType *bgFace=begin,*endFace=std::find(begin+1,end,-1);
7585 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
7586 for(std::size_t l=0;l<nbOfEdgesInFace;l++) { std::pair<mcIdType,mcIdType> p1(bgFace[l],bgFace[(l+1)%nbOfEdgesInFace]); edgesOK.push_back(p1); }
7588 while(std::find(isPerm.begin(),isPerm.end(),false)!=isPerm.end())
7591 std::size_t smthChanged=0;
7592 for(std::size_t i=0;i<nbOfFaces;i++)
7594 endFace=std::find(bgFace+1,end,-1);
7595 nbOfEdgesInFace=std::distance(bgFace,endFace);
7599 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7601 std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7602 std::pair<mcIdType,mcIdType> p2(p1.second,p1.first);
7603 bool b1=std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end();
7604 bool b2=std::find(edgesOK.begin(),edgesOK.end(),p2)!=edgesOK.end();
7605 if(b1 || b2) { b=b2; isPerm[i]=true; smthChanged++; break; }
7610 std::reverse(bgFace+1,endFace);
7611 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7613 std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7614 std::pair<mcIdType,mcIdType> p2(p1.second,p1.first);
7615 if(std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end())
7616 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7617 if(std::find(edgesFinished.begin(),edgesFinished.end(),p1)!=edgesFinished.end() || std::find(edgesFinished.begin(),edgesFinished.end(),p2)!=edgesFinished.end())
7618 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7619 std::list< std::pair<mcIdType,mcIdType> >::iterator it=std::find(edgesOK.begin(),edgesOK.end(),p2);
7620 if(it!=edgesOK.end())
7623 edgesFinished.push_back(p1);
7626 edgesOK.push_back(p1);
7633 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired !"); }
7635 if(!edgesOK.empty())
7636 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired : Some edges are shared only once !"); }
7637 if(INTERP_KERNEL::calculateVolumeForPolyh2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,ToIdType(std::distance(begin,end)),coords)<-EPS_FOR_POLYH_ORIENTATION)
7638 {//not lucky ! The first face was not correctly oriented : reorient all faces...
7640 for(std::size_t i=0;i<nbOfFaces;i++)
7642 endFace=std::find(bgFace+1,end,-1);
7643 std::reverse(bgFace+1,endFace);
7651 * This method makes the assumption spacedimension == meshdimension == 2.
7652 * This method works only for linear cells.
7654 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYGON in pos#0)
7656 DataArrayIdType *MEDCouplingUMesh::buildUnionOf2DMesh() const
7658 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
7659 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : meshdimension, spacedimension must be equal to 2 !");
7660 MCAuto<MEDCouplingUMesh> skin(computeSkin());
7661 mcIdType oldNbOfNodes(skin->getNumberOfNodes());
7662 MCAuto<DataArrayIdType> o2n(skin->zipCoordsTraducer());
7663 mcIdType nbOfNodesExpected(skin->getNumberOfNodes());
7664 MCAuto<DataArrayIdType> n2o(o2n->invertArrayO2N2N2O(oldNbOfNodes));
7665 mcIdType nbCells=skin->getNumberOfCells();
7666 if(nbCells==nbOfNodesExpected)
7667 return buildUnionOf2DMeshLinear(skin,n2o);
7668 else if(2*nbCells==nbOfNodesExpected)
7669 return buildUnionOf2DMeshQuadratic(skin,n2o);
7671 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : the mesh 2D in input appears to be not in a single part of a 2D mesh !");
7675 * This method makes the assumption spacedimension == meshdimension == 3.
7676 * This method works only for linear cells.
7678 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYHED in pos#0)
7680 DataArrayIdType *MEDCouplingUMesh::buildUnionOf3DMesh() const
7682 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
7683 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf3DMesh : meshdimension, spacedimension must be equal to 2 !");
7684 MCAuto<MEDCouplingUMesh> m=computeSkin();
7685 const mcIdType *conn=m->getNodalConnectivity()->begin();
7686 const mcIdType *connI=m->getNodalConnectivityIndex()->begin();
7687 mcIdType nbOfCells=m->getNumberOfCells();
7688 MCAuto<DataArrayIdType> ret=DataArrayIdType::New(); ret->alloc(m->getNodalConnectivity()->getNumberOfTuples(),1);
7689 mcIdType *work=ret->getPointer(); *work++=INTERP_KERNEL::NORM_POLYHED;
7692 work=std::copy(conn+connI[0]+1,conn+connI[1],work);
7693 for(mcIdType i=1;i<nbOfCells;i++)
7696 work=std::copy(conn+connI[i]+1,conn+connI[i+1],work);
7702 * \brief Creates a graph of cell neighbors
7703 * \return MEDCouplingSkyLineArray * - an sky line array the user should delete.
7704 * In the sky line array, graph arcs are stored in terms of (index,value) notation.
7706 * - index: 0 3 5 6 6
7707 * - value: 1 2 3 2 3 3
7708 * means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7709 * Arcs are not doubled but reflexive (1,1) arcs are present for each cell
7711 MEDCouplingSkyLineArray* MEDCouplingUMesh::generateGraph() const
7713 checkConnectivityFullyDefined();
7715 int meshDim = this->getMeshDimension();
7716 MEDCoupling::DataArrayIdType* indexr=MEDCoupling::DataArrayIdType::New();
7717 MEDCoupling::DataArrayIdType* revConn=MEDCoupling::DataArrayIdType::New();
7718 this->getReverseNodalConnectivity(revConn,indexr);
7719 const mcIdType* indexr_ptr=indexr->begin();
7720 const mcIdType* revConn_ptr=revConn->begin();
7722 const MEDCoupling::DataArrayIdType* index;
7723 const MEDCoupling::DataArrayIdType* conn;
7724 conn=this->getNodalConnectivity(); // it includes a type as the 1st element!!!
7725 index=this->getNodalConnectivityIndex();
7726 mcIdType nbCells=this->getNumberOfCells();
7727 const mcIdType* index_ptr=index->begin();
7728 const mcIdType* conn_ptr=conn->begin();
7730 //creating graph arcs (cell to cell relations)
7731 //arcs are stored in terms of (index,value) notation
7734 // means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7735 // in present version arcs are not doubled but reflexive (1,1) arcs are present for each cell
7737 //warning here one node have less than or equal effective number of cell with it
7738 //but cell could have more than effective nodes
7739 //because other equals nodes in other domain (with other global inode)
7740 std::vector <mcIdType> cell2cell_index(nbCells+1,0);
7741 std::vector <mcIdType> cell2cell;
7742 cell2cell.reserve(3*nbCells);
7744 for (mcIdType icell=0; icell<nbCells;icell++)
7746 std::map<mcIdType,mcIdType > counter;
7747 for (mcIdType iconn=index_ptr[icell]+1; iconn<index_ptr[icell+1];iconn++)
7749 mcIdType inode=conn_ptr[iconn];
7750 for (mcIdType iconnr=indexr_ptr[inode]; iconnr<indexr_ptr[inode+1];iconnr++)
7752 mcIdType icell2=revConn_ptr[iconnr];
7753 std::map<mcIdType,mcIdType>::iterator iter=counter.find(icell2);
7754 if (iter!=counter.end()) (iter->second)++;
7755 else counter.insert(std::make_pair(icell2,1));
7758 for (std::map<mcIdType,mcIdType>::const_iterator iter=counter.begin();
7759 iter!=counter.end(); iter++)
7760 if (iter->second >= meshDim)
7762 cell2cell_index[icell+1]++;
7763 cell2cell.push_back(iter->first);
7768 cell2cell_index[0]=0;
7769 for (mcIdType icell=0; icell<nbCells;icell++)
7770 cell2cell_index[icell+1]=cell2cell_index[icell]+cell2cell_index[icell+1];
7772 //filling up index and value to create skylinearray structure
7773 MEDCouplingSkyLineArray * array(MEDCouplingSkyLineArray::New(cell2cell_index,cell2cell));
7778 void MEDCouplingUMesh::writeVTKLL(std::ostream& ofs, const std::string& cellData, const std::string& pointData, DataArrayByte *byteData) const
7780 mcIdType nbOfCells=getNumberOfCells();
7782 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::writeVTK : the unstructured mesh has no cells !");
7783 ofs << " <" << getVTKDataSetType() << ">\n";
7784 ofs << " <Piece NumberOfPoints=\"" << getNumberOfNodes() << "\" NumberOfCells=\"" << nbOfCells << "\">\n";
7785 ofs << " <PointData>\n" << pointData << std::endl;
7786 ofs << " </PointData>\n";
7787 ofs << " <CellData>\n" << cellData << std::endl;
7788 ofs << " </CellData>\n";
7789 ofs << " <Points>\n";
7790 if(getSpaceDimension()==3)
7791 _coords->writeVTK(ofs,8,"Points",byteData);
7794 MCAuto<DataArrayDouble> coo=_coords->changeNbOfComponents(3,0.);
7795 coo->writeVTK(ofs,8,"Points",byteData);
7797 ofs << " </Points>\n";
7798 ofs << " <Cells>\n";
7799 const mcIdType *cPtr=_nodal_connec->begin();
7800 const mcIdType *cIPtr=_nodal_connec_index->begin();
7801 MCAuto<DataArrayIdType> faceoffsets=DataArrayIdType::New(); faceoffsets->alloc(nbOfCells,1);
7802 MCAuto<DataArrayIdType> types=DataArrayIdType::New(); types->alloc(nbOfCells,1);
7803 MCAuto<DataArrayIdType> offsets=DataArrayIdType::New(); offsets->alloc(nbOfCells,1);
7804 MCAuto<DataArrayIdType> connectivity=DataArrayIdType::New(); connectivity->alloc(_nodal_connec->getNumberOfTuples()-nbOfCells,1);
7805 mcIdType *w1=faceoffsets->getPointer(),*w2=types->getPointer(),*w3=offsets->getPointer(),*w4=connectivity->getPointer();
7806 mcIdType szFaceOffsets=0,szConn=0;
7807 for(mcIdType i=0;i<nbOfCells;i++,w1++,w2++,w3++)
7810 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]!=INTERP_KERNEL::NORM_POLYHED)
7813 *w3=szConn+cIPtr[i+1]-cIPtr[i]-1; szConn+=cIPtr[i+1]-cIPtr[i]-1;
7814 w4=std::copy(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],w4);
7818 mcIdType deltaFaceOffset=cIPtr[i+1]-cIPtr[i]+1;
7819 *w1=szFaceOffsets+deltaFaceOffset; szFaceOffsets+=deltaFaceOffset;
7820 std::set<mcIdType> c(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1]); c.erase(-1);
7821 *w3=szConn+ToIdType(c.size()); szConn+=ToIdType(c.size());
7822 w4=std::copy(c.begin(),c.end(),w4);
7825 std::unique_ptr<mcIdType[]> medcoupling2vtkTypeTraducer_mcIdType(new mcIdType[MEDCOUPLING2VTKTYPETRADUCER_LGTH]);
7826 for(auto ii = 0; ii<MEDCOUPLING2VTKTYPETRADUCER_LGTH ; ++ii)
7827 medcoupling2vtkTypeTraducer_mcIdType[ii] = MEDCOUPLING2VTKTYPETRADUCER[ii]!=MEDCOUPLING2VTKTYPETRADUCER_NONE?MEDCOUPLING2VTKTYPETRADUCER[ii] : -1;
7828 types->transformWithIndArr(medcoupling2vtkTypeTraducer_mcIdType.get(),medcoupling2vtkTypeTraducer_mcIdType.get()+MEDCOUPLING2VTKTYPETRADUCER_LGTH);
7829 types->writeVTK(ofs,8,"UInt8","types",byteData);
7830 std::string vtkTypeName = Traits<mcIdType>::VTKReprStr;
7831 offsets->writeVTK(ofs,8,vtkTypeName,"offsets",byteData);
7832 if(szFaceOffsets!=0)
7833 {//presence of Polyhedra
7834 connectivity->reAlloc(szConn);
7835 faceoffsets->writeVTK(ofs,8,vtkTypeName,"faceoffsets",byteData);
7836 MCAuto<DataArrayIdType> faces=DataArrayIdType::New(); faces->alloc(szFaceOffsets,1);
7837 w1=faces->getPointer();
7838 for(mcIdType i=0;i<nbOfCells;i++)
7839 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]==INTERP_KERNEL::NORM_POLYHED)
7841 mcIdType nbFaces=ToIdType(std::count(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],-1))+1;
7843 const mcIdType *w6=cPtr+cIPtr[i]+1,*w5=0;
7844 for(mcIdType j=0;j<nbFaces;j++)
7846 w5=std::find(w6,cPtr+cIPtr[i+1],-1);
7847 *w1++=ToIdType(std::distance(w6,w5));
7848 w1=std::copy(w6,w5,w1);
7852 faces->writeVTK(ofs,8,vtkTypeName,"faces",byteData);
7854 connectivity->writeVTK(ofs,8,vtkTypeName,"connectivity",byteData);
7855 ofs << " </Cells>\n";
7856 ofs << " </Piece>\n";
7857 ofs << " </" << getVTKDataSetType() << ">\n";
7860 void MEDCouplingUMesh::reprQuickOverview(std::ostream& stream) const
7862 stream << "MEDCouplingUMesh C++ instance at " << this << ". Name : \"" << getName() << "\".";
7864 { stream << " Not set !"; return ; }
7865 stream << " Mesh dimension : " << _mesh_dim << ".";
7869 { stream << " No coordinates set !"; return ; }
7870 if(!_coords->isAllocated())
7871 { stream << " Coordinates set but not allocated !"; return ; }
7872 stream << " Space dimension : " << _coords->getNumberOfComponents() << "." << std::endl;
7873 stream << "Number of nodes : " << _coords->getNumberOfTuples() << ".";
7874 if(!_nodal_connec_index)
7875 { stream << std::endl << "Nodal connectivity NOT set !"; return ; }
7876 if(!_nodal_connec_index->isAllocated())
7877 { stream << std::endl << "Nodal connectivity set but not allocated !"; return ; }
7878 mcIdType lgth=_nodal_connec_index->getNumberOfTuples();
7879 std::size_t cpt=_nodal_connec_index->getNumberOfComponents();
7880 if(cpt!=1 || lgth<1)
7882 stream << std::endl << "Number of cells : " << lgth-1 << ".";
7885 std::string MEDCouplingUMesh::getVTKDataSetType() const
7887 return std::string("UnstructuredGrid");
7890 std::string MEDCouplingUMesh::getVTKFileExtension() const
7892 return std::string("vtu");
7898 * Provides a renumbering of the cells of this (which has to be a piecewise connected 1D line), so that
7899 * the segments of the line are indexed in consecutive order (i.e. cells \a i and \a i+1 are neighbors).
7900 * This doesn't modify the mesh. This method only works using nodal connectivity consideration. Coordinates of nodes are ignored here.
7901 * The caller is to deal with the resulting DataArrayIdType.
7902 * \throw If the coordinate array is not set.
7903 * \throw If the nodal connectivity of the cells is not defined.
7904 * \throw If m1 is not a mesh of dimension 2, or m1 is not a mesh of dimension 1
7905 * \throw If m2 is not a (piecewise) line (i.e. if a point has more than 2 adjacent segments)
7907 * \sa DataArrayIdType::sortEachPairToMakeALinkedList
7909 DataArrayIdType *MEDCouplingUMesh::orderConsecutiveCells1D() const
7911 checkFullyDefined();
7912 if(getMeshDimension()!=1)
7913 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D works on unstructured mesh with meshdim = 1 !");
7915 // Check that this is a line (and not a more complex 1D mesh) - each point is used at most by 2 segments:
7916 MCAuto<DataArrayIdType> _d(DataArrayIdType::New()),_dI(DataArrayIdType::New());
7917 MCAuto<DataArrayIdType> _rD(DataArrayIdType::New()),_rDI(DataArrayIdType::New());
7918 MCAuto<MEDCouplingUMesh> m_points(buildDescendingConnectivity(_d, _dI, _rD, _rDI));
7919 const mcIdType *d(_d->begin()), *dI(_dI->begin());
7920 const mcIdType *rD(_rD->begin()), *rDI(_rDI->begin());
7921 MCAuto<DataArrayIdType> _dsi(_rDI->deltaShiftIndex());
7922 const mcIdType * dsi(_dsi->begin());
7923 MCAuto<DataArrayIdType> dsii = _dsi->findIdsNotInRange(0,3);
7925 if (dsii->getNumberOfTuples())
7926 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D only work with a mesh being a (piecewise) connected line!");
7928 mcIdType nc=getNumberOfCells();
7929 MCAuto<DataArrayIdType> result(DataArrayIdType::New());
7930 result->alloc(nc,1);
7932 // set of edges not used so far
7933 std::set<mcIdType> edgeSet;
7934 for (mcIdType i=0; i<nc; edgeSet.insert(i), i++);
7936 mcIdType startSeg=0;
7938 // while we have points with only one neighbor segments
7941 std::list<mcIdType> linePiece;
7942 // fills a list of consecutive segment linked to startSeg. This can go forward or backward.
7943 for (int direction=0;direction<2;direction++) // direction=0 --> forward, direction=1 --> backward
7945 // Fill the list forward (resp. backward) from the start segment:
7946 mcIdType activeSeg = startSeg;
7947 mcIdType prevPointId = -20;
7949 while (!edgeSet.empty())
7951 if (!(direction == 1 && prevPointId==-20)) // prevent adding twice startSeg
7954 linePiece.push_back(activeSeg);
7956 linePiece.push_front(activeSeg);
7957 edgeSet.erase(activeSeg);
7960 mcIdType ptId1 = d[dI[activeSeg]], ptId2 = d[dI[activeSeg]+1];
7961 ptId = direction ? (ptId1 == prevPointId ? ptId2 : ptId1) : (ptId2 == prevPointId ? ptId1 : ptId2);
7962 if (dsi[ptId] == 1) // hitting the end of the line
7966 mcIdType seg1 = rD[rDI[ptId]], seg2 = rD[rDI[ptId]+1];
7967 activeSeg = (seg1 == activeSeg) ? seg2 : seg1;
7969 //for piecewise meshes made up of closed parts
7970 bool segmentAlreadyTreated = (std::find(linePiece.begin(), linePiece.end(), activeSeg) != linePiece.end());
7971 if(segmentAlreadyTreated)
7975 // Done, save final piece into DA:
7976 std::copy(linePiece.begin(), linePiece.end(), result->getPointer()+newIdx);
7977 newIdx += ToIdType(linePiece.size());
7979 // identify next valid start segment (one which is not consumed)
7980 if(!edgeSet.empty())
7981 startSeg = *(edgeSet.begin());
7984 while (!edgeSet.empty());
7985 return result.retn();
7989 * This method split some of edges of 2D cells in \a this. The edges to be split are specified in \a subNodesInSeg
7990 * and in \a subNodesInSegI using \ref numbering-indirect storage mode.
7991 * To do the work this method can optionally needs information about middle of subedges for quadratic cases if
7992 * a minimal creation of new nodes is wanted.
7993 * So this method try to reduce at most the number of new nodes. The only case that can lead this method to add
7994 * nodes if a SEG3 is split without information of middle.
7995 * \b WARNING : is returned value is different from 0 a call to MEDCouplingUMesh::mergeNodes is necessary to
7996 * avoid to have a non conform mesh.
7998 * \return mcIdType - the number of new nodes created (in most of cases 0).
8000 * \throw If \a this is not coherent.
8001 * \throw If \a this has not spaceDim equal to 2.
8002 * \throw If \a this has not meshDim equal to 2.
8003 * \throw If some subcells needed to be split are orphan.
8004 * \sa MEDCouplingUMesh::conformize2D
8006 mcIdType MEDCouplingUMesh::split2DCells(const DataArrayIdType *desc, const DataArrayIdType *descI, const DataArrayIdType *subNodesInSeg, const DataArrayIdType *subNodesInSegI, const DataArrayIdType *midOpt, const DataArrayIdType *midOptI)
8008 if(!desc || !descI || !subNodesInSeg || !subNodesInSegI)
8009 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : the 4 first arrays must be not null !");
8010 desc->checkAllocated(); descI->checkAllocated(); subNodesInSeg->checkAllocated(); subNodesInSegI->checkAllocated();
8011 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
8012 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : This method only works for meshes with spaceDim=2 and meshDim=2 !");
8013 if(midOpt==0 && midOptI==0)
8015 split2DCellsLinear(desc,descI,subNodesInSeg,subNodesInSegI);
8018 else if(midOpt!=0 && midOptI!=0)
8019 return split2DCellsQuadratic(desc,descI,subNodesInSeg,subNodesInSegI,midOpt,midOptI);
8021 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : middle parameters must be set to null for all or not null for all.");
8025 * 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
8026 * 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
8027 * the geometric cell type set to INTERP_KERNEL::NORM_POLYGON.
8028 * 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
8029 * 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.
8031 * \return false if the input connectivity represents already the convex hull, true if the input cell needs to be reordered.
8033 bool MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis(const double *coords, const mcIdType *nodalConnBg, const mcIdType *nodalConnEnd, DataArrayIdType *nodalConnecOut)
8035 std::size_t sz=std::distance(nodalConnBg,nodalConnEnd);
8038 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)*nodalConnBg);
8039 if(cm.getDimension()==2)
8041 const mcIdType *node=nodalConnBg+1;
8042 mcIdType startNode=*node++;
8043 double refX=coords[2*startNode];
8044 for(;node!=nodalConnEnd;node++)
8046 if(coords[2*(*node)]<refX)
8049 refX=coords[2*startNode];
8052 std::vector<mcIdType> tmpOut; tmpOut.reserve(sz); tmpOut.push_back(startNode);
8056 double angle0=-M_PI/2;
8058 mcIdType nextNode=-1;
8059 mcIdType prevNode=-1;
8061 double angleNext=0.;
8062 while(nextNode!=startNode)
8066 for(node=nodalConnBg+1;node!=nodalConnEnd;node++)
8068 if(*node!=tmpOut.back() && *node!=prevNode)
8070 tmp2[0]=coords[2*(*node)]-coords[2*tmpOut.back()]; tmp2[1]=coords[2*(*node)+1]-coords[2*tmpOut.back()+1];
8071 double angleM=INTERP_KERNEL::EdgeArcCircle::GetAbsoluteAngle(tmp2,tmp1);
8076 res=angle0-angleM+2.*M_PI;
8085 if(nextNode!=startNode)
8087 angle0=angleNext-M_PI;
8090 prevNode=tmpOut.back();
8091 tmpOut.push_back(nextNode);
8094 std::vector<mcIdType> tmp3(2*(sz-1));
8095 std::vector<mcIdType>::iterator it=std::copy(nodalConnBg+1,nodalConnEnd,tmp3.begin());
8096 std::copy(nodalConnBg+1,nodalConnEnd,it);
8097 if(std::search(tmp3.begin(),tmp3.end(),tmpOut.begin(),tmpOut.end())!=tmp3.end())
8099 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
8102 if(std::search(tmp3.rbegin(),tmp3.rend(),tmpOut.begin(),tmpOut.end())!=tmp3.rend())
8104 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
8109 nodalConnecOut->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYGON));
8110 nodalConnecOut->insertAtTheEnd(tmpOut.begin(),tmpOut.end());
8115 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
8118 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
8122 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
8123 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
8124 * 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]].
8125 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
8126 * A negative value in \b arrIn means that it is ignored.
8127 * 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.
8129 * \param [in] arrIn arr origin array from which the extraction will be done.
8130 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
8131 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
8132 * \sa MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed, MEDCouplingUMesh::partitionBySpreadZone
8134 DataArrayIdType *MEDCouplingUMesh::ComputeSpreadZoneGradually(const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn)
8136 mcIdType seed=0,nbOfDepthPeelingPerformed=0;
8137 return ComputeSpreadZoneGraduallyFromSeed(&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfDepthPeelingPerformed);
8141 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
8142 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
8143 * 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]].
8144 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
8145 * A negative value in \b arrIn means that it is ignored.
8146 * 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] seedBg the begin pointer (included) of an array containing the seed of the search zone
8148 * \param [in] seedEnd the end pointer (not included) of an array containing the seed of the search zone
8149 * \param [in] arrIn arr origin array from which the extraction will be done.
8150 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
8151 * \param [in] nbOfDepthPeeling the max number of peels requested in search. By default -1, that is to say, no limit.
8152 * \param [out] nbOfDepthPeelingPerformed the number of peels effectively performed. May be different from \a nbOfDepthPeeling
8153 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
8154 * \sa MEDCouplingUMesh::partitionBySpreadZone
8156 DataArrayIdType *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(const mcIdType *seedBg, const mcIdType *seedEnd, const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn, mcIdType nbOfDepthPeeling, mcIdType& nbOfDepthPeelingPerformed)
8158 nbOfDepthPeelingPerformed=0;
8160 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed : arrIndxIn input pointer is NULL !");
8161 mcIdType nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
8164 DataArrayIdType *ret=DataArrayIdType::New(); ret->alloc(0,1);
8168 std::vector<bool> fetched(nbOfTuples,false);
8169 return ComputeSpreadZoneGraduallyFromSeedAlg(fetched,seedBg,seedEnd,arrIn,arrIndxIn,nbOfDepthPeeling,nbOfDepthPeelingPerformed);
8175 * \b this is expected to be a mesh fully defined whose spaceDim==meshDim.
8176 * It returns a new allocated mesh having the same mesh dimension and lying on same coordinates.
8177 * The returned mesh contains as poly cells as number of contiguous zone (regarding connectivity).
8178 * A spread contiguous zone is built using poly cells (polyhedra in 3D, polygons in 2D and polyline in 1D).
8179 * The sum of measure field of returned mesh is equal to the sum of measure field of this.
8181 * \return a newly allocated mesh lying on the same coords than \b this with same meshdimension than \b this.
8183 MEDCouplingUMesh *MEDCouplingUMesh::buildSpreadZonesWithPoly() const
8185 checkFullyDefined();
8186 int mdim=getMeshDimension();
8187 int spaceDim=getSpaceDimension();
8189 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension and spacedimension do not match !");
8190 std::vector<DataArrayIdType *> partition=partitionBySpreadZone();
8191 std::vector< MCAuto<DataArrayIdType> > partitionAuto; partitionAuto.reserve(partition.size());
8192 std::copy(partition.begin(),partition.end(),std::back_insert_iterator<std::vector< MCAuto<DataArrayIdType> > >(partitionAuto));
8193 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
8194 ret->setCoords(getCoords());
8195 ret->allocateCells(ToIdType(partition.size()));
8197 for(std::vector<DataArrayIdType *>::const_iterator it=partition.begin();it!=partition.end();it++)
8199 MCAuto<MEDCouplingUMesh> tmp=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf((*it)->begin(),(*it)->end(),true));
8200 MCAuto<DataArrayIdType> cell;
8204 cell=tmp->buildUnionOf2DMesh();
8207 cell=tmp->buildUnionOf3DMesh();
8210 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension supported are [2,3] ! Not implemented yet for others !");
8213 ret->insertNextCell((INTERP_KERNEL::NormalizedCellType)cell->getIJSafe(0,0),cell->getNumberOfTuples()-1,cell->begin()+1);
8216 ret->finishInsertingCells();
8221 * This method partitions \b this into contiguous zone.
8222 * This method only needs a well defined connectivity. Coordinates are not considered here.
8223 * This method returns a vector of \b newly allocated arrays that the caller has to deal with.
8225 std::vector<DataArrayIdType *> MEDCouplingUMesh::partitionBySpreadZone() const
8227 DataArrayIdType *neigh=0,*neighI=0;
8228 computeNeighborsOfCells(neigh,neighI);
8229 MCAuto<DataArrayIdType> neighAuto(neigh),neighIAuto(neighI);
8230 return PartitionBySpreadZone(neighAuto,neighIAuto);
8233 std::vector<DataArrayIdType *> MEDCouplingUMesh::PartitionBySpreadZone(const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn)
8235 if(!arrIn || !arrIndxIn)
8236 throw INTERP_KERNEL::Exception("PartitionBySpreadZone : null input pointers !");
8237 arrIn->checkAllocated(); arrIndxIn->checkAllocated();
8238 mcIdType nbOfTuples(arrIndxIn->getNumberOfTuples());
8239 if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1 || nbOfTuples<1)
8240 throw INTERP_KERNEL::Exception("PartitionBySpreadZone : invalid arrays in input !");
8241 mcIdType nbOfCellsCur(nbOfTuples-1);
8242 std::vector<DataArrayIdType *> ret;
8245 std::vector<bool> fetchedCells(nbOfCellsCur,false);
8246 std::vector< MCAuto<DataArrayIdType> > ret2;
8248 while(seed<nbOfCellsCur)
8250 mcIdType nbOfPeelPerformed=0;
8251 ret2.push_back(ComputeSpreadZoneGraduallyFromSeedAlg(fetchedCells,&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfPeelPerformed));
8252 seed=ToIdType(std::distance(fetchedCells.begin(),std::find(fetchedCells.begin()+seed,fetchedCells.end(),false)));
8254 for(std::vector< MCAuto<DataArrayIdType> >::iterator it=ret2.begin();it!=ret2.end();it++)
8255 ret.push_back((*it).retn());
8260 * This method returns given a distribution of cell type (returned for example by MEDCouplingUMesh::getDistributionOfTypes method and customized after) a
8261 * newly allocated DataArrayIdType instance with 2 components ready to be interpreted as input of DataArrayIdType::findRangeIdForEachTuple method.
8263 * \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.
8264 * \return a newly allocated DataArrayIdType to be managed by the caller.
8265 * \throw In case of \a code has not the right format (typically of size 3*n)
8267 DataArrayIdType *MEDCouplingUMesh::ComputeRangesFromTypeDistribution(const std::vector<mcIdType>& code)
8269 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
8270 std::size_t nb=code.size()/3;
8271 if(code.size()%3!=0)
8272 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeRangesFromTypeDistribution : invalid input code !");
8274 mcIdType *retPtr=ret->getPointer();
8275 for(std::size_t i=0;i<nb;i++,retPtr+=2)
8277 retPtr[0]=code[3*i+2];
8278 retPtr[1]=code[3*i+2]+code[3*i+1];
8284 * This method expects that \a this a 3D mesh (spaceDim=3 and meshDim=3) with all coordinates and connectivities set.
8285 * All cells in \a this are expected to be linear 3D cells.
8286 * This method will split **all** 3D cells in \a this into INTERP_KERNEL::NORM_TETRA4 cells and put them in the returned mesh.
8287 * It leads to an increase to number of cells.
8288 * This method contrary to MEDCouplingUMesh::simplexize can append coordinates in \a this to perform its work.
8289 * The \a nbOfAdditionalPoints returned value informs about it. If > 0, the coordinates array in returned mesh will have \a nbOfAdditionalPoints
8290 * more tuples (nodes) than in \a this. Anyway, all the nodes in \a this (with the same order) will be in the returned mesh.
8292 * \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.
8293 * For all other cells, the splitting policy will be ignored. See INTERP_KERNEL::SplittingPolicy for the images.
8294 * \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.
8295 * \param [out] n2oCells - A new instance of DataArrayIdType holding, for each new cell,
8296 * an id of old cell producing it. The caller is to delete this array using
8297 * decrRef() as it is no more needed.
8298 * \return MEDCoupling1SGTUMesh * - the mesh containing only INTERP_KERNEL::NORM_TETRA4 cells.
8300 * \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
8301 * the policy PLANAR_FACE_6 should be used on a mesh sorted with MEDCoupling1SGTUMesh::sortHexa8EachOther.
8303 * \throw If \a this is not a 3D mesh (spaceDim==3 and meshDim==3).
8304 * \throw If \a this is not fully constituted with linear 3D cells.
8305 * \sa MEDCouplingUMesh::simplexize, MEDCoupling1SGTUMesh::sortHexa8EachOther
8307 MEDCoupling1SGTUMesh *MEDCouplingUMesh::tetrahedrize(int policy, DataArrayIdType *& n2oCells, mcIdType& nbOfAdditionalPoints) const
8309 INTERP_KERNEL::SplittingPolicy pol((INTERP_KERNEL::SplittingPolicy)policy);
8310 checkConnectivityFullyDefined();
8311 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
8312 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tetrahedrize : only available for mesh with meshdim == 3 and spacedim == 3 !");
8313 mcIdType nbOfCells=getNumberOfCells();
8314 mcIdType nbNodes(getNumberOfNodes());
8315 MCAuto<MEDCoupling1SGTUMesh> ret0(MEDCoupling1SGTUMesh::New(getName(),INTERP_KERNEL::NORM_TETRA4));
8316 MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(nbOfCells,1);
8317 mcIdType *retPt(ret->getPointer());
8318 MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()); newConn->alloc(0,1);
8319 MCAuto<DataArrayDouble> addPts(DataArrayDouble::New()); addPts->alloc(0,1);
8320 const mcIdType *oldc(_nodal_connec->begin());
8321 const mcIdType *oldci(_nodal_connec_index->begin());
8322 const double *coords(_coords->begin());
8323 for(mcIdType i=0;i<nbOfCells;i++,oldci++,retPt++)
8325 std::vector<mcIdType> a; std::vector<double> b;
8326 INTERP_KERNEL::SplitIntoTetras(pol,(INTERP_KERNEL::NormalizedCellType)oldc[oldci[0]],oldc+oldci[0]+1,oldc+oldci[1],coords,a,b);
8327 std::size_t nbOfTet(a.size()/4); *retPt=ToIdType(nbOfTet);
8328 const mcIdType *aa(&a[0]);
8331 for(std::vector<mcIdType>::iterator it=a.begin();it!=a.end();it++)
8333 *it=(-(*(it))-1+nbNodes);
8334 addPts->insertAtTheEnd(b.begin(),b.end());
8335 nbNodes+=ToIdType(b.size()/3);
8337 for(std::size_t j=0;j<nbOfTet;j++,aa+=4)
8338 newConn->insertAtTheEnd(aa,aa+4);
8340 if(!addPts->empty())
8342 addPts->rearrange(3);
8343 nbOfAdditionalPoints=addPts->getNumberOfTuples();
8344 addPts=DataArrayDouble::Aggregate(getCoords(),addPts);
8345 ret0->setCoords(addPts);
8349 nbOfAdditionalPoints=0;
8350 ret0->setCoords(getCoords());
8352 ret0->setNodalConnectivity(newConn);
8354 ret->computeOffsetsFull();
8355 n2oCells=ret->buildExplicitArrOfSliceOnScaledArr(0,nbOfCells,1);
8359 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),
8360 _own_cell(true),_cell_id(-1),_nb_cell(0)
8365 _nb_cell=mesh->getNumberOfCells();
8369 MEDCouplingUMeshCellIterator::~MEDCouplingUMeshCellIterator()
8377 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh, MEDCouplingUMeshCell *itc, mcIdType bg, mcIdType end):_mesh(mesh),_cell(itc),
8378 _own_cell(false),_cell_id(bg-1),
8385 MEDCouplingUMeshCell *MEDCouplingUMeshCellIterator::nextt()
8388 if(_cell_id<_nb_cell)
8397 MEDCouplingUMeshCellByTypeEntry::MEDCouplingUMeshCellByTypeEntry(MEDCouplingUMesh *mesh):_mesh(mesh)
8403 MEDCouplingUMeshCellByTypeIterator *MEDCouplingUMeshCellByTypeEntry::iterator()
8405 return new MEDCouplingUMeshCellByTypeIterator(_mesh);
8408 MEDCouplingUMeshCellByTypeEntry::~MEDCouplingUMeshCellByTypeEntry()
8414 MEDCouplingUMeshCellEntry::MEDCouplingUMeshCellEntry(MEDCouplingUMesh *mesh, INTERP_KERNEL::NormalizedCellType type, MEDCouplingUMeshCell *itc, mcIdType bg, mcIdType end):_mesh(mesh),_type(type),
8422 MEDCouplingUMeshCellEntry::~MEDCouplingUMeshCellEntry()
8428 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCellEntry::getType() const
8433 mcIdType MEDCouplingUMeshCellEntry::getNumberOfElems() const
8438 MEDCouplingUMeshCellIterator *MEDCouplingUMeshCellEntry::iterator()
8440 return new MEDCouplingUMeshCellIterator(_mesh,_itc,_bg,_end);
8443 MEDCouplingUMeshCellByTypeIterator::MEDCouplingUMeshCellByTypeIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),_cell_id(0),_nb_cell(0)
8448 _nb_cell=mesh->getNumberOfCells();
8452 MEDCouplingUMeshCellByTypeIterator::~MEDCouplingUMeshCellByTypeIterator()
8459 MEDCouplingUMeshCellEntry *MEDCouplingUMeshCellByTypeIterator::nextt()
8461 const mcIdType *c=_mesh->getNodalConnectivity()->begin();
8462 const mcIdType *ci=_mesh->getNodalConnectivityIndex()->begin();
8463 if(_cell_id<_nb_cell)
8465 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[_cell_id]];
8466 mcIdType nbOfElems=ToIdType(std::distance(ci+_cell_id,std::find_if(ci+_cell_id,ci+_nb_cell,MEDCouplingImpl::ConnReader(c,type))));
8467 mcIdType startId=_cell_id;
8468 _cell_id+=nbOfElems;
8469 return new MEDCouplingUMeshCellEntry(_mesh,type,_cell,startId,_cell_id);
8475 MEDCouplingUMeshCell::MEDCouplingUMeshCell(MEDCouplingUMesh *mesh):_conn(0),_conn_indx(0),_conn_lgth(NOTICABLE_FIRST_VAL)
8479 _conn=mesh->getNodalConnectivity()->getPointer();
8480 _conn_indx=mesh->getNodalConnectivityIndex()->getPointer();
8484 void MEDCouplingUMeshCell::next()
8486 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8491 _conn_lgth=_conn_indx[1]-_conn_indx[0];
8494 std::string MEDCouplingUMeshCell::repr() const
8496 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8498 std::ostringstream oss; oss << "Cell Type " << INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)_conn[0]).getRepr();
8500 std::copy(_conn+1,_conn+_conn_lgth,std::ostream_iterator<mcIdType>(oss," "));
8504 return std::string("MEDCouplingUMeshCell::repr : Invalid pos");
8507 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCell::getType() const
8509 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8510 return (INTERP_KERNEL::NormalizedCellType)_conn[0];
8512 return INTERP_KERNEL::NORM_ERROR;
8515 const mcIdType *MEDCouplingUMeshCell::getAllConn(mcIdType& lgth) const
8518 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8526 namespace MEDCouplingImpl
8528 const mcIdType theUndefID = std::numeric_limits< mcIdType >::max(); //!< undefined cell id
8530 //================================================================================
8532 * \brief Encode a cell id and a mesh index into a code
8533 * \param [in] id - cell id
8534 * \param [in] iMesh - mesh index [0,1]
8535 * \return mcIdType - code
8537 //================================================================================
8539 mcIdType encodeID( mcIdType id, int iMesh )
8541 return ( id + 1 ) * ( iMesh ? -1 : 1 );
8543 //================================================================================
8545 * \brief Return cell id and mesh index by a given id
8546 * \param [in] id - code of a cell in a mesh
8547 * \param [out] iMesh - returned mesh index
8548 * \return mcIdType - cell id
8550 //================================================================================
8552 mcIdType decodeID( mcIdType id, int& iMesh )
8555 return std::abs( id ) - 1;
8558 //================================================================================
8560 * \brief return another face sharing two given nodes of a face edge
8561 * \param [in] n0 - 1st node of the edge
8562 * \param [in] n1 - 2nd node of the edge
8563 * \param [in] inputFaceID - face including \a n0 andf \a n2
8564 * \param [in] mesh - object and reference meshes
8565 * \param [in] revNodal - reverse nodal connectivity of the two meshes
8566 * \param [in] revNodalIndx - index of reverse nodal connectivity of the two meshes
8567 * \param [out] facesByEdge - return another face including \a n0 andf \a n2
8568 * \param [out] equalFaces - return faces equal to facesByEdge
8570 //================================================================================
8572 void getFacesOfEdge( mcIdType n0,
8574 mcIdType inputFaceID,
8575 MEDCouplingUMesh* mesh[],
8576 MCAuto<DataArrayIdType> revNodal[],
8577 MCAuto<DataArrayIdType> revNodalIndx[],
8578 std::vector< mcIdType >& facesByEdge,
8579 std::vector< mcIdType >& equalFaces)
8581 // find faces sharing the both nodes of edge
8583 facesByEdge.clear();
8584 size_t prevNbF; // nb faces found in 0-th mesh
8585 for ( int iM = 0; iM < 2; ++iM )
8587 const mcIdType * revInd = revNodalIndx[ iM ]->begin();
8588 const mcIdType * rev = revNodal [ iM ]->begin();
8590 mcIdType nbRevFaces0 = revInd[ n0 + 1 ] - revInd[ n0 ];
8591 mcIdType nbRevFaces1 = revInd[ n1 + 1 ] - revInd[ n1 ];
8593 prevNbF = facesByEdge.size();
8594 facesByEdge.resize( prevNbF + std::max( nbRevFaces0, nbRevFaces1 ));
8596 auto it = std::set_intersection( rev + revInd[ n0 ],
8597 rev + revInd[ n0 ] + nbRevFaces0,
8599 rev + revInd[ n1 ] + nbRevFaces1,
8600 facesByEdge.begin() + prevNbF );
8601 facesByEdge.resize( it - facesByEdge.begin() );
8604 // facesByEdge now contains at least the 'inputFaceID'
8605 // check if there are other faces
8607 size_t nbF = facesByEdge.size();
8610 if ( prevNbF > 0 && prevNbF < nbF ) // faces found in both meshes
8612 // remove from facesByEdge equal faces in different meshes
8613 const mcIdType *conn [2] = { mesh[0]->getNodalConnectivity()->getConstPointer(),
8614 mesh[1]->getNodalConnectivity()->getConstPointer() };
8615 const mcIdType *connI[2] = { mesh[0]->getNodalConnectivityIndex()->getConstPointer(),
8616 mesh[1]->getNodalConnectivityIndex()->getConstPointer() };
8617 for ( size_t i0 = 0; i0 < prevNbF; ++i0 )
8619 if ( facesByEdge[ i0 ] == theUndefID )
8621 mcIdType objFaceID = MEDCouplingImpl::encodeID( facesByEdge[ i0 ], 0 );
8622 bool isInputFace = ( objFaceID == inputFaceID );
8624 for ( size_t i1 = prevNbF; i1 < facesByEdge.size(); ++i1 )
8626 if ( facesByEdge[ i1 ] == theUndefID )
8629 mcIdType f0 = facesByEdge[ i0 ];
8630 mcIdType f1 = facesByEdge[ i1 ];
8631 size_t nbNodes0 = connI[0][ f0 + 1 ] - connI[0][ f0 ] - 1;
8632 size_t nbNodes1 = connI[1][ f1 + 1 ] - connI[1][ f1 ] - 1;
8633 if ( nbNodes0 != nbNodes1 )
8636 const mcIdType * fConn0 = conn[0] + connI[0][ f0 ] + 1;
8637 const mcIdType * fConn1 = conn[1] + connI[1][ f1 ] + 1;
8638 if ( std::equal( fConn0, fConn0 + nbNodes0, fConn1 ))
8640 // equal faces; remove an object one
8641 mcIdType refFaceID = MEDCouplingImpl::encodeID( facesByEdge[ i1 ], 1 );
8642 if ( refFaceID == inputFaceID )
8645 if ( std::find( equalFaces.begin(),
8646 equalFaces.end(), objFaceID ) == equalFaces.end() )
8647 equalFaces.push_back( objFaceID );
8649 facesByEdge[ i0 ] = theUndefID;
8651 facesByEdge[ i1 ] = theUndefID;
8656 facesByEdge[ i0 ] = theUndefID;
8661 nbF = facesByEdge.size();
8662 for ( size_t i = 0; i < facesByEdge.size(); ++i )
8664 if ( facesByEdge[ i ] != theUndefID )
8666 facesByEdge[ i ] = MEDCouplingImpl::encodeID( facesByEdge[ i ], i >= prevNbF );
8667 if ( facesByEdge[ i ] == inputFaceID )
8668 facesByEdge[ i ] = theUndefID;
8670 nbF -= ( facesByEdge[ i ] == theUndefID );
8674 return; // non-manifold
8678 facesByEdge.clear();
8680 else // nbF == 1, set a found face first
8682 if ( facesByEdge[ 0 ] == theUndefID )
8684 for ( size_t i = 1; i < facesByEdge.size(); ++i )
8685 if ( facesByEdge[ i ] != theUndefID )
8687 facesByEdge[ 0 ] = facesByEdge[ i ];
8691 facesByEdge.resize( 1 );
8696 //================================================================================
8698 * \brief Remove a face from nodal reversed connectivity
8699 * \param [in] node - a node of the face
8700 * \param [in] face - the face
8701 * \param [in.out] revNodal - reverse nodal connectivity
8702 * \param [in,out] revNodalIndx - reverse nodal connectivity index
8704 //================================================================================
8706 void removeFromRevNodal( mcIdType node,
8708 MCAuto<DataArrayIdType>& revNodal,
8709 MCAuto<DataArrayIdType>& revNodalIndx)
8711 mcIdType* fBeg = revNodal->getPointer() + revNodalIndx->getIJ( node, 0 );
8712 mcIdType* fEnd = revNodal->getPointer() + revNodalIndx->getIJ( node + 1, 0);
8713 auto it = std::find( fBeg, fEnd, face );
8716 for ( auto it2 = it + 1; it2 < fEnd; ++it2 ) // keep faces sorted
8717 *( it2 - 1 ) = *it2;
8719 *( fEnd - 1 ) = theUndefID;
8723 //================================================================================
8725 * \brief Check order of two nodes in a given face
8726 * \param [inout] n0 - node 1
8727 * \param [inout] n1 - node 2
8728 * \param [inout] iFEnc - face
8729 * \param [inout] mesh - mesh
8730 * \return bool - true if the nodes are in [ .., n1, n0, ..] order in face
8732 //================================================================================
8734 bool isReverseOrder( mcIdType n0,
8737 MEDCouplingUMesh* mesh[] )
8740 mcIdType iF = decodeID( iFEnc, iMesh );
8742 const mcIdType *conn = mesh[ iMesh ]->getNodalConnectivity()->getConstPointer();
8743 const mcIdType *connI = mesh[ iMesh ]->getNodalConnectivityIndex()->getConstPointer();
8745 auto it0 = std::find( conn + connI[ iF ] + 1,
8746 conn + connI[ iF + 1 ],
8748 auto it1 = std::find( conn + connI[ iF ] + 1,
8749 conn + connI[ iF + 1 ],
8751 long i0 = it0 - conn;
8752 long i1 = it1 - conn;
8754 bool isRev = ( std::abs( i1 - i0 ) == 1 ) ? i1 < i0 : i0 < i1;
8758 //================================================================================
8760 * \brief Change orientation of a face in one of given meshes
8761 * \param [in] iFEnc - face ID also encoding a mesh index
8762 * \param [in,out] mesh - object and reference meshes
8764 //================================================================================
8766 void reverseFace( mcIdType iFEnc, MEDCouplingUMesh* mesh[] )
8769 mcIdType face = decodeID( iFEnc, iMesh );
8771 mcIdType *conn = mesh[ iMesh ]->getNodalConnectivity()->getPointer();
8772 mcIdType *connI = mesh[ iMesh ]->getNodalConnectivityIndex()->getPointer();
8774 const INTERP_KERNEL::CellModel& cm =
8775 INTERP_KERNEL::CellModel::GetCellModel( mesh[iMesh]->getTypeOfCell( face ));
8777 cm.changeOrientationOf2D( conn + connI[ face ] + 1,
8778 (unsigned int)( connI[ face + 1 ] - connI[ face ] - 1 ));
8785 //================================================================================
8787 * \brief Orient cells of \a this 2D mesh equally to \a refFaces
8788 * \param [in] refFaces - 2D mesh containing correctly oriented faces. It is optional.
8789 * If there are no cells in \a refFaces or it is nullptr, then any face
8790 * in \a this mesh is used as a reference
8791 * \throw If \a this mesh is not well defined.
8792 * \throw If \a this mesh or \refFaces are not 2D.
8793 * \throw If \a this mesh and \refFaces do not share nodes.
8794 * \throw If \a refFaces are not equally oriented.
8795 * \throw If \a this mesh plus \a refFaces together form a non-manifold mesh.
8797 * \if ENABLE_EXAMPLES
8798 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
8799 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
8802 //================================================================================
8804 void MEDCouplingUMesh::orientCorrectly2DCells(const MEDCouplingUMesh* refFaces)
8806 checkConsistencyLight();
8807 if ( getMeshDimension() != 2 )
8808 throw INTERP_KERNEL::Exception("The mesh dimension must be 2");
8811 refFaces->checkConsistencyLight();
8812 if ( refFaces->getMeshDimension() != 2 )
8813 throw INTERP_KERNEL::Exception("The reference mesh dimension must be 2");
8814 if ( getCoords() != refFaces->getCoords() )
8815 throw INTERP_KERNEL::Exception("Object and reference meshes must share nodes ");
8816 if ( refFaces->getNumberOfCells() == 0 )
8819 if ( getNumberOfCells() == 0 )
8822 enum { _OBJ, _REF };
8823 MEDCouplingUMesh* mesh[2] = { this, const_cast< MEDCouplingUMesh* >( refFaces ) };
8824 MCAuto<MEDCouplingUMesh> meshPtr;
8827 meshPtr = mesh[_REF] = MEDCouplingUMesh::New();
8828 mesh[_REF]->setCoords( mesh[_OBJ]->getCoords() );
8829 mesh[_REF]->allocateCells(0);
8830 mesh[_REF]->finishInsertingCells();
8832 mcIdType nbFacesToCheck[2] = { mesh[_OBJ]->getNumberOfCells(),
8833 mesh[_REF]->getNumberOfCells() };
8834 std::vector< bool > isFaceQueued[ 2 ]; // enqueued faces of 2 meshes
8835 isFaceQueued[_OBJ].resize( nbFacesToCheck[_OBJ] );
8836 isFaceQueued[_REF].resize( nbFacesToCheck[_REF] );
8838 MCAuto<DataArrayIdType> revNodal [2] = { DataArrayIdType::New(), DataArrayIdType::New() };
8839 MCAuto<DataArrayIdType> revNodalIndx[2] = { DataArrayIdType::New(), DataArrayIdType::New() };
8840 mesh[_OBJ]->getReverseNodalConnectivity( revNodal[_OBJ], revNodalIndx[_OBJ] );
8841 mesh[_REF]->getReverseNodalConnectivity( revNodal[_REF], revNodalIndx[_REF] );
8843 std::vector< mcIdType > faceNodes(4);
8844 std::vector< mcIdType > facesByEdge(4), equalFaces;
8845 std::vector< mcIdType > faceQueue; // starting faces with IDs counted from 1; negative ID mean a face in ref mesh
8847 while ( nbFacesToCheck[_OBJ] + nbFacesToCheck[_REF] > 0 ) // until all faces checked
8849 if ( faceQueue.empty() ) // all neighbors checked, find more faces to check
8851 for ( int iMesh = 1; iMesh >= 0; --iMesh ) // on [ _REF, _OBJ ]
8852 if ( nbFacesToCheck[iMesh] > 0 )
8853 for ( mcIdType f = 0, nbF = mesh[iMesh]->getNumberOfCells(); f < nbF; ++f )
8854 if ( !isFaceQueued[iMesh][f] )
8856 faceQueue.push_back( MEDCouplingImpl::encodeID( f, iMesh ));
8857 isFaceQueued[ iMesh ][ f ] = true;
8861 if ( faceQueue.empty() )
8865 mcIdType fID = faceQueue.back();
8866 faceQueue.pop_back();
8869 mcIdType refFace = MEDCouplingImpl::decodeID( fID, iMesh );
8871 nbFacesToCheck[iMesh]--;
8875 mesh[iMesh]->getNodeIdsOfCell( refFace, faceNodes );
8876 const INTERP_KERNEL::CellModel& cm = INTERP_KERNEL::CellModel::GetCellModel( mesh[iMesh]->getTypeOfCell( refFace ));
8877 const int nbEdges = cm.getNumberOfSons();
8879 // loop on edges of the refFace
8880 mcIdType n0 = faceNodes[ nbEdges - 1 ]; // 1st node of edge
8881 for ( int edge = 0; edge < nbEdges; ++edge )
8883 mcIdType n1 = faceNodes[ edge ]; // 2nd node of edge
8885 // get faces sharing the edge
8886 MEDCouplingImpl::getFacesOfEdge( n0, n1, fID, mesh, revNodal, revNodalIndx,
8887 facesByEdge, equalFaces );
8889 if ( facesByEdge.size() > 1 )
8890 THROW_IK_EXCEPTION("Non-manifold mesh at edge " << n0+1 << " - " << n1+1);
8892 if ( facesByEdge.size() == 1 )
8894 // compare orientation of two faces
8896 if ( !MEDCouplingImpl::isReverseOrder( n0, n1, facesByEdge[0], mesh ))
8898 if ( facesByEdge[0] < 0 ) // in the ref mesh
8899 throw INTERP_KERNEL::Exception("Different orientation of reference faces");
8901 MEDCouplingImpl::reverseFace( facesByEdge[0], mesh );
8903 mcIdType face2 = MEDCouplingImpl::decodeID( facesByEdge[0], iMesh2 );
8904 if ( !isFaceQueued[iMesh2][face2] )
8906 isFaceQueued[iMesh2][face2] = true;
8907 faceQueue.push_back( facesByEdge[0] );
8913 // remove face and equalFaces from revNodal in order not to treat them again
8914 equalFaces.push_back( fID );
8915 for ( mcIdType face : equalFaces )
8917 mcIdType f = MEDCouplingImpl::decodeID( face, iMesh2 );
8918 const mcIdType *conn = mesh[iMesh2]->getNodalConnectivity()->getConstPointer();
8919 const mcIdType *connI = mesh[iMesh2]->getNodalConnectivityIndex()->getConstPointer();
8920 mcIdType nbNodes = connI[ f + 1 ] - connI[ f ] - 1;
8921 for ( const mcIdType* n = conn + connI[ f ] + 1, *nEnd = n + nbNodes; n < nEnd; ++n )
8923 MEDCouplingImpl::removeFromRevNodal( *n, f, // not to treat f again
8924 revNodal[ iMesh2 ], revNodalIndx[ iMesh2 ] );
8927 } // while() until all faces checked