1 // Copyright (C) 2007-2023 CEA, EDF
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 * This method is a generalization of buildDescendingConnectivity method. This method return mesh containing subcells of this at level specified by \a targetDeltaLevel
702 * and return descending and reverse descending correspondances to this.
704 * \param [in] targetDeltaLevel target delta level compared to \a this mesh dimension. This parameter is expected to be lower than zero.
706 * \throw If targetDeltaLevel is greater or equal to zero
707 * \throw If targetDeltaLevel is lower than -meshDim
708 * \sa MEDCouplingUMesh::buildDescendingConnectivity, MEDCouplingUMesh::explode3DMeshTo1D
710 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::explodeMeshTo(int targetDeltaLevel, MCAuto<DataArrayIdType>& desc, MCAuto<DataArrayIdType>& descIndx, MCAuto<DataArrayIdType>& revDesc, MCAuto<DataArrayIdType>& revDescIndx) const
712 this->checkConsistencyLight();
713 if( targetDeltaLevel >= 0 )
714 THROW_IK_EXCEPTION("Input parameter targetDeltaLevel is expected to be lower than zero !");
715 if( targetDeltaLevel == -1 )
717 desc = DataArrayIdType::New(); descIndx = DataArrayIdType::New(); revDesc = DataArrayIdType::New(); revDescIndx = DataArrayIdType::New();
718 MCAuto<MEDCouplingUMesh> ret( this->buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx) );
721 if( targetDeltaLevel == -2 && this->getMeshDimension() == 3 )
723 desc = DataArrayIdType::New(); descIndx = DataArrayIdType::New(); revDesc = DataArrayIdType::New(); revDescIndx = DataArrayIdType::New();
724 MCAuto<MEDCouplingUMesh> ret( this->explode3DMeshTo1D(desc,descIndx,revDesc,revDescIndx) );
727 if( targetDeltaLevel == -this->getMeshDimension() )
729 MCAuto<MEDCouplingUMesh> ret = MEDCouplingUMesh::Build0DMeshFromCoords( const_cast<DataArrayDouble *>( this->getCoords() ) );
730 MEDCouplingUMesh::DeleteCellTypeInIndexedArray(getNodalConnectivity(),getNodalConnectivityIndex(),desc,descIndx);
731 revDesc = DataArrayIdType::New(); revDescIndx = DataArrayIdType::New();
732 this->getReverseNodalConnectivity(revDesc,revDescIndx);
735 THROW_IK_EXCEPTION("Not valid input targetDeltaLevel regarding mesh dimension");
739 * \a this has to have a mesh dimension equal to 3. If it is not the case an INTERP_KERNEL::Exception will be thrown.
740 * This behaves exactly as MEDCouplingUMesh::buildDescendingConnectivity does except that this method compute directly the transition from mesh dimension 3 to sub edges (dimension 1)
741 * in one shot. That is to say that this method is equivalent to 2 successive calls to MEDCouplingUMesh::buildDescendingConnectivity.
742 * This method returns 4 arrays and a mesh as MEDCouplingUMesh::buildDescendingConnectivity does.
743 * \sa MEDCouplingUMesh::buildDescendingConnectivity
745 MEDCouplingUMesh *MEDCouplingUMesh::explode3DMeshTo1D(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
748 if(getMeshDimension()!=3)
749 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explode3DMeshTo1D : This has to have a mesh dimension to 3 !");
750 return buildDescendingConnectivityGen<MinusTwoSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
754 * 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.
755 * This method works for both meshes with mesh dimension equal to 2 or 3. Dynamical cells are not supported (polygons, polyhedrons...)
757 * \sa explode3DMeshTo1D, buildDescendingConnectiviy
759 MEDCouplingUMesh *MEDCouplingUMesh::explodeMeshIntoMicroEdges(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
762 switch(getMeshDimension())
765 return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
767 return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
769 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explodeMeshIntoMicroEdges : Only 2D and 3D supported !");
774 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
775 * this->getMeshDimension(), that bound cells of \a this mesh. In
776 * addition arrays describing correspondence between cells of \a this and the result
777 * meshes are returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending
778 * connectivity, i.e. enumerate cells of the result mesh bounding each cell of \a this
779 * mesh. This method differs from buildDescendingConnectivity() in that apart
780 * from cell ids, \a desc returns mutual orientation of cells in \a this and the
781 * result meshes. So a positive id means that order of nodes in corresponding cells
782 * of two meshes is same, and a negative id means a reverse order of nodes. Since a
783 * cell with id #0 can't be negative, the array \a desc returns ids in FORTRAN mode,
784 * i.e. cell ids are one-based.
785 * Arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
786 * i.e. enumerate cells of \a this mesh bounded by each cell of the result mesh.
787 * \warning For speed reasons, this method does not check if node ids in the nodal
788 * connectivity correspond to the size of node coordinates array.
789 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
790 * to write this mesh to the MED file, its cells must be sorted using
791 * sortCellsInMEDFileFrmt().
792 * \param [in,out] desc - the array containing cell ids of the result mesh bounding
793 * each cell of \a this mesh.
794 * \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
795 * dividing cell ids in \a desc into groups each referring to one
796 * cell of \a this mesh. Its every element (except the last one) is an index
797 * pointing to the first id of a group of cells. For example cells of the
798 * result mesh bounding the cell #1 of \a this mesh are described by following
800 * [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
801 * \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
802 * Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
803 * \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
804 * \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
805 * by each cell of the result mesh.
806 * \param [in,out] revDescIndx - the array, of length one more than number of cells
807 * in the result mesh,
808 * dividing cell ids in \a revDesc into groups each referring to one
809 * cell of the result mesh the same way as \a descIndx divides \a desc.
810 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This result mesh
811 * shares the node coordinates array with \a this mesh. The caller is to
812 * delete this mesh using decrRef() as it is no more needed.
813 * \throw If the coordinates array is not set.
814 * \throw If the nodal connectivity of cells is node defined.
815 * \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
816 * revDescIndx == NULL.
818 * \if ENABLE_EXAMPLES
819 * \ref cpp_mcumesh_buildDescendingConnectivity2 "Here is a C++ example".<br>
820 * \ref py_mcumesh_buildDescendingConnectivity2 "Here is a Python example".
822 * \sa buildDescendingConnectivity()
824 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity2(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
826 return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingOrientationSensitiveNbrer);
830 * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
831 * For speed reasons no check of this will be done. This method calls
832 * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
833 * This method lists for every cell in \b this its neighbor \b cells. To compute the result
834 * only connectivities are considered.
835 * The neighbor cells of a given cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
836 * The format of return is hence \ref numbering-indirect.
838 * \param [out] neighbors is an array storing all the neighbors of all cells in \b this. This array is newly
839 * allocated and should be dealt by the caller. \b neighborsIndx 2nd output
840 * parameter allows to select the right part in this array (\ref numbering-indirect). The number of tuples
841 * is equal to the last values in \b neighborsIndx.
842 * \param [out] neighborsIndx is an array of size this->getNumberOfCells()+1 newly allocated and should be
843 * dealt by the caller. This arrays allow to use the first output parameter \b neighbors (\ref numbering-indirect).
845 void MEDCouplingUMesh::computeNeighborsOfCells(DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIndx) const
847 MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
848 MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
849 MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
850 MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
851 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
853 ComputeNeighborsOfCellsAdv(desc,descIndx,revDesc,revDescIndx,neighbors,neighborsIndx);
857 * Given a set of identifiers indexed by the node IDs of the mesh (and given in the (\ref numbering-indirect format) ,
858 * 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
859 * of the mesh (e.g. a triangular element will receive the information from its three vertices).
860 * Doublons are eliminated. If present in the inital dataset, the ID of the cell itself is also remooved.
862 * \param [in] nodeNeigh a set of identifiers (mcIdType) stored by node index (\ref numbering-indirect format)
863 * \param [in] nodeNeighI a set of identifiers (mcIdType) stored by node index (\ref numbering-indirect format)
864 * \param [out] cellNeigh This array is newly allocated and should be dealt by the caller. It contains the initial identifiers
865 * provided in the input parameters but stored now by cell index (See 2nd output parameter and \ref numbering-indirect).
866 * \param [out] cellNeighI is an array of size this->getNumberOfCells()+1 newly allocated and should be
867 * dealt by the caller. This arrays allow to use the first output parameter \b neighbors (\ref numbering-indirect).
869 * \raise if the number of tuples in nodeNeighI is not equal to the number of nodes in the mesh.
871 void MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne(const DataArrayIdType *nodeNeigh, const DataArrayIdType *nodeNeighI,
872 MCAuto<DataArrayIdType>& cellNeigh, MCAuto<DataArrayIdType>& cellNeighIndex) const
874 if(!nodeNeigh || !nodeNeighI)
875 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : null pointer !");
876 checkConsistencyLight();
877 nodeNeigh->checkAllocated(); nodeNeighI->checkAllocated();
878 nodeNeigh->checkNbOfComps(1,"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : node neigh");
879 nodeNeighI->checkNbOfComps(1,"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : node neigh index");
880 nodeNeighI->checkNbOfTuples(1+getNumberOfNodes(),"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : invalid length");
881 mcIdType nbCells=getNumberOfCells();
882 const mcIdType *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin()),*ne(nodeNeigh->begin()),*nei(nodeNeighI->begin());
883 cellNeigh=DataArrayIdType::New(); cellNeigh->alloc(0,1); cellNeighIndex=DataArrayIdType::New(); cellNeighIndex->alloc(1,1); cellNeighIndex->setIJ(0,0,0);
884 for(mcIdType i=0;i<nbCells;i++)
886 std::set<mcIdType> s;
887 for(const mcIdType *it=c+ci[i]+1;it!=c+ci[i+1];it++)
888 if(*it>=0) // avoid -1 in polygons or polyedrons
889 s.insert(ne+nei[*it],ne+nei[*it+1]);
891 cellNeigh->insertAtTheEnd(s.begin(),s.end());
892 cellNeighIndex->pushBackSilent(cellNeigh->getNumberOfTuples());
897 * This method is called by MEDCouplingUMesh::computeNeighborsOfCells. This methods performs the algorithm
898 * of MEDCouplingUMesh::computeNeighborsOfCells.
899 * This method is useful for users that want to reduce along a criterion the set of neighbours cell. This is
900 * typically the case to extract a set a neighbours,
901 * excluding a set of meshdim-1 cells in input descending connectivity.
902 * Typically \b desc, \b descIndx, \b revDesc and \b revDescIndx (\ref numbering-indirect) input params are
903 * the result of MEDCouplingUMesh::buildDescendingConnectivity.
904 * This method lists cell by cell in \b this which are its neighbors. To compute the result only connectivities
906 * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
908 * \param [in] desc descending connectivity array.
909 * \param [in] descIndx descending connectivity index array used to walk through \b desc (\ref numbering-indirect).
910 * \param [in] revDesc reverse descending connectivity array.
911 * \param [in] revDescIndx reverse descending connectivity index array used to walk through \b revDesc (\ref numbering-indirect).
912 * \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
913 * parameter allows to select the right part in this array. The number of tuples is equal to the last values in \b neighborsIndx.
914 * \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.
916 void MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(const DataArrayIdType *desc, const DataArrayIdType *descIndx, const DataArrayIdType *revDesc, const DataArrayIdType *revDescIndx,
917 DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIndx)
919 if(!desc || !descIndx || !revDesc || !revDescIndx)
920 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeNeighborsOfCellsAdv some input array is empty !");
921 const mcIdType *descPtr=desc->begin();
922 const mcIdType *descIPtr=descIndx->begin();
923 const mcIdType *revDescPtr=revDesc->begin();
924 const mcIdType *revDescIPtr=revDescIndx->begin();
926 mcIdType nbCells=descIndx->getNumberOfTuples()-1;
927 MCAuto<DataArrayIdType> out0=DataArrayIdType::New();
928 MCAuto<DataArrayIdType> out1=DataArrayIdType::New(); out1->alloc(nbCells+1,1);
929 mcIdType *out1Ptr=out1->getPointer();
931 out0->reserve(desc->getNumberOfTuples());
932 for(mcIdType i=0;i<nbCells;i++,descIPtr++,out1Ptr++)
934 for(const mcIdType *w1=descPtr+descIPtr[0];w1!=descPtr+descIPtr[1];w1++)
936 std::set<mcIdType> s(revDescPtr+revDescIPtr[*w1],revDescPtr+revDescIPtr[(*w1)+1]);
938 out0->insertAtTheEnd(s.begin(),s.end());
940 *out1Ptr=out0->getNumberOfTuples();
942 neighbors=out0.retn();
943 neighborsIndx=out1.retn();
947 * Explodes \a this into edges whatever its dimension.
949 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::explodeIntoEdges(MCAuto<DataArrayIdType>& desc, MCAuto<DataArrayIdType>& descIndex, MCAuto<DataArrayIdType>& revDesc, MCAuto<DataArrayIdType>& revDescIndx) const
952 int mdim(getMeshDimension());
953 desc=DataArrayIdType::New(); descIndex=DataArrayIdType::New(); revDesc=DataArrayIdType::New(); revDescIndx=DataArrayIdType::New();
954 MCAuto<MEDCouplingUMesh> mesh1D;
959 mesh1D=explode3DMeshTo1D(desc,descIndex,revDesc,revDescIndx);
964 mesh1D=buildDescendingConnectivity(desc,descIndex,revDesc,revDescIndx);
969 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2] !");
976 * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
977 * For speed reasons no check of this will be done. This method calls
978 * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
979 * This method lists for every node in \b this its neighbor \b nodes. To compute the result
980 * only connectivities are considered.
981 * The neighbor nodes of node having id 'nodeId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
983 * \param [out] neighbors is an array storing all the neighbors of all nodes in \b this. This array
984 * is newly allocated and should be dealt by the caller. \b neighborsIndx 2nd output
985 * parameter allows to select the right part in this array (\ref numbering-indirect).
986 * The number of tuples is equal to the last values in \b neighborsIndx.
987 * \param [out] neighborsIdx is an array of size this->getNumberOfCells()+1 newly allocated and should
988 * be dealt by the caller. This arrays allow to use the first output parameter \b neighbors.
990 * \sa MEDCouplingUMesh::computeEnlargedNeighborsOfNodes
992 void MEDCouplingUMesh::computeNeighborsOfNodes(DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIdx) const
995 mcIdType mdim(getMeshDimension()),nbNodes(getNumberOfNodes());
996 MCAuto<DataArrayIdType> desc(DataArrayIdType::New()),descIndx(DataArrayIdType::New()),revDesc(DataArrayIdType::New()),revDescIndx(DataArrayIdType::New());
997 MCConstAuto<MEDCouplingUMesh> mesh1D;
1002 mesh1D=explode3DMeshTo1D(desc,descIndx,revDesc,revDescIndx);
1007 mesh1D=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
1012 mesh1D.takeRef(this);
1017 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2,1] !");
1020 desc=DataArrayIdType::New(); descIndx=DataArrayIdType::New(); revDesc=0; revDescIndx=0;
1021 mesh1D->getReverseNodalConnectivity(desc,descIndx);
1022 MCAuto<DataArrayIdType> ret0(DataArrayIdType::New());
1023 ret0->alloc(desc->getNumberOfTuples(),1);
1024 mcIdType *r0Pt(ret0->getPointer());
1025 const mcIdType *c1DPtr(mesh1D->getNodalConnectivity()->begin()),*rn(desc->begin()),*rni(descIndx->begin());
1026 for(mcIdType i=0;i<nbNodes;i++,rni++)
1028 for(const mcIdType *oneDCellIt=rn+rni[0];oneDCellIt!=rn+rni[1];oneDCellIt++)
1029 *r0Pt++=c1DPtr[3*(*oneDCellIt)+1]==i?c1DPtr[3*(*oneDCellIt)+2]:c1DPtr[3*(*oneDCellIt)+1];
1031 neighbors=ret0.retn();
1032 neighborsIdx=descIndx.retn();
1036 * 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.
1037 * 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.
1038 * This method is useful to find ghost cells of a part of a mesh with a code based on fields on nodes.
1040 * \sa MEDCouplingUMesh::computeNeighborsOfNodes
1042 void MEDCouplingUMesh::computeEnlargedNeighborsOfNodes(MCAuto<DataArrayIdType> &neighbors, MCAuto<DataArrayIdType>& neighborsIdx) const
1044 checkFullyDefined();
1045 mcIdType nbOfNodes(getNumberOfNodes());
1046 const mcIdType *conn(_nodal_connec->begin()),*connIndex(_nodal_connec_index->begin());
1047 mcIdType nbOfCells=getNumberOfCells();
1048 std::vector< std::set<mcIdType> > st0(nbOfNodes);
1049 for(mcIdType eltId=0;eltId<nbOfCells;eltId++)
1051 const mcIdType *strtNdlConnOfCurCell(conn+connIndex[eltId]+1),*endNdlConnOfCurCell(conn+connIndex[eltId+1]);
1052 std::set<mcIdType> s(strtNdlConnOfCurCell,endNdlConnOfCurCell); s.erase(-1); //for polyhedrons
1053 for(std::set<mcIdType>::const_iterator iter2=s.begin();iter2!=s.end();iter2++)
1054 st0[*iter2].insert(s.begin(),s.end());
1056 neighborsIdx=DataArrayIdType::New(); neighborsIdx->alloc(nbOfNodes+1,1); neighborsIdx->setIJ(0,0,0);
1058 mcIdType *neighIdx(neighborsIdx->getPointer());
1059 for(std::vector< std::set<mcIdType> >::const_iterator it=st0.begin();it!=st0.end();it++,neighIdx++)
1062 neighIdx[1]=neighIdx[0];
1064 neighIdx[1]=neighIdx[0]+ToIdType((*it).size())-1;
1067 neighbors=DataArrayIdType::New(); neighbors->alloc(neighborsIdx->back(),1);
1069 const mcIdType *neighIdx(neighborsIdx->begin());
1070 mcIdType *neigh(neighbors->getPointer()),nodeId(0);
1071 for(std::vector< std::set<mcIdType> >::const_iterator it=st0.begin();it!=st0.end();it++,neighIdx++,nodeId++)
1073 std::set<mcIdType> s(*it); s.erase(nodeId);
1074 std::copy(s.begin(),s.end(),neigh+*neighIdx);
1080 * Converts specified cells to either polygons (if \a this is a 2D mesh) or
1081 * polyhedrons (if \a this is a 3D mesh). The cells to convert are specified by an
1082 * array of cell ids. Pay attention that after conversion all algorithms work slower
1083 * with \a this mesh than before conversion. <br> If an exception is thrown during the
1084 * conversion due presence of invalid ids in the array of cells to convert, as a
1085 * result \a this mesh contains some already converted elements. In this case the 2D
1086 * mesh remains valid but 3D mesh becomes \b inconsistent!
1087 * \warning This method can significantly modify the order of geometric types in \a this,
1088 * hence, to write this mesh to the MED file, its cells must be sorted using
1089 * sortCellsInMEDFileFrmt().
1090 * \param [in] cellIdsToConvertBg - the array holding ids of cells to convert.
1091 * \param [in] cellIdsToConvertEnd - a pointer to the last-plus-one-th element of \a
1092 * cellIdsToConvertBg.
1093 * \throw If the coordinates array is not set.
1094 * \throw If the nodal connectivity of cells is node defined.
1095 * \throw If dimension of \a this mesh is not either 2 or 3.
1097 * \if ENABLE_EXAMPLES
1098 * \ref cpp_mcumesh_convertToPolyTypes "Here is a C++ example".<br>
1099 * \ref py_mcumesh_convertToPolyTypes "Here is a Python example".
1102 void MEDCouplingUMesh::convertToPolyTypes(const mcIdType *cellIdsToConvertBg, const mcIdType *cellIdsToConvertEnd)
1104 checkFullyDefined();
1105 int dim=getMeshDimension();
1107 throw INTERP_KERNEL::Exception("Invalid mesh dimension : must be 2 or 3 !");
1108 mcIdType nbOfCells=getNumberOfCells();
1111 const mcIdType *connIndex=_nodal_connec_index->begin();
1112 mcIdType *conn=_nodal_connec->getPointer();
1113 for(const mcIdType *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1115 if(*iter>=0 && *iter<nbOfCells)
1117 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*iter]]);
1118 if(!cm.isQuadratic())
1119 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_POLYGON;
1121 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_QPOLYG;
1125 std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1126 oss << " in range [0," << nbOfCells << ") !";
1127 throw INTERP_KERNEL::Exception(oss.str());
1133 mcIdType *connIndex(_nodal_connec_index->getPointer());
1134 const mcIdType *connOld(_nodal_connec->getConstPointer());
1135 MCAuto<DataArrayIdType> connNew(DataArrayIdType::New()),connNewI(DataArrayIdType::New()); connNew->alloc(0,1); connNewI->alloc(1,1); connNewI->setIJ(0,0,0);
1136 std::vector<bool> toBeDone(nbOfCells,false);
1137 for(const mcIdType *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1139 if(*iter>=0 && *iter<nbOfCells)
1140 toBeDone[*iter]=true;
1143 std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1144 oss << " in range [0," << nbOfCells << ") !";
1145 throw INTERP_KERNEL::Exception(oss.str());
1148 for(mcIdType cellId=0;cellId<nbOfCells;cellId++)
1150 mcIdType pos(connIndex[cellId]),posP1(connIndex[cellId+1]);
1151 mcIdType lgthOld(posP1-pos-1);
1152 if(toBeDone[cellId])
1154 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connOld[pos]);
1155 unsigned nbOfFaces(cm.getNumberOfSons2(connOld+pos+1,lgthOld));
1156 mcIdType *tmp(new mcIdType[nbOfFaces*lgthOld+1]);
1157 mcIdType *work=tmp; *work++=INTERP_KERNEL::NORM_POLYHED;
1158 for(unsigned j=0;j<nbOfFaces;j++)
1160 INTERP_KERNEL::NormalizedCellType type;
1161 unsigned offset=cm.fillSonCellNodalConnectivity2(j,connOld+pos+1,lgthOld,work,type);
1165 std::size_t newLgth(std::distance(tmp,work)-1);//-1 for last -1
1166 connNew->pushBackValsSilent(tmp,tmp+newLgth);
1167 connNewI->pushBackSilent(connNewI->back()+ToIdType(newLgth));
1172 connNew->pushBackValsSilent(connOld+pos,connOld+posP1);
1173 connNewI->pushBackSilent(connNewI->back()+posP1-pos);
1176 setConnectivity(connNew,connNewI,false);//false because computeTypes called just behind.
1182 * Converts all cells to either polygons (if \a this is a 2D mesh) or
1183 * polyhedrons (if \a this is a 3D mesh).
1184 * \warning As this method is purely for user-friendliness and no optimization is
1185 * done to avoid construction of a useless vector, this method can be costly
1187 * \throw If the coordinates array is not set.
1188 * \throw If the nodal connectivity of cells is node defined.
1189 * \throw If dimension of \a this mesh is not either 2 or 3.
1191 void MEDCouplingUMesh::convertAllToPoly()
1193 mcIdType nbOfCells=getNumberOfCells();
1194 std::vector<mcIdType> cellIds(nbOfCells);
1195 for(mcIdType i=0;i<nbOfCells;i++)
1197 convertToPolyTypes(&cellIds[0],&cellIds[0]+ToIdType(cellIds.size()));
1201 * Fixes nodal connectivity of invalid cells of type NORM_POLYHED. This method
1202 * expects that all NORM_POLYHED cells have connectivity similar to that of prismatic
1203 * volumes like NORM_HEXA8, NORM_PENTA6 etc., i.e. the first half of nodes describes a
1204 * base facet of the volume and the second half of nodes describes an opposite facet
1205 * having the same number of nodes as the base one. This method converts such
1206 * connectivity to a valid polyhedral format where connectivity of each facet is
1207 * explicitly described and connectivity of facets are separated by -1. If \a this mesh
1208 * contains a NORM_POLYHED cell with a valid connectivity, or an invalid connectivity is
1209 * not as expected, an exception is thrown and the mesh remains unchanged. Care of
1210 * a correct orientation of the first facet of a polyhedron, else orientation of a
1211 * corrected cell is reverse.<br>
1212 * This method is useful to build an extruded unstructured mesh with polyhedrons as
1213 * it releases the user from boring description of polyhedra connectivity in the valid
1215 * \throw If \a this->getMeshDimension() != 3.
1216 * \throw If \a this->getSpaceDimension() != 3.
1217 * \throw If the nodal connectivity of cells is not defined.
1218 * \throw If the coordinates array is not set.
1219 * \throw If \a this mesh contains polyhedrons with the valid connectivity.
1220 * \throw If \a this mesh contains polyhedrons with odd number of nodes.
1222 * \if ENABLE_EXAMPLES
1223 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
1224 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
1227 void MEDCouplingUMesh::convertExtrudedPolyhedra()
1229 checkFullyDefined();
1230 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1231 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertExtrudedPolyhedra works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
1232 mcIdType nbOfCells=getNumberOfCells();
1233 MCAuto<DataArrayIdType> newCi=DataArrayIdType::New();
1234 newCi->alloc(nbOfCells+1,1);
1235 mcIdType *newci=newCi->getPointer();
1236 const mcIdType *ci=_nodal_connec_index->getConstPointer();
1237 const mcIdType *c=_nodal_connec->getConstPointer();
1239 for(mcIdType i=0;i<nbOfCells;i++)
1241 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1242 if(type==INTERP_KERNEL::NORM_POLYHED)
1244 if(std::count(c+ci[i]+1,c+ci[i+1],-1)!=0)
1246 std::ostringstream oss; oss << "MEDCouplingUMesh::convertExtrudedPolyhedra : cell # " << i << " is a polhedron BUT it has NOT exactly 1 face !";
1247 throw INTERP_KERNEL::Exception(oss.str());
1249 std::size_t n2=std::distance(c+ci[i]+1,c+ci[i+1]);
1252 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 !";
1253 throw INTERP_KERNEL::Exception(oss.str());
1255 mcIdType n1=ToIdType(n2/2);
1256 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)
1259 newci[i+1]=(ci[i+1]-ci[i])+newci[i];
1261 MCAuto<DataArrayIdType> newC=DataArrayIdType::New();
1262 newC->alloc(newci[nbOfCells],1);
1263 mcIdType *newc=newC->getPointer();
1264 for(mcIdType i=0;i<nbOfCells;i++)
1266 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1267 if(type==INTERP_KERNEL::NORM_POLYHED)
1269 std::size_t n1=std::distance(c+ci[i]+1,c+ci[i+1])/2;
1270 newc=std::copy(c+ci[i],c+ci[i]+n1+1,newc);
1272 for(std::size_t j=0;j<n1;j++)
1274 newc[j]=c[ci[i]+1+n1+(n1-j)%n1];
1276 newc[n1+5*j+1]=c[ci[i]+1+j];
1277 newc[n1+5*j+2]=c[ci[i]+1+j+n1];
1278 newc[n1+5*j+3]=c[ci[i]+1+(j+1)%n1+n1];
1279 newc[n1+5*j+4]=c[ci[i]+1+(j+1)%n1];
1284 newc=std::copy(c+ci[i],c+ci[i+1],newc);
1286 _nodal_connec_index->decrRef(); _nodal_connec_index=newCi.retn();
1287 _nodal_connec->decrRef(); _nodal_connec=newC.retn();
1292 * Converts all polygons (if \a this is a 2D mesh) or polyhedrons (if \a this is a 3D
1293 * mesh) to cells of classical types. This method is opposite to convertToPolyTypes().
1294 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
1295 * to write this mesh to the MED file, its cells must be sorted using
1296 * sortCellsInMEDFileFrmt().
1297 * \warning Cells (and most notably polyhedrons) must be correctly oriented for this to work
1298 * properly. See orientCorrectlyPolyhedrons() and arePolyhedronsNotCorrectlyOriented().
1299 * \return \c true if at least one cell has been converted, \c false else. In the
1300 * last case the nodal connectivity remains unchanged.
1301 * \throw If the coordinates array is not set.
1302 * \throw If the nodal connectivity of cells is not defined.
1303 * \throw If \a this->getMeshDimension() < 0.
1305 bool MEDCouplingUMesh::unPolyze()
1307 checkFullyDefined();
1308 int mdim=getMeshDimension();
1310 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::unPolyze works on umeshes with meshdim equals to 0, 1 2 or 3 !");
1313 mcIdType nbOfCells=getNumberOfCells();
1316 mcIdType initMeshLgth=getNodalConnectivityArrayLen();
1317 mcIdType *conn=_nodal_connec->getPointer();
1318 mcIdType *index=_nodal_connec_index->getPointer();
1319 mcIdType posOfCurCell=0;
1321 mcIdType lgthOfCurCell;
1323 for(mcIdType i=0;i<nbOfCells;i++)
1325 lgthOfCurCell=index[i+1]-posOfCurCell;
1326 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
1327 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
1328 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::NORM_ERROR;
1332 switch(cm.getDimension())
1336 INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[lgthOfCurCell-1];
1337 std::copy(conn+posOfCurCell+1,conn+posOfCurCell+lgthOfCurCell,(mcIdType *)tmp);
1338 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly2D(cm.isQuadratic(),tmp,lgthOfCurCell-1,conn+newPos+1,newLgth);
1343 mcIdType nbOfFaces,lgthOfPolyhConn;
1344 INTERP_KERNEL::AutoPtr<mcIdType> zipFullReprOfPolyh=INTERP_KERNEL::CellSimplify::getFullPolyh3DCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,nbOfFaces,lgthOfPolyhConn);
1345 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly3D(zipFullReprOfPolyh,nbOfFaces,lgthOfPolyhConn,conn+newPos+1,newLgth);
1348 /* case 1: // Not supported yet
1350 newType=(lgthOfCurCell==3)?INTERP_KERNEL::NORM_SEG2:INTERP_KERNEL::NORM_POLYL;
1355 ret=ret || (newType!=type);
1356 conn[newPos]=newType;
1358 posOfCurCell=index[i+1];
1363 std::copy(conn+posOfCurCell,conn+posOfCurCell+lgthOfCurCell,conn+newPos);
1364 newPos+=lgthOfCurCell;
1365 posOfCurCell+=lgthOfCurCell;
1369 if(newPos!=initMeshLgth)
1370 _nodal_connec->reAlloc(newPos);
1377 * This method expects that spaceDimension is equal to 3 and meshDimension equal to 3.
1378 * This method performs operation only on polyhedrons in \b this. If no polyhedrons exists in \b this, \b this remains unchanged.
1379 * This method allows to merge if any coplanar 3DSurf cells that may appear in some polyhedrons cells.
1381 * \b WARNING: this method will not modify edges connectivity! Take a look at colinearizeEdges for that.
1383 * \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
1386 void MEDCouplingUMesh::simplifyPolyhedra(double eps)
1388 checkFullyDefined();
1389 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1390 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplifyPolyhedra : works on meshdimension 3 and spaceDimension 3 !");
1391 MCAuto<DataArrayDouble> coords=getCoords()->deepCopy();
1392 coords->recenterForMaxPrecision(eps);
1394 mcIdType nbOfCells=getNumberOfCells();
1395 const mcIdType *conn=_nodal_connec->getConstPointer();
1396 const mcIdType *index=_nodal_connec_index->getConstPointer();
1397 MCAuto<DataArrayIdType> connINew=DataArrayIdType::New();
1398 connINew->alloc(nbOfCells+1,1);
1399 mcIdType *connINewPtr=connINew->getPointer(); *connINewPtr++=0;
1400 MCAuto<DataArrayIdType> connNew=DataArrayIdType::New(); connNew->alloc(0,1);
1401 MCAuto<DataArrayIdType> E_Fi(DataArrayIdType::New()), E_F(DataArrayIdType::New()), F_Ei(DataArrayIdType::New()), F_E(DataArrayIdType::New());
1402 MCAuto<MEDCouplingUMesh> m_faces(buildDescendingConnectivity(E_F, E_Fi, F_E, F_Ei));
1404 for(mcIdType i=0;i<nbOfCells;i++,connINewPtr++)
1406 if(conn[index[i]]==ToIdType(INTERP_KERNEL::NORM_POLYHED))
1408 SimplifyPolyhedronCell(eps,coords, i,connNew, m_faces, E_Fi, E_F, F_Ei, F_E);
1412 connNew->insertAtTheEnd(conn+index[i],conn+index[i+1]);
1413 *connINewPtr=connNew->getNumberOfTuples();
1416 setConnectivity(connNew,connINew,false);
1420 * This method expects that spaceDimension is equal to 3 and meshDimension equal to 3.
1421 * This method performs operation only on polyhedrons in \b this. If no polyhedrons exists in \b this, \b this remains unchanged.
1422 * This method allows to simplify edges of polyhedron cells so that consecutive colinear segments (with intermediate points
1423 * not used by any other cell) are merged together.
1425 * \param [in] eps is a relative precision that allows to establish if two consecutive 3D segments are colinear or not.
1427 * \sa simplifyPolyhedra
1429 void MEDCouplingUMesh::colinearizeEdges(double eps)
1432 // Thanks to Antoine Gerschenfeld (CEA) for contributing this method!
1434 using DAI = MCAuto<DataArrayIdType>;
1435 checkFullyDefined();
1436 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1437 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::colinearizeEdges() : works with meshdim=3 and spaceDim=3!");
1438 double seps = sqrt(1-eps);
1439 // Computing connectivities and correspondances : elements -> segments -> points
1440 DAI E_Fi(DataArrayIdType::New()), E_F(DataArrayIdType::New()), F_Ei(DataArrayIdType::New()), F_E(DataArrayIdType::New()),
1441 F_Si(DataArrayIdType::New()), F_S(DataArrayIdType::New()), S_Fi(DataArrayIdType::New()), S_F(DataArrayIdType::New()),
1442 S_Pi(DataArrayIdType::New()), S_P(DataArrayIdType::New()), P_Si(DataArrayIdType::New()), P_S(DataArrayIdType::New());
1443 MCAuto<MEDCouplingUMesh> m_f(buildDescendingConnectivity(E_F, E_Fi, F_E, F_Ei)),
1444 m_s(m_f->buildDescendingConnectivity(F_S, F_Si, S_F, S_Fi)),
1445 m_p(m_s->buildDescendingConnectivity(S_P, S_Pi, P_S, P_Si)); // E: elem, F: faces, S: segments (edges), P: points (vertices)
1446 const mcIdType *S_Pp(S_P->begin()), *S_Pip(S_Pi->begin()), *P_Sp(P_S->begin()), *P_Sip(P_Si->begin());
1447 std::set<mcIdType> pt_rem;
1448 const mcIdType *m_pi = m_p->getNodalConnectivityIndex()->begin(),
1449 *m_pc = m_p->getNodalConnectivity()->begin();
1450 double (*coord)[3] = (double (*)[3]) getCoords()->begin();
1451 // Find all points only connected to exaclty 2 segments - they are the candidates for elimination
1452 // Note that in 3D this can only happen for polyhedrons (when this happens at all)
1453 DAI dsi = P_Si->deltaShiftIndex();
1454 DAI cand = dsi->findIdsEqual(2);
1455 for (const mcIdType& i: *cand) // i is a point to be potentially eliminated, shared by 2 segs only
1457 double n2[2] = {0., 0.}, scal = 0.; // n2 is a squared norm, scal is a scalar product
1458 mcIdType p[2][2]; // p[j][k] is the ID (in the coord array) of the k-th point of the j-th segment
1459 for (mcIdType j = 0; j < 2; j++)
1460 for (mcIdType k = 0; k < 2; k++)
1462 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
1463 mcIdType pt_id = P_Sp[off1] + k; // ID of the k-th point of the j-th seg in the point->seg correspondance
1464 mcIdType pt_id2 = S_Pp[S_Pip[pt_id]]; // ID of the point in the point mesh
1465 p[j][k] = m_pc[m_pi[pt_id2] + 1]; // Absolute ID, as read from the connectvity (+1 to skip type: NORM_POINT1)
1466 // Just for fun, as initially written by Antoine :-)
1467 // 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];
1469 // Geometric test on scalar product
1470 for (int d = 0; d < 3; d++) // dimension
1472 for (int j = 0; j < 2; j++)
1473 n2[j] += std::pow(coord[p[j][1]][d] - coord[p[j][0]][d], 2);
1474 scal += (coord[p[1][1]][d] - coord[p[1][0]][d]) * (coord[p[0][1]][d] - coord[p[0][0]][d]);
1476 if (scal * scal > seps * n2[0] * n2[1]) // seps is a sqrt for homogeneity
1477 pt_rem.insert(m_pc[m_pi[i] + 1]); // point should be removed
1479 // Clean connectivity by filtering points to be removed:
1480 DataArrayIdType *old_index = getNodalConnectivityIndex(), *old_conn = getNodalConnectivity();
1481 DAI new_index(DataArrayIdType::New()), new_conn(DataArrayIdType::New());
1482 const mcIdType *old_index_p(old_index->begin()), *old_conn_p(old_conn->begin());
1483 for (mcIdType i = 0; i < getNumberOfCells(); i++)
1485 new_index->pushBackSilent(new_conn->getNbOfElems());
1486 for (mcIdType j = old_index_p[i]; j < old_index_p[i + 1]; j++)
1488 // Keep point if it is not to be removed, or if is first in connectivity (TODO this last check could be removed?)
1489 if (std::find(pt_rem.begin(), pt_rem.end(), old_conn_p[j]) == pt_rem.end() || j == old_index_p[i])
1490 new_conn->pushBackSilent(old_conn_p[j]);
1493 new_index->pushBackSilent(new_conn->getNbOfElems());
1494 setConnectivity(new_conn, new_index);
1498 * This method returns all node ids used in the connectivity of \b this. The data array returned has to be dealt by the caller.
1499 * The returned node ids are sorted ascendingly. This method is close to MEDCouplingUMesh::getNodeIdsInUse except
1500 * the format of the returned DataArrayIdType instance.
1502 * \return a newly allocated DataArrayIdType sorted ascendingly of fetched node ids.
1503 * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1505 DataArrayIdType *MEDCouplingUMesh::computeFetchedNodeIds() const
1507 checkConnectivityFullyDefined();
1508 const mcIdType *maxEltPt(std::max_element(_nodal_connec->begin(),_nodal_connec->end()));
1509 mcIdType maxElt(maxEltPt==_nodal_connec->end()?0:std::abs(*maxEltPt)+1);
1510 std::vector<bool> retS(maxElt,false);
1511 computeNodeIdsAlg(retS);
1512 return DataArrayIdType::BuildListOfSwitchedOn(retS);
1516 * \param [in,out] nodeIdsInUse an array of size typically equal to nbOfNodes.
1517 * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1519 void MEDCouplingUMesh::computeNodeIdsAlg(std::vector<bool>& nodeIdsInUse) const
1521 mcIdType nbOfNodes=ToIdType(nodeIdsInUse.size()),
1522 nbOfCells=getNumberOfCells();
1523 const mcIdType *connIndex(_nodal_connec_index->getConstPointer()),*conn(_nodal_connec->getConstPointer());
1524 for(mcIdType i=0;i<nbOfCells;i++)
1525 for(mcIdType j=connIndex[i]+1;j<connIndex[i+1];j++)
1528 if(conn[j]<nbOfNodes)
1529 nodeIdsInUse[conn[j]]=true;
1532 std::ostringstream oss; oss << "MEDCouplingUMesh::computeNodeIdsAlg : In cell #" << i << " presence of node id " << conn[j] << " not in [0," << nbOfNodes << ") !";
1533 throw INTERP_KERNEL::Exception(oss.str());
1540 struct MEDCouplingAccVisit
1542 MEDCouplingAccVisit():_new_nb_of_nodes(0) { }
1543 mcIdType operator()(mcIdType val) { if(val!=-1) return _new_nb_of_nodes++; else return -1; }
1544 mcIdType _new_nb_of_nodes;
1550 * Finds nodes not used in any cell and returns an array giving a new id to every node
1551 * by excluding the unused nodes, for which the array holds -1. The result array is
1552 * a mapping in "Old to New" mode.
1553 * \param [out] nbrOfNodesInUse - number of node ids present in the nodal connectivity.
1554 * \return DataArrayIdType * - a new instance of DataArrayIdType. Its length is \a
1555 * this->getNumberOfNodes(). It holds for each node of \a this mesh either -1
1556 * if the node is unused or a new id else. The caller is to delete this
1557 * array using decrRef() as it is no more needed.
1558 * \throw If the coordinates array is not set.
1559 * \throw If the nodal connectivity of cells is not defined.
1560 * \throw If the nodal connectivity includes an invalid id.
1562 * \if ENABLE_EXAMPLES
1563 * \ref cpp_mcumesh_getNodeIdsInUse "Here is a C++ example".<br>
1564 * \ref py_mcumesh_getNodeIdsInUse "Here is a Python example".
1566 * \sa computeFetchedNodeIds, computeNodeIdsAlg()
1568 DataArrayIdType *MEDCouplingUMesh::getNodeIdsInUse(mcIdType& nbrOfNodesInUse) const
1571 mcIdType nbOfNodes(getNumberOfNodes());
1572 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1573 ret->alloc(nbOfNodes,1);
1574 mcIdType *traducer=ret->getPointer();
1575 std::fill(traducer,traducer+nbOfNodes,-1);
1576 mcIdType nbOfCells=getNumberOfCells();
1577 const mcIdType *connIndex=_nodal_connec_index->getConstPointer();
1578 const mcIdType *conn=_nodal_connec->getConstPointer();
1579 for(mcIdType i=0;i<nbOfCells;i++)
1580 for(mcIdType j=connIndex[i]+1;j<connIndex[i+1];j++)
1583 if(conn[j]<nbOfNodes)
1584 traducer[conn[j]]=1;
1587 std::ostringstream oss; oss << "MEDCouplingUMesh::getNodeIdsInUse : In cell #" << i << " presence of node id " << conn[j] << " not in [0," << nbOfNodes << ") !";
1588 throw INTERP_KERNEL::Exception(oss.str());
1591 nbrOfNodesInUse=ToIdType(std::count(traducer,traducer+nbOfNodes,1));
1592 std::transform(traducer,traducer+nbOfNodes,traducer,MEDCouplingAccVisit());
1597 * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1598 * For each cell in \b this the number of nodes constituting cell is computed.
1599 * For each polyhedron cell, the sum of the number of nodes of each face constituting polyhedron cell is returned.
1600 * So for pohyhedrons some nodes can be counted several times in the returned result.
1602 * \return a newly allocated array
1603 * \sa MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell
1605 DataArrayIdType *MEDCouplingUMesh::computeNbOfNodesPerCell() const
1607 checkConnectivityFullyDefined();
1608 mcIdType nbOfCells=getNumberOfCells();
1609 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1610 ret->alloc(nbOfCells,1);
1611 mcIdType *retPtr=ret->getPointer();
1612 const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1613 const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1614 for(mcIdType i=0;i<nbOfCells;i++,retPtr++)
1616 if(conn[connI[i]]!=ToIdType(INTERP_KERNEL::NORM_POLYHED))
1617 *retPtr=connI[i+1]-connI[i]-1;
1619 *retPtr=connI[i+1]-connI[i]-1-ToIdType(std::count(conn+connI[i]+1,conn+connI[i+1],-1));
1625 * This method computes effective number of nodes per cell. That is to say nodes appearing several times in nodal connectivity of a cell,
1626 * will be counted only once here whereas it will be counted several times in MEDCouplingUMesh::computeNbOfNodesPerCell method.
1628 * \return DataArrayIdType * - new object to be deallocated by the caller.
1629 * \sa MEDCouplingUMesh::computeNbOfNodesPerCell
1631 DataArrayIdType *MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell() const
1633 checkConnectivityFullyDefined();
1634 mcIdType nbOfCells=getNumberOfCells();
1635 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1636 ret->alloc(nbOfCells,1);
1637 mcIdType *retPtr=ret->getPointer();
1638 const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1639 const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1640 for(mcIdType i=0;i<nbOfCells;i++,retPtr++)
1642 std::set<mcIdType> s(conn+connI[i]+1,conn+connI[i+1]);
1643 if(conn[connI[i]]!=ToIdType(INTERP_KERNEL::NORM_POLYHED))
1644 *retPtr=ToIdType(s.size());
1648 *retPtr=ToIdType(s.size());
1655 * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1656 * For each cell in \b this the number of faces constituting (entity of dimension this->getMeshDimension()-1) cell is computed.
1658 * \return a newly allocated array
1660 DataArrayIdType *MEDCouplingUMesh::computeNbOfFacesPerCell() const
1662 checkConnectivityFullyDefined();
1663 mcIdType nbOfCells=getNumberOfCells();
1664 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1665 ret->alloc(nbOfCells,1);
1666 mcIdType *retPtr=ret->getPointer();
1667 const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1668 const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1669 for(mcIdType i=0;i<nbOfCells;i++,retPtr++,connI++)
1671 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]);
1672 *retPtr=cm.getNumberOfSons2(conn+connI[0]+1,connI[1]-connI[0]-1);
1678 * Removes unused nodes (the node coordinates array is shorten) and returns an array
1679 * mapping between new and old node ids in "Old to New" mode. -1 values in the returned
1680 * array mean that the corresponding old node is no more used.
1681 * \return DataArrayIdType * - a new instance of DataArrayIdType of length \a
1682 * this->getNumberOfNodes() before call of this method. The caller is to
1683 * delete this array using decrRef() as it is no more needed.
1684 * \throw If the coordinates array is not set.
1685 * \throw If the nodal connectivity of cells is not defined.
1686 * \throw If the nodal connectivity includes an invalid id.
1687 * \sa areAllNodesFetched
1689 * \if ENABLE_EXAMPLES
1690 * \ref cpp_mcumesh_zipCoordsTraducer "Here is a C++ example".<br>
1691 * \ref py_mcumesh_zipCoordsTraducer "Here is a Python example".
1694 DataArrayIdType *MEDCouplingUMesh::zipCoordsTraducer()
1696 return MEDCouplingPointSet::zipCoordsTraducer();
1700 * This method stands if 'cell1' and 'cell2' are equals regarding 'compType' policy.
1701 * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1703 int MEDCouplingUMesh::AreCellsEqual(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2, int compType)
1708 return AreCellsEqualPolicy0(conn,connI,cell1,cell2);
1710 return AreCellsEqualPolicy1(conn,connI,cell1,cell2);
1712 return AreCellsEqualPolicy2(conn,connI,cell1,cell2);
1714 return AreCellsEqualPolicy2NoType(conn,connI,cell1,cell2);
1716 return AreCellsEqualPolicy7(conn,connI,cell1,cell2);
1718 throw INTERP_KERNEL::Exception("Unknown comparison asked ! Must be in 0,1,2,3 or 7.");
1722 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 0.
1724 int MEDCouplingUMesh::AreCellsEqualPolicy0(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1726 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1727 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;
1732 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 1.
1734 int MEDCouplingUMesh::AreCellsEqualPolicy1(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1736 mcIdType sz=connI[cell1+1]-connI[cell1];
1737 if(sz==connI[cell2+1]-connI[cell2])
1739 if(conn[connI[cell1]]==conn[connI[cell2]])
1741 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1742 unsigned dim=cm.getDimension();
1747 mcIdType sz1=2*(sz-1);
1748 INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz1];
1749 mcIdType *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(mcIdType *)tmp);
1750 std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1751 work=std::search((mcIdType *)tmp,(mcIdType *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1752 return work!=tmp+sz1?1:0;
1755 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;//case of SEG2 and SEG3
1758 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy1 : not implemented yet for meshdim == 3 !");
1765 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 2.
1767 int MEDCouplingUMesh::AreCellsEqualPolicy2(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1769 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1771 if(conn[connI[cell1]]==conn[connI[cell2]])
1773 std::set<mcIdType> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1774 std::set<mcIdType> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1782 * This method is less restrictive than AreCellsEqualPolicy2. Here the geometric type is absolutely not taken into account !
1784 int MEDCouplingUMesh::AreCellsEqualPolicy2NoType(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1786 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1788 std::set<mcIdType> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1789 std::set<mcIdType> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1796 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 7.
1798 int MEDCouplingUMesh::AreCellsEqualPolicy7(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1800 mcIdType sz=connI[cell1+1]-connI[cell1];
1801 if(sz==connI[cell2+1]-connI[cell2])
1803 if(conn[connI[cell1]]==conn[connI[cell2]])
1805 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1806 unsigned dim=cm.getDimension();
1811 mcIdType sz1=2*(sz-1);
1812 INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz1];
1813 mcIdType *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(mcIdType *)tmp);
1814 std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1815 work=std::search((mcIdType *)tmp,(mcIdType *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1820 std::reverse_iterator<mcIdType *> it1((mcIdType *)tmp+sz1);
1821 std::reverse_iterator<mcIdType *> it2((mcIdType *)tmp);
1822 if(std::search(it1,it2,conn+connI[cell2]+1,conn+connI[cell2+1])!=it2)
1829 {//case of SEG2 and SEG3
1830 if(std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1))
1832 if(!cm.isQuadratic())
1834 std::reverse_iterator<const mcIdType *> it1(conn+connI[cell1+1]);
1835 std::reverse_iterator<const mcIdType *> it2(conn+connI[cell1]+1);
1836 if(std::equal(it1,it2,conn+connI[cell2]+1))
1842 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])
1849 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy7 : not implemented yet for meshdim == 3 !");
1857 * This method find cells that are equal (regarding \a compType) in \a this. The comparison is specified by \a compType (see zipConnectivityTraducer).
1858 * This method keeps the coordinates of \a this. The comparison starts at rank \a startCellId cell id (included).
1859 * 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.
1860 * If \a startCellId is greater than 0 algorithm starts at cell #startCellId but for each cell all candidates are considered.
1861 * This method is time consuming.
1863 * \param [in] compType input specifying the technique used to compare cells each other.
1864 * - 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.
1865 * - 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)
1866 * and their type equal. For 1D mesh the policy 1 is equivalent to 0.
1867 * - 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
1868 * can be used for users not sensitive to orientation of cell
1869 * \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.
1870 * \param [out] commonCellsArr common cells ids (\ref numbering-indirect)
1871 * \param [out] commonCellsIArr common cells ids (\ref numbering-indirect)
1874 void MEDCouplingUMesh::findCommonCells(int compType, mcIdType startCellId, DataArrayIdType *& commonCellsArr, DataArrayIdType *& commonCellsIArr) const
1876 MCAuto<DataArrayIdType> revNodal=DataArrayIdType::New(),revNodalI=DataArrayIdType::New();
1877 getReverseNodalConnectivity(revNodal,revNodalI);
1878 FindCommonCellsAlg(compType,startCellId,_nodal_connec,_nodal_connec_index,revNodal,revNodalI,commonCellsArr,commonCellsIArr);
1881 void MEDCouplingUMesh::FindCommonCellsAlg(int compType, mcIdType startCellId, const DataArrayIdType *nodal, const DataArrayIdType *nodalI, const DataArrayIdType *revNodal, const DataArrayIdType *revNodalI,
1882 DataArrayIdType *& commonCellsArr, DataArrayIdType *& commonCellsIArr)
1884 MCAuto<DataArrayIdType> commonCells=DataArrayIdType::New(),commonCellsI=DataArrayIdType::New(); commonCells->alloc(0,1);
1885 mcIdType nbOfCells=nodalI->getNumberOfTuples()-1;
1886 commonCellsI->reserve(1); commonCellsI->pushBackSilent(0);
1887 const mcIdType *revNodalPtr=revNodal->getConstPointer(),*revNodalIPtr=revNodalI->getConstPointer();
1888 const mcIdType *connPtr=nodal->getConstPointer(),*connIPtr=nodalI->getConstPointer();
1889 std::vector<bool> isFetched(nbOfCells,false);
1892 for(mcIdType i=startCellId;i<nbOfCells;i++)
1896 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));
1897 std::vector<mcIdType> v,v2;
1898 if(connOfNode!=connPtr+connIPtr[i+1])
1900 const mcIdType *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1901 v2.insert(v2.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1]);
1904 for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1908 const mcIdType *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1909 std::vector<mcIdType>::iterator it=std::set_intersection(v.begin(),v.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1910 v2.resize(std::distance(v2.begin(),it));
1914 if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1916 mcIdType pos=commonCellsI->back();
1917 commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1918 for(const mcIdType *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1919 isFetched[*it]=true;
1927 for(mcIdType i=startCellId;i<nbOfCells;i++)
1931 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));
1932 // v2 contains the result of successive intersections using rev nodal on on each node of cell #i
1933 std::vector<mcIdType> v,v2;
1934 if(connOfNode!=connPtr+connIPtr[i+1])
1936 v2.insert(v2.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1]);
1939 for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1943 std::vector<mcIdType>::iterator it=std::set_intersection(v.begin(),v.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1944 v2.resize(std::distance(v2.begin(),it));
1946 // v2 contains now candidates. Problem candidates are sorted using id rank.
1951 auto it(std::find(v2.begin(),v2.end(),i));
1952 std::swap(*v2.begin(),*it);
1954 if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1956 mcIdType newPos(commonCells->getNumberOfTuples());
1957 mcIdType pos(commonCellsI->back());
1958 std::sort(commonCells->getPointerSilent()+pos,commonCells->getPointerSilent()+newPos);
1959 commonCellsI->pushBackSilent(newPos);
1960 for(const mcIdType *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1961 isFetched[*it]=true;
1967 commonCellsArr=commonCells.retn();
1968 commonCellsIArr=commonCellsI.retn();
1972 * Checks if \a this mesh includes all cells of an \a other mesh, and returns an array
1973 * giving for each cell of the \a other an id of a cell in \a this mesh. A value larger
1974 * than \a this->getNumberOfCells() in the returned array means that there is no
1975 * corresponding cell in \a this mesh.
1976 * It is expected that \a this and \a other meshes share the same node coordinates
1977 * array, if it is not so an exception is thrown.
1978 * \param [in] other - the mesh to compare with.
1979 * \param [in] compType - specifies a cell comparison technique. For meaning of its
1980 * valid values [0,1,2], see zipConnectivityTraducer().
1981 * \param [out] arr - a new instance of DataArrayIdType returning correspondence
1982 * between cells of the two meshes. It contains \a other->getNumberOfCells()
1983 * values. The caller is to delete this array using
1984 * decrRef() as it is no more needed.
1985 * \return bool - \c true if all cells of \a other mesh are present in the \a this
1988 * \if ENABLE_EXAMPLES
1989 * \ref cpp_mcumesh_areCellsIncludedIn "Here is a C++ example".<br>
1990 * \ref py_mcumesh_areCellsIncludedIn "Here is a Python example".
1992 * \sa checkDeepEquivalOnSameNodesWith()
1993 * \sa checkGeoEquivalWith()
1995 bool MEDCouplingUMesh::areCellsIncludedIn(const MEDCouplingUMesh *other, int compType, DataArrayIdType *& arr) const
1997 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1998 mcIdType nbOfCells=getNumberOfCells();
1999 static const int possibleCompType[]={0,1,2};
2000 if(std::find(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),compType)==possibleCompType+sizeof(possibleCompType)/sizeof(int))
2002 std::ostringstream oss; oss << "MEDCouplingUMesh::areCellsIncludedIn : only following policies are possible : ";
2003 std::copy(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),std::ostream_iterator<int>(oss," "));
2005 throw INTERP_KERNEL::Exception(oss.str());
2008 if(other->getNumberOfCells()==0)
2010 MCAuto<DataArrayIdType> dftRet(DataArrayIdType::New()); dftRet->alloc(0,1); arr=dftRet.retn(); arr->setName(other->getName());
2013 DataArrayIdType *commonCells(nullptr),*commonCellsI(nullptr);
2014 mesh->findCommonCells(compType,nbOfCells,commonCells,commonCellsI);
2015 MCAuto<DataArrayIdType> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
2016 mcIdType newNbOfCells=-1;
2017 MCAuto<DataArrayIdType> o2n = DataArrayIdType::ConvertIndexArrayToO2N(ToIdType(mesh->getNumberOfCells()),commonCells->begin(),commonCellsI->begin(),commonCellsI->end(),newNbOfCells);
2018 MCAuto<DataArrayIdType> p0(o2n->selectByTupleIdSafeSlice(0,nbOfCells,1));
2019 mcIdType maxPart(p0->getMaxValueInArray());
2020 bool ret(maxPart==newNbOfCells-1);
2021 MCAuto<DataArrayIdType> p1(p0->invertArrayO2N2N2O(newNbOfCells));
2022 // fill p1 array in case of presence of cells in other not in this
2023 mcIdType *pt(p1->getPointer());
2024 for(mcIdType i = maxPart ; i < newNbOfCells-1 ; ++i )
2027 MCAuto<DataArrayIdType> p2(o2n->subArray(nbOfCells));
2028 p2->transformWithIndArr(p1->begin(),p1->end()); p2->setName(other->getName());
2034 * This method makes the assumption that \a this and \a other share the same coords. If not an exception will be thrown !
2035 * This method tries to determine if \b other is fully included in \b this.
2036 * The main difference is that this method is not expected to throw exception.
2037 * This method has two outputs :
2039 * \param other other mesh
2040 * \param arr is an output parameter that returns a \b newly created instance. This array is of size 'other->getNumberOfCells()'.
2041 * \return If \a other is fully included in 'this 'true is returned. If not false is returned.
2043 bool MEDCouplingUMesh::areCellsIncludedInPolicy7(const MEDCouplingUMesh *other, DataArrayIdType *& arr) const
2045 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
2046 DataArrayIdType *commonCells=0,*commonCellsI=0;
2047 mcIdType thisNbCells=getNumberOfCells();
2048 mesh->findCommonCells(7,thisNbCells,commonCells,commonCellsI);
2049 MCAuto<DataArrayIdType> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
2050 const mcIdType *commonCellsPtr=commonCells->getConstPointer(),*commonCellsIPtr=commonCellsI->getConstPointer();
2051 mcIdType otherNbCells=other->getNumberOfCells();
2052 MCAuto<DataArrayIdType> arr2=DataArrayIdType::New();
2053 arr2->alloc(otherNbCells,1);
2054 arr2->fillWithZero();
2055 mcIdType *arr2Ptr=arr2->getPointer();
2056 mcIdType nbOfCommon=commonCellsI->getNumberOfTuples()-1;
2057 for(mcIdType i=0;i<nbOfCommon;i++)
2059 mcIdType start=commonCellsPtr[commonCellsIPtr[i]];
2060 if(start<thisNbCells)
2062 for(mcIdType j=commonCellsIPtr[i]+1;j!=commonCellsIPtr[i+1];j++)
2064 mcIdType sig=commonCellsPtr[j]>0?1:-1;
2065 mcIdType val=std::abs(commonCellsPtr[j])-1;
2066 if(val>=thisNbCells)
2067 arr2Ptr[val-thisNbCells]=sig*(start+1);
2071 arr2->setName(other->getName());
2072 if(arr2->presenceOfValue(0))
2078 MEDCouplingUMesh *MEDCouplingUMesh::mergeMyselfWithOnSameCoords(const MEDCouplingPointSet *other) const
2081 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : input other is null !");
2082 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
2084 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : the input other mesh is not of type unstructured !");
2085 std::vector<const MEDCouplingUMesh *> ms(2);
2088 return MergeUMeshesOnSameCoords(ms);
2092 * Build a sub part of \b this lying or not on the same coordinates than \b this (regarding value of \b keepCoords).
2093 * By default coordinates are kept. This method is close to MEDCouplingUMesh::buildPartOfMySelf except that here input
2094 * cellIds is not given explicitly but by a range python like.
2096 * \param start starting ID
2097 * \param end end ID (excluded)
2098 * \param step step size
2099 * \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.
2100 * \return a newly allocated
2102 * \warning This method modifies can generate an unstructured mesh whose cells are not sorted by geometric type order.
2103 * In view of the MED file writing, a renumbering of cells of returned unstructured mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
2105 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfSlice(mcIdType start, mcIdType end, mcIdType step, bool keepCoords) const
2107 if(getMeshDimension()!=-1)
2108 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelfSlice(start,end,step,keepCoords));
2111 mcIdType newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfSlice for -1 dimension mesh ");
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 * Creates a new MEDCouplingUMesh containing specified cells of \a this mesh.
2123 * The result mesh shares or not the node coordinates array with \a this mesh depending
2124 * on \a keepCoords parameter.
2125 * \warning Cells of the result mesh can be \b not sorted by geometric type, hence,
2126 * to write this mesh to the MED file, its cells must be sorted using
2127 * sortCellsInMEDFileFrmt().
2128 * \param [in] begin - an array of cell ids to include to the new mesh.
2129 * \param [in] end - a pointer to last-plus-one-th element of \a begin.
2130 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2131 * array of \a this mesh, else "free" nodes are removed from the result mesh
2132 * by calling zipCoords().
2133 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2134 * to delete this mesh using decrRef() as it is no more needed.
2135 * \throw If the coordinates array is not set.
2136 * \throw If the nodal connectivity of cells is not defined.
2137 * \throw If any cell id in the array \a begin is not valid.
2139 * \if ENABLE_EXAMPLES
2140 * \ref cpp_mcumesh_buildPartOfMySelf "Here is a C++ example".<br>
2141 * \ref py_mcumesh_buildPartOfMySelf "Here is a Python example".
2144 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelf(const mcIdType *begin, const mcIdType *end, bool keepCoords) const
2146 if(getMeshDimension()!=-1)
2147 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelf(begin,end,keepCoords));
2151 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
2153 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
2155 return const_cast<MEDCouplingUMesh *>(this);
2160 * This method operates only on nodal connectivity on \b this. Coordinates of \b this is completely ignored here.
2162 * 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.
2163 * Size of [ \b cellIdsBg, \b cellIdsEnd ) ) must be equal to the number of cells of otherOnSameCoordsThanThis.
2164 * The number of cells of \b this will remain the same with this method.
2166 * \param [in] cellIdsBg begin of cell ids (included) of cells in this to assign
2167 * \param [in] cellIdsEnd end of cell ids (excluded) of cells in this to assign
2168 * \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 ).
2169 * Coordinate pointer of \b this and those of \b otherOnSameCoordsThanThis must be the same
2171 void MEDCouplingUMesh::setPartOfMySelf(const mcIdType *cellIdsBg, const mcIdType *cellIdsEnd, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2173 checkConnectivityFullyDefined();
2174 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2175 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2176 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelf : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2177 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2179 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2180 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2181 throw INTERP_KERNEL::Exception(oss.str());
2183 mcIdType nbOfCellsToModify( ToIdType((std::distance(cellIdsBg,cellIdsEnd))));
2184 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2186 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2187 throw INTERP_KERNEL::Exception(oss.str());
2189 mcIdType nbOfCells(getNumberOfCells());
2190 bool easyAssign(true);
2191 const mcIdType *connI(_nodal_connec_index->begin());
2192 const mcIdType *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->begin();
2193 for(const mcIdType *it=cellIdsBg;it!=cellIdsEnd && easyAssign;it++,connIOther++)
2195 if(*it>=0 && *it<nbOfCells)
2197 easyAssign=(connIOther[1]-connIOther[0])==(connI[*it+1]-connI[*it]);
2201 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : On pos #" << std::distance(cellIdsBg,it) << " id is equal to " << *it << " which is not in [0," << nbOfCells << ") !";
2202 throw INTERP_KERNEL::Exception(oss.str());
2207 DataArrayIdType::SetPartOfIndexedArraysSameIdx(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2212 DataArrayIdType *arrOut=0,*arrIOut=0;
2213 DataArrayIdType::SetPartOfIndexedArrays(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2215 MCAuto<DataArrayIdType> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2216 setConnectivity(arrOut,arrIOut,true);
2220 void MEDCouplingUMesh::setPartOfMySelfSlice(mcIdType start, mcIdType end, mcIdType step, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2222 checkConnectivityFullyDefined();
2223 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2224 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2225 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelfSlice : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2226 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2228 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2229 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2230 throw INTERP_KERNEL::Exception(oss.str());
2232 mcIdType nbOfCellsToModify=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::setPartOfMySelfSlice : ");
2233 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2235 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2236 throw INTERP_KERNEL::Exception(oss.str());
2238 mcIdType nbOfCells=getNumberOfCells();
2239 bool easyAssign=true;
2240 const mcIdType *connI=_nodal_connec_index->getConstPointer();
2241 const mcIdType *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2243 for(mcIdType i=0;i<nbOfCellsToModify && easyAssign;i++,it+=step,connIOther++)
2245 if(it>=0 && it<nbOfCells)
2247 easyAssign=(connIOther[1]-connIOther[0])==(connI[it+1]-connI[it]);
2251 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : On pos #" << i << " id is equal to " << it << " which is not in [0," << nbOfCells << ") !";
2252 throw INTERP_KERNEL::Exception(oss.str());
2257 DataArrayIdType::SetPartOfIndexedArraysSameIdxSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2262 DataArrayIdType *arrOut=0,*arrIOut=0;
2263 DataArrayIdType::SetPartOfIndexedArraysSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2265 MCAuto<DataArrayIdType> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2266 setConnectivity(arrOut,arrIOut,true);
2272 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2273 * this->getMeshDimension(), that bound some cells of \a this mesh.
2274 * The cells of lower dimension to include to the result mesh are selected basing on
2275 * specified node ids and the value of \a fullyIn parameter. If \a fullyIn ==\c true, a
2276 * cell is copied if its all nodes are in the array \a begin of node ids. If \a fullyIn
2277 * ==\c false, a cell is copied if any its node is in the array of node ids. The
2278 * created mesh shares the node coordinates array with \a this mesh.
2279 * \param [in] begin - the array of node ids.
2280 * \param [in] end - a pointer to the (last+1)-th element of \a begin.
2281 * \param [in] fullyIn - if \c true, then cells whose all nodes are in the
2282 * array \a begin are added, else cells whose any node is in the
2283 * array \a begin are added.
2284 * \return MEDCouplingUMesh * - new instance of MEDCouplingUMesh. The caller is
2285 * to delete this mesh using decrRef() as it is no more needed.
2286 * \throw If the coordinates array is not set.
2287 * \throw If the nodal connectivity of cells is not defined.
2288 * \throw If any node id in \a begin is not valid.
2290 * \if ENABLE_EXAMPLES
2291 * \ref cpp_mcumesh_buildFacePartOfMySelfNode "Here is a C++ example".<br>
2292 * \ref py_mcumesh_buildFacePartOfMySelfNode "Here is a Python example".
2295 MEDCouplingUMesh *MEDCouplingUMesh::buildFacePartOfMySelfNode(const mcIdType *begin, const mcIdType *end, bool fullyIn) const
2297 MCAuto<DataArrayIdType> desc,descIndx,revDesc,revDescIndx;
2298 desc=DataArrayIdType::New(); descIndx=DataArrayIdType::New(); revDesc=DataArrayIdType::New(); revDescIndx=DataArrayIdType::New();
2299 MCAuto<MEDCouplingUMesh> subMesh=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2300 desc=0; descIndx=0; revDesc=0; revDescIndx=0;
2301 return static_cast<MEDCouplingUMesh*>(subMesh->buildPartOfMySelfNode(begin,end,fullyIn));
2305 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2306 * this->getMeshDimension(), which bound only one cell of \a this mesh.
2307 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2308 * array of \a this mesh, else "free" nodes are removed from the result mesh
2309 * by calling zipCoords().
2310 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2311 * to delete this mesh using decrRef() as it is no more needed.
2312 * \throw If the coordinates array is not set.
2313 * \throw If the nodal connectivity of cells is not defined.
2315 * \if ENABLE_EXAMPLES
2316 * \ref cpp_mcumesh_buildBoundaryMesh "Here is a C++ example".<br>
2317 * \ref py_mcumesh_buildBoundaryMesh "Here is a Python example".
2320 MEDCouplingUMesh *MEDCouplingUMesh::buildBoundaryMesh(bool keepCoords) const
2322 DataArrayIdType *desc=DataArrayIdType::New();
2323 DataArrayIdType *descIndx=DataArrayIdType::New();
2324 DataArrayIdType *revDesc=DataArrayIdType::New();
2325 DataArrayIdType *revDescIndx=DataArrayIdType::New();
2327 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2330 descIndx->decrRef();
2331 mcIdType nbOfCells=meshDM1->getNumberOfCells();
2332 const mcIdType *revDescIndxC=revDescIndx->getConstPointer();
2333 std::vector<mcIdType> boundaryCells;
2334 for(mcIdType i=0;i<nbOfCells;i++)
2335 if(revDescIndxC[i+1]-revDescIndxC[i]==1)
2336 boundaryCells.push_back(i);
2337 revDescIndx->decrRef();
2338 MEDCouplingUMesh *ret=meshDM1->buildPartOfMySelf(&boundaryCells[0],&boundaryCells[0]+boundaryCells.size(),keepCoords);
2343 * This method returns a newly created DataArrayIdType instance containing ids of cells located in boundary.
2344 * A cell is detected to be on boundary if it contains one or more than one face having only one father.
2345 * This method makes the assumption that \a this is fully defined (coords,connectivity). If not an exception will be thrown.
2347 DataArrayIdType *MEDCouplingUMesh::findCellIdsOnBoundary() const
2349 checkFullyDefined();
2350 MCAuto<DataArrayIdType> ret2(DataArrayIdType::New());
2352 if (getNumberOfCells() == 0)
2358 MCAuto<DataArrayIdType> desc(DataArrayIdType::New()), descIndx(DataArrayIdType::New()), revDesc(DataArrayIdType::New()), revDescIndx(DataArrayIdType::New());
2360 buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx)->decrRef();
2361 desc=(DataArrayIdType*)0; descIndx=(DataArrayIdType*)0;
2363 MCAuto<DataArrayIdType> tmp=revDescIndx->deltaShiftIndex();
2364 MCAuto<DataArrayIdType> faceIds=tmp->findIdsEqual(1); tmp=(DataArrayIdType*)0;
2365 const mcIdType *revDescPtr=revDesc->getConstPointer();
2366 const mcIdType *revDescIndxPtr=revDescIndx->getConstPointer();
2367 mcIdType nbOfCells=getNumberOfCells();
2368 std::vector<bool> ret1(nbOfCells,false);
2370 for(const mcIdType *pt=faceIds->begin();pt!=faceIds->end();pt++)
2371 if(!ret1[revDescPtr[revDescIndxPtr[*pt]]])
2372 { ret1[revDescPtr[revDescIndxPtr[*pt]]]=true; sz++; }
2375 mcIdType *ret2Ptr=ret2->getPointer();
2377 for(std::vector<bool>::const_iterator it=ret1.begin();it!=ret1.end();it++,sz++)
2380 ret2->setName("BoundaryCells");
2385 * This method finds in \b this the cell ids that lie on mesh \b otherDimM1OnSameCoords.
2386 * \b this and \b otherDimM1OnSameCoords have to lie on the same coordinate array pointer. The coherency of that coords array with connectivity
2387 * of \b this and \b otherDimM1OnSameCoords is not important here because this method works only on connectivity.
2388 * this->getMeshDimension() - 1 must be equal to otherDimM1OnSameCoords.getMeshDimension()
2390 * s0 is the cell ids set in \b this lying on at least one node in the fetched nodes in \b otherDimM1OnSameCoords.
2391 * 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
2392 * equals a cell in \b otherDimM1OnSameCoords.
2394 * \throw if \b otherDimM1OnSameCoords is not part of constituent of \b this, or if coordinate pointer of \b this and \b otherDimM1OnSameCoords
2395 * are not same, or if this->getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension()
2397 * \param [in] otherDimM1OnSameCoords other mesh
2398 * \param [out] cellIdsRk0 a newly allocated array containing the cell ids of s0 (which are cell ids of \b this) in the above algorithm.
2399 * \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
2400 * cellIdsRk1->transformWithIndArr(cellIdsRk0->begin(),cellIdsRk0->end());
2402 void MEDCouplingUMesh::findCellIdsLyingOn(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayIdType *&cellIdsRk0, DataArrayIdType *&cellIdsRk1) const
2404 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2405 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : coordinates pointer are not the same ! Use tryToShareSameCoords method !");
2406 checkConnectivityFullyDefined();
2407 otherDimM1OnSameCoords.checkConnectivityFullyDefined();
2408 if(getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension())
2409 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : invalid mesh dimension of input mesh regarding meshdimesion of this !");
2410 MCAuto<DataArrayIdType> fetchedNodeIds1=otherDimM1OnSameCoords.computeFetchedNodeIds();
2411 MCAuto<DataArrayIdType> s0arr=getCellIdsLyingOnNodes(fetchedNodeIds1->begin(),fetchedNodeIds1->end(),false);
2412 MCAuto<MEDCouplingUMesh> thisPart=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(s0arr->begin(),s0arr->end(),true));
2413 MCAuto<DataArrayIdType> descThisPart=DataArrayIdType::New(),descIThisPart=DataArrayIdType::New(),revDescThisPart=DataArrayIdType::New(),revDescIThisPart=DataArrayIdType::New();
2414 MCAuto<MEDCouplingUMesh> thisPartConsti=thisPart->buildDescendingConnectivity(descThisPart,descIThisPart,revDescThisPart,revDescIThisPart);
2415 const mcIdType *revDescThisPartPtr=revDescThisPart->getConstPointer(),*revDescIThisPartPtr=revDescIThisPart->getConstPointer();
2416 DataArrayIdType *idsOtherInConsti=0;
2417 bool b=thisPartConsti->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsOtherInConsti);
2418 MCAuto<DataArrayIdType> idsOtherInConstiAuto(idsOtherInConsti);
2420 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : the given mdim-1 mesh in other is not a constituent of this !");
2421 std::set<mcIdType> s1;
2422 for(const mcIdType *idOther=idsOtherInConsti->begin();idOther!=idsOtherInConsti->end();idOther++)
2423 s1.insert(revDescThisPartPtr+revDescIThisPartPtr[*idOther],revDescThisPartPtr+revDescIThisPartPtr[*idOther+1]);
2424 MCAuto<DataArrayIdType> s1arr_renum1=DataArrayIdType::New(); s1arr_renum1->alloc(s1.size(),1); std::copy(s1.begin(),s1.end(),s1arr_renum1->getPointer());
2425 s1arr_renum1->sort();
2426 cellIdsRk0=s0arr.retn();
2427 //cellIdsRk1=s_renum1.retn();
2428 cellIdsRk1=s1arr_renum1.retn();
2432 * 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
2433 * returned. This subpart of meshdim-1 mesh is built using meshdim-1 cells in it shared only one cell in \b this.
2435 * \return a newly allocated mesh lying on the same coordinates than \b this. The caller has to deal with returned mesh.
2437 MEDCouplingUMesh *MEDCouplingUMesh::computeSkin() const
2439 MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
2440 MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
2441 MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
2442 MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
2444 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2445 revDesc=0; desc=0; descIndx=0;
2446 MCAuto<DataArrayIdType> revDescIndx2=revDescIndx->deltaShiftIndex();
2447 MCAuto<DataArrayIdType> part=revDescIndx2->findIdsEqual(1);
2448 return static_cast<MEDCouplingUMesh *>(meshDM1->buildPartOfMySelf(part->begin(),part->end(),true));
2452 * Finds nodes lying on the boundary of \a this mesh.
2453 * \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of found
2454 * nodes. The caller is to delete this array using decrRef() as it is no
2456 * \throw If the coordinates array is not set.
2457 * \throw If the nodal connectivity of cells is node defined.
2459 * \if ENABLE_EXAMPLES
2460 * \ref cpp_mcumesh_findBoundaryNodes "Here is a C++ example".<br>
2461 * \ref py_mcumesh_findBoundaryNodes "Here is a Python example".
2464 DataArrayIdType *MEDCouplingUMesh::findBoundaryNodes() const
2466 MCAuto<MEDCouplingUMesh> skin=computeSkin();
2467 return skin->computeFetchedNodeIds();
2470 MEDCouplingUMesh *MEDCouplingUMesh::buildUnstructured() const
2473 return const_cast<MEDCouplingUMesh *>(this);
2477 * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2478 * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2479 * 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.
2480 * If a node is in the boundary of \b this \b and in the boundary of \b otherDimM1OnSameCoords, it will be duplicated.
2481 * 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.
2483 * \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
2484 * parameter is altered during the call.
2485 * \return node ids which need to be duplicated following the algorithm explained above.
2488 DataArrayIdType* MEDCouplingUMesh::findNodesToDuplicate(const MEDCouplingUMesh& crackingMesh) const
2490 // DEBUG NOTE: in case of issue with the algorithm in this method, see Python script in resources/dev
2491 // which mimicks the C++
2492 using DAInt = MCAuto<DataArrayIdType>;
2493 using MCUMesh = MCAuto<MEDCouplingUMesh>;
2495 checkFullyDefined();
2496 crackingMesh.checkFullyDefined();
2497 if(getCoords()!=crackingMesh.getCoords())
2498 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : meshes do not share the same coords array !");
2499 if(crackingMesh.getMeshDimension()!=getMeshDimension()-1)
2500 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the mesh given in other parameter must have this->getMeshDimension()-1 !");
2502 // 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!)
2503 MCUMesh m0skin = computeSkin();
2504 DataArrayIdType *idsToKeepP;
2505 m0skin->areCellsIncludedIn(&crackingMesh,2, idsToKeepP);
2506 DAInt idsToKeep(idsToKeepP);
2507 DAInt ids2 = idsToKeep->findIdsNotInRange(0, m0skin->getNumberOfCells()); // discard cells on the skin of M0
2508 MCUMesh otherDimM1OnSameCoords =static_cast<MEDCouplingUMesh *>(crackingMesh.buildPartOfMySelf(ids2->begin(), ids2->end(), true));
2510 if (!otherDimM1OnSameCoords->getNumberOfCells())
2511 return MCAuto<DataArrayIdType>(DataArrayIdType::New()).retn();
2513 // Checking star-shaped M1 group:
2514 DAInt dt0=DataArrayIdType::New(),dit0=DataArrayIdType::New(),rdt0=DataArrayIdType::New(),rdit0=DataArrayIdType::New();
2515 MCUMesh meshM2 = otherDimM1OnSameCoords->buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); // 2D: a mesh of points, 3D: a mesh of segs
2516 DAInt dsi = rdit0->deltaShiftIndex();
2517 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.
2518 if(idsTmp0->getNumberOfTuples())
2519 throw INTERP_KERNEL::Exception("MEDFileUMesh::buildInnerBoundaryAlongM1Group: group is too complex: some points (or edges) have more than two connected segments (or faces)!");
2520 dt0=0; dit0=0; rdt0=0; rdit0=0; idsTmp0=0;
2522 // Get extreme nodes from the group (they won't be duplicated except if they also lie on bound of M0 -- see below),
2523 // ie nodes belonging to the boundary "cells" (might be points) of M1
2524 DAInt xtremIdsM2 = dsi->findIdsEqual(1); dsi = 0;
2525 MCUMesh meshM2Part = static_cast<MEDCouplingUMesh *>(meshM2->buildPartOfMySelf(xtremIdsM2->begin(), xtremIdsM2->end(),true));
2526 DAInt xtrem = meshM2Part->computeFetchedNodeIds();
2527 // Remove from the list points on the boundary of the M0 mesh (those need duplication!).
2528 // 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)
2529 // 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
2530 // although they are technically on the skin of the cube.
2531 DAInt fNodes = m0skin->computeFetchedNodeIds();
2533 if (getMeshDimension() == 3)
2535 DAInt dnu1=DataArrayIdType::New(), dnu2=DataArrayIdType::New(), dnu3=DataArrayIdType::New(), dnu4=DataArrayIdType::New();
2536 MCUMesh m0skinDesc = m0skin->buildDescendingConnectivity(dnu1, dnu2, dnu3, dnu4); // all segments of the skin of the 3D (M0) mesh
2537 dnu1=0;dnu2=0;dnu3=0;dnu4=0;
2538 DataArrayIdType * corresp=0;
2539 meshM2->areCellsIncludedIn(m0skinDesc,2,corresp);
2540 // validIds is the list of segments which are on both the skin of *this*, and in the segments of the M1 group
2541 // In the cube example above, this is a U-shaped polyline.
2542 DAInt validIds = corresp->findIdsInRange(0, meshM2->getNumberOfCells());
2544 if (validIds->getNumberOfTuples())
2546 // 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:
2547 // (the U-shaped polyline described above)
2548 MCUMesh m1IntersecSkin = static_cast<MEDCouplingUMesh *>(m0skinDesc->buildPartOfMySelf(validIds->begin(), validIds->end(), true));
2549 // Its boundary nodes should no be duplicated (this is for example the tip of the crack inside the cube described above)
2550 DAInt notDuplSkin = m1IntersecSkin->findBoundaryNodes();
2551 DAInt fNodes1 = fNodes->buildSubstraction(notDuplSkin);
2553 // Specific logic to handle singular points :
2554 // - a point on this U-shape line used in a cell which has no face in common with M1 is deemed singular.
2555 // - indeed, if duplicated, such a point would lead to the duplication of a cell which has no face touching M1 ! The
2556 // algorithm would be duplicating too much ...
2557 // 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:
2558 dnu1=DataArrayIdType::New(), dnu2=DataArrayIdType::New(), dnu3=DataArrayIdType::New(), rdit0=DataArrayIdType::New();
2559 MCUMesh meshM2Desc = meshM2->buildDescendingConnectivity(dnu1, dnu2, dnu3, rdit0); // a mesh made of node cells
2560 dnu1=0;dnu2=0;dnu3=0;
2561 dsi = rdit0->deltaShiftIndex(); rdit0=0;
2562 DAInt singPoints = dsi->findIdsNotInRange(-1,4) ; dsi=0;// points connected to (strictly) more than 3 segments
2563 if (singPoints->getNumberOfTuples())
2565 DAInt boundNodes = m1IntersecSkin->computeFetchedNodeIds();
2566 // If a point on this U-shape line is connected to cells which do not share any face with M1, then it
2567 // should not be duplicated
2568 // 1. Extract N D cells touching U-shape line:
2569 DAInt cellsAroundBN = getCellIdsLyingOnNodes(boundNodes->begin(), boundNodes->end(), false); // false= take cell in, even if not all nodes are in dupl
2570 MCUMesh mAroundBN = static_cast<MEDCouplingUMesh *>(this->buildPartOfMySelf(cellsAroundBN->begin(), cellsAroundBN->end(), true));
2571 DAInt descBN=DataArrayIdType::New(), descIBN=DataArrayIdType::New(), revDescBN=DataArrayIdType::New(), revDescIBN=DataArrayIdType::New();
2572 MCUMesh mAroundBNDesc = mAroundBN->buildDescendingConnectivity(descBN,descIBN,revDescBN,revDescIBN);
2573 // 2. Identify cells in sub-mesh mAroundBN which have a face in common with M1
2574 DataArrayIdType *idsOfM1BNt;
2575 mAroundBNDesc->areCellsIncludedIn(otherDimM1OnSameCoords,2, idsOfM1BNt);
2576 DAInt idsOfM1BN(idsOfM1BNt);
2577 mcIdType nCells=mAroundBN->getNumberOfCells(), nCellsDesc=mAroundBNDesc->getNumberOfCells();
2578 DAInt idsTouch=DataArrayIdType::New(); idsTouch->alloc(0,1);
2579 const mcIdType *revDescIBNP=revDescIBN->begin(), *revDescBNP=revDescBN->begin();
2580 for(const auto& v: *idsOfM1BN)
2582 if (v >= nCellsDesc) // Keep valid match only
2584 mcIdType idx0 = revDescIBNP[v];
2585 // Keep the two cells on either side of the face v of M1:
2586 mcIdType c1=revDescBNP[idx0], c2=revDescBNP[idx0+1];
2587 idsTouch->pushBackSilent(c1); idsTouch->pushBackSilent(c2);
2589 // 3. Build complement
2590 DAInt idsTouchCompl = idsTouch->buildComplement(nCells);
2591 MCUMesh mAroundBNStrict = static_cast<MEDCouplingUMesh *>(mAroundBN->buildPartOfMySelf(idsTouchCompl->begin(), idsTouchCompl->end(), true));
2592 DAInt nod3 = mAroundBNStrict->computeFetchedNodeIds();
2593 DAInt inters = boundNodes->buildIntersection(nod3);
2594 fNodes1 = fNodes1->buildSubstraction(inters); // reminder: fNodes1 represent nodes that need dupl.
2596 notDup = xtrem->buildSubstraction(fNodes1);
2598 else // if (validIds-> ...)
2599 notDup = xtrem->buildSubstraction(fNodes);
2602 notDup = xtrem->buildSubstraction(fNodes);
2604 DAInt m1Nodes = otherDimM1OnSameCoords->computeFetchedNodeIds();
2605 DAInt dupl = m1Nodes->buildSubstraction(notDup);
2611 * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2612 * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2613 * This method is part of the MEDFileUMesh::buildInnerBoundaryAlongM1Group() algorithm.
2614 * Given a set of nodes to duplicate, this method identifies which cells should have their connectivity modified
2615 * to produce the inner boundary. It is typically called after findNodesToDuplicate().
2617 * \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.
2618 * \param [in] nodeIdsToDuplicateBg node ids needed to be duplicated, as returned by findNodesToDuplicate.
2619 * \param [in] nodeIdsToDuplicateEnd node ids needed to be duplicated, as returned by findNodesToDuplicate.
2620 * \param [out] cellIdsNeededToBeRenum cell ids in \b this in which the renumber of nodes should be performed.
2621 * \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.
2624 void MEDCouplingUMesh::findCellsToRenumber(const MEDCouplingUMesh& otherDimM1OnSameCoords, const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd,
2625 DataArrayIdType *& cellIdsNeededToBeRenum, DataArrayIdType *& cellIdsNotModified) const
2627 using DAInt = MCAuto<DataArrayIdType>;
2628 using MCUMesh = MCAuto<MEDCouplingUMesh>;
2630 checkFullyDefined();
2631 otherDimM1OnSameCoords.checkFullyDefined();
2632 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2633 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellsToRenumber: meshes do not share the same coords array !");
2634 if(otherDimM1OnSameCoords.getMeshDimension()!=getMeshDimension()-1)
2635 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellsToRenumber: the mesh given in other parameter must have this->getMeshDimension()-1 !");
2637 // Degenerated case - no nodes to duplicate
2638 if (nodeIdsToDuplicateBg == nodeIdsToDuplicateEnd)
2640 cellIdsNeededToBeRenum = DataArrayIdType::New(); cellIdsNeededToBeRenum->alloc(0,1);
2641 cellIdsNotModified = DataArrayIdType::New(); cellIdsNotModified->alloc(0,1);
2645 // Compute cell IDs of the mesh with cells that touch the M1 group with a least one node:
2646 DAInt cellsAroundGroupLarge = getCellIdsLyingOnNodes(nodeIdsToDuplicateBg, nodeIdsToDuplicateEnd, false); // false= take cell in, even if not all nodes are in dupl
2647 MCUMesh mAroundGrpLarge=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(cellsAroundGroupLarge->begin(),cellsAroundGroupLarge->end(),true));
2648 mcIdType nCellsLarge=cellsAroundGroupLarge->getNumberOfTuples();
2649 DAInt descL=DataArrayIdType::New(),descIL=DataArrayIdType::New(),revDescL=DataArrayIdType::New(),revDescIL=DataArrayIdType::New();
2650 MCUMesh mArGrpLargeDesc=mAroundGrpLarge->buildDescendingConnectivity(descL,descIL,revDescL,revDescIL);
2651 const mcIdType *descILP=descIL->begin(), *descLP=descL->begin();
2652 DataArrayIdType *idsOfM1t;
2653 mArGrpLargeDesc->areCellsIncludedIn(&otherDimM1OnSameCoords,2, idsOfM1t);
2654 DAInt idsOfM1Large(idsOfM1t);
2655 mcIdType nL = mArGrpLargeDesc->getNumberOfCells();
2657 // Computation of the neighbor information of the mesh WITH the crack (some neighbor links are removed):
2658 // In the neighbor information remove the connection between high dimension cells and its low level constituents which are part
2659 // of the frontier given in parameter (i.e. the cells of low dimension from the group delimiting the crack):
2660 DAInt descLTrunc = descL->deepCopy(), descILTrunc = descIL->deepCopy();
2661 DataArrayIdType::RemoveIdsFromIndexedArrays(idsOfM1Large->begin(), idsOfM1Large->end(),descLTrunc,descILTrunc);
2662 DataArrayIdType *neight=0, *neighIt=0;
2663 MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(descLTrunc,descILTrunc,revDescL,revDescIL, neight, neighIt);
2664 DAInt neighL(neight), neighIL(neighIt);
2666 DAInt hitCellsLarge = DataArrayIdType::New(); hitCellsLarge->alloc(nCellsLarge,1);
2667 hitCellsLarge->fillWithValue(0); // 0 : not hit, +1: one side of the crack, -1: other side of the crack,
2668 mcIdType* hitCellsLargeP = hitCellsLarge->rwBegin();
2670 // Now loop on the faces of the M1 group and fill spread zones on either side of the crack:
2671 const mcIdType *revDescILP=revDescIL->begin(), *revDescLP=revDescL->begin();
2672 for(const auto& v: *idsOfM1Large)
2674 if (v >= nL) continue; // Keep valid match only - see doc of areCellsIncludedIn()
2675 mcIdType idx0 = revDescILP[v];
2676 // Retrieve the two cells on either side of the face v of M1:
2677 mcIdType c1=revDescLP[idx0], c2=revDescLP[idx0+1];
2678 std::map<mcIdType, mcIdType> toOther = {{c1, c2}, {c2, c1}};
2679 // Handle the spread zones on the two sides of the crack:
2680 for (const auto c: {c1, c2})
2682 if (hitCellsLargeP[c]) continue;
2683 // Identify connex zone around this cell - if we find a value already assigned there, use it.
2685 DAInt spreadZone = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&c, &c+1, neighL,neighIL, -1, dnu);
2686 std::set<mcIdType> sv;
2687 for (const mcIdType& s: *spreadZone)
2688 if (hitCellsLargeP[s]) sv.insert(hitCellsLargeP[s]);
2690 // Strange: we find in the same spread zone a +1 and -1 !
2691 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellsToRenumber: internal error #0 - conflicting values - should not happen!");
2692 // If a valid value was found, use it:
2693 mcIdType val = sv.size()==1 ? *sv.begin() : 0;
2694 // Hopefully this does not conflict with an potential value on the other side:
2695 mcIdType other = toOther[c];
2696 if (hitCellsLargeP[other])
2698 if(val && hitCellsLargeP[other] != -val)
2699 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellsToRenumber: internal error #1 - conflicting values - should not happen!");;
2700 // We do not yet have a value, but other side has one. Use it!
2701 if(!val) val = -hitCellsLargeP[other];
2703 // Cover first initialisation:
2705 // And finally, fill the current spread zone:
2706 for(const mcIdType& s: *spreadZone) hitCellsLargeP[s] = val;
2710 DAInt cellsRet1 = hitCellsLarge->findIdsEqual(1);
2711 DAInt cellsRet2 = hitCellsLarge->findIdsEqual(-1);
2713 if (cellsRet1->getNumberOfTuples() + cellsRet2->getNumberOfTuples() != cellsAroundGroupLarge->getNumberOfTuples())
2715 DAInt nonHitCells = hitCellsLarge->findIdsEqual(0); // variable kept for debug ...
2716 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellsToRenumber: Some cells not hit - Internal error should not happen");
2718 cellsRet1->transformWithIndArr(cellsAroundGroupLarge->begin(),cellsAroundGroupLarge->end());
2719 cellsRet2->transformWithIndArr(cellsAroundGroupLarge->begin(),cellsAroundGroupLarge->end());
2721 cellIdsNeededToBeRenum=cellsRet1.retn();
2722 cellIdsNotModified=cellsRet2.retn();
2726 * This method operates a modification of the connectivity and coords in \b this.
2727 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2728 * its ids will be modified to id this->getNumberOfNodes()+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2729 * 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
2730 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id this->getNumberOfNodes()+0, node id nodeIdsToDuplicateBg[1] will have id this->getNumberOfNodes()+1,
2731 * node id nodeIdsToDuplicateBg[2] will have id this->getNumberOfNodes()+2...
2733 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2735 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2736 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2738 void MEDCouplingUMesh::duplicateNodes(const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd)
2740 mcIdType nbOfNodes=getNumberOfNodes();
2741 duplicateNodesInCoords(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd);
2742 duplicateNodesInConn(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,nbOfNodes);
2746 * This method renumbers only nodal connectivity in \a this. The renumbering is only an offset applied. So this method is a specialization of
2747 * \a renumberNodesInConn. \b WARNING, this method does not check that the resulting node ids in the nodal connectivity is in a valid range !
2749 * \param [in] offset - specifies the offset to be applied on each element of connectivity.
2751 * \sa renumberNodesInConn
2753 void MEDCouplingUMesh::renumberNodesWithOffsetInConn(mcIdType offset)
2755 checkConnectivityFullyDefined();
2756 mcIdType *conn(getNodalConnectivity()->getPointer());
2757 const mcIdType *connIndex(getNodalConnectivityIndex()->getConstPointer());
2758 mcIdType nbOfCells=getNumberOfCells();
2759 for(mcIdType i=0;i<nbOfCells;i++)
2760 for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2762 mcIdType& node=conn[iconn];
2763 if(node>=0)//avoid polyhedron separator
2768 _nodal_connec->declareAsNew();
2773 * Same than renumberNodesInConn(const mcIdType *) except that here the format of old-to-new traducer is using map instead
2774 * 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
2777 void MEDCouplingUMesh::renumberNodesInConn(const INTERP_KERNEL::HashMap<mcIdType,mcIdType>& newNodeNumbersO2N)
2779 this->renumberNodesInConnT< INTERP_KERNEL::HashMap<mcIdType,mcIdType> >(newNodeNumbersO2N);
2783 * Same than renumberNodesInConn(const mcIdType *) except that here the format of old-to-new traducer is using map instead
2784 * 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
2787 void MEDCouplingUMesh::renumberNodesInConn(const std::map<mcIdType,mcIdType>& newNodeNumbersO2N)
2789 this->renumberNodesInConnT< std::map<mcIdType,mcIdType> >(newNodeNumbersO2N);
2793 * Changes ids of nodes within the nodal connectivity arrays according to a permutation
2794 * array in "Old to New" mode. The node coordinates array is \b not changed by this method.
2795 * This method is a generalization of shiftNodeNumbersInConn().
2796 * \warning This method performs no check of validity of new ids. **Use it with care !**
2797 * \param [in] newNodeNumbersO2N - a permutation array, of length \a
2798 * this->getNumberOfNodes(), in "Old to New" mode.
2799 * See \ref numbering for more info on renumbering modes.
2800 * \throw If the nodal connectivity of cells is not defined.
2802 * \if ENABLE_EXAMPLES
2803 * \ref cpp_mcumesh_renumberNodesInConn "Here is a C++ example".<br>
2804 * \ref py_mcumesh_renumberNodesInConn "Here is a Python example".
2807 void MEDCouplingUMesh::renumberNodesInConn(const mcIdType *newNodeNumbersO2N)
2809 checkConnectivityFullyDefined();
2810 mcIdType *conn=getNodalConnectivity()->getPointer();
2811 const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2812 mcIdType nbOfCells=getNumberOfCells();
2813 for(mcIdType i=0;i<nbOfCells;i++)
2814 for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2816 mcIdType& node=conn[iconn];
2817 if(node>=0)//avoid polyhedron separator
2819 node=newNodeNumbersO2N[node];
2822 _nodal_connec->declareAsNew();
2827 * This method renumbers nodes \b in \b connectivity \b only \b without \b any \b reference \b to \b coords.
2828 * This method performs no check on the fact that new coordinate ids are valid. \b Use \b it \b with \b care !
2829 * This method is an specialization of \ref MEDCoupling::MEDCouplingUMesh::renumberNodesInConn "renumberNodesInConn method".
2831 * \param [in] delta specifies the shift size applied to nodeId in nodal connectivity in \b this.
2833 void MEDCouplingUMesh::shiftNodeNumbersInConn(mcIdType delta)
2835 checkConnectivityFullyDefined();
2836 mcIdType *conn=getNodalConnectivity()->getPointer();
2837 const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2838 mcIdType nbOfCells=getNumberOfCells();
2839 for(mcIdType i=0;i<nbOfCells;i++)
2840 for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2842 mcIdType& node=conn[iconn];
2843 if(node>=0)//avoid polyhedron separator
2848 _nodal_connec->declareAsNew();
2853 * This method operates a modification of the connectivity in \b this.
2854 * 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.
2855 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2856 * its ids will be modified to id offset+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2857 * 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
2858 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id offset+0, node id nodeIdsToDuplicateBg[1] will have id offset+1,
2859 * node id nodeIdsToDuplicateBg[2] will have id offset+2...
2861 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2862 * As an another consequense after the call of this method \b this can be transiently non cohrent.
2864 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2865 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2866 * \param [in] offset the offset applied to all node ids in connectivity that are in [ \a nodeIdsToDuplicateBg, \a nodeIdsToDuplicateEnd ).
2868 void MEDCouplingUMesh::duplicateNodesInConn(const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd, mcIdType offset)
2870 checkConnectivityFullyDefined();
2871 std::map<mcIdType,mcIdType> m;
2872 mcIdType val=offset;
2873 for(const mcIdType *work=nodeIdsToDuplicateBg;work!=nodeIdsToDuplicateEnd;work++,val++)
2875 mcIdType *conn=getNodalConnectivity()->getPointer();
2876 const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2877 mcIdType nbOfCells=getNumberOfCells();
2878 for(mcIdType i=0;i<nbOfCells;i++)
2879 for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2881 mcIdType& node=conn[iconn];
2882 if(node>=0)//avoid polyhedron separator
2884 std::map<mcIdType,mcIdType>::iterator it=m.find(node);
2893 * This method renumbers cells of \a this using the array specified by [old2NewBg;old2NewBg+getNumberOfCells())
2895 * Contrary to MEDCouplingPointSet::renumberNodes, this method makes a permutation without any fuse of cell.
2896 * After the call of this method the number of cells remains the same as before.
2898 * If 'check' equals true the method will check that any elements in [ \a old2NewBg; \a old2NewEnd ) is unique ; if not
2899 * an INTERP_KERNEL::Exception will be thrown. When 'check' equals true [ \a old2NewBg ; \a old2NewEnd ) is not expected to
2900 * be strictly in [0;this->getNumberOfCells()).
2902 * If 'check' equals false the method will not check the content of [ \a old2NewBg ; \a old2NewEnd ).
2903 * To avoid any throw of SIGSEGV when 'check' equals false, the elements in [ \a old2NewBg ; \a old2NewEnd ) should be unique and
2904 * should be contained in[0;this->getNumberOfCells()).
2906 * \param [in] old2NewBg is expected to be a dynamically allocated pointer of size at least equal to this->getNumberOfCells()
2907 * \param check whether to check content of old2NewBg
2909 void MEDCouplingUMesh::renumberCells(const mcIdType *old2NewBg, bool check)
2911 checkConnectivityFullyDefined();
2912 mcIdType nbCells=getNumberOfCells();
2913 const mcIdType *array=old2NewBg;
2915 array=DataArrayIdType::CheckAndPreparePermutation(old2NewBg,old2NewBg+nbCells);
2917 const mcIdType *conn=_nodal_connec->getConstPointer();
2918 const mcIdType *connI=_nodal_connec_index->getConstPointer();
2919 MCAuto<DataArrayIdType> o2n=DataArrayIdType::New(); o2n->useArray(array,false,DeallocType::C_DEALLOC,nbCells,1);
2920 MCAuto<DataArrayIdType> n2o=o2n->invertArrayO2N2N2O(nbCells);
2921 const mcIdType *n2oPtr=n2o->begin();
2922 MCAuto<DataArrayIdType> newConn=DataArrayIdType::New();
2923 newConn->alloc(_nodal_connec->getNumberOfTuples(),_nodal_connec->getNumberOfComponents());
2924 newConn->copyStringInfoFrom(*_nodal_connec);
2925 MCAuto<DataArrayIdType> newConnI=DataArrayIdType::New();
2926 newConnI->alloc(_nodal_connec_index->getNumberOfTuples(),_nodal_connec_index->getNumberOfComponents());
2927 newConnI->copyStringInfoFrom(*_nodal_connec_index);
2929 mcIdType *newC=newConn->getPointer();
2930 mcIdType *newCI=newConnI->getPointer();
2933 for(mcIdType i=0;i<nbCells;i++)
2935 mcIdType pos=n2oPtr[i];
2936 mcIdType nbOfElts=connI[pos+1]-connI[pos];
2937 newC=std::copy(conn+connI[pos],conn+connI[pos+1],newC);
2942 setConnectivity(newConn,newConnI);
2944 free(const_cast<mcIdType *>(array));
2948 * Finds cells whose bounding boxes intersect a given bounding box.
2949 * \param [in] bbox - an array defining the bounding box via coordinates of its
2950 * extremum points in "no interlace" mode, i.e. xMin, xMax, yMin, yMax, zMin,
2952 * \param [in] eps - a factor used to increase size of the bounding box of cell
2953 * before comparing it with \a bbox. This factor is multiplied by the maximal
2954 * extent of the bounding box of cell to produce an addition to this bounding box.
2955 * \return DataArrayIdType * - a new instance of DataArrayIdType holding ids for found
2956 * cells. The caller is to delete this array using decrRef() as it is no more
2958 * \throw If the coordinates array is not set.
2959 * \throw If the nodal connectivity of cells is not defined.
2961 * \if ENABLE_EXAMPLES
2962 * \ref cpp_mcumesh_getCellsInBoundingBox "Here is a C++ example".<br>
2963 * \ref py_mcumesh_getCellsInBoundingBox "Here is a Python example".
2966 DataArrayIdType *MEDCouplingUMesh::getCellsInBoundingBox(const double *bbox, double eps) const
2968 MCAuto<DataArrayIdType> elems=DataArrayIdType::New(); elems->alloc(0,1);
2969 if(getMeshDimension()==-1)
2971 elems->pushBackSilent(0);
2972 return elems.retn();
2974 int dim=getSpaceDimension();
2975 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2976 const mcIdType* conn = getNodalConnectivity()->getConstPointer();
2977 const mcIdType* conn_index= getNodalConnectivityIndex()->getConstPointer();
2978 const double* coords = getCoords()->getConstPointer();
2979 mcIdType nbOfCells=getNumberOfCells();
2980 for ( mcIdType ielem=0; ielem<nbOfCells;ielem++ )
2982 for (int i=0; i<dim; i++)
2984 elem_bb[i*2]=std::numeric_limits<double>::max();
2985 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2988 for (mcIdType inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2990 mcIdType node= conn[inode];
2991 if(node>=0)//avoid polyhedron separator
2993 for (int idim=0; idim<dim; idim++)
2995 if ( coords[node*dim+idim] < elem_bb[idim*2] )
2997 elem_bb[idim*2] = coords[node*dim+idim] ;
2999 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
3001 elem_bb[idim*2+1] = coords[node*dim+idim] ;
3006 if (intersectsBoundingBox(elem_bb, bbox, dim, eps))
3007 elems->pushBackSilent(ielem);
3009 return elems.retn();
3013 * Given a boundary box 'bbox' returns elements 'elems' contained in this 'bbox' or touching 'bbox' (within 'eps' distance).
3014 * Warning 'elems' is incremented during the call so if elems is not empty before call returned elements will be
3015 * added in 'elems' parameter.
3017 DataArrayIdType *MEDCouplingUMesh::getCellsInBoundingBox(const INTERP_KERNEL::DirectedBoundingBox& bbox, double eps)
3019 MCAuto<DataArrayIdType> elems=DataArrayIdType::New(); elems->alloc(0,1);
3020 if(getMeshDimension()==-1)
3022 elems->pushBackSilent(0);
3023 return elems.retn();
3025 int dim=getSpaceDimension();
3026 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
3027 const mcIdType* conn = getNodalConnectivity()->getConstPointer();
3028 const mcIdType* conn_index= getNodalConnectivityIndex()->getConstPointer();
3029 const double* coords = getCoords()->getConstPointer();
3030 mcIdType nbOfCells=getNumberOfCells();
3031 for ( mcIdType ielem=0; ielem<nbOfCells;ielem++ )
3033 for (int i=0; i<dim; i++)
3035 elem_bb[i*2]=std::numeric_limits<double>::max();
3036 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
3039 for (mcIdType inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
3041 mcIdType node= conn[inode];
3042 if(node>=0)//avoid polyhedron separator
3044 for (int idim=0; idim<dim; idim++)
3046 if ( coords[node*dim+idim] < elem_bb[idim*2] )
3048 elem_bb[idim*2] = coords[node*dim+idim] ;
3050 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
3052 elem_bb[idim*2+1] = coords[node*dim+idim] ;
3057 if(intersectsBoundingBox(bbox, elem_bb, dim, eps))
3058 elems->pushBackSilent(ielem);
3060 return elems.retn();
3064 * Returns a type of a cell by its id.
3065 * \param [in] cellId - the id of the cell of interest.
3066 * \return INTERP_KERNEL::NormalizedCellType - enumeration item describing the cell type.
3067 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
3069 INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::getTypeOfCell(mcIdType cellId) const
3071 const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
3072 if(cellId<_nodal_connec_index->getNbOfElems()-1)
3073 return (INTERP_KERNEL::NormalizedCellType) pt[ptI[cellId]];
3076 std::ostringstream oss; oss << "MEDCouplingUMesh::getTypeOfCell : Requesting type of cell #" << cellId << " but it should be in [0," << _nodal_connec_index->getNbOfElems()-1 << ") !";
3077 throw INTERP_KERNEL::Exception(oss.str());
3082 * This method returns a newly allocated array containing cell ids (ascendingly sorted) whose geometric type are equal to type.
3083 * This method does not throw exception if geometric type \a type is not in \a this.
3084 * This method throws an INTERP_KERNEL::Exception if meshdimension of \b this is not equal to those of \b type.
3085 * The coordinates array is not considered here.
3087 * \param [in] type the geometric type
3088 * \return cell ids in this having geometric type \a type.
3090 DataArrayIdType *MEDCouplingUMesh::giveCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
3093 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
3095 checkConnectivityFullyDefined();
3096 mcIdType nbCells=getNumberOfCells();
3097 int mdim=getMeshDimension();
3098 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
3099 if(mdim!=ToIdType(cm.getDimension()))
3100 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::giveCellsWithType : Mismatch between mesh dimension and dimension of the cell !");
3101 const mcIdType *ptI=_nodal_connec_index->getConstPointer();
3102 const mcIdType *pt=_nodal_connec->getConstPointer();
3103 for(mcIdType i=0;i<nbCells;i++)
3105 if((INTERP_KERNEL::NormalizedCellType)pt[ptI[i]]==type)
3106 ret->pushBackSilent(i);
3112 * Returns nb of cells having the geometric type \a type. No throw if no cells in \a this has the geometric type \a type.
3114 mcIdType MEDCouplingUMesh::getNumberOfCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
3116 const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
3117 mcIdType nbOfCells(getNumberOfCells()),ret(0);
3118 for(mcIdType i=0;i<nbOfCells;i++)
3119 if((INTERP_KERNEL::NormalizedCellType) pt[ptI[i]]==type)
3125 * Returns the nodal connectivity of a given cell.
3126 * The separator of faces within polyhedron connectivity (-1) is not returned, thus
3127 * all returned node ids can be used in getCoordinatesOfNode().
3128 * \param [in] cellId - an id of the cell of interest.
3129 * \param [in,out] conn - a vector where the node ids are appended. It is not
3130 * cleared before the appending.
3131 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
3133 void MEDCouplingUMesh::getNodeIdsOfCell(mcIdType cellId, std::vector<mcIdType>& conn) const
3135 const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
3136 for(const mcIdType *w=pt+ptI[cellId]+1;w!=pt+ptI[cellId+1];w++)
3141 std::string MEDCouplingUMesh::simpleRepr() const
3143 static const char msg0[]="No coordinates specified !";
3144 std::ostringstream ret;
3145 ret << "Unstructured mesh with name : \"" << getName() << "\"\n";
3146 ret << "Description of mesh : \"" << getDescription() << "\"\n";
3148 double tt=getTime(tmpp1,tmpp2);
3149 ret << "Time attached to the mesh [unit] : " << tt << " [" << getTimeUnit() << "]\n";
3150 ret << "Iteration : " << tmpp1 << " Order : " << tmpp2 << "\n";
3152 { ret << "Mesh dimension : " << _mesh_dim << "\nSpace dimension : "; }
3154 { ret << " Mesh dimension has not been set or is invalid !"; }
3157 const int spaceDim=getSpaceDimension();
3158 ret << spaceDim << "\nInfo attached on space dimension : ";
3159 for(int i=0;i<spaceDim;i++)
3160 ret << "\"" << _coords->getInfoOnComponent(i) << "\" ";
3164 ret << msg0 << "\n";
3165 ret << "Number of nodes : ";
3167 ret << getNumberOfNodes() << "\n";
3169 ret << msg0 << "\n";
3170 ret << "Number of cells : ";
3171 if(_nodal_connec!=0 && _nodal_connec_index!=0)
3172 ret << getNumberOfCells() << "\n";
3174 ret << "No connectivity specified !" << "\n";
3175 ret << "Cell types present : ";
3176 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
3178 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter);
3179 ret << cm.getRepr() << " ";
3185 std::string MEDCouplingUMesh::advancedRepr() const
3187 std::ostringstream ret;
3188 ret << simpleRepr();
3189 ret << "\nCoordinates array : \n___________________\n\n";
3191 _coords->reprWithoutNameStream(ret);
3193 ret << "No array set !\n";
3194 ret << "\n\nConnectivity arrays : \n_____________________\n\n";
3195 reprConnectivityOfThisLL(ret);
3200 * This method returns a C++ code that is a dump of \a this.
3201 * This method will throw if this is not fully defined.
3203 std::string MEDCouplingUMesh::cppRepr() const
3205 static const char coordsName[]="coords";
3206 static const char connName[]="conn";
3207 static const char connIName[]="connI";
3208 checkFullyDefined();
3209 std::ostringstream ret; ret << "// coordinates" << std::endl;
3210 _coords->reprCppStream(coordsName,ret); ret << std::endl << "// connectivity" << std::endl;
3211 _nodal_connec->reprCppStream(connName,ret); ret << std::endl;
3212 _nodal_connec_index->reprCppStream(connIName,ret); ret << std::endl;
3213 ret << "MEDCouplingUMesh *mesh=MEDCouplingUMesh::New(\"" << getName() << "\"," << getMeshDimension() << ");" << std::endl;
3214 ret << "mesh->setCoords(" << coordsName << ");" << std::endl;
3215 ret << "mesh->setConnectivity(" << connName << "," << connIName << ",true);" << std::endl;
3216 ret << coordsName << "->decrRef(); " << connName << "->decrRef(); " << connIName << "->decrRef();" << std::endl;
3220 std::string MEDCouplingUMesh::reprConnectivityOfThis() const
3222 std::ostringstream ret;
3223 reprConnectivityOfThisLL(ret);
3228 * This method builds a newly allocated instance (with the same name than \a this) that the caller has the responsibility to deal with.
3229 * This method returns an instance with all arrays allocated (connectivity, connectivity index, coordinates)
3230 * but with length of these arrays set to 0. It allows to define an "empty" mesh (with nor cells nor nodes but compliant with
3233 * This method expects that \a this has a mesh dimension set and higher or equal to 0. If not an exception will be thrown.
3234 * 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
3235 * with number of tuples set to 0, if not the array is taken as this in the returned instance.
3237 MEDCouplingUMesh *MEDCouplingUMesh::buildSetInstanceFromThis(std::size_t spaceDim) const
3239 int mdim=getMeshDimension();
3241 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSetInstanceFromThis : invalid mesh dimension ! Should be >= 0 !");
3242 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
3243 MCAuto<DataArrayIdType> tmp1,tmp2;
3244 bool needToCpyCT=true;
3247 tmp1=DataArrayIdType::New(); tmp1->alloc(0,1);
3255 if(!_nodal_connec_index)
3257 tmp2=DataArrayIdType::New(); tmp2->alloc(1,1); tmp2->setIJ(0,0,0);
3262 tmp2=_nodal_connec_index;
3265 ret->setConnectivity(tmp1,tmp2,false);
3270 MCAuto<DataArrayDouble> coords=DataArrayDouble::New(); coords->alloc(0,spaceDim);
3271 ret->setCoords(coords);
3274 ret->setCoords(_coords);
3278 mcIdType MEDCouplingUMesh::getNumberOfNodesInCell(mcIdType cellId) const
3280 const mcIdType *ptI=_nodal_connec_index->getConstPointer();
3281 const mcIdType *pt=_nodal_connec->getConstPointer();
3282 if(pt[ptI[cellId]]!=INTERP_KERNEL::NORM_POLYHED)
3283 return ptI[cellId+1]-ptI[cellId]-1;
3285 return ToIdType(std::count_if(pt+ptI[cellId]+1,pt+ptI[cellId+1],std::bind(std::not_equal_to<mcIdType>(),std::placeholders::_1,-1)));
3289 * Returns types of cells of the specified part of \a this mesh.
3290 * This method avoids computing sub-mesh explicitly to get its types.
3291 * \param [in] begin - an array of cell ids of interest.
3292 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3293 * \return std::set<INTERP_KERNEL::NormalizedCellType> - a set of enumeration items
3294 * describing the cell types.
3295 * \throw If the coordinates array is not set.
3296 * \throw If the nodal connectivity of cells is not defined.
3297 * \sa getAllGeoTypes()
3299 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getTypesOfPart(const mcIdType *begin, const mcIdType *end) const
3301 checkFullyDefined();
3302 std::set<INTERP_KERNEL::NormalizedCellType> ret;
3303 const mcIdType *conn=_nodal_connec->getConstPointer();
3304 const mcIdType *connIndex=_nodal_connec_index->getConstPointer();
3305 for(const mcIdType *w=begin;w!=end;w++)
3306 ret.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]);
3311 * Defines the nodal connectivity using given connectivity arrays in \ref numbering-indirect format.
3312 * Optionally updates
3313 * a set of types of cells constituting \a this mesh.
3314 * This method is for advanced users having prepared their connectivity before. For
3315 * more info on using this method see \ref MEDCouplingUMeshAdvBuild.
3316 * \param [in] conn - the nodal connectivity array.
3317 * \param [in] connIndex - the nodal connectivity index array.
3318 * \param [in] isComputingTypes - if \c true, the set of types constituting \a this
3321 void MEDCouplingUMesh::setConnectivity(DataArrayIdType *conn, DataArrayIdType *connIndex, bool isComputingTypes)
3323 DataArrayIdType::SetArrayIn(conn,_nodal_connec);
3324 DataArrayIdType::SetArrayIn(connIndex,_nodal_connec_index);
3325 if(isComputingTypes)
3331 * Copy constructor. If 'deepCopy' is false \a this is a shallow copy of other.
3332 * If 'deeCpy' is true all arrays (coordinates and connectivities) are deeply copied.
3334 MEDCouplingUMesh::MEDCouplingUMesh(const MEDCouplingUMesh& other, bool deepCpy):MEDCouplingPointSet(other,deepCpy),_mesh_dim(other._mesh_dim),
3335 _nodal_connec(0),_nodal_connec_index(0),
3336 _types(other._types)
3338 if(other._nodal_connec)
3339 _nodal_connec=other._nodal_connec->performCopyOrIncrRef(deepCpy);
3340 if(other._nodal_connec_index)
3341 _nodal_connec_index=other._nodal_connec_index->performCopyOrIncrRef(deepCpy);
3344 MEDCouplingUMesh::~MEDCouplingUMesh()
3347 _nodal_connec->decrRef();
3348 if(_nodal_connec_index)
3349 _nodal_connec_index->decrRef();
3353 * Recomputes a set of cell types of \a this mesh. For more info see
3354 * \ref MEDCouplingUMeshNodalConnectivity.
3356 void MEDCouplingUMesh::computeTypes()
3358 ComputeAllTypesInternal(_types,_nodal_connec,_nodal_connec_index);
3363 * Returns a number of cells constituting \a this mesh.
3364 * \return mcIdType - the number of cells in \a this mesh.
3365 * \throw If the nodal connectivity of cells is not defined.
3367 mcIdType MEDCouplingUMesh::getNumberOfCells() const
3369 if(_nodal_connec_index)
3370 return _nodal_connec_index->getNumberOfTuples()-1;
3375 throw INTERP_KERNEL::Exception("Unable to get number of cells because no connectivity specified !");
3379 * Returns a dimension of \a this mesh, i.e. a dimension of cells constituting \a this
3380 * mesh. For more info see \ref meshes.
3381 * \return int - the dimension of \a this mesh.
3382 * \throw If the mesh dimension is not defined using setMeshDimension().
3384 int MEDCouplingUMesh::getMeshDimension() const
3387 throw INTERP_KERNEL::Exception("No mesh dimension specified !");
3392 * Returns a length of the nodal connectivity array.
3393 * This method is for test reason. Normally the integer returned is not useable by
3394 * user. For more info see \ref MEDCouplingUMeshNodalConnectivity.
3395 * \return mcIdType - the length of the nodal connectivity array.
3397 mcIdType MEDCouplingUMesh::getNodalConnectivityArrayLen() const
3399 return _nodal_connec->getNbOfElems();
3403 * First step of serialization process. Used by ParaMEDMEM and MEDCouplingCorba to transfert data between process.
3405 void MEDCouplingUMesh::getTinySerializationInformation(std::vector<double>& tinyInfoD, std::vector<mcIdType>& tinyInfo, std::vector<std::string>& littleStrings) const
3407 MEDCouplingPointSet::getTinySerializationInformation(tinyInfoD,tinyInfo,littleStrings);
3408 tinyInfo.push_back(ToIdType(getMeshDimension()));
3409 tinyInfo.push_back(getNumberOfCells());
3411 tinyInfo.push_back(getNodalConnectivityArrayLen());
3413 tinyInfo.push_back(-1);
3417 * First step of unserialization process.
3419 bool MEDCouplingUMesh::isEmptyMesh(const std::vector<mcIdType>& tinyInfo) const
3421 return tinyInfo[6]<=0;
3425 * Second step of serialization process.
3426 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3427 * \param a1 DataArrayDouble
3428 * \param a2 DataArrayDouble
3429 * \param littleStrings string vector
3431 void MEDCouplingUMesh::resizeForUnserialization(const std::vector<mcIdType>& tinyInfo, DataArrayIdType *a1, DataArrayDouble *a2, std::vector<std::string>& littleStrings) const
3433 MEDCouplingPointSet::resizeForUnserialization(tinyInfo,a1,a2,littleStrings);
3435 a1->alloc(tinyInfo[7]+tinyInfo[6]+1,1);
3439 * Third and final step of serialization process.
3441 void MEDCouplingUMesh::serialize(DataArrayIdType *&a1, DataArrayDouble *&a2) const
3443 MEDCouplingPointSet::serialize(a1,a2);
3444 if(getMeshDimension()>-1)
3446 a1=DataArrayIdType::New();
3447 a1->alloc(getNodalConnectivityArrayLen()+getNumberOfCells()+1,1);
3448 mcIdType *ptA1=a1->getPointer();
3449 const mcIdType *conn=getNodalConnectivity()->getConstPointer();
3450 const mcIdType *index=getNodalConnectivityIndex()->getConstPointer();
3451 ptA1=std::copy(index,index+getNumberOfCells()+1,ptA1);
3452 std::copy(conn,conn+getNodalConnectivityArrayLen(),ptA1);
3459 * Second and final unserialization process.
3460 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3462 void MEDCouplingUMesh::unserialization(const std::vector<double>& tinyInfoD, const std::vector<mcIdType>& tinyInfo, const DataArrayIdType *a1, DataArrayDouble *a2, const std::vector<std::string>& littleStrings)
3464 MEDCouplingPointSet::unserialization(tinyInfoD,tinyInfo,a1,a2,littleStrings);
3465 setMeshDimension(FromIdType<int>(tinyInfo[5]));
3469 const mcIdType *recvBuffer=a1->getConstPointer();
3470 MCAuto<DataArrayIdType> myConnecIndex=DataArrayIdType::New();
3471 myConnecIndex->alloc(tinyInfo[6]+1,1);
3472 std::copy(recvBuffer,recvBuffer+tinyInfo[6]+1,myConnecIndex->getPointer());
3473 MCAuto<DataArrayIdType> myConnec=DataArrayIdType::New();
3474 myConnec->alloc(tinyInfo[7],1);
3475 std::copy(recvBuffer+tinyInfo[6]+1,recvBuffer+tinyInfo[6]+1+tinyInfo[7],myConnec->getPointer());
3476 setConnectivity(myConnec, myConnecIndex);
3483 * Returns a new MEDCouplingFieldDouble containing volumes of cells constituting \a this
3485 * For 1D cells, the returned field contains lengths.<br>
3486 * For 2D cells, the returned field contains areas.<br>
3487 * For 3D cells, the returned field contains volumes.
3488 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3489 * orientation, i.e. the volume is always positive.
3490 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on cells
3491 * and one time . The caller is to delete this field using decrRef() as it is no
3494 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureField(bool isAbs) const
3496 std::string name="MeasureOfMesh_";
3498 mcIdType nbelem=getNumberOfCells();
3499 MCAuto<MEDCouplingFieldDouble> field=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3500 field->setName(name);
3501 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3502 array->alloc(nbelem,1);
3503 double *area_vol=array->getPointer();
3504 field->setArray(array) ; array=0;
3505 field->setMesh(const_cast<MEDCouplingUMesh *>(this));
3506 field->synchronizeTimeWithMesh();
3507 if(getMeshDimension()!=-1)
3510 INTERP_KERNEL::NormalizedCellType type;
3511 int dim_space=getSpaceDimension();
3512 const double *coords=getCoords()->getConstPointer();
3513 const mcIdType *connec=getNodalConnectivity()->getConstPointer();
3514 const mcIdType *connec_index=getNodalConnectivityIndex()->getConstPointer();
3515 for(mcIdType iel=0;iel<nbelem;iel++)
3517 ipt=connec_index[iel];
3518 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3519 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);
3522 std::transform(area_vol,area_vol+nbelem,area_vol,[](double c){return fabs(c);});
3526 area_vol[0]=std::numeric_limits<double>::max();
3528 return field.retn();
3532 * Returns a new DataArrayDouble containing volumes of specified cells of \a this
3534 * For 1D cells, the returned array contains lengths.<br>
3535 * For 2D cells, the returned array contains areas.<br>
3536 * For 3D cells, the returned array contains volumes.
3537 * This method avoids building explicitly a part of \a this mesh to perform the work.
3538 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3539 * orientation, i.e. the volume is always positive.
3540 * \param [in] begin - an array of cell ids of interest.
3541 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3542 * \return DataArrayDouble * - a new instance of DataArrayDouble. The caller is to
3543 * delete this array using decrRef() as it is no more needed.
3545 * \if ENABLE_EXAMPLES
3546 * \ref cpp_mcumesh_getPartMeasureField "Here is a C++ example".<br>
3547 * \ref py_mcumesh_getPartMeasureField "Here is a Python example".
3549 * \sa getMeasureField()
3551 DataArrayDouble *MEDCouplingUMesh::getPartMeasureField(bool isAbs, const mcIdType *begin, const mcIdType *end) const
3553 std::string name="PartMeasureOfMesh_";
3555 std::size_t nbelem=std::distance(begin,end);
3556 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3557 array->setName(name);
3558 array->alloc(nbelem,1);
3559 double *area_vol=array->getPointer();
3560 if(getMeshDimension()!=-1)
3563 INTERP_KERNEL::NormalizedCellType type;
3564 int dim_space=getSpaceDimension();
3565 const double *coords=getCoords()->getConstPointer();
3566 const mcIdType *connec=getNodalConnectivity()->getConstPointer();
3567 const mcIdType *connec_index=getNodalConnectivityIndex()->getConstPointer();
3568 for(const mcIdType *iel=begin;iel!=end;iel++)
3570 ipt=connec_index[*iel];
3571 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3572 *area_vol++=INTERP_KERNEL::computeVolSurfOfCell2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,connec+ipt+1,connec_index[*iel+1]-ipt-1,coords,dim_space);
3575 std::transform(array->getPointer(),area_vol,array->getPointer(),[](double c){return fabs(c);});
3579 area_vol[0]=std::numeric_limits<double>::max();
3581 return array.retn();
3585 * Returns a new MEDCouplingFieldDouble containing volumes of cells of a dual mesh of
3586 * \a this one. The returned field contains the dual cell volume for each corresponding
3587 * node in \a this mesh. In other words, the field returns the getMeasureField() of
3588 * the dual mesh in P1 sens of \a this.<br>
3589 * For 1D cells, the returned field contains lengths.<br>
3590 * For 2D cells, the returned field contains areas.<br>
3591 * For 3D cells, the returned field contains volumes.
3592 * This method is useful to check "P1*" conservative interpolators.
3593 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3594 * orientation, i.e. the volume is always positive.
3595 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3596 * nodes and one time. The caller is to delete this array using decrRef() as
3597 * it is no more needed.
3599 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureFieldOnNode(bool isAbs) const
3601 MCAuto<MEDCouplingFieldDouble> tmp=getMeasureField(isAbs);
3602 std::string name="MeasureOnNodeOfMesh_";
3604 mcIdType nbNodes=getNumberOfNodes();
3605 MCAuto<DataArrayDouble> nnpc;
3607 MCAuto<DataArrayIdType> tmp2(computeNbOfNodesPerCell());
3608 nnpc=tmp2->convertToDblArr();
3610 std::for_each(nnpc->rwBegin(),nnpc->rwEnd(),[](double& v) { v=1./v; });
3611 const double *nnpcPtr(nnpc->begin());
3612 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_NODES);
3613 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3614 array->alloc(nbNodes,1);
3615 double *valsToFill=array->getPointer();
3616 std::fill(valsToFill,valsToFill+nbNodes,0.);
3617 const double *values=tmp->getArray()->getConstPointer();
3618 MCAuto<DataArrayIdType> da=DataArrayIdType::New();
3619 MCAuto<DataArrayIdType> daInd=DataArrayIdType::New();
3620 getReverseNodalConnectivity(da,daInd);
3621 const mcIdType *daPtr=da->getConstPointer();
3622 const mcIdType *daIPtr=daInd->getConstPointer();
3623 for(mcIdType i=0;i<nbNodes;i++)
3624 for(const mcIdType *cell=daPtr+daIPtr[i];cell!=daPtr+daIPtr[i+1];cell++)
3625 valsToFill[i]+=nnpcPtr[*cell]*values[*cell];
3627 ret->setArray(array);
3632 * Returns a new MEDCouplingFieldDouble holding normal vectors to cells of \a this
3633 * mesh. The returned normal vectors to each cell have a norm2 equal to 1.
3634 * The computed vectors have <em> this->getMeshDimension()+1 </em> components
3635 * and are normalized.
3636 * <br> \a this can be either
3637 * - a 2D mesh in 2D or 3D space or
3638 * - an 1D mesh in 2D space.
3640 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3641 * cells and one time. The caller is to delete this field using decrRef() as
3642 * it is no more needed.
3643 * \throw If the nodal connectivity of cells is not defined.
3644 * \throw If the coordinates array is not set.
3645 * \throw If the mesh dimension is not set.
3646 * \throw If the mesh and space dimension is not as specified above.
3648 MEDCouplingFieldDouble *MEDCouplingUMesh::buildOrthogonalField() const
3650 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3651 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3652 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3653 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3654 mcIdType nbOfCells=getNumberOfCells();
3655 int nbComp=getMeshDimension()+1;
3656 array->alloc(nbOfCells,nbComp);
3657 double *vals=array->getPointer();
3658 const mcIdType *connI=_nodal_connec_index->getConstPointer();
3659 const mcIdType *conn=_nodal_connec->getConstPointer();
3660 const double *coords=_coords->getConstPointer();
3661 if(getMeshDimension()==2)
3663 if(getSpaceDimension()==3)
3665 MCAuto<DataArrayDouble> loc=computeCellCenterOfMass();
3666 const double *locPtr=loc->getConstPointer();
3667 for(mcIdType i=0;i<nbOfCells;i++,vals+=3)
3669 mcIdType offset=connI[i];
3670 INTERP_KERNEL::crossprod<3>(locPtr+3*i,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3671 double n=INTERP_KERNEL::norm<3>(vals);
3672 std::transform(vals,vals+3,vals,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3677 MCAuto<MEDCouplingFieldDouble> isAbs=getMeasureField(false);
3678 const double *isAbsPtr=isAbs->getArray()->begin();
3679 for(mcIdType i=0;i<nbOfCells;i++,isAbsPtr++)
3680 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=*isAbsPtr>0.?1.:-1.; }
3683 else//meshdimension==1
3686 for(mcIdType i=0;i<nbOfCells;i++)
3688 mcIdType offset=connI[i];
3689 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3690 double n=INTERP_KERNEL::norm<2>(tmp);
3691 std::transform(tmp,tmp+2,tmp,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3696 ret->setArray(array);
3698 ret->synchronizeTimeWithSupport();
3703 * Returns a new MEDCouplingFieldDouble holding normal vectors to specified cells of
3704 * \a this mesh. The computed vectors have <em> this->getMeshDimension()+1 </em> components
3705 * and are normalized.
3706 * <br> \a this can be either
3707 * - a 2D mesh in 2D or 3D space or
3708 * - an 1D mesh in 2D space.
3710 * This method avoids building explicitly a part of \a this mesh to perform the work.
3711 * \param [in] begin - an array of cell ids of interest.
3712 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3713 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3714 * cells and one time. The caller is to delete this field using decrRef() as
3715 * it is no more needed.
3716 * \throw If the nodal connectivity of cells is not defined.
3717 * \throw If the coordinates array is not set.
3718 * \throw If the mesh dimension is not set.
3719 * \throw If the mesh and space dimension is not as specified above.
3720 * \sa buildOrthogonalField()
3722 * \if ENABLE_EXAMPLES
3723 * \ref cpp_mcumesh_buildPartOrthogonalField "Here is a C++ example".<br>
3724 * \ref py_mcumesh_buildPartOrthogonalField "Here is a Python example".
3727 MEDCouplingFieldDouble *MEDCouplingUMesh::buildPartOrthogonalField(const mcIdType *begin, const mcIdType *end) const
3729 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3730 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3731 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3732 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3733 std::size_t nbelems=std::distance(begin,end);
3734 int nbComp=getMeshDimension()+1;
3735 array->alloc(nbelems,nbComp);
3736 double *vals=array->getPointer();
3737 const mcIdType *connI=_nodal_connec_index->getConstPointer();
3738 const mcIdType *conn=_nodal_connec->getConstPointer();
3739 const double *coords=_coords->getConstPointer();
3740 if(getMeshDimension()==2)
3742 if(getSpaceDimension()==3)
3744 MCAuto<DataArrayDouble> loc=getPartBarycenterAndOwner(begin,end);
3745 const double *locPtr=loc->getConstPointer();
3746 for(const mcIdType *i=begin;i!=end;i++,vals+=3,locPtr+=3)
3748 mcIdType offset=connI[*i];
3749 INTERP_KERNEL::crossprod<3>(locPtr,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3750 double n=INTERP_KERNEL::norm<3>(vals);
3751 std::transform(vals,vals+3,vals,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3756 for(std::size_t i=0;i<nbelems;i++)
3757 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=1.; }
3760 else//meshdimension==1
3763 for(const mcIdType *i=begin;i!=end;i++)
3765 mcIdType offset=connI[*i];
3766 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3767 double n=INTERP_KERNEL::norm<2>(tmp);
3768 std::transform(tmp,tmp+2,tmp,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3773 ret->setArray(array);
3775 ret->synchronizeTimeWithSupport();
3780 * Returns a new MEDCouplingFieldDouble holding a direction vector for each SEG2 in \a
3781 * this 1D mesh. The computed vectors have <em> this->getSpaceDimension() </em> components
3782 * and are \b not normalized.
3783 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3784 * cells and one time. The caller is to delete this field using decrRef() as
3785 * it is no more needed.
3786 * \throw If the nodal connectivity of cells is not defined.
3787 * \throw If the coordinates array is not set.
3788 * \throw If \a this->getMeshDimension() != 1.
3789 * \throw If \a this mesh includes cells of type other than SEG2.
3791 MEDCouplingFieldDouble *MEDCouplingUMesh::buildDirectionVectorField() const
3793 if(getMeshDimension()!=1)
3794 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for buildDirectionVectorField !");
3795 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3796 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for buildDirectionVectorField !");
3797 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3798 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3799 mcIdType nbOfCells=getNumberOfCells();
3800 int spaceDim=getSpaceDimension();
3801 array->alloc(nbOfCells,spaceDim);
3802 double *pt=array->getPointer();
3803 const double *coo=getCoords()->getConstPointer();
3804 std::vector<mcIdType> conn;
3806 for(mcIdType i=0;i<nbOfCells;i++)
3809 getNodeIdsOfCell(i,conn);
3810 pt=std::transform(coo+conn[1]*spaceDim,coo+(conn[1]+1)*spaceDim,coo+conn[0]*spaceDim,pt,std::minus<double>());
3812 ret->setArray(array);
3814 ret->synchronizeTimeWithSupport();
3819 * Creates a 2D mesh by cutting \a this 3D mesh with a plane. In addition to the mesh,
3820 * returns a new DataArrayIdType, of length equal to the number of 2D cells in the result
3821 * mesh, holding, for each cell in the result mesh, an id of a 3D cell it comes
3822 * from. If a result face is shared by two 3D cells, then the face in included twice in
3824 * \param [in] origin - 3 components of a point defining location of the plane.
3825 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3826 * must be greater than 1e-6.
3827 * \param [in] eps - half-thickness of the plane.
3828 * \param [out] cellIds - a new instance of DataArrayIdType holding ids of 3D cells
3829 * producing correspondent 2D cells. The caller is to delete this array
3830 * using decrRef() as it is no more needed.
3831 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This mesh does
3832 * not share the node coordinates array with \a this mesh. The caller is to
3833 * delete this mesh using decrRef() as it is no more needed.
3834 * \throw If the coordinates array is not set.
3835 * \throw If the nodal connectivity of cells is not defined.
3836 * \throw If \a this->getMeshDimension() != 3 or \a this->getSpaceDimension() != 3.
3837 * \throw If magnitude of \a vec is less than 1e-6.
3838 * \throw If the plane does not intersect any 3D cell of \a this mesh.
3839 * \throw If \a this includes quadratic cells.
3841 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3D(const double *origin, const double *vec, double eps, DataArrayIdType *&cellIds) const
3843 checkFullyDefined();
3844 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3845 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3846 MCAuto<DataArrayIdType> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3847 if(candidates->empty())
3848 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane considering bounding boxes !");
3849 std::vector<mcIdType> nodes;
3850 DataArrayIdType *cellIds1D=0;
3851 MCAuto<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3852 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3853 MCAuto<DataArrayIdType> desc1=DataArrayIdType::New(),desc2=DataArrayIdType::New();
3854 MCAuto<DataArrayIdType> descIndx1=DataArrayIdType::New(),descIndx2=DataArrayIdType::New();
3855 MCAuto<DataArrayIdType> revDesc1=DataArrayIdType::New(),revDesc2=DataArrayIdType::New();
3856 MCAuto<DataArrayIdType> revDescIndx1=DataArrayIdType::New(),revDescIndx2=DataArrayIdType::New();
3857 MCAuto<MEDCouplingUMesh> mDesc2=subMesh->buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2);//meshDim==2 spaceDim==3
3858 revDesc2=0; revDescIndx2=0;
3859 MCAuto<MEDCouplingUMesh> mDesc1=mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3860 revDesc1=0; revDescIndx1=0;
3861 //Marking all 1D cells that contained at least one node located on the plane
3862 //the intersection between those cells and the plane, which consist of the nodes previously tagged, thus don't need to be computed afterwards
3863 //(if said intersection is computed in MEDCouplingUMesh::split3DCurveWithPlane, then we might create additional nodes
3864 //due to accuracy errors when the needed nodes already exist)
3865 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),false,cellIds1D);
3866 MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3868 std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3869 for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3871 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3872 std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(mDesc2->getNumberOfCells());
3873 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->getConstPointer(),mDesc2->getNodalConnectivityIndex()->getConstPointer(),
3874 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3875 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3876 MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New()),cellIds2(DataArrayIdType::New());
3877 connI->pushBackSilent(0); conn->alloc(0,1); cellIds2->alloc(0,1);
3878 subMesh->assemblyForSplitFrom3DSurf(cut3DSurf,desc2->getConstPointer(),descIndx2->getConstPointer(),conn,connI,cellIds2);
3879 if(cellIds2->empty())
3880 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3881 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3D",2);
3882 ret->setCoords(mDesc1->getCoords());
3883 ret->setConnectivity(conn,connI,true);
3884 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3889 * Creates an 1D mesh by cutting \a this 2D mesh in 3D space with a plane. In
3890 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
3891 from. If a result segment is shared by two 2D cells, then the segment in included twice in
3893 * \param [in] origin - 3 components of a point defining location of the plane.
3894 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3895 * must be greater than 1e-6.
3896 * \param [in] eps - half-thickness of the plane.
3897 * \param [out] cellIds - a new instance of DataArrayIdType holding ids of faces
3898 * producing correspondent segments. The caller is to delete this array
3899 * using decrRef() as it is no more needed.
3900 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This is an 1D
3901 * mesh in 3D space. This mesh does not share the node coordinates array with
3902 * \a this mesh. The caller is to delete this mesh using decrRef() as it is
3904 * \throw If the coordinates array is not set.
3905 * \throw If the nodal connectivity of cells is not defined.
3906 * \throw If \a this->getMeshDimension() != 2 or \a this->getSpaceDimension() != 3.
3907 * \throw If magnitude of \a vec is less than 1e-6.
3908 * \throw If the plane does not intersect any 2D cell of \a this mesh.
3909 * \throw If \a this includes quadratic cells.
3911 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3DSurf(const double *origin, const double *vec, double eps, DataArrayIdType *&cellIds) const
3913 checkFullyDefined();
3914 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
3915 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf works on umeshes with meshdim equal to 2 and spaceDim equal to 3 !");
3916 MCAuto<DataArrayIdType> candidates(getCellIdsCrossingPlane(origin,vec,eps));
3917 if(candidates->empty())
3918 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3D surf cells in this intercepts the specified plane considering bounding boxes !");
3919 std::vector<mcIdType> nodes;
3920 DataArrayIdType *cellIds1D(0);
3921 MCAuto<MEDCouplingUMesh> subMesh(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3922 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3923 MCAuto<DataArrayIdType> desc1(DataArrayIdType::New()),descIndx1(DataArrayIdType::New()),revDesc1(DataArrayIdType::New()),revDescIndx1(DataArrayIdType::New());
3924 MCAuto<MEDCouplingUMesh> mDesc1(subMesh->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3925 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3926 MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3928 std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3929 for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3931 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3932 mcIdType ncellsSub=subMesh->getNumberOfCells();
3933 std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(ncellsSub);
3934 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,subMesh->getNodalConnectivity()->getConstPointer(),subMesh->getNodalConnectivityIndex()->getConstPointer(),
3935 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3936 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3937 MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New()),cellIds2(DataArrayIdType::New()); connI->pushBackSilent(0);
3939 const mcIdType *nodal=subMesh->getNodalConnectivity()->getConstPointer();
3940 const mcIdType *nodalI=subMesh->getNodalConnectivityIndex()->getConstPointer();
3941 for(mcIdType i=0;i<ncellsSub;i++)
3943 if(cut3DSurf[i].first!=-1 && cut3DSurf[i].second!=-1)
3945 if(cut3DSurf[i].first!=-2)
3947 conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_SEG2)); conn->pushBackSilent(cut3DSurf[i].first); conn->pushBackSilent(cut3DSurf[i].second);
3948 connI->pushBackSilent(conn->getNumberOfTuples());
3949 cellIds2->pushBackSilent(i);
3953 mcIdType cellId3DSurf=cut3DSurf[i].second;
3954 mcIdType offset=nodalI[cellId3DSurf]+1;
3955 mcIdType nbOfEdges=nodalI[cellId3DSurf+1]-offset;
3956 for(mcIdType j=0;j<nbOfEdges;j++)
3958 conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_SEG2)); conn->pushBackSilent(nodal[offset+j]); conn->pushBackSilent(nodal[offset+(j+1)%nbOfEdges]);
3959 connI->pushBackSilent(conn->getNumberOfTuples());
3960 cellIds2->pushBackSilent(cellId3DSurf);
3965 if(cellIds2->empty())
3966 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3DSurf cells in this intercepts the specified plane !");
3967 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3DSurf",1);
3968 ret->setCoords(mDesc1->getCoords());
3969 ret->setConnectivity(conn,connI,true);
3970 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3974 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::clipSingle3DCellByPlane(const double origin[3], const double vec[3], double eps) const
3976 checkFullyDefined();
3977 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3978 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3979 if(getNumberOfCells()!=1)
3980 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works only on mesh containing exactly one cell !");
3982 std::vector<mcIdType> nodes;
3983 findNodesOnPlane(origin,vec,eps,nodes);
3984 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());
3985 MCAuto<MEDCouplingUMesh> mDesc2(buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2));//meshDim==2 spaceDim==3
3986 revDesc2=0; revDescIndx2=0;
3987 MCAuto<MEDCouplingUMesh> mDesc1(mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3988 revDesc1=0; revDescIndx1=0;
3989 DataArrayIdType *cellIds1D(0);
3990 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3991 MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3992 std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3993 for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3997 mcIdType oldNbNodes(mDesc1->getNumberOfNodes());
3998 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3999 sameNbNodes=(mDesc1->getNumberOfNodes()==oldNbNodes);
4001 std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(mDesc2->getNumberOfCells());
4002 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->begin(),mDesc2->getNodalConnectivityIndex()->begin(),
4003 mDesc1->getNodalConnectivity()->begin(),mDesc1->getNodalConnectivityIndex()->begin(),
4004 desc1->begin(),descIndx1->begin(),cut3DSurf);
4005 MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New());
4006 connI->pushBackSilent(0); conn->alloc(0,1);
4008 MCAuto<DataArrayIdType> cellIds2(DataArrayIdType::New()); cellIds2->alloc(0,1);
4009 assemblyForSplitFrom3DSurf(cut3DSurf,desc2->begin(),descIndx2->begin(),conn,connI,cellIds2);
4010 if(cellIds2->empty())
4011 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
4013 std::vector<std::vector<mcIdType> > res;
4014 buildSubCellsFromCut(cut3DSurf,desc2->begin(),descIndx2->begin(),mDesc1->getCoords()->begin(),eps,res);
4015 std::size_t sz(res.size());
4016 if(ToIdType(res.size())==mDesc1->getNumberOfCells() && sameNbNodes)
4017 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane : cell is not clipped !");
4018 for(std::size_t i=0;i<sz;i++)
4020 conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYGON));
4021 conn->insertAtTheEnd(res[i].begin(),res[i].end());
4022 connI->pushBackSilent(conn->getNumberOfTuples());
4024 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
4025 ret->setCoords(mDesc1->getCoords());
4026 ret->setConnectivity(conn,connI,true);
4027 mcIdType nbCellsRet(ret->getNumberOfCells());
4029 MCAuto<DataArrayDouble> vec2(DataArrayDouble::New()); vec2->alloc(1,3); std::copy(vec,vec+3,vec2->getPointer());
4030 MCAuto<MEDCouplingFieldDouble> ortho(ret->buildOrthogonalField());
4031 MCAuto<DataArrayDouble> ortho2(ortho->getArray()->selectByTupleIdSafeSlice(0,1,1));
4032 MCAuto<DataArrayDouble> dott(DataArrayDouble::Dot(ortho2,vec2));
4033 MCAuto<DataArrayDouble> ccm(ret->computeCellCenterOfMass());
4034 MCAuto<DataArrayDouble> occm;
4036 MCAuto<DataArrayDouble> pt(DataArrayDouble::New()); pt->alloc(1,3); std::copy(origin,origin+3,pt->getPointer());
4037 occm=DataArrayDouble::Substract(ccm,pt);
4039 vec2=DataArrayDouble::New(); vec2->alloc(nbCellsRet,3);
4040 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);
4041 MCAuto<DataArrayDouble> dott2(DataArrayDouble::Dot(occm,vec2));
4043 const mcIdType *cPtr(ret->getNodalConnectivity()->begin()),*ciPtr(ret->getNodalConnectivityIndex()->begin());
4044 MCAuto<MEDCouplingUMesh> ret2(MEDCouplingUMesh::New("Clip3D",3));
4045 ret2->setCoords(mDesc1->getCoords());
4046 MCAuto<DataArrayIdType> conn2(DataArrayIdType::New()),conn2I(DataArrayIdType::New());
4047 conn2I->pushBackSilent(0); conn2->alloc(0,1);
4048 std::vector<mcIdType> cell0(1,ToIdType(INTERP_KERNEL::NORM_POLYHED));
4049 std::vector<mcIdType> cell1(1,ToIdType(INTERP_KERNEL::NORM_POLYHED));
4050 if(dott->getIJ(0,0)>0)
4052 cell0.insert(cell0.end(),cPtr+1,cPtr+ciPtr[1]);
4053 std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell1,cell1.end()));
4057 cell1.insert(cell1.end(),cPtr+1,cPtr+ciPtr[1]);
4058 std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell0,cell0.end()));
4060 for(mcIdType i=1;i<nbCellsRet;i++)
4062 if(dott2->getIJ(i,0)<0)
4064 if(ciPtr[i+1]-ciPtr[i]>=4)
4066 cell0.push_back(-1);
4067 cell0.insert(cell0.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
4072 if(ciPtr[i+1]-ciPtr[i]>=4)
4074 cell1.push_back(-1);
4075 cell1.insert(cell1.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
4079 conn2->insertAtTheEnd(cell0.begin(),cell0.end());
4080 conn2I->pushBackSilent(conn2->getNumberOfTuples());
4081 conn2->insertAtTheEnd(cell1.begin(),cell1.end());
4082 conn2I->pushBackSilent(conn2->getNumberOfTuples());
4083 ret2->setConnectivity(conn2,conn2I,true);
4084 ret2->checkConsistencyLight();
4085 ret2->orientCorrectlyPolyhedrons();
4090 * Finds cells whose bounding boxes intersect a given plane.
4091 * \param [in] origin - 3 components of a point defining location of the plane.
4092 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
4093 * must be greater than 1e-6.
4094 * \param [in] eps - half-thickness of the plane.
4095 * \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of the found
4096 * cells. The caller is to delete this array using decrRef() as it is no more
4098 * \throw If the coordinates array is not set.
4099 * \throw If the nodal connectivity of cells is not defined.
4100 * \throw If \a this->getSpaceDimension() != 3.
4101 * \throw If magnitude of \a vec is less than 1e-6.
4102 * \sa buildSlice3D()
4104 DataArrayIdType *MEDCouplingUMesh::getCellIdsCrossingPlane(const double *origin, const double *vec, double eps) const
4106 checkFullyDefined();
4107 if(getSpaceDimension()!=3)
4108 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with spaceDim equal to 3 !");
4109 double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
4111 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellIdsCrossingPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
4113 vec2[0]=vec[1]; vec2[1]=-vec[0]; vec2[2]=0.;//vec2 is the result of cross product of vec with (0,0,1)
4114 double angle=acos(vec[2]/normm);
4115 MCAuto<DataArrayIdType> cellIds;
4119 MCAuto<DataArrayDouble> coo=_coords->deepCopy();
4120 double normm2(sqrt(vec2[0]*vec2[0]+vec2[1]*vec2[1]+vec2[2]*vec2[2]));
4121 if(normm2/normm>1e-6)
4122 DataArrayDouble::Rotate3DAlg(origin,vec2,angle,coo->getNumberOfTuples(),coo->getPointer(),coo->getPointer());
4123 MCAuto<MEDCouplingUMesh> mw=clone(false);//false -> shallow copy
4125 mw->getBoundingBox(bbox);
4126 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
4127 cellIds=mw->getCellsInBoundingBox(bbox,eps);
4131 getBoundingBox(bbox);
4132 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
4133 cellIds=getCellsInBoundingBox(bbox,eps);
4135 return cellIds.retn();
4139 * This method checks that \a this is a contiguous mesh. The user is expected to call this method on a mesh with meshdim==1.
4140 * If not an exception will thrown. If this is an empty mesh with no cell an exception will be thrown too.
4141 * No consideration of coordinate is done by this method.
4142 * 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)
4143 * If not false is returned. In case that false is returned a call to MEDCoupling::MEDCouplingUMesh::mergeNodes could be useful.
4145 bool MEDCouplingUMesh::isContiguous1D() const
4147 if(getMeshDimension()!=1)
4148 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense only for 1D mesh !");
4149 mcIdType nbCells=getNumberOfCells();
4151 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense for non empty mesh !");
4152 const mcIdType *connI(_nodal_connec_index->begin()),*conn(_nodal_connec->begin());
4153 mcIdType ref=conn[connI[0]+2];
4154 for(mcIdType i=1;i<nbCells;i++)
4156 if(conn[connI[i]+1]!=ref)
4158 ref=conn[connI[i]+2];
4164 * This method is only callable on mesh with meshdim == 1 containing only SEG2 and spaceDim==3.
4165 * This method projects this on the 3D line defined by (pt,v). This methods first checks that all SEG2 are along v vector.
4166 * \param pt reference point of the line
4167 * \param v normalized director vector of the line
4168 * \param eps max precision before throwing an exception
4169 * \param res output of size this->getNumberOfCells
4171 void MEDCouplingUMesh::project1D(const double *pt, const double *v, double eps, double *res) const
4173 if(getMeshDimension()!=1)
4174 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for project1D !");
4175 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
4176 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for project1D !");
4177 if(getSpaceDimension()!=3)
4178 throw INTERP_KERNEL::Exception("Expected a umesh with spaceDim==3 for project1D !");
4179 MCAuto<MEDCouplingFieldDouble> f=buildDirectionVectorField();
4180 const double *fPtr=f->getArray()->getConstPointer();
4182 for(mcIdType i=0;i<getNumberOfCells();i++)
4184 const double *tmp1=fPtr+3*i;
4185 tmp[0]=tmp1[1]*v[2]-tmp1[2]*v[1];
4186 tmp[1]=tmp1[2]*v[0]-tmp1[0]*v[2];
4187 tmp[2]=tmp1[0]*v[1]-tmp1[1]*v[0];
4188 double n1=INTERP_KERNEL::norm<3>(tmp);
4189 n1/=INTERP_KERNEL::norm<3>(tmp1);
4191 throw INTERP_KERNEL::Exception("UMesh::Projection 1D failed !");
4193 const double *coo=getCoords()->getConstPointer();
4194 for(mcIdType i=0;i<getNumberOfNodes();i++)
4196 std::transform(coo+i*3,coo+i*3+3,pt,tmp,std::minus<double>());
4197 std::transform(tmp,tmp+3,v,tmp,std::multiplies<double>());
4198 res[i]=std::accumulate(tmp,tmp+3,0.);
4203 * 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.
4204 * \a this is expected to be a mesh so that its space dimension is equal to its
4205 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4206 * 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).
4208 * 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
4209 * 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).
4210 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4212 * So this method is more accurate (so, more costly) than simply searching for the closest point in \a this.
4213 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4215 * \param [in] ptBg the start pointer (included) of the coordinates of the point
4216 * \param [in] ptEnd the end pointer (not included) of the coordinates of the point
4217 * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4218 * \return the positive value of the distance.
4219 * \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
4221 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoints
4223 double MEDCouplingUMesh::distanceToPoint(const double *ptBg, const double *ptEnd, mcIdType& cellId) const
4225 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4226 if(meshDim!=spaceDim-1)
4227 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint works only for spaceDim=meshDim+1 !");
4228 if(meshDim!=2 && meshDim!=1)
4229 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint : only mesh dimension 2 and 1 are implemented !");
4230 checkFullyDefined();
4231 if(ToIdType(std::distance(ptBg,ptEnd))!=spaceDim)
4232 { 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()); }
4233 DataArrayIdType *ret1=0;
4234 MCAuto<DataArrayDouble> pts=DataArrayDouble::New(); pts->useArray(ptBg,false,DeallocType::C_DEALLOC,1,spaceDim);
4235 MCAuto<DataArrayDouble> ret0=distanceToPoints(pts,ret1);
4236 MCAuto<DataArrayIdType> ret1Safe(ret1);
4237 cellId=*ret1Safe->begin();
4238 return *ret0->begin();
4242 * This method computes the distance from each point of points serie \a pts (stored in a DataArrayDouble in which each tuple represents a point)
4243 * to \a this and the first \a cellId in \a this corresponding to the returned distance.
4244 * 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
4245 * 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).
4246 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4248 * \a this is expected to be a mesh so that its space dimension is equal to its
4249 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4250 * 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).
4252 * So this method is more accurate (so, more costly) than simply searching for each point in \a pts the closest point in \a this.
4253 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4255 * \param [in] pts the list of points in which each tuple represents a point
4256 * \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.
4257 * \return a newly allocated object to be dealed by the caller that tells for each point in \a pts the distance to \a this.
4258 * \throw if number of components of \a pts is not equal to the space dimension.
4259 * \throw if mesh dimension of \a this is not equal to space dimension - 1.
4260 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoint
4262 DataArrayDouble *MEDCouplingUMesh::distanceToPoints(const DataArrayDouble *pts, DataArrayIdType *& cellIds) const
4265 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : input points pointer is NULL !");
4266 pts->checkAllocated();
4267 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4268 if(meshDim!=spaceDim-1)
4269 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints works only for spaceDim=meshDim+1 !");
4270 if(meshDim!=2 && meshDim!=1)
4271 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only mesh dimension 2 and 1 are implemented !");
4272 if(ToIdType(pts->getNumberOfComponents())!=spaceDim)
4274 std::ostringstream oss; oss << "MEDCouplingUMesh::distanceToPoints : input pts DataArrayDouble has " << pts->getNumberOfComponents() << " components whereas it should be equal to " << spaceDim << " (mesh spaceDimension) !";
4275 throw INTERP_KERNEL::Exception(oss.str());
4277 checkFullyDefined();
4278 mcIdType nbCells=getNumberOfCells();
4280 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : no cells in this !");
4281 mcIdType nbOfPts=pts->getNumberOfTuples();
4282 MCAuto<DataArrayDouble> ret0=DataArrayDouble::New(); ret0->alloc(nbOfPts,1);
4283 MCAuto<DataArrayIdType> ret1=DataArrayIdType::New(); ret1->alloc(nbOfPts,1);
4284 const mcIdType *nc=_nodal_connec->begin(),*ncI=_nodal_connec_index->begin(); const double *coords=_coords->begin();
4285 double *ret0Ptr=ret0->getPointer(); mcIdType *ret1Ptr=ret1->getPointer(); const double *ptsPtr=pts->begin();
4286 MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree());
4287 const double *bbox(bboxArr->begin());
4292 BBTreeDst<3> myTree(bbox,0,0,nbCells);
4293 for(mcIdType i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=3)
4295 double x=std::numeric_limits<double>::max();
4296 std::vector<mcIdType> elems;
4297 myTree.getMinDistanceOfMax(ptsPtr,x);
4298 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4299 DistanceToPoint3DSurfAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4305 BBTreeDst<2> myTree(bbox,0,0,nbCells);
4306 for(mcIdType i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=2)
4308 double x=std::numeric_limits<double>::max();
4309 std::vector<mcIdType> elems;
4310 myTree.getMinDistanceOfMax(ptsPtr,x);
4311 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4312 DistanceToPoint2DCurveAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4317 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only spacedim 2 and 3 supported !");
4319 cellIds=ret1.retn();
4328 * Finds cells in contact with a ball (i.e. a point with precision).
4329 * 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.
4330 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4332 * \warning This method is suitable if the caller intends to evaluate only one
4333 * point, for more points getCellsContainingPoints() is recommended as it is
4335 * \param [in] pos - array of coordinates of the ball central point.
4336 * \param [in] eps - ball radius.
4337 * \return mcIdType - a smallest id of cells being in contact with the ball, -1 in case
4338 * if there are no such cells.
4339 * \throw If the coordinates array is not set.
4340 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4342 mcIdType MEDCouplingUMesh::getCellContainingPoint(const double *pos, double eps) const
4344 std::vector<mcIdType> elts;
4345 getCellsContainingPoint(pos,eps,elts);
4348 return elts.front();
4352 * Finds cells in contact with a ball (i.e. a point with precision).
4353 * 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.
4354 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4355 * \warning This method is suitable if the caller intends to evaluate only one
4356 * point, for more points getCellsContainingPoints() is recommended as it is
4358 * \param [in] pos - array of coordinates of the ball central point.
4359 * \param [in] eps - ball radius (i.e. the precision) relative to max dimension along X, Y or Z of the the considered cell bounding box.
4360 * \param [out] elts - vector returning ids of the found cells. It is cleared
4361 * before inserting ids.
4362 * \throw If the coordinates array is not set.
4363 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4365 * \if ENABLE_EXAMPLES
4366 * \ref cpp_mcumesh_getCellsContainingPoint "Here is a C++ example".<br>
4367 * \ref py_mcumesh_getCellsContainingPoint "Here is a Python example".
4370 void MEDCouplingUMesh::getCellsContainingPoint(const double *pos, double eps, std::vector<mcIdType>& elts) const
4372 MCAuto<DataArrayIdType> eltsUg,eltsIndexUg;
4373 getCellsContainingPoints(pos,1,eps,eltsUg,eltsIndexUg);
4374 elts.clear(); elts.insert(elts.end(),eltsUg->begin(),eltsUg->end());
4377 void MEDCouplingUMesh::getCellsContainingPointsZeAlg(const double *pos, mcIdType nbOfPoints, double eps,
4378 MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex,
4379 std::function<bool(INTERP_KERNEL::NormalizedCellType,mcIdType)> sensibilityTo2DQuadraticLinearCellsFunc) const
4381 int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
4386 const double *coords=_coords->getConstPointer();
4387 getCellsContainingPointsAlg<3>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4390 throw INTERP_KERNEL::Exception("For spaceDim==3 only meshDim==3 implemented for getelementscontainingpoints !");
4392 else if(spaceDim==2)
4396 const double *coords=_coords->getConstPointer();
4397 getCellsContainingPointsAlg<2>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4400 throw INTERP_KERNEL::Exception("For spaceDim==2 only meshDim==2 implemented for getelementscontainingpoints !");
4402 else if(spaceDim==1)
4406 const double *coords=_coords->getConstPointer();
4407 getCellsContainingPointsAlg<1>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4410 throw INTERP_KERNEL::Exception("For spaceDim==1 only meshDim==1 implemented for getelementscontainingpoints !");
4413 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPoints : not managed for mdim not in [1,2,3] !");
4417 * Finds cells in contact with several balls (i.e. points with precision).
4418 * This method is an extension of getCellContainingPoint() and
4419 * getCellsContainingPoint() for the case of multiple points.
4420 * 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.
4421 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4422 * \param [in] pos - an array of coordinates of points in full interlace mode :
4423 * X0,Y0,Z0,X1,Y1,Z1,... Size of the array must be \a
4424 * this->getSpaceDimension() * \a nbOfPoints
4425 * \param [in] nbOfPoints - number of points to locate within \a this mesh.
4426 * \param [in] eps - ball radius (i.e. the precision) relative to max dimension along X, Y or Z of the the considered cell bounding box.
4427 * \param [out] elts - vector returning ids of found cells.
4428 * \param [out] eltsIndex - an array, of length \a nbOfPoints + 1,
4429 * dividing cell ids in \a elts into groups each referring to one
4430 * point. Its every element (except the last one) is an index pointing to the
4431 * first id of a group of cells. For example cells in contact with the *i*-th
4432 * point are described by following range of indices:
4433 * [ \a eltsIndex[ *i* ], \a eltsIndex[ *i*+1 ] ) and the cell ids are
4434 * \a elts[ \a eltsIndex[ *i* ]], \a elts[ \a eltsIndex[ *i* ] + 1 ], ...
4435 * Number of cells in contact with the *i*-th point is
4436 * \a eltsIndex[ *i*+1 ] - \a eltsIndex[ *i* ].
4437 * \throw If the coordinates array is not set.
4438 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4440 * \if ENABLE_EXAMPLES
4441 * \ref cpp_mcumesh_getCellsContainingPoints "Here is a C++ example".<br>
4442 * \ref py_mcumesh_getCellsContainingPoints "Here is a Python example".
4445 void MEDCouplingUMesh::getCellsContainingPoints(const double *pos, mcIdType nbOfPoints, double eps,
4446 MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex) const
4448 auto yesImSensibleTo2DQuadraticLinearCellsFunc([](INTERP_KERNEL::NormalizedCellType ct, int mdim) { return INTERP_KERNEL::CellModel::GetCellModel(ct).isQuadratic() && mdim == 2; } );
4449 this->getCellsContainingPointsZeAlg(pos,nbOfPoints,eps,elts,eltsIndex,yesImSensibleTo2DQuadraticLinearCellsFunc);
4453 * Behaves like MEDCouplingMesh::getCellsContainingPoints for cells in \a this that are linear.
4454 * For quadratic cells in \a this, this method behaves by just considering linear part of cells.
4455 * This method is here only for backward compatibility (interpolation GaussPoints to GaussPoints).
4457 * \sa MEDCouplingUMesh::getCellsContainingPoints, MEDCouplingRemapper::prepareNotInterpKernelOnlyGaussGauss
4459 void MEDCouplingUMesh::getCellsContainingPointsLinearPartOnlyOnNonDynType(const double *pos, mcIdType nbOfPoints, double eps, MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex) const
4461 auto noImNotSensibleTo2DQuadraticLinearCellsFunc([](INTERP_KERNEL::NormalizedCellType,mcIdType) { return false; } );
4462 this->getCellsContainingPointsZeAlg(pos,nbOfPoints,eps,elts,eltsIndex,noImNotSensibleTo2DQuadraticLinearCellsFunc);
4466 * Finds butterfly cells in \a this mesh. A 2D cell is considered to be butterfly if at
4467 * least two its edges intersect each other anywhere except their extremities. An
4468 * INTERP_KERNEL::NORM_NORI3 cell can \b not be butterfly.
4469 * \param [in,out] cells - a vector returning ids of the found cells. It is not
4470 * cleared before filling in.
4471 * \param [in] eps - precision.
4472 * \throw If \a this->getMeshDimension() != 2.
4473 * \throw If \a this->getSpaceDimension() != 2 && \a this->getSpaceDimension() != 3.
4475 void MEDCouplingUMesh::checkButterflyCells(std::vector<mcIdType>& cells, double eps) const
4477 const char msg[]="Butterfly detection work only for 2D cells with spaceDim==2 or 3!";
4478 if(getMeshDimension()!=2)
4479 throw INTERP_KERNEL::Exception(msg);
4480 int spaceDim=getSpaceDimension();
4481 if(spaceDim!=2 && spaceDim!=3)
4482 throw INTERP_KERNEL::Exception(msg);
4483 const mcIdType *conn=_nodal_connec->getConstPointer();
4484 const mcIdType *connI=_nodal_connec_index->getConstPointer();
4485 mcIdType nbOfCells=getNumberOfCells();
4486 std::vector<double> cell2DinS2;
4487 for(mcIdType i=0;i<nbOfCells;i++)
4489 mcIdType offset=connI[i];
4490 mcIdType nbOfNodesForCell=connI[i+1]-offset-1;
4491 if(nbOfNodesForCell<=3)
4493 bool isQuad=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[offset]).isQuadratic();
4494 project2DCellOnXY(conn+offset+1,conn+connI[i+1],cell2DinS2);
4495 if(isButterfly2DCell(cell2DinS2,isQuad,eps))
4502 * This method is typically requested to unbutterfly 2D linear cells in \b this.
4504 * 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.
4505 * 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.
4507 * For each 2D linear cell in \b this, this method builds the convex envelop (or the convex hull) of the current cell.
4508 * This convex envelop is computed using Jarvis march algorithm.
4509 * The coordinates and the number of cells of \b this remain unchanged on invocation of this method.
4510 * 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)
4511 * 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.
4513 * \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.
4514 * \sa MEDCouplingUMesh::colinearize2D
4516 DataArrayIdType *MEDCouplingUMesh::convexEnvelop2D()
4518 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
4519 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convexEnvelop2D works only for meshDim=2 and spaceDim=2 !");
4520 checkFullyDefined();
4521 const double *coords=getCoords()->getConstPointer();
4522 mcIdType nbOfCells=getNumberOfCells();
4523 MCAuto<DataArrayIdType> nodalConnecIndexOut=DataArrayIdType::New();
4524 nodalConnecIndexOut->alloc(nbOfCells+1,1);
4525 MCAuto<DataArrayIdType> nodalConnecOut(DataArrayIdType::New());
4526 mcIdType *workIndexOut=nodalConnecIndexOut->getPointer();
4528 const mcIdType *nodalConnecIn=_nodal_connec->getConstPointer();
4529 const mcIdType *nodalConnecIndexIn=_nodal_connec_index->getConstPointer();
4530 std::set<INTERP_KERNEL::NormalizedCellType> types;
4531 MCAuto<DataArrayIdType> isChanged(DataArrayIdType::New());
4532 isChanged->alloc(0,1);
4533 for(mcIdType i=0;i<nbOfCells;i++,workIndexOut++)
4535 mcIdType pos=nodalConnecOut->getNumberOfTuples();
4536 if(BuildConvexEnvelopOf2DCellJarvis(coords,nodalConnecIn+nodalConnecIndexIn[i],nodalConnecIn+nodalConnecIndexIn[i+1],nodalConnecOut))
4537 isChanged->pushBackSilent(i);
4538 types.insert((INTERP_KERNEL::NormalizedCellType)nodalConnecOut->getIJ(pos,0));
4539 workIndexOut[1]=nodalConnecOut->getNumberOfTuples();
4541 if(isChanged->empty())
4543 setConnectivity(nodalConnecOut,nodalConnecIndexOut,false);
4545 return isChanged.retn();
4549 * This method is \b NOT const because it can modify \a this.
4550 * \a this is expected to be an unstructured mesh with meshDim==2 and spaceDim==3. If not an exception will be thrown.
4551 * \param mesh1D is an unstructured mesh with MeshDim==1 and spaceDim==3. If not an exception will be thrown.
4552 * \param policy specifies the type of extrusion chosen:
4553 * - \b 0 for translation only (most simple): the cells of the 1D mesh represent the vectors along which the 2D mesh
4554 * will be repeated to build each level
4555 * - \b 1 for translation and rotation: the translation is done as above. For each level, an arc of circle is fitted on
4556 * 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
4557 * 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
4559 * \return an unstructured mesh with meshDim==3 and spaceDim==3. The returned mesh has the same coords than \a this.
4561 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMesh(const MEDCouplingUMesh *mesh1D, int policy)
4563 checkFullyDefined();
4564 mesh1D->checkFullyDefined();
4565 if(!mesh1D->isContiguous1D())
4566 throw INTERP_KERNEL::Exception("buildExtrudedMesh : 1D mesh passed in parameter is not contiguous !");
4567 if(getSpaceDimension()!=mesh1D->getSpaceDimension())
4568 throw INTERP_KERNEL::Exception("Invalid call to buildExtrudedMesh this and mesh1D must have same space dimension !");
4569 if((getMeshDimension()!=2 || getSpaceDimension()!=3) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
4570 throw INTERP_KERNEL::Exception("Invalid 'this' for buildExtrudedMesh method : must be (meshDim==2 and spaceDim==3) or (meshDim==1 and spaceDim==2) !");
4571 if(mesh1D->getMeshDimension()!=1)
4572 throw INTERP_KERNEL::Exception("Invalid 'mesh1D' for buildExtrudedMesh method : must be meshDim==1 !");
4574 if(isPresenceOfQuadratic())
4576 if(mesh1D->isFullyQuadratic())
4579 throw INTERP_KERNEL::Exception("Invalid 2D mesh and 1D mesh because 2D mesh has quadratic cells and 1D is not fully quadratic !");
4581 mcIdType oldNbOfNodes(getNumberOfNodes());
4582 MCAuto<DataArrayDouble> newCoords;
4587 newCoords=fillExtCoordsUsingTranslation(mesh1D,isQuad);
4592 newCoords=fillExtCoordsUsingTranslAndAutoRotation(mesh1D,isQuad);
4596 throw INTERP_KERNEL::Exception("Not implemented extrusion policy : must be in (0) !");
4598 setCoords(newCoords);
4599 MCAuto<MEDCouplingUMesh> ret(buildExtrudedMeshFromThisLowLev(oldNbOfNodes,isQuad));
4606 * Checks if \a this mesh is constituted by only quadratic cells.
4607 * \return bool - \c true if there are only quadratic cells in \a this mesh.
4608 * \throw If the coordinates array is not set.
4609 * \throw If the nodal connectivity of cells is not defined.
4611 bool MEDCouplingUMesh::isFullyQuadratic() const
4613 checkFullyDefined();
4615 mcIdType nbOfCells=getNumberOfCells();
4616 for(mcIdType i=0;i<nbOfCells && ret;i++)
4618 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4619 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4620 ret=cm.isQuadratic();
4626 * Checks if \a this mesh includes any quadratic cell.
4627 * \return bool - \c true if there is at least one quadratic cells in \a this mesh.
4628 * \throw If the coordinates array is not set.
4629 * \throw If the nodal connectivity of cells is not defined.
4631 bool MEDCouplingUMesh::isPresenceOfQuadratic() const
4633 checkFullyDefined();
4635 mcIdType nbOfCells=getNumberOfCells();
4636 for(mcIdType i=0;i<nbOfCells && !ret;i++)
4638 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4639 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4640 ret=cm.isQuadratic();
4646 * Converts all quadratic cells to linear ones. If there are no quadratic cells in \a
4647 * this mesh, it remains unchanged.
4648 * \throw If the coordinates array is not set.
4649 * \throw If the nodal connectivity of cells is not defined.
4651 void MEDCouplingUMesh::convertQuadraticCellsToLinear()
4653 checkFullyDefined();
4654 mcIdType nbOfCells=getNumberOfCells();
4656 const mcIdType *iciptr=_nodal_connec_index->begin();
4657 for(mcIdType i=0;i<nbOfCells;i++)
4659 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4660 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4661 if(cm.isQuadratic())
4663 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4664 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4665 if(!cml.isDynamic())
4666 delta+=cm.getNumberOfNodes()-cml.getNumberOfNodes();
4668 delta+=(iciptr[i+1]-iciptr[i]-1)/2;
4673 MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()),newConnI(DataArrayIdType::New());
4674 const mcIdType *icptr(_nodal_connec->begin());
4675 newConn->alloc(getNodalConnectivityArrayLen()-delta,1);
4676 newConnI->alloc(nbOfCells+1,1);
4677 mcIdType *ocptr(newConn->getPointer()),*ociptr(newConnI->getPointer());
4680 for(mcIdType i=0;i<nbOfCells;i++,ociptr++)
4682 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)icptr[iciptr[i]];
4683 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4684 if(!cm.isQuadratic())
4686 _types.insert(type);
4687 ocptr=std::copy(icptr+iciptr[i],icptr+iciptr[i+1],ocptr);
4688 ociptr[1]=ociptr[0]+iciptr[i+1]-iciptr[i];
4692 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4693 _types.insert(typel);
4694 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4695 mcIdType newNbOfNodes=cml.getNumberOfNodes();
4697 newNbOfNodes=(iciptr[i+1]-iciptr[i]-1)/2;
4698 *ocptr++=ToIdType(typel);
4699 ocptr=std::copy(icptr+iciptr[i]+1,icptr+iciptr[i]+newNbOfNodes+1,ocptr);
4700 ociptr[1]=ociptr[0]+newNbOfNodes+1;
4703 setConnectivity(newConn,newConnI,false);
4707 * This method converts all linear cell in \a this to quadratic one.
4708 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, here it is needed to specify the target
4709 * 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)
4710 * 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.
4711 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, the coordinates in \a this can be become bigger. All created nodes will be put at the
4712 * end of the existing coordinates.
4714 * \param [in] conversionType specifies the type of conversion expected. Only 0 (default) and 1 are supported presently. 0 those that creates the 'most' simple
4715 * corresponding quadratic cells. 1 is those creating the 'most' complex.
4716 * \return a newly created DataArrayIdType instance that the caller should deal with containing cell ids of converted cells.
4718 * \throw if \a this is not fully defined. It throws too if \a conversionType is not in [0,1].
4720 * \sa MEDCouplingUMesh::convertQuadraticCellsToLinear
4722 DataArrayIdType *MEDCouplingUMesh::convertLinearCellsToQuadratic(int conversionType)
4724 DataArrayIdType *conn=0,*connI=0;
4725 DataArrayDouble *coords=0;
4726 std::set<INTERP_KERNEL::NormalizedCellType> types;
4727 checkFullyDefined();
4728 MCAuto<DataArrayIdType> ret,connSafe,connISafe;
4729 MCAuto<DataArrayDouble> coordsSafe;
4730 int meshDim=getMeshDimension();
4731 switch(conversionType)
4737 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);
4738 connSafe=conn; connISafe=connI; coordsSafe=coords;
4741 ret=convertLinearCellsToQuadratic2D0(conn,connI,coords,types);
4742 connSafe=conn; connISafe=connI; coordsSafe=coords;
4745 ret=convertLinearCellsToQuadratic3D0(conn,connI,coords,types);
4746 connSafe=conn; connISafe=connI; coordsSafe=coords;
4749 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 0 mesh dimensions available are [1,2,3] !");
4757 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);//it is not a bug. In 1D policy 0 and 1 are equals
4758 connSafe=conn; connISafe=connI; coordsSafe=coords;
4761 ret=convertLinearCellsToQuadratic2D1(conn,connI,coords,types);
4762 connSafe=conn; connISafe=connI; coordsSafe=coords;
4765 ret=convertLinearCellsToQuadratic3D1(conn,connI,coords,types);
4766 connSafe=conn; connISafe=connI; coordsSafe=coords;
4769 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 1 mesh dimensions available are [1,2,3] !");
4774 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion type available are 0 (default, the simplest) and 1 (the most complex) !");
4776 setConnectivity(connSafe,connISafe,false);
4778 setCoords(coordsSafe);
4783 * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
4784 * so that the number of cells remains the same. Quadratic faces are converted to
4785 * polygons. This method works only for 2D meshes in
4786 * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
4787 * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
4788 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
4789 * \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
4790 * a polylinized edge constituting the input polygon.
4791 * \throw If the coordinates array is not set.
4792 * \throw If the nodal connectivity of cells is not defined.
4793 * \throw If \a this->getMeshDimension() != 2.
4794 * \throw If \a this->getSpaceDimension() != 2.
4796 void MEDCouplingUMesh::tessellate2D(double eps)
4798 int meshDim(getMeshDimension()),spaceDim(getSpaceDimension());
4800 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : works only with space dimension equal to 2 !");
4804 return tessellate2DCurveInternal(eps);
4806 return tessellate2DInternal(eps);
4808 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : mesh dimension must be in [1,2] !");
4814 * This method only works if \a this has spaceDimension equal to 2 and meshDimension also equal to 2.
4815 * This method allows to modify connectivity of cells in \a this that shares some edges in \a edgeIdsToBeSplit.
4816 * The nodes to be added in those 2D cells are defined by the pair of \a nodeIdsToAdd and \a nodeIdsIndexToAdd.
4817 * Length of \a nodeIdsIndexToAdd is expected to equal to length of \a edgeIdsToBeSplit + 1.
4818 * The node ids in \a nodeIdsToAdd should be valid. Those nodes have to be sorted exactly following exactly the direction of the edge.
4819 * This method can be seen as the opposite method of colinearize2D.
4820 * 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
4821 * to avoid to modify the numbering of existing nodes.
4823 * \param [in] nodeIdsToAdd - the list of node ids to be added (\a nodeIdsIndexToAdd array allows to walk on this array)
4824 * \param [in] nodeIdsIndexToAdd - the entry point of \a nodeIdsToAdd to point to the corresponding nodes to be added.
4825 * \param [in] mesh1Desc - 1st output of buildDescendingConnectivity2 on \a this.
4826 * \param [in] desc - 2nd output of buildDescendingConnectivity2 on \a this.
4827 * \param [in] descI - 3rd output of buildDescendingConnectivity2 on \a this.
4828 * \param [in] revDesc - 4th output of buildDescendingConnectivity2 on \a this.
4829 * \param [in] revDescI - 5th output of buildDescendingConnectivity2 on \a this.
4831 * \sa buildDescendingConnectivity2
4833 void MEDCouplingUMesh::splitSomeEdgesOf2DMesh(const DataArrayIdType *nodeIdsToAdd, const DataArrayIdType *nodeIdsIndexToAdd, const DataArrayIdType *edgeIdsToBeSplit,
4834 const MEDCouplingUMesh *mesh1Desc, const DataArrayIdType *desc, const DataArrayIdType *descI, const DataArrayIdType *revDesc, const DataArrayIdType *revDescI)
4836 if(!nodeIdsToAdd || !nodeIdsIndexToAdd || !edgeIdsToBeSplit || !mesh1Desc || !desc || !descI || !revDesc || !revDescI)
4837 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : input pointers must be not NULL !");
4838 nodeIdsToAdd->checkAllocated(); nodeIdsIndexToAdd->checkAllocated(); edgeIdsToBeSplit->checkAllocated(); desc->checkAllocated(); descI->checkAllocated(); revDesc->checkAllocated(); revDescI->checkAllocated();
4839 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
4840 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : this must have spacedim=meshdim=2 !");
4841 if(mesh1Desc->getSpaceDimension()!=2 || mesh1Desc->getMeshDimension()!=1)
4842 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : mesh1Desc must be the explosion of this with spaceDim=2 and meshDim = 1 !");
4843 //DataArrayIdType *out0(0),*outi0(0);
4844 //MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
4845 //MCAuto<DataArrayIdType> out0s(out0),outi0s(outi0);
4846 //out0s=out0s->buildUnique(); out0s->sort(true);
4852 * Divides every cell of \a this mesh into simplices (triangles in 2D and tetrahedra in 3D).
4853 * In addition, returns an array mapping new cells to old ones. <br>
4854 * This method typically increases the number of cells in \a this mesh
4855 * but the number of nodes remains \b unchanged.
4856 * That's why the 3D splitting policies
4857 * INTERP_KERNEL::GENERAL_24 and INTERP_KERNEL::GENERAL_48 are not available here.
4858 * \param [in] policy - specifies a pattern used for splitting.
4859 * The semantic of \a policy is:
4860 * - 0 - to split QUAD4 by cutting it along 0-2 diagonal (for 2D mesh only).
4861 * - 1 - to split QUAD4 by cutting it along 1-3 diagonal (for 2D mesh only).
4862 * - INTERP_KERNEL::PLANAR_FACE_5 - to split HEXA8 into 5 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4863 * - INTERP_KERNEL::PLANAR_FACE_6 - to split HEXA8 into 6 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4866 * \return DataArrayIdType * - a new instance of DataArrayIdType holding, for each new cell,
4867 * an id of old cell producing it. The caller is to delete this array using
4868 * decrRef() as it is no more needed.
4870 * \throw If \a policy is 0 or 1 and \a this->getMeshDimension() != 2.
4871 * \throw If \a policy is INTERP_KERNEL::PLANAR_FACE_5 or INTERP_KERNEL::PLANAR_FACE_6
4872 * and \a this->getMeshDimension() != 3.
4873 * \throw If \a policy is not one of the four discussed above.
4874 * \throw If the nodal connectivity of cells is not defined.
4875 * \sa MEDCouplingUMesh::tetrahedrize, MEDCoupling1SGTUMesh::sortHexa8EachOther
4877 DataArrayIdType *MEDCouplingUMesh::simplexize(int policy)
4882 return simplexizePol0();
4884 return simplexizePol1();
4885 case INTERP_KERNEL::PLANAR_FACE_5:
4886 return simplexizePlanarFace5();
4887 case INTERP_KERNEL::PLANAR_FACE_6:
4888 return simplexizePlanarFace6();
4890 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)");
4895 * Checks if \a this mesh is constituted by simplex cells only. Simplex cells are:
4896 * - 1D: INTERP_KERNEL::NORM_SEG2
4897 * - 2D: INTERP_KERNEL::NORM_TRI3
4898 * - 3D: INTERP_KERNEL::NORM_TETRA4.
4900 * This method is useful for users that need to use P1 field services as
4901 * MEDCouplingFieldDouble::getValueOn(), MEDCouplingField::buildMeasureField() etc.
4902 * All these methods need mesh support containing only simplex cells.
4903 * \return bool - \c true if there are only simplex cells in \a this mesh.
4904 * \throw If the coordinates array is not set.
4905 * \throw If the nodal connectivity of cells is not defined.
4906 * \throw If \a this->getMeshDimension() < 1.
4908 bool MEDCouplingUMesh::areOnlySimplexCells() const
4910 checkFullyDefined();
4911 int mdim=getMeshDimension();
4912 if(mdim<1 || mdim>3)
4913 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::areOnlySimplexCells : only available with meshes having a meshdim 1, 2 or 3 !");
4914 mcIdType nbCells=getNumberOfCells();
4915 const mcIdType *conn=_nodal_connec->begin();
4916 const mcIdType *connI=_nodal_connec_index->begin();
4917 for(mcIdType i=0;i<nbCells;i++)
4919 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4929 * Converts degenerated 2D or 3D linear cells of \a this mesh into cells of simpler
4930 * type. For example an INTERP_KERNEL::NORM_QUAD4 cell having only three unique nodes in
4931 * its connectivity is transformed into an INTERP_KERNEL::NORM_TRI3 cell.
4932 * Quadratic cells in 2D are also handled. In those cells edges where start=end=midpoint are removed.
4933 * This method does \b not perform geometrical checks and checks only nodal connectivity of cells,
4934 * so it can be useful to call mergeNodes() before calling this method.
4935 * \throw If \a this->getMeshDimension() <= 1.
4936 * \throw If the coordinates array is not set.
4937 * \throw If the nodal connectivity of cells is not defined.
4939 void MEDCouplingUMesh::convertDegeneratedCells()
4941 checkFullyDefined();
4942 if(getMeshDimension()<=1)
4943 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4944 mcIdType nbOfCells=getNumberOfCells();
4947 mcIdType initMeshLgth=getNodalConnectivityArrayLen();
4948 mcIdType *conn=_nodal_connec->getPointer();
4949 mcIdType *index=_nodal_connec_index->getPointer();
4950 mcIdType posOfCurCell=0;
4952 mcIdType lgthOfCurCell;
4953 for(mcIdType i=0;i<nbOfCells;i++)
4955 lgthOfCurCell=index[i+1]-posOfCurCell;
4956 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4958 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
4959 conn+newPos+1,newLgth);
4960 conn[newPos]=newType;
4962 posOfCurCell=index[i+1];
4965 if(newPos!=initMeshLgth)
4966 _nodal_connec->reAlloc(newPos);
4971 * Same as MEDCouplingUMesh::convertDegeneratedCells() plus deletion of the flat cells.
4972 * A cell is flat in the following cases:
4973 * - for a linear cell, all points in the connectivity are equal
4974 * - for a quadratic cell, either the above, or a quadratic polygon with two (linear) points and two
4975 * identical quadratic points
4976 * \return a new instance of DataArrayIdType holding ids of removed cells. The caller is to delete
4977 * this array using decrRef() as it is no more needed.
4979 DataArrayIdType *MEDCouplingUMesh::convertDegeneratedCellsAndRemoveFlatOnes()
4981 checkFullyDefined();
4982 if(getMeshDimension()<=1)
4983 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4984 mcIdType nbOfCells=getNumberOfCells();
4985 MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(0,1);
4988 mcIdType initMeshLgth=getNodalConnectivityArrayLen();
4989 mcIdType *conn=_nodal_connec->getPointer();
4990 mcIdType *index=_nodal_connec_index->getPointer();
4991 mcIdType posOfCurCell=0;
4993 mcIdType lgthOfCurCell, nbDelCells(0);
4994 for(mcIdType i=0;i<nbOfCells;i++)
4996 lgthOfCurCell=index[i+1]-posOfCurCell;
4997 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4999 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
5000 conn+newPos+1,newLgth);
5001 // Shall we delete the cell if it is completely degenerated:
5002 bool delCell=INTERP_KERNEL::CellSimplify::isFlatCell(conn, newPos, newLgth, newType);
5006 ret->pushBackSilent(i);
5008 else //if the cell is to be deleted, simply stay at the same place
5010 conn[newPos]=newType;
5013 posOfCurCell=index[i+1];
5014 index[i+1-nbDelCells]=newPos;
5016 if(newPos!=initMeshLgth)
5017 _nodal_connec->reAlloc(newPos);
5018 const mcIdType nCellDel=ret->getNumberOfTuples();
5020 _nodal_connec_index->reAlloc(nbOfCells-nCellDel+1);
5026 * This method remove null 1D cells from \a this. A 1D cell is considered null if start node is equal to end node.
5027 * Only connectivity is considered here.
5029 bool MEDCouplingUMesh::removeDegenerated1DCells()
5031 checkConnectivityFullyDefined();
5032 if(getMeshDimension()!=1)
5033 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::removeDegenerated1DCells works on umeshes with meshdim equals to 1 !");
5034 std::size_t nbCells(getNumberOfCells()),newSize(0),newSize2(0);
5035 const mcIdType *conn(getNodalConnectivity()->begin()),*conni(getNodalConnectivityIndex()->begin());
5037 for(std::size_t i=0;i<nbCells;i++)
5039 INTERP_KERNEL::NormalizedCellType ct((INTERP_KERNEL::NormalizedCellType)conn[conni[i]]);
5040 if(ct==INTERP_KERNEL::NORM_SEG2 || ct==INTERP_KERNEL::NORM_SEG3)
5042 if(conn[conni[i]+1]!=conn[conni[i]+2])
5045 newSize2+=conni[i+1]-conni[i];
5050 std::ostringstream oss; oss << "MEDCouplingUMesh::removeDegenerated1DCells : cell #" << i << " in this is not of type SEG2/SEG3 !";
5051 throw INTERP_KERNEL::Exception(oss.str());
5055 if(newSize==nbCells)//no cells has been removed -> do nothing
5057 MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()),newConnI(DataArrayIdType::New()); newConnI->alloc(newSize+1,1); newConn->alloc(newSize2,1);
5058 mcIdType *newConnPtr(newConn->getPointer()),*newConnIPtr(newConnI->getPointer()); newConnIPtr[0]=0;
5059 for(std::size_t i=0;i<nbCells;i++)
5061 if(conn[conni[i]+1]!=conn[conni[i]+2])
5063 newConnIPtr[1]=newConnIPtr[0]+conni[i+1]-conni[i];
5064 newConnPtr=std::copy(conn+conni[i],conn+conni[i+1],newConnPtr);
5068 setConnectivity(newConn,newConnI,true);
5073 * Finds incorrectly oriented cells of this 2D mesh in 3D space.
5074 * A cell is considered to be oriented correctly if an angle between its
5075 * normal vector and a 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 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
5081 * is not cleared before filling in.
5082 * \throw If \a this->getMeshDimension() != 2.
5083 * \throw If \a this->getSpaceDimension() != 3.
5085 * \if ENABLE_EXAMPLES
5086 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
5087 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
5090 void MEDCouplingUMesh::are2DCellsNotCorrectlyOriented(const double *vec, bool polyOnly, std::vector<mcIdType>& cells) const
5092 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
5093 throw INTERP_KERNEL::Exception("Invalid mesh to apply are2DCellsNotCorrectlyOriented on it : must be meshDim==2 and spaceDim==3 !");
5094 mcIdType nbOfCells=getNumberOfCells();
5095 const mcIdType *conn=_nodal_connec->begin();
5096 const mcIdType *connI=_nodal_connec_index->begin();
5097 const double *coordsPtr=_coords->begin();
5098 for(mcIdType i=0;i<nbOfCells;i++)
5100 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5101 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
5103 bool isQuadratic=INTERP_KERNEL::CellModel::GetCellModel(type).isQuadratic();
5104 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5111 * Reverse connectivity of 2D cells whose orientation is not correct. A cell is
5112 * considered to be oriented correctly if an angle between its normal vector and a
5113 * given vector is less than \c PI / \c 2.
5114 * \param [in] vec - 3 components of the vector specifying the correct orientation of
5116 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
5118 * \throw If \a this->getMeshDimension() != 2.
5119 * \throw If \a this->getSpaceDimension() != 3.
5121 * \if ENABLE_EXAMPLES
5122 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
5123 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
5126 * \sa changeOrientationOfCells
5128 void MEDCouplingUMesh::orientCorrectly2DCells(const double *vec, bool polyOnly)
5130 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
5131 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectly2DCells on it : must be meshDim==2 and spaceDim==3 !");
5132 mcIdType nbOfCells=getNumberOfCells();
5133 mcIdType *conn(_nodal_connec->getPointer());
5134 const mcIdType *connI(_nodal_connec_index->begin());
5135 const double *coordsPtr(_coords->begin());
5136 bool isModified(false);
5137 for(mcIdType i=0;i<nbOfCells;i++)
5139 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5140 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
5142 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
5143 bool isQuadratic(cm.isQuadratic());
5144 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5147 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
5152 _nodal_connec->declareAsNew();
5157 * This method change the orientation of cells in \a this without any consideration of coordinates. Only connectivity is impacted.
5159 * \sa orientCorrectly2DCells
5161 void MEDCouplingUMesh::changeOrientationOfCells()
5163 int mdim(getMeshDimension());
5164 if(mdim!=2 && mdim!=1)
5165 throw INTERP_KERNEL::Exception("Invalid mesh to apply changeOrientationOfCells on it : must be meshDim==2 or meshDim==1 !");
5166 mcIdType nbOfCells=getNumberOfCells();
5167 mcIdType *conn(_nodal_connec->getPointer());
5168 const mcIdType *connI(_nodal_connec_index->begin());
5171 for(mcIdType i=0;i<nbOfCells;i++)
5173 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5174 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
5175 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
5180 for(mcIdType i=0;i<nbOfCells;i++)
5182 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5183 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
5184 cm.changeOrientationOf1D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
5190 * Finds incorrectly oriented polyhedral cells, i.e. polyhedrons having correctly
5191 * oriented facets. The normal vector of the facet should point out of the cell.
5192 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
5193 * is not cleared before filling in.
5194 * \throw If \a this->getMeshDimension() != 3.
5195 * \throw If \a this->getSpaceDimension() != 3.
5196 * \throw If the coordinates array is not set.
5197 * \throw If the nodal connectivity of cells is not defined.
5199 * \if ENABLE_EXAMPLES
5200 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
5201 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
5204 void MEDCouplingUMesh::arePolyhedronsNotCorrectlyOriented(std::vector<mcIdType>& cells) const
5206 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
5207 throw INTERP_KERNEL::Exception("Invalid mesh to apply arePolyhedronsNotCorrectlyOriented on it : must be meshDim==3 and spaceDim==3 !");
5208 mcIdType nbOfCells=getNumberOfCells();
5209 const mcIdType *conn=_nodal_connec->begin();
5210 const mcIdType *connI=_nodal_connec_index->begin();
5211 const double *coordsPtr=_coords->begin();
5212 for(mcIdType i=0;i<nbOfCells;i++)
5214 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5215 if(type==INTERP_KERNEL::NORM_POLYHED)
5217 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5224 * Tries to fix connectivity of polyhedra, so that normal vector of all facets to point
5226 * \throw If \a this->getMeshDimension() != 3.
5227 * \throw If \a this->getSpaceDimension() != 3.
5228 * \throw If the coordinates array is not set.
5229 * \throw If the nodal connectivity of cells is not defined.
5230 * \throw If the reparation fails.
5232 * \if ENABLE_EXAMPLES
5233 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
5234 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
5236 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
5238 void MEDCouplingUMesh::orientCorrectlyPolyhedrons()
5240 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
5241 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectlyPolyhedrons on it : must be meshDim==3 and spaceDim==3 !");
5242 mcIdType nbOfCells=getNumberOfCells();
5243 mcIdType *conn=_nodal_connec->getPointer();
5244 const mcIdType *connI=_nodal_connec_index->begin();
5245 const double *coordsPtr=_coords->begin();
5246 for(mcIdType i=0;i<nbOfCells;i++)
5248 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5249 if(type==INTERP_KERNEL::NORM_POLYHED)
5253 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5254 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
5256 catch(INTERP_KERNEL::Exception& e)
5258 std::ostringstream oss; oss << "Something wrong in polyhedron #" << i << " : " << e.what();
5259 throw INTERP_KERNEL::Exception(oss.str());
5267 * This method invert orientation of all cells in \a this.
5268 * After calling this method the absolute value of measure of cells in \a this are the same than before calling.
5269 * This method only operates on the connectivity so coordinates are not touched at all.
5271 void MEDCouplingUMesh::invertOrientationOfAllCells()
5273 checkConnectivityFullyDefined();
5274 std::set<INTERP_KERNEL::NormalizedCellType> gts(getAllGeoTypes());
5275 mcIdType *conn(_nodal_connec->getPointer());
5276 const mcIdType *conni(_nodal_connec_index->begin());
5277 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator gt=gts.begin();gt!=gts.end();gt++)
5279 INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::OrientationInverter> oi(INTERP_KERNEL::OrientationInverter::BuildInstanceFrom(*gt));
5280 MCAuto<DataArrayIdType> cwt(giveCellsWithType(*gt));
5281 for(const mcIdType *it=cwt->begin();it!=cwt->end();it++)
5282 oi->operate(conn+conni[*it]+1,conn+conni[*it+1]);
5288 * Finds and fixes incorrectly oriented linear extruded volumes (INTERP_KERNEL::NORM_HEXA8,
5289 * INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXGP12 etc) to respect the MED convention
5290 * according to which the first facet of the cell should be oriented to have the normal vector
5291 * pointing out of cell.
5292 * \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of fixed
5293 * cells. The caller is to delete this array using decrRef() as it is no more
5295 * \throw If \a this->getMeshDimension() != 3.
5296 * \throw If \a this->getSpaceDimension() != 3.
5297 * \throw If the coordinates array is not set.
5298 * \throw If the nodal connectivity of cells is not defined.
5300 * \if ENABLE_EXAMPLES
5301 * \ref cpp_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a C++ example".<br>
5302 * \ref py_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a Python example".
5304 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
5306 DataArrayIdType *MEDCouplingUMesh::findAndCorrectBadOriented3DExtrudedCells()
5308 const char msg[]="check3DCellsWellOriented detection works only for 3D cells !";
5309 if(getMeshDimension()!=3)
5310 throw INTERP_KERNEL::Exception(msg);
5311 int spaceDim=getSpaceDimension();
5313 throw INTERP_KERNEL::Exception(msg);
5315 mcIdType nbOfCells=getNumberOfCells();
5316 mcIdType *conn=_nodal_connec->getPointer();
5317 const mcIdType *connI=_nodal_connec_index->begin();
5318 const double *coo=getCoords()->begin();
5319 MCAuto<DataArrayIdType> cells(DataArrayIdType::New()); cells->alloc(0,1);
5320 for(mcIdType i=0;i<nbOfCells;i++)
5322 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5323 if(cm.isExtruded() && !cm.isDynamic() && !cm.isQuadratic())
5325 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coo))
5327 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
5328 cells->pushBackSilent(i);
5332 return cells.retn();
5336 * This method is a faster method to correct orientation of all 3D cells in \a this.
5337 * 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.
5338 * This method makes the hypothesis that \a this a coherent that is to say MEDCouplingUMesh::checkConsistency should throw no exception.
5340 * \return a newly allocated mcIdType array with one components containing cell ids renumbered to fit the convention of MED (MED file and MEDCoupling)
5341 * \sa MEDCouplingUMesh::orientCorrectlyPolyhedrons,
5343 DataArrayIdType *MEDCouplingUMesh::findAndCorrectBadOriented3DCells()
5345 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
5346 throw INTERP_KERNEL::Exception("Invalid mesh to apply findAndCorrectBadOriented3DCells on it : must be meshDim==3 and spaceDim==3 !");
5347 mcIdType nbOfCells=getNumberOfCells();
5348 mcIdType *conn=_nodal_connec->getPointer();
5349 const mcIdType *connI=_nodal_connec_index->begin();
5350 const double *coordsPtr=_coords->begin();
5351 MCAuto<DataArrayIdType> ret=DataArrayIdType::New(); ret->alloc(0,1);
5352 for(mcIdType i=0;i<nbOfCells;i++)
5354 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5357 case INTERP_KERNEL::NORM_TETRA4:
5359 if(!IsTetra4WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5361 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+3));
5362 ret->pushBackSilent(i);
5366 case INTERP_KERNEL::NORM_PYRA5:
5368 if(!IsPyra5WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5370 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+4));
5371 ret->pushBackSilent(i);
5375 case INTERP_KERNEL::NORM_PENTA6:
5376 case INTERP_KERNEL::NORM_HEXA8:
5377 case INTERP_KERNEL::NORM_HEXGP12:
5379 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5381 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
5382 ret->pushBackSilent(i);
5386 case INTERP_KERNEL::NORM_POLYHED:
5388 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5390 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
5391 ret->pushBackSilent(i);
5396 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 !");
5404 * This method has a sense for meshes with spaceDim==3 and meshDim==2.
5405 * If it is not the case an exception will be thrown.
5406 * This method is fast because the first cell of \a this is used to compute the plane.
5407 * \param vec output of size at least 3 used to store the normal vector (with norm equal to Area ) of searched plane.
5408 * \param pos output of size at least 3 used to store a point owned of searched plane.
5410 void MEDCouplingUMesh::getFastAveragePlaneOfThis(double *vec, double *pos) const
5412 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
5413 throw INTERP_KERNEL::Exception("Invalid mesh to apply getFastAveragePlaneOfThis on it : must be meshDim==2 and spaceDim==3 !");
5414 const mcIdType *conn=_nodal_connec->begin();
5415 const mcIdType *connI=_nodal_connec_index->begin();
5416 const double *coordsPtr=_coords->begin();
5417 INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(conn+1,connI[1]-connI[0]-1,coordsPtr,vec);
5418 std::copy(coordsPtr+3*conn[1],coordsPtr+3*conn[1]+3,pos);
5422 * Creates a new MEDCouplingFieldDouble holding Edge Ratio values of all
5423 * cells. Currently cells of the following types are treated:
5424 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5425 * For a cell of other type an exception is thrown.
5426 * Space dimension of a 2D mesh can be either 2 or 3.
5427 * The Edge Ratio of a cell \f$t\f$ is:
5428 * \f$\frac{|t|_\infty}{|t|_0}\f$,
5429 * where \f$|t|_\infty\f$ and \f$|t|_0\f$ respectively denote the greatest and
5430 * the smallest edge lengths of \f$t\f$.
5431 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5432 * cells and one time, lying on \a this mesh. The caller is to delete this
5433 * field using decrRef() as it is no more needed.
5434 * \throw If the coordinates array is not set.
5435 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5436 * \throw If the connectivity data array has more than one component.
5437 * \throw If the connectivity data array has a named component.
5438 * \throw If the connectivity index data array has more than one component.
5439 * \throw If the connectivity index data array has a named component.
5440 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
5441 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5442 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5444 MEDCouplingFieldDouble *MEDCouplingUMesh::getEdgeRatioField() const
5446 checkConsistencyLight();
5447 int spaceDim=getSpaceDimension();
5448 int meshDim=getMeshDimension();
5449 if(spaceDim!=2 && spaceDim!=3)
5450 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : SpaceDimension must be equal to 2 or 3 !");
5451 if(meshDim!=2 && meshDim!=3)
5452 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : MeshDimension must be equal to 2 or 3 !");
5453 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5455 mcIdType nbOfCells=getNumberOfCells();
5456 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5457 arr->alloc(nbOfCells,1);
5458 double *pt=arr->getPointer();
5459 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5460 const mcIdType *conn=_nodal_connec->begin();
5461 const mcIdType *connI=_nodal_connec_index->begin();
5462 const double *coo=_coords->begin();
5464 for(mcIdType i=0;i<nbOfCells;i++,pt++)
5466 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5469 case INTERP_KERNEL::NORM_TRI3:
5471 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5472 *pt=INTERP_KERNEL::triEdgeRatio(tmp);
5475 case INTERP_KERNEL::NORM_QUAD4:
5477 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5478 *pt=INTERP_KERNEL::quadEdgeRatio(tmp);
5481 case INTERP_KERNEL::NORM_TETRA4:
5483 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5484 *pt=INTERP_KERNEL::tetraEdgeRatio(tmp);
5488 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5490 conn+=connI[i+1]-connI[i];
5492 ret->setName("EdgeRatio");
5493 ret->synchronizeTimeWithSupport();
5498 * Creates a new MEDCouplingFieldDouble holding Aspect Ratio values of all
5499 * cells. Currently cells of the following types are treated:
5500 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5501 * For a cell of other type an exception is thrown.
5502 * Space dimension of a 2D mesh can be either 2 or 3.
5503 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5504 * cells and one time, lying on \a this mesh. The caller is to delete this
5505 * field using decrRef() as it is no more needed.
5506 * \throw If the coordinates array is not set.
5507 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5508 * \throw If the connectivity data array has more than one component.
5509 * \throw If the connectivity data array has a named component.
5510 * \throw If the connectivity index data array has more than one component.
5511 * \throw If the connectivity index data array has a named component.
5512 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
5513 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5514 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5516 MEDCouplingFieldDouble *MEDCouplingUMesh::getAspectRatioField() const
5518 checkConsistencyLight();
5519 int spaceDim=getSpaceDimension();
5520 int meshDim=getMeshDimension();
5521 if(spaceDim!=2 && spaceDim!=3)
5522 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : SpaceDimension must be equal to 2 or 3 !");
5523 if(meshDim!=2 && meshDim!=3)
5524 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : MeshDimension must be equal to 2 or 3 !");
5525 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5527 mcIdType nbOfCells=getNumberOfCells();
5528 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5529 arr->alloc(nbOfCells,1);
5530 double *pt=arr->getPointer();
5531 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5532 const mcIdType *conn=_nodal_connec->begin();
5533 const mcIdType *connI=_nodal_connec_index->begin();
5534 const double *coo=_coords->begin();
5536 for(mcIdType i=0;i<nbOfCells;i++,pt++)
5538 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5541 case INTERP_KERNEL::NORM_TRI3:
5543 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5544 *pt=INTERP_KERNEL::triAspectRatio(tmp);
5547 case INTERP_KERNEL::NORM_QUAD4:
5549 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5550 *pt=INTERP_KERNEL::quadAspectRatio(tmp);
5553 case INTERP_KERNEL::NORM_TETRA4:
5555 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5556 *pt=INTERP_KERNEL::tetraAspectRatio(tmp);
5560 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5562 conn+=connI[i+1]-connI[i];
5564 ret->setName("AspectRatio");
5565 ret->synchronizeTimeWithSupport();
5570 * Creates a new MEDCouplingFieldDouble holding Warping factor values of all
5571 * cells of \a this 2D mesh in 3D space. It is a measure of the "planarity" of 2D cell
5572 * in 3D space. Currently only cells of the following types are
5573 * treated: INTERP_KERNEL::NORM_QUAD4.
5574 * For a cell of other type an exception is thrown.
5575 * The warp field is computed as follows: let (a,b,c,d) be the points of the quad.
5577 * \f$t=\vec{da}\times\vec{ab}\f$,
5578 * \f$u=\vec{ab}\times\vec{bc}\f$
5579 * \f$v=\vec{bc}\times\vec{cd}\f$
5580 * \f$w=\vec{cd}\times\vec{da}\f$, the warp is defined as \f$W^3\f$ with
5582 * W=min(\frac{t}{|t|}\cdot\frac{v}{|v|}, \frac{u}{|u|}\cdot\frac{w}{|w|})
5584 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5585 * cells and one time, lying on \a this mesh. The caller is to delete this
5586 * field using decrRef() as it is no more needed.
5587 * \throw If the coordinates array is not set.
5588 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5589 * \throw If the connectivity data array has more than one component.
5590 * \throw If the connectivity data array has a named component.
5591 * \throw If the connectivity index data array has more than one component.
5592 * \throw If the connectivity index data array has a named component.
5593 * \throw If \a this->getMeshDimension() != 2.
5594 * \throw If \a this->getSpaceDimension() != 3.
5595 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5597 MEDCouplingFieldDouble *MEDCouplingUMesh::getWarpField() const
5599 checkConsistencyLight();
5600 int spaceDim=getSpaceDimension();
5601 int meshDim=getMeshDimension();
5603 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : SpaceDimension must be equal to 3 !");
5605 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : MeshDimension must be equal to 2 !");
5606 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5608 mcIdType nbOfCells=getNumberOfCells();
5609 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5610 arr->alloc(nbOfCells,1);
5611 double *pt=arr->getPointer();
5612 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5613 const mcIdType *conn=_nodal_connec->begin();
5614 const mcIdType *connI=_nodal_connec_index->begin();
5615 const double *coo=_coords->begin();
5617 for(mcIdType i=0;i<nbOfCells;i++,pt++)
5619 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5622 case INTERP_KERNEL::NORM_QUAD4:
5624 FillInCompact3DMode(3,4,conn+1,coo,tmp);
5625 *pt=INTERP_KERNEL::quadWarp(tmp);
5629 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : A cell with not manged type (NORM_QUAD4) has been detected !");
5631 conn+=connI[i+1]-connI[i];
5633 ret->setName("Warp");
5634 ret->synchronizeTimeWithSupport();
5640 * Creates a new MEDCouplingFieldDouble holding Skew factor values of all
5641 * cells of \a this 2D mesh in 3D space. Currently cells of the following types are
5642 * treated: INTERP_KERNEL::NORM_QUAD4.
5643 * The skew is computed as follow for a quad with points (a,b,c,d): let
5644 * \f$u=\vec{ab}+\vec{dc}\f$ and \f$v=\vec{ac}+\vec{bd}\f$
5645 * then the skew is computed as:
5647 * s=\frac{u}{|u|}\cdot\frac{v}{|v|}
5650 * For a cell of other type an exception is thrown.
5651 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5652 * cells and one time, lying on \a this mesh. The caller is to delete this
5653 * field using decrRef() as it is no more needed.
5654 * \throw If the coordinates array is not set.
5655 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5656 * \throw If the connectivity data array has more than one component.
5657 * \throw If the connectivity data array has a named component.
5658 * \throw If the connectivity index data array has more than one component.
5659 * \throw If the connectivity index data array has a named component.
5660 * \throw If \a this->getMeshDimension() != 2.
5661 * \throw If \a this->getSpaceDimension() != 3.
5662 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5664 MEDCouplingFieldDouble *MEDCouplingUMesh::getSkewField() const
5666 checkConsistencyLight();
5667 int spaceDim=getSpaceDimension();
5668 int meshDim=getMeshDimension();
5670 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : SpaceDimension must be equal to 3 !");
5672 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : MeshDimension must be equal to 2 !");
5673 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5675 mcIdType nbOfCells=getNumberOfCells();
5676 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5677 arr->alloc(nbOfCells,1);
5678 double *pt=arr->getPointer();
5679 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5680 const mcIdType *conn=_nodal_connec->begin();
5681 const mcIdType *connI=_nodal_connec_index->begin();
5682 const double *coo=_coords->begin();
5684 for(mcIdType i=0;i<nbOfCells;i++,pt++)
5686 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5689 case INTERP_KERNEL::NORM_QUAD4:
5691 FillInCompact3DMode(3,4,conn+1,coo,tmp);
5692 *pt=INTERP_KERNEL::quadSkew(tmp);
5696 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : A cell with not manged type (NORM_QUAD4) has been detected !");
5698 conn+=connI[i+1]-connI[i];
5700 ret->setName("Skew");
5701 ret->synchronizeTimeWithSupport();
5706 * 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.
5708 * \return a new instance of field containing the result. The returned instance has to be deallocated by the caller.
5710 * \sa getSkewField, getWarpField, getAspectRatioField, getEdgeRatioField
5712 MEDCouplingFieldDouble *MEDCouplingUMesh::computeDiameterField() const
5714 checkConsistencyLight();
5715 MCAuto<MEDCouplingFieldDouble> ret(MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME));
5717 std::set<INTERP_KERNEL::NormalizedCellType> types;
5718 ComputeAllTypesInternal(types,_nodal_connec,_nodal_connec_index);
5719 int spaceDim(getSpaceDimension());
5720 mcIdType nbCells(getNumberOfCells());
5721 MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
5722 arr->alloc(nbCells,1);
5723 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++)
5725 INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::DiameterCalculator> dc(INTERP_KERNEL::CellModel::GetCellModel(*it).buildInstanceOfDiameterCalulator(spaceDim));
5726 MCAuto<DataArrayIdType> cellIds(giveCellsWithType(*it));
5727 dc->computeForListOfCellIdsUMeshFrmt(cellIds->begin(),cellIds->end(),_nodal_connec_index->begin(),_nodal_connec->begin(),getCoords()->begin(),arr->getPointer());
5730 ret->setName("Diameter");
5735 * This method aggregate the bbox of each cell and put it into bbox parameter (xmin,xmax,ymin,ymax,zmin,zmax).
5737 * \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)
5738 * For all other cases this input parameter is ignored.
5739 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5741 * \throw If \a this is not fully set (coordinates and connectivity).
5742 * \throw If a cell in \a this has no valid nodeId.
5743 * \sa MEDCouplingUMesh::getBoundingBoxForBBTreeFast, MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5745 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree(double arcDetEps) const
5747 int mDim(getMeshDimension()),sDim(getSpaceDimension());
5748 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.
5749 return getBoundingBoxForBBTreeFast();
5750 if((mDim==2 && sDim==2) || (mDim==1 && sDim==2))
5752 bool presenceOfQuadratic(false);
5753 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=_types.begin();it!=_types.end();it++)
5755 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(*it));
5756 if(cm.isQuadratic())
5757 presenceOfQuadratic=true;
5759 if(!presenceOfQuadratic)
5760 return getBoundingBoxForBBTreeFast();
5761 if(mDim==2 && sDim==2)
5762 return getBoundingBoxForBBTree2DQuadratic(arcDetEps);
5764 return getBoundingBoxForBBTree1DQuadratic(arcDetEps);
5766 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) !");
5770 * This method aggregate the bbox of each cell only considering the nodes constituting each cell and put it into bbox parameter.
5771 * So meshes having quadratic cells the computed bounding boxes can be invalid !
5773 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5775 * \throw If \a this is not fully set (coordinates and connectivity).
5776 * \throw If a cell in \a this has no valid nodeId.
5778 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTreeFast() const
5780 checkFullyDefined();
5781 int spaceDim(getSpaceDimension());
5782 mcIdType nbOfCells(getNumberOfCells()), nbOfNodes(getNumberOfNodes());
5783 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5784 double *bbox(ret->getPointer());
5785 for(mcIdType i=0;i<nbOfCells*spaceDim;i++)
5787 bbox[2*i]=std::numeric_limits<double>::max();
5788 bbox[2*i+1]=-std::numeric_limits<double>::max();
5790 const double *coordsPtr(_coords->begin());
5791 const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5792 for(mcIdType i=0;i<nbOfCells;i++)
5794 mcIdType offset=connI[i]+1;
5795 mcIdType nbOfNodesForCell(connI[i+1]-offset),kk(0);
5796 for(mcIdType j=0;j<nbOfNodesForCell;j++)
5798 mcIdType nodeId=conn[offset+j];
5799 if(nodeId>=0 && nodeId<nbOfNodes)
5801 for(int k=0;k<spaceDim;k++)
5803 bbox[2*spaceDim*i+2*k]=std::min(bbox[2*spaceDim*i+2*k],coordsPtr[spaceDim*nodeId+k]);
5804 bbox[2*spaceDim*i+2*k+1]=std::max(bbox[2*spaceDim*i+2*k+1],coordsPtr[spaceDim*nodeId+k]);
5811 std::ostringstream oss; oss << "MEDCouplingUMesh::getBoundingBoxForBBTree : cell #" << i << " contains no valid nodeId !";
5812 throw INTERP_KERNEL::Exception(oss.str());
5819 * This method aggregates the bbox of each 2D cell in \a this considering the whole shape. This method is particularly
5820 * useful for 2D meshes having quadratic cells
5821 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5822 * the two extremities of the arc of circle).
5824 * \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)
5825 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5826 * \throw If \a this is not fully defined.
5827 * \throw If \a this is not a mesh with meshDimension equal to 2.
5828 * \throw If \a this is not a mesh with spaceDimension equal to 2.
5829 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic
5831 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic(double arcDetEps) const
5833 checkFullyDefined();
5834 INTERP_KERNEL::QuadraticPlanarPrecision arcPrec(arcDetEps);
5836 int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
5837 mcIdType nbOfCells=getNumberOfCells();
5838 if(spaceDim!=2 || mDim!=2)
5839 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!");
5840 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5841 double *bbox(ret->getPointer());
5842 const double *coords(_coords->begin());
5843 const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5844 for(mcIdType i=0;i<nbOfCells;i++,bbox+=4,connI++)
5846 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5847 mcIdType sz(connI[1]-connI[0]-1);
5848 std::vector<INTERP_KERNEL::Node *> nodes(sz);
5849 INTERP_KERNEL::QuadraticPolygon *pol(0);
5850 for(mcIdType j=0;j<sz;j++)
5852 mcIdType nodeId(conn[*connI+1+j]);
5853 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5855 if(!cm.isQuadratic())
5856 pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
5858 pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
5859 INTERP_KERNEL::Bounds b; b.prepareForAggregation(); pol->fillBounds(b); delete pol;
5860 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax();
5866 * This method aggregates the bbox of each 1D cell in \a this considering the whole shape. This method is particularly
5867 * useful for 2D meshes having quadratic cells
5868 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5869 * the two extremities of the arc of circle).
5871 * \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)
5872 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5873 * \throw If \a this is not fully defined.
5874 * \throw If \a this is not a mesh with meshDimension equal to 1.
5875 * \throw If \a this is not a mesh with spaceDimension equal to 2.
5876 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5878 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic(double arcDetEps) const
5880 checkFullyDefined();
5881 int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
5882 mcIdType nbOfCells=getNumberOfCells();
5883 if(spaceDim!=2 || mDim!=1)
5884 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!");
5885 INTERP_KERNEL::QuadraticPlanarPrecision arcPrec(arcDetEps);
5886 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5887 double *bbox(ret->getPointer());
5888 const double *coords(_coords->begin());
5889 const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5890 for(mcIdType i=0;i<nbOfCells;i++,bbox+=4,connI++)
5892 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5893 mcIdType sz(connI[1]-connI[0]-1);
5894 std::vector<INTERP_KERNEL::Node *> nodes(sz);
5895 INTERP_KERNEL::Edge *edge(0);
5896 for(mcIdType j=0;j<sz;j++)
5898 mcIdType nodeId(conn[*connI+1+j]);
5899 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5901 if(!cm.isQuadratic())
5902 edge=INTERP_KERNEL::QuadraticPolygon::BuildLinearEdge(nodes);
5904 edge=INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(nodes);
5905 const INTERP_KERNEL::Bounds& b(edge->getBounds());
5906 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax(); edge->decrRef();
5913 namespace MEDCouplingImpl
5918 ConnReader(const mcIdType *c, mcIdType val):_conn(c),_val(val) { }
5919 bool operator() (const mcIdType& pos) { return _conn[pos]!=_val; }
5921 const mcIdType *_conn;
5928 ConnReader2(const mcIdType *c, mcIdType val):_conn(c),_val(val) { }
5929 bool operator() (const mcIdType& pos) { return _conn[pos]==_val; }
5931 const mcIdType *_conn;
5939 * This method expects that \a this is sorted by types. If not an exception will be thrown.
5940 * This method returns in the same format as code (see MEDCouplingUMesh::checkTypeConsistencyAndContig or MEDCouplingUMesh::splitProfilePerType) how
5941 * \a this is composed in cell types.
5942 * The returned array is of size 3*n where n is the number of different types present in \a this.
5943 * For every k in [0,n] ret[3*k+2]==-1 because it has no sense here.
5944 * This parameter is kept only for compatibility with other method listed above.
5946 std::vector<mcIdType> MEDCouplingUMesh::getDistributionOfTypes() const
5948 checkConnectivityFullyDefined();
5949 const mcIdType *conn=_nodal_connec->begin();
5950 const mcIdType *connI=_nodal_connec_index->begin();
5951 const mcIdType *work=connI;
5952 mcIdType nbOfCells=getNumberOfCells();
5953 std::size_t n=getAllGeoTypes().size();
5954 std::vector<mcIdType> ret(3*n,-1); //ret[3*k+2]==-1 because it has no sense here
5955 std::set<INTERP_KERNEL::NormalizedCellType> types;
5956 for(std::size_t i=0;work!=connI+nbOfCells;i++)
5958 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn[*work];
5959 if(types.find(typ)!=types.end())
5961 std::ostringstream oss; oss << "MEDCouplingUMesh::getDistributionOfTypes : Type " << INTERP_KERNEL::CellModel::GetCellModel(typ).getRepr();
5962 oss << " is not contiguous !";
5963 throw INTERP_KERNEL::Exception(oss.str());
5967 const mcIdType *work2=std::find_if(work+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,typ));
5968 ret[3*i+1]=ToIdType(std::distance(work,work2));
5975 * This method is used to check that this has contiguous cell type in same order than described in \a code.
5976 * only for types cell, type node is not managed.
5977 * Format of \a code is the following. \a code should be of size 3*n and non empty. If not an exception is thrown.
5978 * foreach k in [0,n) on 3*k pos represent the geometric type and 3*k+1 number of elements of type 3*k.
5979 * 3*k+2 refers if different from -1 the pos in 'idsPerType' to get the corresponding array.
5980 * If 2 or more same geometric type is in \a code and exception is thrown too.
5982 * This method firstly checks
5983 * If it exists k so that 3*k geometric type is not in geometric types of this an exception will be thrown.
5984 * If it exists k so that 3*k geometric type exists but the number of consecutive cell types does not match,
5985 * an exception is thrown too.
5987 * If all geometric types in \a code are exactly those in \a this null pointer is returned.
5988 * If it exists a geometric type in \a this \b not in \a code \b no exception is thrown
5989 * and a DataArrayIdType instance is returned that the user has the responsibility to deallocate.
5991 DataArrayIdType *MEDCouplingUMesh::checkTypeConsistencyAndContig(const std::vector<mcIdType>& code, const std::vector<const DataArrayIdType *>& idsPerType) const
5994 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code is empty, should not !");
5995 std::size_t sz=code.size();
5998 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code size is NOT %3 !");
5999 std::vector<INTERP_KERNEL::NormalizedCellType> types;
6001 bool isNoPflUsed=true;
6002 for(std::size_t i=0;i<n;i++)
6003 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)code[3*i])==types.end())
6005 types.push_back((INTERP_KERNEL::NormalizedCellType)code[3*i]);
6007 if(_types.find((INTERP_KERNEL::NormalizedCellType)code[3*i])==_types.end())
6008 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : expected geo types not in this !");
6009 isNoPflUsed=isNoPflUsed && (code[3*i+2]==-1);
6012 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code contains duplication of types in unstructured mesh !");
6015 if(!checkConsecutiveCellTypesAndOrder(&types[0],&types[0]+types.size()))
6016 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : non contiguous type !");
6017 if(types.size()==_types.size())
6020 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
6022 mcIdType *retPtr=ret->getPointer();
6023 const mcIdType *connI=_nodal_connec_index->begin();
6024 const mcIdType *conn=_nodal_connec->begin();
6025 mcIdType nbOfCells=getNumberOfCells();
6026 const mcIdType *i=connI;
6028 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++,kk++)
6030 i=std::find_if(i,connI+nbOfCells,MEDCouplingImpl::ConnReader2(conn,ToIdType((*it))));
6031 mcIdType offset=ToIdType(std::distance(connI,i));
6032 const mcIdType *j=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType((*it))));
6033 mcIdType nbOfCellsOfCurType=ToIdType(std::distance(i,j));
6034 if(code[3*kk+2]==-1)
6035 for(mcIdType k=0;k<nbOfCellsOfCurType;k++)
6039 mcIdType idInIdsPerType=code[3*kk+2];
6040 if(idInIdsPerType>=0 && idInIdsPerType<ToIdType(idsPerType.size()))
6042 const DataArrayIdType *zePfl=idsPerType[idInIdsPerType];
6045 zePfl->checkAllocated();
6046 if(zePfl->getNumberOfComponents()==1)
6048 for(const mcIdType *k=zePfl->begin();k!=zePfl->end();k++,retPtr++)
6050 if(*k>=0 && *k<nbOfCellsOfCurType)
6051 *retPtr=(*k)+offset;
6054 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : the section " << kk << " points to the profile #" << idInIdsPerType;
6055 oss << ", and this profile contains a value " << *k << " should be in [0," << nbOfCellsOfCurType << ") !";
6056 throw INTERP_KERNEL::Exception(oss.str());
6061 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of a profile with nb of compo != 1 !");
6064 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of null profile !");
6068 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : at section " << kk << " of code it points to the array #" << idInIdsPerType;
6069 oss << " should be in [0," << idsPerType.size() << ") !";
6070 throw INTERP_KERNEL::Exception(oss.str());
6079 * This method makes the hypothesis that \a this is sorted by type. If not an exception will be thrown.
6080 * 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.
6081 * 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.
6082 * This method has 1 input \a profile and 3 outputs \a code \a idsInPflPerType and \a idsPerType.
6084 * \param [in] profile list of IDs constituing the profile
6085 * \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.
6086 * \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,
6087 * \a idsInPflPerType[i] stores the tuple ids in \a profile that correspond to the geometric type code[3*i+0]
6088 * \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.
6089 * This vector can be empty in case of all geometric type cells are fully covered in ascending in the given input \a profile.
6090 * \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
6092 void MEDCouplingUMesh::splitProfilePerType(const DataArrayIdType *profile, std::vector<mcIdType>& code, std::vector<DataArrayIdType *>& idsInPflPerType, std::vector<DataArrayIdType *>& idsPerType, bool smartPflKiller) const
6095 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile is NULL !");
6096 if(profile->getNumberOfComponents()!=1)
6097 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile should have exactly one component !");
6098 checkConnectivityFullyDefined();
6099 const mcIdType *conn=_nodal_connec->begin();
6100 const mcIdType *connI=_nodal_connec_index->begin();
6101 mcIdType nbOfCells=getNumberOfCells();
6102 std::vector<INTERP_KERNEL::NormalizedCellType> types;
6103 std::vector<mcIdType> typeRangeVals(1);
6104 for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6106 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6107 if(std::find(types.begin(),types.end(),curType)!=types.end())
6109 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : current mesh is not sorted by type !");
6111 types.push_back(curType);
6112 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6113 typeRangeVals.push_back(ToIdType(std::distance(connI,i)));
6116 DataArrayIdType *castArr=0,*rankInsideCast=0,*castsPresent=0;
6117 profile->splitByValueRange(&typeRangeVals[0],&typeRangeVals[0]+typeRangeVals.size(),castArr,rankInsideCast,castsPresent);
6118 MCAuto<DataArrayIdType> tmp0=castArr;
6119 MCAuto<DataArrayIdType> tmp1=rankInsideCast;
6120 MCAuto<DataArrayIdType> tmp2=castsPresent;
6122 mcIdType nbOfCastsFinal=castsPresent->getNumberOfTuples();
6123 code.resize(3*nbOfCastsFinal);
6124 std::vector< MCAuto<DataArrayIdType> > idsInPflPerType2;
6125 std::vector< MCAuto<DataArrayIdType> > idsPerType2;
6126 for(mcIdType i=0;i<nbOfCastsFinal;i++)
6128 mcIdType castId=castsPresent->getIJ(i,0);
6129 MCAuto<DataArrayIdType> tmp3=castArr->findIdsEqual(castId);
6130 idsInPflPerType2.push_back(tmp3);
6131 code[3*i]=ToIdType(types[castId]);
6132 code[3*i+1]=tmp3->getNumberOfTuples();
6133 MCAuto<DataArrayIdType> tmp4=rankInsideCast->selectByTupleId(tmp3->begin(),tmp3->begin()+tmp3->getNumberOfTuples());
6134 if(!smartPflKiller || !tmp4->isIota(typeRangeVals[castId+1]-typeRangeVals[castId]))
6136 tmp4->copyStringInfoFrom(*profile);
6137 idsPerType2.push_back(tmp4);
6138 code[3*i+2]=ToIdType(idsPerType2.size())-1;
6145 std::size_t sz2=idsInPflPerType2.size();
6146 idsInPflPerType.resize(sz2);
6147 for(std::size_t i=0;i<sz2;i++)
6149 DataArrayIdType *locDa=idsInPflPerType2[i];
6151 idsInPflPerType[i]=locDa;
6153 std::size_t sz=idsPerType2.size();
6154 idsPerType.resize(sz);
6155 for(std::size_t i=0;i<sz;i++)
6157 DataArrayIdType *locDa=idsPerType2[i];
6159 idsPerType[i]=locDa;
6164 * This method is here too emulate the MEDMEM behaviour on BDC (buildDescendingConnectivity). Hoping this method becomes deprecated very soon.
6165 * This method make the assumption that \a this and 'nM1LevMesh' mesh lyies on same coords (same pointer) as MED and MEDMEM does.
6166 * The following equality should be verified 'nM1LevMesh->getMeshDimension()==this->getMeshDimension()-1'
6167 * 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.
6169 MEDCouplingUMesh *MEDCouplingUMesh::emulateMEDMEMBDC(const MEDCouplingUMesh *nM1LevMesh, DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *&revDesc, DataArrayIdType *&revDescIndx, DataArrayIdType *& nM1LevMeshIds, DataArrayIdType *&meshnM1Old2New) const
6171 checkFullyDefined();
6172 nM1LevMesh->checkFullyDefined();
6173 if(getMeshDimension()-1!=nM1LevMesh->getMeshDimension())
6174 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : The mesh passed as first argument should have a meshDim equal to this->getMeshDimension()-1 !" );
6175 if(_coords!=nM1LevMesh->getCoords())
6176 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : 'this' and mesh in first argument should share the same coords : Use tryToShareSameCoords method !");
6177 MCAuto<DataArrayIdType> tmp0=DataArrayIdType::New();
6178 MCAuto<DataArrayIdType> tmp1=DataArrayIdType::New();
6179 MCAuto<MEDCouplingUMesh> ret1=buildDescendingConnectivity(desc,descIndx,tmp0,tmp1);
6180 MCAuto<DataArrayIdType> ret0=ret1->sortCellsInMEDFileFrmt();
6181 desc->transformWithIndArr(ret0->begin(),ret0->begin()+ret0->getNbOfElems());
6182 MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
6183 tmp->setConnectivity(tmp0,tmp1);
6184 tmp->renumberCells(ret0->begin(),false);
6185 revDesc=tmp->getNodalConnectivity();
6186 revDescIndx=tmp->getNodalConnectivityIndex();
6187 DataArrayIdType *ret=0;
6188 if(!ret1->areCellsIncludedIn(nM1LevMesh,2,ret))
6191 ret->getMaxValue(tmp2);
6193 std::ostringstream oss; oss << "MEDCouplingUMesh::emulateMEDMEMBDC : input N-1 mesh present a cell not in descending mesh ... Id of cell is " << tmp2 << " !";
6194 throw INTERP_KERNEL::Exception(oss.str());
6199 revDescIndx->incrRef();
6202 meshnM1Old2New=ret0;
6207 * Permutes the nodal connectivity arrays so that the cells are sorted by type, which is
6208 * necessary for writing the mesh to MED file. Additionally returns a permutation array
6209 * in "Old to New" mode.
6210 * \return DataArrayIdType * - a new instance of DataArrayIdType. The caller is to delete
6211 * this array using decrRef() as it is no more needed.
6212 * \throw If the nodal connectivity of cells is not defined.
6214 DataArrayIdType *MEDCouplingUMesh::sortCellsInMEDFileFrmt()
6216 checkConnectivityFullyDefined();
6217 MCAuto<DataArrayIdType> ret=getRenumArrForMEDFileFrmt();
6218 renumberCells(ret->begin(),false);
6223 * This methods checks that cells are sorted by their types.
6224 * This method makes asumption (no check) that connectivity is correctly set before calling.
6226 bool MEDCouplingUMesh::checkConsecutiveCellTypes() const
6228 checkFullyDefined();
6229 const mcIdType *conn=_nodal_connec->begin();
6230 const mcIdType *connI=_nodal_connec_index->begin();
6231 mcIdType nbOfCells=getNumberOfCells();
6232 std::set<INTERP_KERNEL::NormalizedCellType> types;
6233 for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6235 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6236 if(types.find(curType)!=types.end())
6238 types.insert(curType);
6239 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6245 * This method is a specialization of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method that is called here.
6246 * The geometric type order is specified by MED file.
6248 * \sa MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder
6250 bool MEDCouplingUMesh::checkConsecutiveCellTypesForMEDFileFrmt() const
6252 return checkConsecutiveCellTypesAndOrder(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
6256 * This method performs the same job as checkConsecutiveCellTypes except that the order of types sequence is analyzed to check
6257 * that the order is specified in array defined by [ \a orderBg , \a orderEnd ).
6258 * If there is some geo types in \a this \b NOT in [ \a orderBg, \a orderEnd ) it is OK (return true) if contiguous.
6259 * If there is some geo types in [ \a orderBg, \a orderEnd ) \b NOT in \a this it is OK too (return true) if contiguous.
6261 bool MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
6263 checkFullyDefined();
6264 const mcIdType *conn=_nodal_connec->begin();
6265 const mcIdType *connI=_nodal_connec_index->begin();
6266 mcIdType nbOfCells=getNumberOfCells();
6269 mcIdType lastPos=-1;
6270 std::set<INTERP_KERNEL::NormalizedCellType> sg;
6271 for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6273 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6274 const INTERP_KERNEL::NormalizedCellType *isTypeExists=std::find(orderBg,orderEnd,curType);
6275 if(isTypeExists!=orderEnd)
6277 mcIdType pos=ToIdType(std::distance(orderBg,isTypeExists));
6281 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6285 if(sg.find(curType)==sg.end())
6287 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6298 * This method returns 2 newly allocated DataArrayIdType instances. The first is an array of size 'this->getNumberOfCells()' with one component,
6299 * 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
6300 * 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'.
6302 DataArrayIdType *MEDCouplingUMesh::getLevArrPerCellTypes(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd, DataArrayIdType *&nbPerType) const
6304 checkConnectivityFullyDefined();
6305 mcIdType nbOfCells=getNumberOfCells();
6306 const mcIdType *conn=_nodal_connec->begin();
6307 const mcIdType *connI=_nodal_connec_index->begin();
6308 MCAuto<DataArrayIdType> tmpa=DataArrayIdType::New();
6309 MCAuto<DataArrayIdType> tmpb=DataArrayIdType::New();
6310 tmpa->alloc(nbOfCells,1);
6311 tmpb->alloc(std::distance(orderBg,orderEnd),1);
6312 tmpb->fillWithZero();
6313 mcIdType *tmp=tmpa->getPointer();
6314 mcIdType *tmp2=tmpb->getPointer();
6315 for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6317 const INTERP_KERNEL::NormalizedCellType *where=std::find(orderBg,orderEnd,(INTERP_KERNEL::NormalizedCellType)conn[*i]);
6320 mcIdType pos=ToIdType(std::distance(orderBg,where));
6322 tmp[std::distance(connI,i)]=pos;
6326 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*i]);
6327 std::ostringstream oss; oss << "MEDCouplingUMesh::getLevArrPerCellTypes : Cell #" << std::distance(connI,i);
6328 oss << " has a type " << cm.getRepr() << " not in input array of type !";
6329 throw INTERP_KERNEL::Exception(oss.str());
6332 nbPerType=tmpb.retn();
6337 * This method behaves exactly as MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec but the order is those defined in MED file spec.
6339 * \return a new object containing the old to new correspondence.
6341 * \sa MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec, MEDCouplingUMesh::sortCellsInMEDFileFrmt.
6343 DataArrayIdType *MEDCouplingUMesh::getRenumArrForMEDFileFrmt() const
6345 return getRenumArrForConsecutiveCellTypesSpec(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
6349 * 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.
6350 * This method returns an array of size getNumberOfCells() that gives a renumber array old2New that can be used as input of MEDCouplingMesh::renumberCells.
6351 * The mesh after this call to MEDCouplingMesh::renumberCells will pass the test of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder with the same inputs.
6352 * The returned array minimizes the permutations that is to say the order of cells inside same geometric type remains the same.
6354 DataArrayIdType *MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
6356 DataArrayIdType *nbPerType=0;
6357 MCAuto<DataArrayIdType> tmpa=getLevArrPerCellTypes(orderBg,orderEnd,nbPerType);
6358 nbPerType->decrRef();
6359 return tmpa->buildPermArrPerLevel();
6363 * This method reorganize the cells of \a this so that the cells with same geometric types are put together.
6364 * The number of cells remains unchanged after the call of this method.
6365 * This method tries to minimizes the number of needed permutations. So, this method behaves not exactly as
6366 * MEDCouplingUMesh::sortCellsInMEDFileFrmt.
6368 * \return the array giving the correspondence old to new.
6370 DataArrayIdType *MEDCouplingUMesh::rearrange2ConsecutiveCellTypes()
6372 checkFullyDefined();
6374 const mcIdType *conn=_nodal_connec->begin();
6375 const mcIdType *connI=_nodal_connec_index->begin();
6376 mcIdType nbOfCells=getNumberOfCells();
6377 std::vector<INTERP_KERNEL::NormalizedCellType> types;
6378 for(const mcIdType *i=connI;i!=connI+nbOfCells && (types.size()!=_types.size());)
6379 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)conn[*i])==types.end())
6381 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6382 types.push_back(curType);
6383 for(i++;i!=connI+nbOfCells && (INTERP_KERNEL::NormalizedCellType)conn[*i]==curType;i++);
6385 DataArrayIdType *ret=DataArrayIdType::New();
6386 ret->alloc(nbOfCells,1);
6387 mcIdType *retPtr=ret->getPointer();
6388 std::fill(retPtr,retPtr+nbOfCells,-1);
6389 mcIdType newCellId=0;
6390 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
6392 for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6393 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
6394 retPtr[std::distance(connI,i)]=newCellId++;
6396 renumberCells(retPtr,false);
6401 * This method splits \a this into as mush as untructured meshes that consecutive set of same type cells.
6402 * So this method has typically a sense if MEDCouplingUMesh::checkConsecutiveCellTypes has a sense.
6403 * This method makes asumption that connectivity is correctly set before calling.
6405 std::vector<MEDCouplingUMesh *> MEDCouplingUMesh::splitByType() const
6407 checkConnectivityFullyDefined();
6408 const mcIdType *conn=_nodal_connec->begin();
6409 const mcIdType *connI=_nodal_connec_index->begin();
6410 mcIdType nbOfCells=getNumberOfCells();
6411 std::vector<MEDCouplingUMesh *> ret;
6412 for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6414 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6415 mcIdType beginCellId=ToIdType(std::distance(connI,i));
6416 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6417 mcIdType endCellId=ToIdType(std::distance(connI,i));
6418 mcIdType sz=endCellId-beginCellId;
6419 mcIdType *cells=new mcIdType[sz];
6420 for(mcIdType j=0;j<sz;j++)
6421 cells[j]=beginCellId+j;
6422 MEDCouplingUMesh *m=(MEDCouplingUMesh *)buildPartOfMySelf(cells,cells+sz,true);
6430 * This method performs the opposite operation than those in MEDCoupling1SGTUMesh::buildUnstructured.
6431 * If \a this is a single geometric type unstructured mesh, it will be converted into a more compact data structure,
6432 * MEDCoupling1GTUMesh instance. The returned instance will aggregate the same DataArrayDouble instance of coordinates than \a this.
6434 * \return a newly allocated instance, that the caller must manage.
6435 * \throw If \a this contains more than one geometric type.
6436 * \throw If the nodal connectivity of \a this is not fully defined.
6437 * \throw If the internal data is not coherent.
6439 MEDCoupling1GTUMesh *MEDCouplingUMesh::convertIntoSingleGeoTypeMesh() const
6441 checkConnectivityFullyDefined();
6442 if(_types.size()!=1)
6443 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6444 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6445 MCAuto<MEDCoupling1GTUMesh> ret=MEDCoupling1GTUMesh::New(getName(),typ);
6446 ret->setCoords(getCoords());
6447 MEDCoupling1SGTUMesh *retC=dynamic_cast<MEDCoupling1SGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6450 MCAuto<DataArrayIdType> c=convertNodalConnectivityToStaticGeoTypeMesh();
6451 retC->setNodalConnectivity(c);
6455 MEDCoupling1DGTUMesh *retD=dynamic_cast<MEDCoupling1DGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6457 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : Internal error !");
6458 DataArrayIdType *c=0,*ci=0;
6459 convertNodalConnectivityToDynamicGeoTypeMesh(c,ci);
6460 MCAuto<DataArrayIdType> cs(c),cis(ci);
6461 retD->setNodalConnectivity(cs,cis);
6466 DataArrayIdType *MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh() const
6468 checkConnectivityFullyDefined();
6469 if(_types.size()!=1)
6470 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6471 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6472 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6475 std::ostringstream oss; oss << "MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : this contains a single geo type (" << cm.getRepr() << ") but ";
6476 oss << "this type is dynamic ! Only static geometric type is possible for that type ! call convertNodalConnectivityToDynamicGeoTypeMesh instead !";
6477 throw INTERP_KERNEL::Exception(oss.str());
6479 mcIdType nbCells=getNumberOfCells();
6480 mcIdType typi=ToIdType(typ);
6481 mcIdType nbNodesPerCell=ToIdType(cm.getNumberOfNodes());
6482 MCAuto<DataArrayIdType> connOut=DataArrayIdType::New(); connOut->alloc(nbCells*nbNodesPerCell,1);
6483 mcIdType *outPtr=connOut->getPointer();
6484 const mcIdType *conn=_nodal_connec->begin();
6485 const mcIdType *connI=_nodal_connec_index->begin();
6487 for(mcIdType i=0;i<nbCells;i++,connI++)
6489 if(conn[connI[0]]==typi && connI[1]-connI[0]==nbNodesPerCell)
6490 outPtr=std::copy(conn+connI[0]+1,conn+connI[1],outPtr);
6493 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 << ") !";
6494 throw INTERP_KERNEL::Exception(oss.str());
6497 return connOut.retn();
6501 * Convert the nodal connectivity of the mesh so that all the cells are of dynamic types (polygon or quadratic
6502 * polygon). This returns the corresponding new nodal connectivity in \ref numbering-indirect format.
6503 * \param nodalConn nodal connectivity
6504 * \param nodalConnIndex nodal connectivity indices
6506 void MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh(DataArrayIdType *&nodalConn, DataArrayIdType *&nodalConnIndex) const
6508 static const char msg0[]="MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : nodal connectivity in this are invalid ! Call checkConsistency !";
6509 checkConnectivityFullyDefined();
6510 if(_types.size()!=1)
6511 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6512 mcIdType nbCells=getNumberOfCells(),
6513 lgth=_nodal_connec->getNumberOfTuples();
6515 throw INTERP_KERNEL::Exception(msg0);
6516 MCAuto<DataArrayIdType> c(DataArrayIdType::New()),ci(DataArrayIdType::New());
6517 c->alloc(lgth-nbCells,1); ci->alloc(nbCells+1,1);
6518 mcIdType *cp(c->getPointer()),*cip(ci->getPointer());
6519 const mcIdType *incp(_nodal_connec->begin()),*incip(_nodal_connec_index->begin());
6521 for(mcIdType i=0;i<nbCells;i++,cip++,incip++)
6523 mcIdType strt(incip[0]+1),stop(incip[1]);//+1 to skip geo type
6524 mcIdType delta(stop-strt);
6527 if((strt>=0 && strt<lgth) && (stop>=0 && stop<=lgth))
6528 cp=std::copy(incp+strt,incp+stop,cp);
6530 throw INTERP_KERNEL::Exception(msg0);
6533 throw INTERP_KERNEL::Exception(msg0);
6534 cip[1]=cip[0]+delta;
6536 nodalConn=c.retn(); nodalConnIndex=ci.retn();
6540 * This method takes in input a vector of MEDCouplingUMesh instances lying on the same coordinates with same mesh dimensions.
6541 * Each mesh in \b ms must be sorted by type with the same order (typically using MEDCouplingUMesh::sortCellsInMEDFileFrmt).
6542 * This method is particularly useful for MED file interaction. It allows to aggregate several meshes and keeping the type sorting
6543 * and the track of the permutation by chunk of same geotype cells to retrieve it. The traditional formats old2new and new2old
6544 * are not used here to avoid the build of big permutation array.
6546 * \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
6547 * those specified in MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6548 * \param [out] szOfCellGrpOfSameType is a newly allocated DataArrayIdType instance whose number of tuples is equal to the number of chunks of same geotype
6549 * in all meshes in \b ms. The accumulation of all values of this array is equal to the number of cells of returned mesh.
6550 * \param [out] idInMsOfCellGrpOfSameType is a newly allocated DataArrayIdType instance having the same size than \b szOfCellGrpOfSameType. This
6551 * output array gives for each chunck of same type the corresponding mesh id in \b ms.
6552 * \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
6553 * is sorted by type following the geo cell types order of MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6555 MEDCouplingUMesh *MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& ms,
6556 DataArrayIdType *&szOfCellGrpOfSameType,
6557 DataArrayIdType *&idInMsOfCellGrpOfSameType)
6559 std::vector<const MEDCouplingUMesh *> ms2;
6560 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms.begin();it!=ms.end();it++)
6563 (*it)->checkConnectivityFullyDefined();
6567 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : input vector is empty !");
6568 const DataArrayDouble *refCoo=ms2[0]->getCoords();
6569 int meshDim=ms2[0]->getMeshDimension();
6570 std::vector<const MEDCouplingUMesh *> m1ssm;
6571 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmAuto;
6573 std::vector<const MEDCouplingUMesh *> m1ssmSingle;
6574 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmSingleAuto;
6575 mcIdType fake=0,rk=0;
6576 MCAuto<DataArrayIdType> ret1(DataArrayIdType::New()),ret2(DataArrayIdType::New());
6577 ret1->alloc(0,1); ret2->alloc(0,1);
6578 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms2.begin();it!=ms2.end();it++,rk++)
6580 if(meshDim!=(*it)->getMeshDimension())
6581 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshdims mismatch !");
6582 if(refCoo!=(*it)->getCoords())
6583 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshes are not shared by a single coordinates coords !");
6584 std::vector<MEDCouplingUMesh *> sp=(*it)->splitByType();
6585 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<const MEDCouplingUMesh *> >(m1ssm));
6586 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<MCAuto<MEDCouplingUMesh> > >(m1ssmAuto));
6587 for(std::vector<MEDCouplingUMesh *>::const_iterator it2=sp.begin();it2!=sp.end();it2++)
6589 MEDCouplingUMesh *singleCell=static_cast<MEDCouplingUMesh *>((*it2)->buildPartOfMySelf(&fake,&fake+1,true));
6590 m1ssmSingleAuto.push_back(singleCell);
6591 m1ssmSingle.push_back(singleCell);
6592 ret1->pushBackSilent((*it2)->getNumberOfCells()); ret2->pushBackSilent(rk);
6595 MCAuto<MEDCouplingUMesh> m1ssmSingle2=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmSingle);
6596 MCAuto<DataArrayIdType> renum=m1ssmSingle2->sortCellsInMEDFileFrmt();
6597 std::vector<const MEDCouplingUMesh *> m1ssmfinal(m1ssm.size());
6598 for(mcIdType i=0;i<ToIdType(m1ssm.size());i++)
6599 m1ssmfinal[renum->getIJ(i,0)]=m1ssm[i];
6600 MCAuto<MEDCouplingUMesh> ret0=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmfinal);
6601 szOfCellGrpOfSameType=ret1->renumber(renum->begin());
6602 idInMsOfCellGrpOfSameType=ret2->renumber(renum->begin());
6607 * This method returns a newly created DataArrayIdType instance.
6608 * This method retrieves cell ids in [ \a begin, \a end ) that have the type \a type.
6610 DataArrayIdType *MEDCouplingUMesh::keepCellIdsByType(INTERP_KERNEL::NormalizedCellType type, const mcIdType *begin, const mcIdType *end) const
6612 checkFullyDefined();
6613 const mcIdType *conn=_nodal_connec->begin();
6614 const mcIdType *connIndex=_nodal_connec_index->begin();
6615 MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(0,1);
6616 for(const mcIdType *w=begin;w!=end;w++)
6617 if((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]==type)
6618 ret->pushBackSilent(*w);
6623 * This method makes the assumption that da->getNumberOfTuples()<this->getNumberOfCells(). This method makes the assumption that ids contained in 'da'
6624 * are in [0:getNumberOfCells())
6626 DataArrayIdType *MEDCouplingUMesh::convertCellArrayPerGeoType(const DataArrayIdType *da) const
6628 checkFullyDefined();
6629 const mcIdType *conn=_nodal_connec->begin();
6630 const mcIdType *connI=_nodal_connec_index->begin();
6631 mcIdType nbOfCells=getNumberOfCells();
6632 std::set<INTERP_KERNEL::NormalizedCellType> types(getAllGeoTypes());
6633 mcIdType *tmp=new mcIdType[nbOfCells];
6634 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
6637 for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6638 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
6639 tmp[std::distance(connI,i)]=j++;
6641 DataArrayIdType *ret=DataArrayIdType::New();
6642 ret->alloc(da->getNumberOfTuples(),da->getNumberOfComponents());
6643 ret->copyStringInfoFrom(*da);
6644 mcIdType *retPtr=ret->getPointer();
6645 const mcIdType *daPtr=da->begin();
6646 mcIdType nbOfElems=da->getNbOfElems();
6647 for(mcIdType k=0;k<nbOfElems;k++)
6648 retPtr[k]=tmp[daPtr[k]];
6654 * This method reduced number of cells of this by keeping cells whose type is different from 'type' and if type=='type'
6655 * This method \b works \b for mesh sorted by type.
6656 * cells whose ids is in 'idsPerGeoType' array.
6657 * This method conserves coords and name of mesh.
6659 MEDCouplingUMesh *MEDCouplingUMesh::keepSpecifiedCells(INTERP_KERNEL::NormalizedCellType type, const mcIdType *idsPerGeoTypeBg, const mcIdType *idsPerGeoTypeEnd) const
6661 std::vector<mcIdType> code=getDistributionOfTypes();
6662 std::size_t nOfTypesInThis=code.size()/3;
6663 mcIdType sz=0,szOfType=0;
6664 for(std::size_t i=0;i<nOfTypesInThis;i++)
6669 szOfType=code[3*i+1];
6671 for(const mcIdType *work=idsPerGeoTypeBg;work!=idsPerGeoTypeEnd;work++)
6672 if(*work<0 || *work>=szOfType)
6674 std::ostringstream oss; oss << "MEDCouplingUMesh::keepSpecifiedCells : Request on type " << type << " at place #" << std::distance(idsPerGeoTypeBg,work) << " value " << *work;
6675 oss << ". It should be in [0," << szOfType << ") !";
6676 throw INTERP_KERNEL::Exception(oss.str());
6678 MCAuto<DataArrayIdType> idsTokeep=DataArrayIdType::New(); idsTokeep->alloc(sz+std::distance(idsPerGeoTypeBg,idsPerGeoTypeEnd),1);
6679 mcIdType *idsPtr=idsTokeep->getPointer();
6681 for(std::size_t i=0;i<nOfTypesInThis;i++)
6684 for(mcIdType j=0;j<code[3*i+1];j++)
6687 idsPtr=std::transform(idsPerGeoTypeBg,idsPerGeoTypeEnd,idsPtr,std::bind(std::plus<mcIdType>(),std::placeholders::_1,offset));
6688 offset+=code[3*i+1];
6690 MCAuto<MEDCouplingUMesh> ret=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(idsTokeep->begin(),idsTokeep->end(),true));
6691 ret->copyTinyInfoFrom(this);
6696 * This method returns a vector of size 'this->getNumberOfCells()'.
6697 * This method retrieves for each cell in \a this if it is linear (false) or quadratic(true).
6699 std::vector<bool> MEDCouplingUMesh::getQuadraticStatus() const
6701 mcIdType ncell=getNumberOfCells();
6702 std::vector<bool> ret(ncell);
6703 const mcIdType *cI=getNodalConnectivityIndex()->begin();
6704 const mcIdType *c=getNodalConnectivity()->begin();
6705 for(mcIdType i=0;i<ncell;i++)
6707 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[i]];
6708 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6709 ret[i]=cm.isQuadratic();
6715 * Returns a newly created mesh (with ref count ==1) that contains merge of \a this and \a other.
6717 MEDCouplingMesh *MEDCouplingUMesh::mergeMyselfWith(const MEDCouplingMesh *other) const
6719 if(other->getType()!=UNSTRUCTURED)
6720 throw INTERP_KERNEL::Exception("Merge of umesh only available with umesh each other !");
6721 const MEDCouplingUMesh *otherC=static_cast<const MEDCouplingUMesh *>(other);
6722 return MergeUMeshes(this,otherC);
6726 * Returns a new DataArrayDouble holding barycenters of all cells. The barycenter is
6727 * computed by averaging coordinates of cell nodes, so this method is not a right
6728 * choice for degenerated meshes (not well oriented, cells with measure close to zero).
6729 * Beware also that for quadratic meshes, degenerated arc of circles are turned into linear edges for the computation.
6730 * This happens with a default detection precision of eps=1.0e-14. If you need control over this use computeCellCenterOfMassWithPrecision().
6731 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
6732 * this->getNumberOfCells() tuples per \a this->getSpaceDimension()
6733 * components. The caller is to delete this array using decrRef() as it is
6735 * \throw If the coordinates array is not set.
6736 * \throw If the nodal connectivity of cells is not defined.
6737 * \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
6738 * \sa MEDCouplingUMesh::computeCellCenterOfMassWithPrecision
6740 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMass() const
6742 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6743 int spaceDim=getSpaceDimension();
6744 mcIdType nbOfCells=getNumberOfCells();
6745 ret->alloc(nbOfCells,spaceDim);
6746 ret->copyStringInfoFrom(*getCoords());
6747 double *ptToFill=ret->getPointer();
6748 const mcIdType *nodal=_nodal_connec->begin();
6749 const mcIdType *nodalI=_nodal_connec_index->begin();
6750 const double *coor=_coords->begin();
6751 for(mcIdType i=0;i<nbOfCells;i++)
6753 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6754 INTERP_KERNEL::computeBarycenter2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[i]+1,nodalI[i+1]-nodalI[i]-1,coor,spaceDim,ptToFill);
6762 * See computeCellCenterOfMass().
6763 * \param eps a precision for the detection of degenerated arc of circles.
6764 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
6765 * this->getNumberOfCells() tuples per \a this->getSpaceDimension()
6766 * components. The caller is to delete this array using decrRef() as it is
6768 * \throw If the coordinates array is not set.
6769 * \throw If the nodal connectivity of cells is not defined.
6770 * \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
6771 * \sa MEDCouplingUMesh::computeCellCenterOfMassWithPrecision
6773 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMassWithPrecision(double eps) const
6775 INTERP_KERNEL::QuadraticPlanarPrecision prec(eps);
6776 MCAuto<DataArrayDouble> ret = computeCellCenterOfMass();
6782 * This method computes for each cell in \a this, the location of the iso barycenter of nodes constituting
6783 * the cell. Contrary to badly named MEDCouplingUMesh::computeCellCenterOfMass method that returns the center of inertia of the
6785 * \return a newly allocated DataArrayDouble instance that the caller has to deal with. The returned
6786 * DataArrayDouble instance will have \c this->getNumberOfCells() tuples and \c this->getSpaceDimension() components.
6788 * \sa MEDCouplingUMesh::computeCellCenterOfMass
6789 * \throw If \a this is not fully defined (coordinates and connectivity)
6790 * \throw If there is presence in nodal connectivity in \a this of node ids not in [0, \c this->getNumberOfNodes() )
6792 DataArrayDouble *MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell() const
6794 checkFullyDefined();
6795 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6796 int spaceDim=getSpaceDimension();
6797 mcIdType nbOfCells=getNumberOfCells();
6798 mcIdType nbOfNodes=getNumberOfNodes();
6799 ret->alloc(nbOfCells,spaceDim);
6800 double *ptToFill=ret->getPointer();
6801 const mcIdType *nodal=_nodal_connec->begin();
6802 const mcIdType *nodalI=_nodal_connec_index->begin();
6803 const double *coor=_coords->begin();
6804 for(mcIdType i=0;i<nbOfCells;i++,ptToFill+=spaceDim)
6806 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6807 std::fill(ptToFill,ptToFill+spaceDim,0.);
6808 if(type!=INTERP_KERNEL::NORM_POLYHED)
6810 for(const mcIdType *conn=nodal+nodalI[i]+1;conn!=nodal+nodalI[i+1];conn++)
6812 if(*conn>=0 && *conn<nbOfNodes)
6813 std::transform(coor+spaceDim*conn[0],coor+spaceDim*(conn[0]+1),ptToFill,ptToFill,std::plus<double>());
6816 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of nodeId #" << *conn << " should be in [0," << nbOfNodes << ") !";
6817 throw INTERP_KERNEL::Exception(oss.str());
6820 mcIdType nbOfNodesInCell=nodalI[i+1]-nodalI[i]-1;
6821 if(nbOfNodesInCell>0)
6822 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind(std::multiplies<double>(),std::placeholders::_1,1./(double)nbOfNodesInCell));
6825 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of cell with no nodes !";
6826 throw INTERP_KERNEL::Exception(oss.str());
6831 std::set<mcIdType> s(nodal+nodalI[i]+1,nodal+nodalI[i+1]);
6833 for(std::set<mcIdType>::const_iterator it=s.begin();it!=s.end();it++)
6835 if(*it>=0 && *it<nbOfNodes)
6836 std::transform(coor+spaceDim*(*it),coor+spaceDim*((*it)+1),ptToFill,ptToFill,std::plus<double>());
6839 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell polyhedron cell #" << i << " presence of nodeId #" << *it << " should be in [0," << nbOfNodes << ") !";
6840 throw INTERP_KERNEL::Exception(oss.str());
6844 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind(std::multiplies<double>(),std::placeholders::_1,1./(double)s.size()));
6847 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on polyhedron cell #" << i << " there are no nodes !";
6848 throw INTERP_KERNEL::Exception(oss.str());
6856 * Returns a new DataArrayDouble holding barycenters of specified cells. The
6857 * barycenter is computed by averaging coordinates of cell nodes. The cells to treat
6858 * are specified via an array of cell ids.
6859 * \warning Validity of the specified cell ids is not checked!
6860 * Valid range is [ 0, \a this->getNumberOfCells() ).
6861 * \param [in] begin - an array of cell ids of interest.
6862 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
6863 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size ( \a
6864 * end - \a begin ) tuples per \a this->getSpaceDimension() components. The
6865 * caller is to delete this array using decrRef() as it is no more needed.
6866 * \throw If the coordinates array is not set.
6867 * \throw If the nodal connectivity of cells is not defined.
6869 * \if ENABLE_EXAMPLES
6870 * \ref cpp_mcumesh_getPartBarycenterAndOwner "Here is a C++ example".<br>
6871 * \ref py_mcumesh_getPartBarycenterAndOwner "Here is a Python example".
6874 DataArrayDouble *MEDCouplingUMesh::getPartBarycenterAndOwner(const mcIdType *begin, const mcIdType *end) const
6876 DataArrayDouble *ret=DataArrayDouble::New();
6877 int spaceDim=getSpaceDimension();
6878 std::size_t nbOfTuple=std::distance(begin,end);
6879 ret->alloc(nbOfTuple,spaceDim);
6880 double *ptToFill=ret->getPointer();
6881 double *tmp=new double[spaceDim];
6882 const mcIdType *nodal=_nodal_connec->begin();
6883 const mcIdType *nodalI=_nodal_connec_index->begin();
6884 const double *coor=_coords->begin();
6885 for(const mcIdType *w=begin;w!=end;w++)
6887 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[*w]];
6888 INTERP_KERNEL::computeBarycenter2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[*w]+1,nodalI[*w+1]-nodalI[*w]-1,coor,spaceDim,ptToFill);
6896 * 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".
6897 * So the returned instance will have 4 components and \c this->getNumberOfCells() tuples.
6898 * So this method expects that \a this has a spaceDimension equal to 3 and meshDimension equal to 2.
6899 * The computation of the plane equation is done using each time the 3 first nodes of 2D cells.
6900 * This method is useful to detect 2D cells in 3D space that are not coplanar.
6902 * \return DataArrayDouble * - a new instance of DataArrayDouble having 4 components and a number of tuples equal to number of cells in \a this.
6903 * \throw If spaceDim!=3 or meshDim!=2.
6904 * \throw If connectivity of \a this is invalid.
6905 * \throw If connectivity of a cell in \a this points to an invalid node.
6907 DataArrayDouble *MEDCouplingUMesh::computePlaneEquationOf3DFaces() const
6909 MCAuto<DataArrayDouble> ret(DataArrayDouble::New());
6910 mcIdType nbOfCells=getNumberOfCells();
6911 mcIdType nbOfNodes(getNumberOfNodes());
6912 if(getSpaceDimension()!=3 || getMeshDimension()!=2)
6913 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computePlaneEquationOf3DFaces : This method must be applied on a mesh having meshDimension equal 2 and a spaceDimension equal to 3 !");
6914 ret->alloc(nbOfCells,4);
6915 double *retPtr(ret->getPointer());
6916 const mcIdType *nodal(_nodal_connec->begin()),*nodalI(_nodal_connec_index->begin());
6917 const double *coor(_coords->begin());
6918 for(mcIdType i=0;i<nbOfCells;i++,nodalI++,retPtr+=4)
6920 double matrix[16]={0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,0},matrix2[16];
6921 if(nodalI[1]-nodalI[0]>=4)
6923 double aa[3]={coor[nodal[nodalI[0]+1+1]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6924 coor[nodal[nodalI[0]+1+1]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6925 coor[nodal[nodalI[0]+1+1]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]}
6926 ,bb[3]={coor[nodal[nodalI[0]+1+2]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6927 coor[nodal[nodalI[0]+1+2]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6928 coor[nodal[nodalI[0]+1+2]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]};
6929 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]};
6930 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]));
6931 for(int j=0;j<3;j++)
6933 mcIdType nodeId(nodal[nodalI[0]+1+j]);
6934 if(nodeId>=0 && nodeId<nbOfNodes)
6935 std::copy(coor+nodeId*3,coor+(nodeId+1)*3,matrix+4*j);
6938 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! This cell points to an invalid nodeId : " << nodeId << " !";
6939 throw INTERP_KERNEL::Exception(oss.str());
6942 if(sqrt(cc[0]*cc[0]+cc[1]*cc[1]+cc[2]*cc[2])>(1e-3*aa_norm*bb_norm))
6944 INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6945 retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6949 if(nodalI[1]-nodalI[0]==4)
6951 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : cell" << i << " : Presence of The 3 colinear points !";
6952 throw INTERP_KERNEL::Exception(oss.str());
6955 double dd[3]={0.,0.,0.};
6956 for(mcIdType offset=nodalI[0]+1;offset<nodalI[1];offset++)
6957 std::transform(coor+3*nodal[offset],coor+3*(nodal[offset]+1),dd,dd,std::plus<double>());
6958 mcIdType nbOfNodesInCell(nodalI[1]-nodalI[0]-1);
6959 std::transform(dd,dd+3,dd,std::bind(std::multiplies<double>(),std::placeholders::_1,1./(double)nbOfNodesInCell));
6960 std::copy(dd,dd+3,matrix+4*2);
6961 INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6962 retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6967 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! Must be constitued by more than 3 nodes !";
6968 throw INTERP_KERNEL::Exception(oss.str());
6975 * This method expects as input a DataArrayDouble non nul instance 'da' that should be allocated. If not an exception is thrown.
6978 MEDCouplingUMesh *MEDCouplingUMesh::Build0DMeshFromCoords(DataArrayDouble *da)
6981 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build0DMeshFromCoords : instance of DataArrayDouble must be not null !");
6982 da->checkAllocated();
6983 std::string name(da->getName());
6984 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New(name,0));
6986 ret->setName("Mesh");
6988 mcIdType nbOfTuples(da->getNumberOfTuples());
6989 MCAuto<DataArrayIdType> c(DataArrayIdType::New()),cI(DataArrayIdType::New());
6990 c->alloc(2*nbOfTuples,1);
6991 cI->alloc(nbOfTuples+1,1);
6992 mcIdType *cp(c->getPointer()),*cip(cI->getPointer());
6994 for(mcIdType i=0;i<nbOfTuples;i++)
6996 *cp++=INTERP_KERNEL::NORM_POINT1;
7000 ret->setConnectivity(c,cI,true);
7004 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::Build1DMeshFromCoords(DataArrayDouble *da)
7007 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build01MeshFromCoords : instance of DataArrayDouble must be not null !");
7008 da->checkAllocated();
7009 std::string name(da->getName());
7010 MCAuto<MEDCouplingUMesh> ret;
7012 MCAuto<MEDCouplingCMesh> tmp(MEDCouplingCMesh::New());
7013 MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
7014 arr->alloc(da->getNumberOfTuples());
7015 tmp->setCoordsAt(0,arr);
7016 ret=tmp->buildUnstructured();
7020 ret->setName("Mesh");
7027 * Creates a new MEDCouplingUMesh by concatenating two given meshes of the same dimension.
7028 * Cells and nodes of
7029 * the first mesh precede cells and nodes of the second mesh within the result mesh.
7030 * \param [in] mesh1 - the first mesh.
7031 * \param [in] mesh2 - the second mesh.
7032 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7033 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7034 * is no more needed.
7035 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
7036 * \throw If the coordinates array is not set in none of the meshes.
7037 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
7038 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
7040 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
7042 std::vector<const MEDCouplingUMesh *> tmp(2);
7043 tmp[0]=const_cast<MEDCouplingUMesh *>(mesh1); tmp[1]=const_cast<MEDCouplingUMesh *>(mesh2);
7044 return MergeUMeshes(tmp);
7048 * Creates a new MEDCouplingUMesh by concatenating all given meshes of the same dimension.
7049 * Cells and nodes of
7050 * the *i*-th mesh precede cells and nodes of the (*i*+1)-th mesh within the result mesh.
7051 * \param [in] a - a vector of meshes (MEDCouplingUMesh) to concatenate.
7052 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7053 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7054 * is no more needed.
7055 * \throw If \a a.size() == 0.
7056 * \throw If \a a[ *i* ] == NULL.
7057 * \throw If the coordinates array is not set in none of the meshes.
7058 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
7059 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
7061 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const std::vector<const MEDCouplingUMesh *>& a)
7063 std::size_t sz=a.size();
7065 return MergeUMeshesLL(a);
7066 for(std::size_t ii=0;ii<sz;ii++)
7069 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshes : item #" << ii << " in input array of size "<< sz << " is empty !";
7070 throw INTERP_KERNEL::Exception(oss.str());
7072 std::vector< MCAuto<MEDCouplingUMesh> > bb(sz);
7073 std::vector< const MEDCouplingUMesh * > aa(sz);
7075 for(std::size_t i=0;i<sz && spaceDim==-3;i++)
7077 const MEDCouplingUMesh *cur=a[i];
7078 const DataArrayDouble *coo=cur->getCoords();
7080 spaceDim=int(coo->getNumberOfComponents());
7083 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : no spaceDim specified ! unable to perform merge !");
7084 for(std::size_t i=0;i<sz;i++)
7086 bb[i]=a[i]->buildSetInstanceFromThis(spaceDim);
7089 return MergeUMeshesLL(aa);
7093 * Creates a new MEDCouplingUMesh by concatenating cells of two given meshes of same
7094 * dimension and sharing the node coordinates array.
7095 * All cells of the first mesh precede all cells of the second mesh
7096 * within the result mesh.
7097 * \param [in] mesh1 - the first mesh.
7098 * \param [in] mesh2 - the second mesh.
7099 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7100 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7101 * is no more needed.
7102 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
7103 * \throw If the meshes do not share the node coordinates array.
7104 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
7105 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
7107 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
7109 std::vector<const MEDCouplingUMesh *> tmp(2);
7110 tmp[0]=mesh1; tmp[1]=mesh2;
7111 return MergeUMeshesOnSameCoords(tmp);
7115 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
7116 * dimension and sharing the node coordinates array.
7117 * All cells of the *i*-th mesh precede all cells of the
7118 * (*i*+1)-th mesh within the result mesh.
7119 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
7120 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7121 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7122 * is no more needed.
7123 * \throw If \a a.size() == 0.
7124 * \throw If \a a[ *i* ] == NULL.
7125 * \throw If the meshes do not share the node coordinates array.
7126 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
7127 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
7129 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes)
7132 throw INTERP_KERNEL::Exception("meshes input parameter is expected to be non empty.");
7133 for(std::size_t ii=0;ii<meshes.size();ii++)
7136 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshesOnSameCoords : item #" << ii << " in input array of size "<< meshes.size() << " is empty !";
7137 throw INTERP_KERNEL::Exception(oss.str());
7139 const DataArrayDouble *coords=meshes.front()->getCoords();
7140 int meshDim=meshes.front()->getMeshDimension();
7141 std::vector<const MEDCouplingUMesh *>::const_iterator iter=meshes.begin();
7142 mcIdType meshLgth=0;
7143 mcIdType meshIndexLgth=0;
7144 for(;iter!=meshes.end();iter++)
7146 if(coords!=(*iter)->getCoords())
7147 throw INTERP_KERNEL::Exception("meshes does not share the same coords ! Try using tryToShareSameCoords method !");
7148 if(meshDim!=(*iter)->getMeshDimension())
7149 throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, FuseUMeshesOnSameCoords impossible !");
7150 meshLgth+=(*iter)->getNodalConnectivityArrayLen();
7151 meshIndexLgth+=(*iter)->getNumberOfCells();
7153 MCAuto<DataArrayIdType> nodal=DataArrayIdType::New();
7154 nodal->alloc(meshLgth,1);
7155 mcIdType *nodalPtr=nodal->getPointer();
7156 MCAuto<DataArrayIdType> nodalIndex=DataArrayIdType::New();
7157 nodalIndex->alloc(meshIndexLgth+1,1);
7158 mcIdType *nodalIndexPtr=nodalIndex->getPointer();
7160 for(iter=meshes.begin();iter!=meshes.end();iter++)
7162 const mcIdType *nod=(*iter)->getNodalConnectivity()->begin();
7163 const mcIdType *index=(*iter)->getNodalConnectivityIndex()->begin();
7164 mcIdType nbOfCells=(*iter)->getNumberOfCells();
7165 mcIdType meshLgth2=(*iter)->getNodalConnectivityArrayLen();
7166 nodalPtr=std::copy(nod,nod+meshLgth2,nodalPtr);
7167 if(iter!=meshes.begin())
7168 nodalIndexPtr=std::transform(index+1,index+nbOfCells+1,nodalIndexPtr,std::bind(std::plus<mcIdType>(),std::placeholders::_1,offset));
7170 nodalIndexPtr=std::copy(index,index+nbOfCells+1,nodalIndexPtr);
7173 MEDCouplingUMesh *ret=MEDCouplingUMesh::New();
7174 ret->setName("merge");
7175 ret->setMeshDimension(meshDim);
7176 ret->setConnectivity(nodal,nodalIndex,true);
7177 ret->setCoords(coords);
7182 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
7183 * dimension and sharing the node coordinates array. Cells of the *i*-th mesh precede
7184 * cells of the (*i*+1)-th mesh within the result mesh. Duplicates of cells are
7185 * removed from \a this mesh and arrays mapping between new and old cell ids in "Old to
7186 * New" mode are returned for each input mesh.
7187 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
7188 * \param [in] compType - specifies a cell comparison technique. For meaning of its
7189 * valid values [0,1,2], see zipConnectivityTraducer().
7190 * \param [in,out] corr - an array of DataArrayIdType, of the same size as \a
7191 * meshes. The *i*-th array describes cell ids mapping for \a meshes[ *i* ]
7192 * mesh. The caller is to delete each of the arrays using decrRef() as it is
7194 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7195 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7196 * is no more needed.
7197 * \throw If \a meshes.size() == 0.
7198 * \throw If \a meshes[ *i* ] == NULL.
7199 * \throw If the meshes do not share the node coordinates array.
7200 * \throw If \a meshes[ *i* ]->getMeshDimension() < 0.
7201 * \throw If the \a meshes are of different dimension (getMeshDimension()).
7202 * \throw If the nodal connectivity of cells of any of \a meshes is not defined.
7203 * \throw If the nodal connectivity any of \a meshes includes an invalid id.
7205 MEDCouplingUMesh *MEDCouplingUMesh::FuseUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes, int compType, std::vector<DataArrayIdType *>& corr)
7207 //All checks are delegated to MergeUMeshesOnSameCoords
7208 MCAuto<MEDCouplingUMesh> ret=MergeUMeshesOnSameCoords(meshes);
7209 MCAuto<DataArrayIdType> o2n=ret->zipConnectivityTraducer(compType);
7210 corr.resize(meshes.size());
7211 std::size_t nbOfMeshes=meshes.size();
7213 const mcIdType *o2nPtr=o2n->begin();
7214 for(std::size_t i=0;i<nbOfMeshes;i++)
7216 DataArrayIdType *tmp=DataArrayIdType::New();
7217 mcIdType curNbOfCells=meshes[i]->getNumberOfCells();
7218 tmp->alloc(curNbOfCells,1);
7219 std::copy(o2nPtr+offset,o2nPtr+offset+curNbOfCells,tmp->getPointer());
7220 offset+=curNbOfCells;
7221 tmp->setName(meshes[i]->getName());
7228 * Makes all given meshes share the nodal connectivity array. The common connectivity
7229 * array is created by concatenating the connectivity arrays of all given meshes. All
7230 * the given meshes must be of the same space dimension but dimension of cells **can
7231 * differ**. This method is particularly useful in MEDLoader context to build a \ref
7232 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
7233 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
7234 * \param [in,out] meshes - a vector of meshes to update.
7235 * \throw If any of \a meshes is NULL.
7236 * \throw If the coordinates array is not set in any of \a meshes.
7237 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
7238 * \throw If \a meshes are of different space dimension.
7240 void MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords(const std::vector<MEDCouplingUMesh *>& meshes)
7242 std::size_t sz=meshes.size();
7245 std::vector< const DataArrayDouble * > coords(meshes.size());
7246 std::vector< const DataArrayDouble * >::iterator it2=coords.begin();
7247 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++,it2++)
7251 (*it)->checkConnectivityFullyDefined();
7252 const DataArrayDouble *coo=(*it)->getCoords();
7257 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
7258 oss << " has no coordinate array defined !";
7259 throw INTERP_KERNEL::Exception(oss.str());
7264 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
7265 oss << " is null !";
7266 throw INTERP_KERNEL::Exception(oss.str());
7269 MCAuto<DataArrayDouble> res=DataArrayDouble::Aggregate(coords);
7270 std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();
7271 mcIdType offset=(*it)->getNumberOfNodes();
7272 (*it++)->setCoords(res);
7273 for(;it!=meshes.end();it++)
7275 mcIdType oldNumberOfNodes=(*it)->getNumberOfNodes();
7276 (*it)->setCoords(res);
7277 (*it)->shiftNodeNumbersInConn(offset);
7278 offset+=oldNumberOfNodes;
7283 * Merges nodes coincident with a given precision within all given meshes that share
7284 * the nodal connectivity array. The given meshes **can be of different** mesh
7285 * dimension. This method is particularly useful in MEDLoader context to build a \ref
7286 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
7287 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
7288 * \param [in,out] meshes - a vector of meshes to update.
7289 * \param [in] eps - the precision used to detect coincident nodes (infinite norm).
7290 * \throw If any of \a meshes is NULL.
7291 * \throw If the \a meshes do not share the same node coordinates array.
7292 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
7294 void MEDCouplingUMesh::MergeNodesOnUMeshesSharingSameCoords(const std::vector<MEDCouplingUMesh *>& meshes, double eps)
7298 std::set<const DataArrayDouble *> s;
7299 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
7302 s.insert((*it)->getCoords());
7305 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 !";
7306 throw INTERP_KERNEL::Exception(oss.str());
7311 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 !";
7312 throw INTERP_KERNEL::Exception(oss.str());
7314 const DataArrayDouble *coo=*(s.begin());
7318 DataArrayIdType *comm,*commI;
7319 coo->findCommonTuples(eps,-1,comm,commI);
7320 MCAuto<DataArrayIdType> tmp1(comm),tmp2(commI);
7321 mcIdType oldNbOfNodes=coo->getNumberOfTuples();
7322 mcIdType newNbOfNodes;
7323 MCAuto<DataArrayIdType> o2n=DataArrayIdType::ConvertIndexArrayToO2N(oldNbOfNodes,comm->begin(),commI->begin(),commI->end(),newNbOfNodes);
7324 if(oldNbOfNodes==newNbOfNodes)
7326 MCAuto<DataArrayDouble> newCoords=coo->renumberAndReduce(o2n->begin(),newNbOfNodes);
7327 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
7329 (*it)->renumberNodesInConn(o2n->begin());
7330 (*it)->setCoords(newCoords);
7336 * This static operates only for coords in 3D. The polygon is specified by its connectivity nodes in [ \a begin , \a end ).
7338 bool MEDCouplingUMesh::IsPolygonWellOriented(bool isQuadratic, const double *vec, const mcIdType *begin, const mcIdType *end, const double *coords)
7341 double v[3]={0.,0.,0.};
7342 std::size_t sz=std::distance(begin,end);
7346 // Algorithm: sum in v the cross products of (e1, e2) where e_i it the vector between (0,0,0) and point i
7347 // and e2 is linear point directly following e1 in the connectivity. All points are used.
7348 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];
7349 v[1]+=coords[3*begin[i]+2]*coords[3*begin[(i+1)%sz]]-coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+2];
7350 v[2]+=coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+1]-coords[3*begin[i]+1]*coords[3*begin[(i+1)%sz]];
7354 // Same algorithm as above but also using intermediate quadratic points.
7355 // (taking only linear points might lead to issues if the linearized version of the
7356 // polygon is not convex or self-intersecting ... see testCellOrientation4)
7357 std::size_t hsz = sz/2;
7358 for(std::size_t j=0;j<sz;j++)
7360 if (j%2) // current point i is quadratic, next point i+1 is standard
7363 ip1 = ((j-1)/2 + 1)%hsz; // ip1 means "i+1", i.e. next point
7365 else // current point i is standard, next point i+1 is quadratic
7370 v[0]+=coords[3*begin[i]+1]*coords[3*begin[ip1]+2]-coords[3*begin[i]+2]*coords[3*begin[ip1]+1];
7371 v[1]+=coords[3*begin[i]+2]*coords[3*begin[ip1]]-coords[3*begin[i]]*coords[3*begin[ip1]+2];
7372 v[2]+=coords[3*begin[i]]*coords[3*begin[ip1]+1]-coords[3*begin[i]+1]*coords[3*begin[ip1]];
7375 double ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
7380 * The polyhedron is specified by its connectivity nodes in [ \a begin , \a end ).
7382 bool MEDCouplingUMesh::IsPolyhedronWellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7384 std::vector<std::pair<mcIdType,mcIdType> > edges;
7385 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
7386 const mcIdType *bgFace=begin;
7387 for(std::size_t i=0;i<nbOfFaces;i++)
7389 const mcIdType *endFace=std::find(bgFace+1,end,-1);
7390 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
7391 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7393 std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7394 if(std::find(edges.begin(),edges.end(),p1)!=edges.end())
7396 edges.push_back(p1);
7400 return INTERP_KERNEL::calculateVolumeForPolyh2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,ToIdType(std::distance(begin,end)),coords)>-EPS_FOR_POLYH_ORIENTATION;
7404 * The 3D extruded static cell (PENTA6,HEXA8,HEXAGP12...) its connectivity nodes in [ \a begin , \a end ).
7406 bool MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7408 double vec0[3],vec1[3];
7409 std::size_t sz=std::distance(begin,end);
7411 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented : the length of nodal connectivity of extruded cell is not even !");
7412 mcIdType nbOfNodes=ToIdType(sz/2);
7413 INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,nbOfNodes,coords,vec0);
7414 const double *pt0=coords+3*begin[0];
7415 const double *pt1=coords+3*begin[nbOfNodes];
7416 vec1[0]=pt1[0]-pt0[0]; vec1[1]=pt1[1]-pt0[1]; vec1[2]=pt1[2]-pt0[2];
7417 return (vec0[0]*vec1[0]+vec0[1]*vec1[1]+vec0[2]*vec1[2])<0.;
7420 void MEDCouplingUMesh::CorrectExtrudedStaticCell(mcIdType *begin, mcIdType *end)
7422 std::size_t sz=std::distance(begin,end);
7423 INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz];
7424 std::size_t nbOfNodes(sz/2);
7425 std::copy(begin,end,(mcIdType *)tmp);
7426 for(std::size_t j=1;j<nbOfNodes;j++)
7428 begin[j]=tmp[nbOfNodes-j];
7429 begin[j+nbOfNodes]=tmp[nbOfNodes+nbOfNodes-j];
7433 bool MEDCouplingUMesh::IsTetra4WellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7435 std::size_t sz=std::distance(begin,end);
7437 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsTetra4WellOriented : Tetra4 cell with not 4 nodes ! Call checkConsistency !");
7438 double vec0[3],vec1[3];
7439 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[1],*pt2=coords+3*begin[2],*pt3=coords+3*begin[3];
7440 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];
7441 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;
7444 bool MEDCouplingUMesh::IsPyra5WellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7446 std::size_t sz=std::distance(begin,end);
7448 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsPyra5WellOriented : Pyra5 cell with not 5 nodes ! Call checkConsistency !");
7450 INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,4,coords,vec0);
7451 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[4];
7452 return (vec0[0]*(pt1[0]-pt0[0])+vec0[1]*(pt1[1]-pt0[1])+vec0[2]*(pt1[2]-pt0[2]))<0.;
7456 * 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 )
7457 * 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
7460 * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not.
7461 * \param [in] coords the coordinates with nb of components exactly equal to 3
7462 * \param [in] index begin of the nodal connectivity (geometric type included) of a single polyhedron cell
7463 * \param [out] res the result is put at the end of the vector without any alteration of the data.
7465 void MEDCouplingUMesh::SimplifyPolyhedronCell(double eps, const DataArrayDouble *coords, mcIdType index, DataArrayIdType *res, MEDCouplingUMesh *faces,
7466 DataArrayIdType *E_Fi, DataArrayIdType *E_F, DataArrayIdType *F_Ei, DataArrayIdType *F_E)
7468 mcIdType nbFaces = E_Fi->getIJ(index + 1, 0) - E_Fi->getIJ(index, 0);
7469 MCAuto<DataArrayDouble> v=DataArrayDouble::New(); v->alloc(nbFaces,3);
7470 double *vPtr=v->getPointer();
7471 MCAuto<DataArrayDouble> p=DataArrayDouble::New(); p->alloc(nbFaces,2);
7472 double *pPtr=p->getPointer();
7473 mcIdType *e_fi = E_Fi->getPointer(), *e_f = E_F->getPointer(), *f_ei = F_Ei->getPointer(), *f_e = F_E->getPointer();
7474 const mcIdType *f_idx = faces->getNodalConnectivityIndex()->getPointer(), *f_cnn = faces->getNodalConnectivity()->getPointer();
7475 for(mcIdType i=0;i<nbFaces;i++,vPtr+=3,pPtr++)
7477 mcIdType face = e_f[e_fi[index] + i];
7478 ComputeVecAndPtOfFace(eps, coords->begin(), f_cnn + f_idx[face] + 1, f_cnn + f_idx[face + 1], vPtr, pPtr);
7479 // to differentiate faces going to different cells:
7481 for (mcIdType j = f_ei[face]; j < f_ei[face + 1]; j++)
7482 *pPtr += FromIdType<double>(f_e[j]);
7484 pPtr=p->getPointer(); vPtr=v->getPointer();
7485 DataArrayIdType *comm1=0,*commI1=0;
7486 v->findCommonTuples(eps,-1,comm1,commI1);
7487 for (mcIdType i = 0; i < nbFaces; i++)
7488 if (comm1->findIdFirstEqual(i) < 0)
7490 comm1->pushBackSilent(i);
7491 commI1->pushBackSilent(comm1->getNumberOfTuples());
7493 MCAuto<DataArrayIdType> comm1Auto(comm1),commI1Auto(commI1);
7494 const mcIdType *comm1Ptr=comm1->begin();
7495 const mcIdType *commI1Ptr=commI1->begin();
7496 mcIdType nbOfGrps1=commI1Auto->getNumberOfTuples()-1;
7497 res->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYHED));
7499 for(mcIdType i=0;i<nbOfGrps1;i++)
7501 mcIdType vecId=comm1Ptr[commI1Ptr[i]];
7502 MCAuto<DataArrayDouble> tmpgrp2=p->selectByTupleId(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7503 DataArrayIdType *comm2=0,*commI2=0;
7504 tmpgrp2->findCommonTuples(eps,-1,comm2,commI2);
7505 for (mcIdType j = 0; j < commI1Ptr[i+1] - commI1Ptr[i]; j++)
7506 if (comm2->findIdFirstEqual(j) < 0)
7508 comm2->pushBackSilent(j);
7509 commI2->pushBackSilent(comm2->getNumberOfTuples());
7511 MCAuto<DataArrayIdType> comm2Auto(comm2),commI2Auto(commI2);
7512 const mcIdType *comm2Ptr=comm2->begin();
7513 const mcIdType *commI2Ptr=commI2->begin();
7514 mcIdType nbOfGrps2=commI2Auto->getNumberOfTuples()-1;
7515 for(mcIdType j=0;j<nbOfGrps2;j++)
7517 if(commI2Ptr[j+1] == commI2Ptr[j] + 1)
7519 mcIdType face = e_f[e_fi[index] + comm1Ptr[commI1Ptr[i] + comm2Ptr[commI2Ptr[j]]]]; //hmmm
7520 res->insertAtTheEnd(f_cnn + f_idx[face] + 1, f_cnn + f_idx[face + 1]);
7521 res->pushBackSilent(-1);
7525 mcIdType pointId=comm1Ptr[commI1Ptr[i]+comm2Ptr[commI2Ptr[j]]];
7526 MCAuto<DataArrayIdType> ids2=comm2->selectByTupleIdSafeSlice(commI2Ptr[j],commI2Ptr[j+1],1);
7527 ids2->transformWithIndArr(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7528 ids2->transformWithIndArr(e_f + e_fi[index], e_f + e_fi[index + 1]);
7529 MCAuto<MEDCouplingUMesh> mm3=static_cast<MEDCouplingUMesh *>(faces->buildPartOfMySelf(ids2->begin(),ids2->end(),true));
7530 MCAuto<DataArrayIdType> idsNodeTmp=mm3->zipCoordsTraducer();
7531 MCAuto<DataArrayIdType> idsNode=idsNodeTmp->invertArrayO2N2N2O(mm3->getNumberOfNodes());
7532 const mcIdType *idsNodePtr=idsNode->begin();
7533 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];
7534 double vec[3]; vec[0]=vPtr[3*vecId+1]; vec[1]=-vPtr[3*vecId]; vec[2]=0.;
7535 double norm=vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2];
7536 if(std::abs(norm)>eps)
7538 double angle=INTERP_KERNEL::EdgeArcCircle::SafeAsin(norm);
7539 mm3->rotate(center,vec,angle);
7541 mm3->changeSpaceDimension(2);
7542 MCAuto<MEDCouplingUMesh> mm4=mm3->buildSpreadZonesWithPoly();
7543 const mcIdType *conn4=mm4->getNodalConnectivity()->begin();
7544 const mcIdType *connI4=mm4->getNodalConnectivityIndex()->begin();
7545 mcIdType nbOfCells=mm4->getNumberOfCells();
7546 for(mcIdType k=0;k<nbOfCells;k++)
7549 for(const mcIdType *work=conn4+connI4[k]+1;work!=conn4+connI4[k+1];work++,l++)
7550 res->pushBackSilent(idsNodePtr[*work]);
7551 res->pushBackSilent(-1);
7556 res->popBackSilent();
7560 * 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
7561 * through origin. The plane is defined by its nodal connectivity [ \b begin, \b end ).
7563 * \param [in] eps below that value the dot product of 2 vectors is considered as colinears
7564 * \param [in] coords coordinates expected to have 3 components.
7565 * \param [in] begin start of the nodal connectivity of the face.
7566 * \param [in] end end of the nodal connectivity (excluded) of the face.
7567 * \param [out] v the normalized vector of size 3
7568 * \param [out] p the pos of plane
7570 void MEDCouplingUMesh::ComputeVecAndPtOfFace(double eps, const double *coords, const mcIdType *begin, const mcIdType *end, double *v, double *p)
7572 std::size_t nbPoints=std::distance(begin,end);
7574 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeVecAndPtOfFace : < of 3 points in face ! not able to find a plane on that face !");
7575 double vec[3]={0.,0.,0.};
7577 bool refFound=false;
7578 for(;j<nbPoints-1 && !refFound;j++)
7580 vec[0]=coords[3*begin[j+1]]-coords[3*begin[j]];
7581 vec[1]=coords[3*begin[j+1]+1]-coords[3*begin[j]+1];
7582 vec[2]=coords[3*begin[j+1]+2]-coords[3*begin[j]+2];
7583 double norm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
7587 vec[0]/=norm; vec[1]/=norm; vec[2]/=norm;
7590 for(std::size_t i=j;i<nbPoints-1;i++)
7593 curVec[0]=coords[3*begin[i+1]]-coords[3*begin[i]];
7594 curVec[1]=coords[3*begin[i+1]+1]-coords[3*begin[i]+1];
7595 curVec[2]=coords[3*begin[i+1]+2]-coords[3*begin[i]+2];
7596 double norm=sqrt(curVec[0]*curVec[0]+curVec[1]*curVec[1]+curVec[2]*curVec[2]);
7599 curVec[0]/=norm; curVec[1]/=norm; curVec[2]/=norm;
7600 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];
7601 norm=sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
7604 v[0]/=norm; v[1]/=norm; v[2]/=norm;
7605 *p=v[0]*coords[3*begin[i]]+v[1]*coords[3*begin[i]+1]+v[2]*coords[3*begin[i]+2];
7609 throw INTERP_KERNEL::Exception("Not able to find a normal vector of that 3D face !");
7613 * This method tries to obtain a well oriented polyhedron.
7614 * If the algorithm fails, an exception will be thrown.
7616 void MEDCouplingUMesh::TryToCorrectPolyhedronOrientation(mcIdType *begin, mcIdType *end, const double *coords)
7618 std::list< std::pair<mcIdType,mcIdType> > edgesOK,edgesFinished;
7619 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
7620 std::vector<bool> isPerm(nbOfFaces,false);//field on faces False: I don't know, True : oriented
7622 mcIdType *bgFace=begin,*endFace=std::find(begin+1,end,-1);
7623 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
7624 for(std::size_t l=0;l<nbOfEdgesInFace;l++) { std::pair<mcIdType,mcIdType> p1(bgFace[l],bgFace[(l+1)%nbOfEdgesInFace]); edgesOK.push_back(p1); }
7626 while(std::find(isPerm.begin(),isPerm.end(),false)!=isPerm.end())
7629 std::size_t smthChanged=0;
7630 for(std::size_t i=0;i<nbOfFaces;i++)
7632 endFace=std::find(bgFace+1,end,-1);
7633 nbOfEdgesInFace=std::distance(bgFace,endFace);
7637 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7639 std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7640 std::pair<mcIdType,mcIdType> p2(p1.second,p1.first);
7641 bool b1=std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end();
7642 bool b2=std::find(edgesOK.begin(),edgesOK.end(),p2)!=edgesOK.end();
7643 if(b1 || b2) { b=b2; isPerm[i]=true; smthChanged++; break; }
7648 std::reverse(bgFace+1,endFace);
7649 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7651 std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7652 std::pair<mcIdType,mcIdType> p2(p1.second,p1.first);
7653 if(std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end())
7654 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7655 if(std::find(edgesFinished.begin(),edgesFinished.end(),p1)!=edgesFinished.end() || std::find(edgesFinished.begin(),edgesFinished.end(),p2)!=edgesFinished.end())
7656 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7657 std::list< std::pair<mcIdType,mcIdType> >::iterator it=std::find(edgesOK.begin(),edgesOK.end(),p2);
7658 if(it!=edgesOK.end())
7661 edgesFinished.push_back(p1);
7664 edgesOK.push_back(p1);
7671 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired !"); }
7673 if(!edgesOK.empty())
7674 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired : Some edges are shared only once !"); }
7675 if(INTERP_KERNEL::calculateVolumeForPolyh2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,ToIdType(std::distance(begin,end)),coords)<-EPS_FOR_POLYH_ORIENTATION)
7676 {//not lucky ! The first face was not correctly oriented : reorient all faces...
7678 for(std::size_t i=0;i<nbOfFaces;i++)
7680 endFace=std::find(bgFace+1,end,-1);
7681 std::reverse(bgFace+1,endFace);
7689 * This method makes the assumption spacedimension == meshdimension == 2.
7690 * This method works only for linear cells.
7692 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYGON in pos#0)
7694 DataArrayIdType *MEDCouplingUMesh::buildUnionOf2DMesh() const
7696 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
7697 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : meshdimension, spacedimension must be equal to 2 !");
7698 MCAuto<MEDCouplingUMesh> skin(computeSkin());
7699 mcIdType oldNbOfNodes(skin->getNumberOfNodes());
7700 MCAuto<DataArrayIdType> o2n(skin->zipCoordsTraducer());
7701 mcIdType nbOfNodesExpected(skin->getNumberOfNodes());
7702 MCAuto<DataArrayIdType> n2o(o2n->invertArrayO2N2N2O(oldNbOfNodes));
7703 mcIdType nbCells=skin->getNumberOfCells();
7704 if(nbCells==nbOfNodesExpected)
7705 return buildUnionOf2DMeshLinear(skin,n2o);
7706 else if(2*nbCells==nbOfNodesExpected)
7707 return buildUnionOf2DMeshQuadratic(skin,n2o);
7709 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : the mesh 2D in input appears to be not in a single part of a 2D mesh !");
7713 * This method makes the assumption spacedimension == meshdimension == 3.
7714 * This method works only for linear cells.
7716 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYHED in pos#0)
7718 DataArrayIdType *MEDCouplingUMesh::buildUnionOf3DMesh() const
7720 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
7721 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf3DMesh : meshdimension, spacedimension must be equal to 2 !");
7722 MCAuto<MEDCouplingUMesh> m=computeSkin();
7723 const mcIdType *conn=m->getNodalConnectivity()->begin();
7724 const mcIdType *connI=m->getNodalConnectivityIndex()->begin();
7725 mcIdType nbOfCells=m->getNumberOfCells();
7726 MCAuto<DataArrayIdType> ret=DataArrayIdType::New(); ret->alloc(m->getNodalConnectivity()->getNumberOfTuples(),1);
7727 mcIdType *work=ret->getPointer(); *work++=INTERP_KERNEL::NORM_POLYHED;
7730 work=std::copy(conn+connI[0]+1,conn+connI[1],work);
7731 for(mcIdType i=1;i<nbOfCells;i++)
7734 work=std::copy(conn+connI[i]+1,conn+connI[i+1],work);
7740 * \brief Creates a graph of cell neighbors
7741 * \return MEDCouplingSkyLineArray * - an sky line array the user should delete.
7742 * In the sky line array, graph arcs are stored in terms of (index,value) notation.
7744 * - index: 0 3 5 6 6
7745 * - value: 1 2 3 2 3 3
7746 * means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7747 * Arcs are not doubled but reflexive (1,1) arcs are present for each cell
7749 MEDCouplingSkyLineArray* MEDCouplingUMesh::generateGraph() const
7751 checkConnectivityFullyDefined();
7753 int meshDim = this->getMeshDimension();
7754 MEDCoupling::DataArrayIdType* indexr=MEDCoupling::DataArrayIdType::New();
7755 MEDCoupling::DataArrayIdType* revConn=MEDCoupling::DataArrayIdType::New();
7756 this->getReverseNodalConnectivity(revConn,indexr);
7757 const mcIdType* indexr_ptr=indexr->begin();
7758 const mcIdType* revConn_ptr=revConn->begin();
7760 const MEDCoupling::DataArrayIdType* index;
7761 const MEDCoupling::DataArrayIdType* conn;
7762 conn=this->getNodalConnectivity(); // it includes a type as the 1st element!!!
7763 index=this->getNodalConnectivityIndex();
7764 mcIdType nbCells=this->getNumberOfCells();
7765 const mcIdType* index_ptr=index->begin();
7766 const mcIdType* conn_ptr=conn->begin();
7768 //creating graph arcs (cell to cell relations)
7769 //arcs are stored in terms of (index,value) notation
7772 // means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7773 // in present version arcs are not doubled but reflexive (1,1) arcs are present for each cell
7775 //warning here one node have less than or equal effective number of cell with it
7776 //but cell could have more than effective nodes
7777 //because other equals nodes in other domain (with other global inode)
7778 std::vector <mcIdType> cell2cell_index(nbCells+1,0);
7779 std::vector <mcIdType> cell2cell;
7780 cell2cell.reserve(3*nbCells);
7782 for (mcIdType icell=0; icell<nbCells;icell++)
7784 std::map<mcIdType,mcIdType > counter;
7785 for (mcIdType iconn=index_ptr[icell]+1; iconn<index_ptr[icell+1];iconn++)
7787 mcIdType inode=conn_ptr[iconn];
7788 for (mcIdType iconnr=indexr_ptr[inode]; iconnr<indexr_ptr[inode+1];iconnr++)
7790 mcIdType icell2=revConn_ptr[iconnr];
7791 std::map<mcIdType,mcIdType>::iterator iter=counter.find(icell2);
7792 if (iter!=counter.end()) (iter->second)++;
7793 else counter.insert(std::make_pair(icell2,1));
7796 for (std::map<mcIdType,mcIdType>::const_iterator iter=counter.begin();
7797 iter!=counter.end(); iter++)
7798 if (iter->second >= meshDim)
7800 cell2cell_index[icell+1]++;
7801 cell2cell.push_back(iter->first);
7806 cell2cell_index[0]=0;
7807 for (mcIdType icell=0; icell<nbCells;icell++)
7808 cell2cell_index[icell+1]=cell2cell_index[icell]+cell2cell_index[icell+1];
7810 //filling up index and value to create skylinearray structure
7811 MEDCouplingSkyLineArray * array(MEDCouplingSkyLineArray::New(cell2cell_index,cell2cell));
7816 void MEDCouplingUMesh::writeVTKLL(std::ostream& ofs, const std::string& cellData, const std::string& pointData, DataArrayByte *byteData) const
7818 mcIdType nbOfCells=getNumberOfCells();
7820 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::writeVTK : the unstructured mesh has no cells !");
7821 ofs << " <" << getVTKDataSetType() << ">\n";
7822 ofs << " <Piece NumberOfPoints=\"" << getNumberOfNodes() << "\" NumberOfCells=\"" << nbOfCells << "\">\n";
7823 ofs << " <PointData>\n" << pointData << std::endl;
7824 ofs << " </PointData>\n";
7825 ofs << " <CellData>\n" << cellData << std::endl;
7826 ofs << " </CellData>\n";
7827 ofs << " <Points>\n";
7828 if(getSpaceDimension()==3)
7829 _coords->writeVTK(ofs,8,"Points",byteData);
7832 MCAuto<DataArrayDouble> coo=_coords->changeNbOfComponents(3,0.);
7833 coo->writeVTK(ofs,8,"Points",byteData);
7835 ofs << " </Points>\n";
7836 ofs << " <Cells>\n";
7837 const mcIdType *cPtr=_nodal_connec->begin();
7838 const mcIdType *cIPtr=_nodal_connec_index->begin();
7839 MCAuto<DataArrayIdType> faceoffsets=DataArrayIdType::New(); faceoffsets->alloc(nbOfCells,1);
7840 MCAuto<DataArrayIdType> types=DataArrayIdType::New(); types->alloc(nbOfCells,1);
7841 MCAuto<DataArrayIdType> offsets=DataArrayIdType::New(); offsets->alloc(nbOfCells,1);
7842 MCAuto<DataArrayIdType> connectivity=DataArrayIdType::New(); connectivity->alloc(_nodal_connec->getNumberOfTuples()-nbOfCells,1);
7843 mcIdType *w1=faceoffsets->getPointer(),*w2=types->getPointer(),*w3=offsets->getPointer(),*w4=connectivity->getPointer();
7844 mcIdType szFaceOffsets=0,szConn=0;
7845 for(mcIdType i=0;i<nbOfCells;i++,w1++,w2++,w3++)
7848 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]!=INTERP_KERNEL::NORM_POLYHED)
7851 *w3=szConn+cIPtr[i+1]-cIPtr[i]-1; szConn+=cIPtr[i+1]-cIPtr[i]-1;
7852 w4=std::copy(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],w4);
7856 mcIdType deltaFaceOffset=cIPtr[i+1]-cIPtr[i]+1;
7857 *w1=szFaceOffsets+deltaFaceOffset; szFaceOffsets+=deltaFaceOffset;
7858 std::set<mcIdType> c(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1]); c.erase(-1);
7859 *w3=szConn+ToIdType(c.size()); szConn+=ToIdType(c.size());
7860 w4=std::copy(c.begin(),c.end(),w4);
7863 std::unique_ptr<mcIdType[]> medcoupling2vtkTypeTraducer_mcIdType(new mcIdType[MEDCOUPLING2VTKTYPETRADUCER_LGTH]);
7864 for(auto ii = 0; ii<MEDCOUPLING2VTKTYPETRADUCER_LGTH ; ++ii)
7865 medcoupling2vtkTypeTraducer_mcIdType[ii] = MEDCOUPLING2VTKTYPETRADUCER[ii]!=MEDCOUPLING2VTKTYPETRADUCER_NONE?MEDCOUPLING2VTKTYPETRADUCER[ii] : -1;
7866 types->transformWithIndArr(medcoupling2vtkTypeTraducer_mcIdType.get(),medcoupling2vtkTypeTraducer_mcIdType.get()+MEDCOUPLING2VTKTYPETRADUCER_LGTH);
7867 types->writeVTK(ofs,8,"UInt8","types",byteData);
7868 std::string vtkTypeName = Traits<mcIdType>::VTKReprStr;
7869 offsets->writeVTK(ofs,8,vtkTypeName,"offsets",byteData);
7870 if(szFaceOffsets!=0)
7871 {//presence of Polyhedra
7872 connectivity->reAlloc(szConn);
7873 faceoffsets->writeVTK(ofs,8,vtkTypeName,"faceoffsets",byteData);
7874 MCAuto<DataArrayIdType> faces=DataArrayIdType::New(); faces->alloc(szFaceOffsets,1);
7875 w1=faces->getPointer();
7876 for(mcIdType i=0;i<nbOfCells;i++)
7877 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]==INTERP_KERNEL::NORM_POLYHED)
7879 mcIdType nbFaces=ToIdType(std::count(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],-1))+1;
7881 const mcIdType *w6=cPtr+cIPtr[i]+1,*w5=0;
7882 for(mcIdType j=0;j<nbFaces;j++)
7884 w5=std::find(w6,cPtr+cIPtr[i+1],-1);
7885 *w1++=ToIdType(std::distance(w6,w5));
7886 w1=std::copy(w6,w5,w1);
7890 faces->writeVTK(ofs,8,vtkTypeName,"faces",byteData);
7892 connectivity->writeVTK(ofs,8,vtkTypeName,"connectivity",byteData);
7893 ofs << " </Cells>\n";
7894 ofs << " </Piece>\n";
7895 ofs << " </" << getVTKDataSetType() << ">\n";
7898 void MEDCouplingUMesh::reprQuickOverview(std::ostream& stream) const
7900 stream << "MEDCouplingUMesh C++ instance at " << this << ". Name : \"" << getName() << "\".";
7902 { stream << " Not set !"; return ; }
7903 stream << " Mesh dimension : " << _mesh_dim << ".";
7907 { stream << " No coordinates set !"; return ; }
7908 if(!_coords->isAllocated())
7909 { stream << " Coordinates set but not allocated !"; return ; }
7910 stream << " Space dimension : " << _coords->getNumberOfComponents() << "." << std::endl;
7911 stream << "Number of nodes : " << _coords->getNumberOfTuples() << ".";
7912 if(!_nodal_connec_index)
7913 { stream << std::endl << "Nodal connectivity NOT set !"; return ; }
7914 if(!_nodal_connec_index->isAllocated())
7915 { stream << std::endl << "Nodal connectivity set but not allocated !"; return ; }
7916 mcIdType lgth=_nodal_connec_index->getNumberOfTuples();
7917 std::size_t cpt=_nodal_connec_index->getNumberOfComponents();
7918 if(cpt!=1 || lgth<1)
7920 stream << std::endl << "Number of cells : " << lgth-1 << ".";
7923 std::string MEDCouplingUMesh::getVTKDataSetType() const
7925 return std::string("UnstructuredGrid");
7928 std::string MEDCouplingUMesh::getVTKFileExtension() const
7930 return std::string("vtu");
7936 * Provides a renumbering of the cells of this (which has to be a piecewise connected 1D line), so that
7937 * the segments of the line are indexed in consecutive order (i.e. cells \a i and \a i+1 are neighbors).
7938 * This doesn't modify the mesh. This method only works using nodal connectivity consideration. Coordinates of nodes are ignored here.
7939 * The caller is to deal with the resulting DataArrayIdType.
7940 * \throw If the coordinate array is not set.
7941 * \throw If the nodal connectivity of the cells is not defined.
7942 * \throw If m1 is not a mesh of dimension 2, or m1 is not a mesh of dimension 1
7943 * \throw If m2 is not a (piecewise) line (i.e. if a point has more than 2 adjacent segments)
7945 * \sa DataArrayIdType::sortEachPairToMakeALinkedList
7947 DataArrayIdType *MEDCouplingUMesh::orderConsecutiveCells1D() const
7949 checkFullyDefined();
7950 if(getMeshDimension()!=1)
7951 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D works on unstructured mesh with meshdim = 1 !");
7953 // Check that this is a line (and not a more complex 1D mesh) - each point is used at most by 2 segments:
7954 MCAuto<DataArrayIdType> _d(DataArrayIdType::New()),_dI(DataArrayIdType::New());
7955 MCAuto<DataArrayIdType> _rD(DataArrayIdType::New()),_rDI(DataArrayIdType::New());
7956 MCAuto<MEDCouplingUMesh> m_points(buildDescendingConnectivity(_d, _dI, _rD, _rDI));
7957 const mcIdType *d(_d->begin()), *dI(_dI->begin());
7958 const mcIdType *rD(_rD->begin()), *rDI(_rDI->begin());
7959 MCAuto<DataArrayIdType> _dsi(_rDI->deltaShiftIndex());
7960 const mcIdType * dsi(_dsi->begin());
7961 MCAuto<DataArrayIdType> dsii = _dsi->findIdsNotInRange(0,3);
7963 if (dsii->getNumberOfTuples())
7964 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D only work with a mesh being a (piecewise) connected line!");
7966 mcIdType nc=getNumberOfCells();
7967 MCAuto<DataArrayIdType> result(DataArrayIdType::New());
7968 result->alloc(nc,1);
7970 // set of edges not used so far
7971 std::set<mcIdType> edgeSet;
7972 for (mcIdType i=0; i<nc; edgeSet.insert(i), i++);
7974 mcIdType startSeg=0;
7976 // while we have points with only one neighbor segments
7979 std::list<mcIdType> linePiece;
7980 // fills a list of consecutive segment linked to startSeg. This can go forward or backward.
7981 for (int direction=0;direction<2;direction++) // direction=0 --> forward, direction=1 --> backward
7983 // Fill the list forward (resp. backward) from the start segment:
7984 mcIdType activeSeg = startSeg;
7985 mcIdType prevPointId = -20;
7987 while (!edgeSet.empty())
7989 if (!(direction == 1 && prevPointId==-20)) // prevent adding twice startSeg
7992 linePiece.push_back(activeSeg);
7994 linePiece.push_front(activeSeg);
7995 edgeSet.erase(activeSeg);
7998 mcIdType ptId1 = d[dI[activeSeg]], ptId2 = d[dI[activeSeg]+1];
7999 ptId = direction ? (ptId1 == prevPointId ? ptId2 : ptId1) : (ptId2 == prevPointId ? ptId1 : ptId2);
8000 if (dsi[ptId] == 1) // hitting the end of the line
8004 mcIdType seg1 = rD[rDI[ptId]], seg2 = rD[rDI[ptId]+1];
8005 activeSeg = (seg1 == activeSeg) ? seg2 : seg1;
8007 //for piecewise meshes made up of closed parts
8008 bool segmentAlreadyTreated = (std::find(linePiece.begin(), linePiece.end(), activeSeg) != linePiece.end());
8009 if(segmentAlreadyTreated)
8013 // Done, save final piece into DA:
8014 std::copy(linePiece.begin(), linePiece.end(), result->getPointer()+newIdx);
8015 newIdx += ToIdType(linePiece.size());
8017 // identify next valid start segment (one which is not consumed)
8018 if(!edgeSet.empty())
8019 startSeg = *(edgeSet.begin());
8022 while (!edgeSet.empty());
8023 return result.retn();
8027 * This method split some of edges of 2D cells in \a this. The edges to be split are specified in \a subNodesInSeg
8028 * and in \a subNodesInSegI using \ref numbering-indirect storage mode.
8029 * To do the work this method can optionally needs information about middle of subedges for quadratic cases if
8030 * a minimal creation of new nodes is wanted.
8031 * So this method try to reduce at most the number of new nodes. The only case that can lead this method to add
8032 * nodes if a SEG3 is split without information of middle.
8033 * \b WARNING : is returned value is different from 0 a call to MEDCouplingUMesh::mergeNodes is necessary to
8034 * avoid to have a non conform mesh.
8036 * \return mcIdType - the number of new nodes created (in most of cases 0).
8038 * \throw If \a this is not coherent.
8039 * \throw If \a this has not spaceDim equal to 2.
8040 * \throw If \a this has not meshDim equal to 2.
8041 * \throw If some subcells needed to be split are orphan.
8042 * \sa MEDCouplingUMesh::conformize2D
8044 mcIdType MEDCouplingUMesh::split2DCells(const DataArrayIdType *desc, const DataArrayIdType *descI, const DataArrayIdType *subNodesInSeg, const DataArrayIdType *subNodesInSegI, const DataArrayIdType *midOpt, const DataArrayIdType *midOptI)
8046 if(!desc || !descI || !subNodesInSeg || !subNodesInSegI)
8047 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : the 4 first arrays must be not null !");
8048 desc->checkAllocated(); descI->checkAllocated(); subNodesInSeg->checkAllocated(); subNodesInSegI->checkAllocated();
8049 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
8050 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : This method only works for meshes with spaceDim=2 and meshDim=2 !");
8051 if(midOpt==0 && midOptI==0)
8053 split2DCellsLinear(desc,descI,subNodesInSeg,subNodesInSegI);
8056 else if(midOpt!=0 && midOptI!=0)
8057 return split2DCellsQuadratic(desc,descI,subNodesInSeg,subNodesInSegI,midOpt,midOptI);
8059 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : middle parameters must be set to null for all or not null for all.");
8063 * 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
8064 * 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
8065 * the geometric cell type set to INTERP_KERNEL::NORM_POLYGON.
8066 * 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
8067 * 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.
8069 * \return false if the input connectivity represents already the convex hull, true if the input cell needs to be reordered.
8071 bool MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis(const double *coords, const mcIdType *nodalConnBg, const mcIdType *nodalConnEnd, DataArrayIdType *nodalConnecOut)
8073 std::size_t sz=std::distance(nodalConnBg,nodalConnEnd);
8076 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)*nodalConnBg);
8077 if(cm.getDimension()==2)
8079 const mcIdType *node=nodalConnBg+1;
8080 mcIdType startNode=*node++;
8081 double refX=coords[2*startNode];
8082 for(;node!=nodalConnEnd;node++)
8084 if(coords[2*(*node)]<refX)
8087 refX=coords[2*startNode];
8090 std::vector<mcIdType> tmpOut; tmpOut.reserve(sz); tmpOut.push_back(startNode);
8094 double angle0=-M_PI/2;
8096 mcIdType nextNode=-1;
8097 mcIdType prevNode=-1;
8099 double angleNext=0.;
8100 while(nextNode!=startNode)
8104 for(node=nodalConnBg+1;node!=nodalConnEnd;node++)
8106 if(*node!=tmpOut.back() && *node!=prevNode)
8108 tmp2[0]=coords[2*(*node)]-coords[2*tmpOut.back()]; tmp2[1]=coords[2*(*node)+1]-coords[2*tmpOut.back()+1];
8109 double angleM=INTERP_KERNEL::EdgeArcCircle::GetAbsoluteAngle(tmp2,tmp1);
8114 res=angle0-angleM+2.*M_PI;
8123 if(nextNode!=startNode)
8125 angle0=angleNext-M_PI;
8128 prevNode=tmpOut.back();
8129 tmpOut.push_back(nextNode);
8132 std::vector<mcIdType> tmp3(2*(sz-1));
8133 std::vector<mcIdType>::iterator it=std::copy(nodalConnBg+1,nodalConnEnd,tmp3.begin());
8134 std::copy(nodalConnBg+1,nodalConnEnd,it);
8135 if(std::search(tmp3.begin(),tmp3.end(),tmpOut.begin(),tmpOut.end())!=tmp3.end())
8137 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
8140 if(std::search(tmp3.rbegin(),tmp3.rend(),tmpOut.begin(),tmpOut.end())!=tmp3.rend())
8142 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
8147 nodalConnecOut->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYGON));
8148 nodalConnecOut->insertAtTheEnd(tmpOut.begin(),tmpOut.end());
8153 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
8156 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
8160 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
8161 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
8162 * 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]].
8163 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
8164 * A negative value in \b arrIn means that it is ignored.
8165 * 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.
8167 * \param [in] arrIn arr origin array from which the extraction will be done.
8168 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
8169 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
8170 * \sa MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed, MEDCouplingUMesh::partitionBySpreadZone
8172 DataArrayIdType *MEDCouplingUMesh::ComputeSpreadZoneGradually(const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn)
8174 mcIdType seed=0,nbOfDepthPeelingPerformed=0;
8175 return ComputeSpreadZoneGraduallyFromSeed(&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfDepthPeelingPerformed);
8179 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
8180 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
8181 * 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]].
8182 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
8183 * A negative value in \b arrIn means that it is ignored.
8184 * 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.
8185 * \param [in] seedBg the begin pointer (included) of an array containing the seed of the search zone
8186 * \param [in] seedEnd the end pointer (not included) of an array containing the seed of the search zone
8187 * \param [in] arrIn arr origin array from which the extraction will be done.
8188 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
8189 * \param [in] nbOfDepthPeeling the max number of peels requested in search. By default -1, that is to say, no limit.
8190 * \param [out] nbOfDepthPeelingPerformed the number of peels effectively performed. May be different from \a nbOfDepthPeeling
8191 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
8192 * \sa MEDCouplingUMesh::partitionBySpreadZone
8194 DataArrayIdType *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(const mcIdType *seedBg, const mcIdType *seedEnd, const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn, mcIdType nbOfDepthPeeling, mcIdType& nbOfDepthPeelingPerformed)
8196 nbOfDepthPeelingPerformed=0;
8198 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed : arrIndxIn input pointer is NULL !");
8199 mcIdType nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
8202 DataArrayIdType *ret=DataArrayIdType::New(); ret->alloc(0,1);
8206 std::vector<bool> fetched(nbOfTuples,false);
8207 return ComputeSpreadZoneGraduallyFromSeedAlg(fetched,seedBg,seedEnd,arrIn,arrIndxIn,nbOfDepthPeeling,nbOfDepthPeelingPerformed);
8213 * \b this is expected to be a mesh fully defined whose spaceDim==meshDim.
8214 * It returns a new allocated mesh having the same mesh dimension and lying on same coordinates.
8215 * The returned mesh contains as poly cells as number of contiguous zone (regarding connectivity).
8216 * A spread contiguous zone is built using poly cells (polyhedra in 3D, polygons in 2D and polyline in 1D).
8217 * The sum of measure field of returned mesh is equal to the sum of measure field of this.
8219 * \return a newly allocated mesh lying on the same coords than \b this with same meshdimension than \b this.
8221 MEDCouplingUMesh *MEDCouplingUMesh::buildSpreadZonesWithPoly() const
8223 checkFullyDefined();
8224 int mdim=getMeshDimension();
8225 int spaceDim=getSpaceDimension();
8227 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension and spacedimension do not match !");
8228 std::vector<DataArrayIdType *> partition=partitionBySpreadZone();
8229 std::vector< MCAuto<DataArrayIdType> > partitionAuto; partitionAuto.reserve(partition.size());
8230 std::copy(partition.begin(),partition.end(),std::back_insert_iterator<std::vector< MCAuto<DataArrayIdType> > >(partitionAuto));
8231 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
8232 ret->setCoords(getCoords());
8233 ret->allocateCells(ToIdType(partition.size()));
8235 for(std::vector<DataArrayIdType *>::const_iterator it=partition.begin();it!=partition.end();it++)
8237 MCAuto<MEDCouplingUMesh> tmp=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf((*it)->begin(),(*it)->end(),true));
8238 MCAuto<DataArrayIdType> cell;
8242 cell=tmp->buildUnionOf2DMesh();
8245 cell=tmp->buildUnionOf3DMesh();
8248 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension supported are [2,3] ! Not implemented yet for others !");
8251 ret->insertNextCell((INTERP_KERNEL::NormalizedCellType)cell->getIJSafe(0,0),cell->getNumberOfTuples()-1,cell->begin()+1);
8254 ret->finishInsertingCells();
8259 * This method partitions \b this into contiguous zone.
8260 * This method only needs a well defined connectivity. Coordinates are not considered here.
8261 * This method returns a vector of \b newly allocated arrays that the caller has to deal with.
8263 std::vector<DataArrayIdType *> MEDCouplingUMesh::partitionBySpreadZone() const
8265 DataArrayIdType *neigh=0,*neighI=0;
8266 computeNeighborsOfCells(neigh,neighI);
8267 MCAuto<DataArrayIdType> neighAuto(neigh),neighIAuto(neighI);
8268 return PartitionBySpreadZone(neighAuto,neighIAuto);
8271 std::vector<DataArrayIdType *> MEDCouplingUMesh::PartitionBySpreadZone(const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn)
8273 if(!arrIn || !arrIndxIn)
8274 throw INTERP_KERNEL::Exception("PartitionBySpreadZone : null input pointers !");
8275 arrIn->checkAllocated(); arrIndxIn->checkAllocated();
8276 mcIdType nbOfTuples(arrIndxIn->getNumberOfTuples());
8277 if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1 || nbOfTuples<1)
8278 throw INTERP_KERNEL::Exception("PartitionBySpreadZone : invalid arrays in input !");
8279 mcIdType nbOfCellsCur(nbOfTuples-1);
8280 std::vector<DataArrayIdType *> ret;
8283 std::vector<bool> fetchedCells(nbOfCellsCur,false);
8284 std::vector< MCAuto<DataArrayIdType> > ret2;
8286 while(seed<nbOfCellsCur)
8288 mcIdType nbOfPeelPerformed=0;
8289 ret2.push_back(ComputeSpreadZoneGraduallyFromSeedAlg(fetchedCells,&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfPeelPerformed));
8290 seed=ToIdType(std::distance(fetchedCells.begin(),std::find(fetchedCells.begin()+seed,fetchedCells.end(),false)));
8292 for(std::vector< MCAuto<DataArrayIdType> >::iterator it=ret2.begin();it!=ret2.end();it++)
8293 ret.push_back((*it).retn());
8298 * This method returns given a distribution of cell type (returned for example by MEDCouplingUMesh::getDistributionOfTypes method and customized after) a
8299 * newly allocated DataArrayIdType instance with 2 components ready to be interpreted as input of DataArrayIdType::findRangeIdForEachTuple method.
8301 * \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.
8302 * \return a newly allocated DataArrayIdType to be managed by the caller.
8303 * \throw In case of \a code has not the right format (typically of size 3*n)
8305 DataArrayIdType *MEDCouplingUMesh::ComputeRangesFromTypeDistribution(const std::vector<mcIdType>& code)
8307 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
8308 std::size_t nb=code.size()/3;
8309 if(code.size()%3!=0)
8310 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeRangesFromTypeDistribution : invalid input code !");
8312 mcIdType *retPtr=ret->getPointer();
8313 for(std::size_t i=0;i<nb;i++,retPtr+=2)
8315 retPtr[0]=code[3*i+2];
8316 retPtr[1]=code[3*i+2]+code[3*i+1];
8322 * This method expects that \a this a 3D mesh (spaceDim=3 and meshDim=3) with all coordinates and connectivities set.
8323 * All cells in \a this are expected to be linear 3D cells.
8324 * This method will split **all** 3D cells in \a this into INTERP_KERNEL::NORM_TETRA4 cells and put them in the returned mesh.
8325 * It leads to an increase to number of cells.
8326 * This method contrary to MEDCouplingUMesh::simplexize can append coordinates in \a this to perform its work.
8327 * The \a nbOfAdditionalPoints returned value informs about it. If > 0, the coordinates array in returned mesh will have \a nbOfAdditionalPoints
8328 * more tuples (nodes) than in \a this. Anyway, all the nodes in \a this (with the same order) will be in the returned mesh.
8330 * \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.
8331 * For all other cells, the splitting policy will be ignored. See INTERP_KERNEL::SplittingPolicy for the images.
8332 * \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.
8333 * \param [out] n2oCells - A new instance of DataArrayIdType holding, for each new cell,
8334 * an id of old cell producing it. The caller is to delete this array using
8335 * decrRef() as it is no more needed.
8336 * \return MEDCoupling1SGTUMesh * - the mesh containing only INTERP_KERNEL::NORM_TETRA4 cells.
8338 * \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
8339 * the policy PLANAR_FACE_6 should be used on a mesh sorted with MEDCoupling1SGTUMesh::sortHexa8EachOther.
8341 * \throw If \a this is not a 3D mesh (spaceDim==3 and meshDim==3).
8342 * \throw If \a this is not fully constituted with linear 3D cells.
8343 * \sa MEDCouplingUMesh::simplexize, MEDCoupling1SGTUMesh::sortHexa8EachOther
8345 MEDCoupling1SGTUMesh *MEDCouplingUMesh::tetrahedrize(int policy, DataArrayIdType *& n2oCells, mcIdType& nbOfAdditionalPoints) const
8347 INTERP_KERNEL::SplittingPolicy pol((INTERP_KERNEL::SplittingPolicy)policy);
8348 checkConnectivityFullyDefined();
8349 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
8350 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tetrahedrize : only available for mesh with meshdim == 3 and spacedim == 3 !");
8351 mcIdType nbOfCells=getNumberOfCells();
8352 mcIdType nbNodes(getNumberOfNodes());
8353 MCAuto<MEDCoupling1SGTUMesh> ret0(MEDCoupling1SGTUMesh::New(getName(),INTERP_KERNEL::NORM_TETRA4));
8354 MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(nbOfCells,1);
8355 mcIdType *retPt(ret->getPointer());
8356 MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()); newConn->alloc(0,1);
8357 MCAuto<DataArrayDouble> addPts(DataArrayDouble::New()); addPts->alloc(0,1);
8358 const mcIdType *oldc(_nodal_connec->begin());
8359 const mcIdType *oldci(_nodal_connec_index->begin());
8360 const double *coords(_coords->begin());
8361 for(mcIdType i=0;i<nbOfCells;i++,oldci++,retPt++)
8363 std::vector<mcIdType> a; std::vector<double> b;
8364 INTERP_KERNEL::SplitIntoTetras(pol,(INTERP_KERNEL::NormalizedCellType)oldc[oldci[0]],oldc+oldci[0]+1,oldc+oldci[1],coords,a,b);
8365 std::size_t nbOfTet(a.size()/4); *retPt=ToIdType(nbOfTet);
8366 const mcIdType *aa(&a[0]);
8369 for(std::vector<mcIdType>::iterator it=a.begin();it!=a.end();it++)
8371 *it=(-(*(it))-1+nbNodes);
8372 addPts->insertAtTheEnd(b.begin(),b.end());
8373 nbNodes+=ToIdType(b.size()/3);
8375 for(std::size_t j=0;j<nbOfTet;j++,aa+=4)
8376 newConn->insertAtTheEnd(aa,aa+4);
8378 if(!addPts->empty())
8380 addPts->rearrange(3);
8381 nbOfAdditionalPoints=addPts->getNumberOfTuples();
8382 addPts=DataArrayDouble::Aggregate(getCoords(),addPts);
8383 ret0->setCoords(addPts);
8387 nbOfAdditionalPoints=0;
8388 ret0->setCoords(getCoords());
8390 ret0->setNodalConnectivity(newConn);
8392 ret->computeOffsetsFull();
8393 n2oCells=ret->buildExplicitArrOfSliceOnScaledArr(0,nbOfCells,1);
8397 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),
8398 _own_cell(true),_cell_id(-1),_nb_cell(0)
8403 _nb_cell=mesh->getNumberOfCells();
8407 MEDCouplingUMeshCellIterator::~MEDCouplingUMeshCellIterator()
8415 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh, MEDCouplingUMeshCell *itc, mcIdType bg, mcIdType end):_mesh(mesh),_cell(itc),
8416 _own_cell(false),_cell_id(bg-1),
8423 MEDCouplingUMeshCell *MEDCouplingUMeshCellIterator::nextt()
8426 if(_cell_id<_nb_cell)
8435 MEDCouplingUMeshCellByTypeEntry::MEDCouplingUMeshCellByTypeEntry(MEDCouplingUMesh *mesh):_mesh(mesh)
8441 MEDCouplingUMeshCellByTypeIterator *MEDCouplingUMeshCellByTypeEntry::iterator()
8443 return new MEDCouplingUMeshCellByTypeIterator(_mesh);
8446 MEDCouplingUMeshCellByTypeEntry::~MEDCouplingUMeshCellByTypeEntry()
8452 MEDCouplingUMeshCellEntry::MEDCouplingUMeshCellEntry(MEDCouplingUMesh *mesh, INTERP_KERNEL::NormalizedCellType type, MEDCouplingUMeshCell *itc, mcIdType bg, mcIdType end):_mesh(mesh),_type(type),
8460 MEDCouplingUMeshCellEntry::~MEDCouplingUMeshCellEntry()
8466 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCellEntry::getType() const
8471 mcIdType MEDCouplingUMeshCellEntry::getNumberOfElems() const
8476 MEDCouplingUMeshCellIterator *MEDCouplingUMeshCellEntry::iterator()
8478 return new MEDCouplingUMeshCellIterator(_mesh,_itc,_bg,_end);
8481 MEDCouplingUMeshCellByTypeIterator::MEDCouplingUMeshCellByTypeIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),_cell_id(0),_nb_cell(0)
8486 _nb_cell=mesh->getNumberOfCells();
8490 MEDCouplingUMeshCellByTypeIterator::~MEDCouplingUMeshCellByTypeIterator()
8497 MEDCouplingUMeshCellEntry *MEDCouplingUMeshCellByTypeIterator::nextt()
8499 const mcIdType *c=_mesh->getNodalConnectivity()->begin();
8500 const mcIdType *ci=_mesh->getNodalConnectivityIndex()->begin();
8501 if(_cell_id<_nb_cell)
8503 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[_cell_id]];
8504 mcIdType nbOfElems=ToIdType(std::distance(ci+_cell_id,std::find_if(ci+_cell_id,ci+_nb_cell,MEDCouplingImpl::ConnReader(c,type))));
8505 mcIdType startId=_cell_id;
8506 _cell_id+=nbOfElems;
8507 return new MEDCouplingUMeshCellEntry(_mesh,type,_cell,startId,_cell_id);
8513 MEDCouplingUMeshCell::MEDCouplingUMeshCell(MEDCouplingUMesh *mesh):_conn(0),_conn_indx(0),_conn_lgth(NOTICABLE_FIRST_VAL)
8517 _conn=mesh->getNodalConnectivity()->getPointer();
8518 _conn_indx=mesh->getNodalConnectivityIndex()->getPointer();
8522 void MEDCouplingUMeshCell::next()
8524 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8529 _conn_lgth=_conn_indx[1]-_conn_indx[0];
8532 std::string MEDCouplingUMeshCell::repr() const
8534 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8536 std::ostringstream oss; oss << "Cell Type " << INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)_conn[0]).getRepr();
8538 std::copy(_conn+1,_conn+_conn_lgth,std::ostream_iterator<mcIdType>(oss," "));
8542 return std::string("MEDCouplingUMeshCell::repr : Invalid pos");
8545 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCell::getType() const
8547 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8548 return (INTERP_KERNEL::NormalizedCellType)_conn[0];
8550 return INTERP_KERNEL::NORM_ERROR;
8553 const mcIdType *MEDCouplingUMeshCell::getAllConn(mcIdType& lgth) const
8556 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8564 namespace MEDCouplingImpl
8566 const mcIdType theUndefID = std::numeric_limits< mcIdType >::max(); //!< undefined cell id
8568 //================================================================================
8570 * \brief Encode a cell id and a mesh index into a code
8571 * \param [in] id - cell id
8572 * \param [in] iMesh - mesh index [0,1]
8573 * \return mcIdType - code
8575 //================================================================================
8577 mcIdType encodeID( mcIdType id, int iMesh )
8579 return ( id + 1 ) * ( iMesh ? -1 : 1 );
8581 //================================================================================
8583 * \brief Return cell id and mesh index by a given id
8584 * \param [in] id - code of a cell in a mesh
8585 * \param [out] iMesh - returned mesh index
8586 * \return mcIdType - cell id
8588 //================================================================================
8590 mcIdType decodeID( mcIdType id, int& iMesh )
8593 return std::abs( id ) - 1;
8596 //================================================================================
8598 * \brief return another face sharing two given nodes of a face edge
8599 * \param [in] n0 - 1st node of the edge
8600 * \param [in] n1 - 2nd node of the edge
8601 * \param [in] inputFaceID - face including \a n0 andf \a n2
8602 * \param [in] mesh - object and reference meshes
8603 * \param [in] revNodal - reverse nodal connectivity of the two meshes
8604 * \param [in] revNodalIndx - index of reverse nodal connectivity of the two meshes
8605 * \param [out] facesByEdge - return another face including \a n0 andf \a n2
8606 * \param [out] equalFaces - return faces equal to facesByEdge
8608 //================================================================================
8610 void getFacesOfEdge( mcIdType n0,
8612 mcIdType inputFaceID,
8613 MEDCouplingUMesh* mesh[],
8614 MCAuto<DataArrayIdType> revNodal[],
8615 MCAuto<DataArrayIdType> revNodalIndx[],
8616 std::vector< mcIdType >& facesByEdge,
8617 std::vector< mcIdType >& equalFaces)
8619 // find faces sharing the both nodes of edge
8621 facesByEdge.clear();
8622 size_t prevNbF; // nb faces found in 0-th mesh
8623 for ( int iM = 0; iM < 2; ++iM )
8625 const mcIdType * revInd = revNodalIndx[ iM ]->begin();
8626 const mcIdType * rev = revNodal [ iM ]->begin();
8628 mcIdType nbRevFaces0 = revInd[ n0 + 1 ] - revInd[ n0 ];
8629 mcIdType nbRevFaces1 = revInd[ n1 + 1 ] - revInd[ n1 ];
8631 prevNbF = facesByEdge.size();
8632 facesByEdge.resize( prevNbF + std::max( nbRevFaces0, nbRevFaces1 ));
8634 auto it = std::set_intersection( rev + revInd[ n0 ],
8635 rev + revInd[ n0 ] + nbRevFaces0,
8637 rev + revInd[ n1 ] + nbRevFaces1,
8638 facesByEdge.begin() + prevNbF );
8639 facesByEdge.resize( it - facesByEdge.begin() );
8642 // facesByEdge now contains at least the 'inputFaceID'
8643 // check if there are other faces
8645 size_t nbF = facesByEdge.size();
8648 if ( prevNbF > 0 && prevNbF < nbF ) // faces found in both meshes
8650 // remove from facesByEdge equal faces in different meshes
8651 const mcIdType *conn [2] = { mesh[0]->getNodalConnectivity()->getConstPointer(),
8652 mesh[1]->getNodalConnectivity()->getConstPointer() };
8653 const mcIdType *connI[2] = { mesh[0]->getNodalConnectivityIndex()->getConstPointer(),
8654 mesh[1]->getNodalConnectivityIndex()->getConstPointer() };
8655 for ( size_t i0 = 0; i0 < prevNbF; ++i0 )
8657 if ( facesByEdge[ i0 ] == theUndefID )
8659 mcIdType objFaceID = MEDCouplingImpl::encodeID( facesByEdge[ i0 ], 0 );
8660 bool isInputFace = ( objFaceID == inputFaceID );
8662 for ( size_t i1 = prevNbF; i1 < facesByEdge.size(); ++i1 )
8664 if ( facesByEdge[ i1 ] == theUndefID )
8667 mcIdType f0 = facesByEdge[ i0 ];
8668 mcIdType f1 = facesByEdge[ i1 ];
8669 size_t nbNodes0 = connI[0][ f0 + 1 ] - connI[0][ f0 ] - 1;
8670 size_t nbNodes1 = connI[1][ f1 + 1 ] - connI[1][ f1 ] - 1;
8671 if ( nbNodes0 != nbNodes1 )
8674 const mcIdType * fConn0 = conn[0] + connI[0][ f0 ] + 1;
8675 const mcIdType * fConn1 = conn[1] + connI[1][ f1 ] + 1;
8676 if ( std::equal( fConn0, fConn0 + nbNodes0, fConn1 ))
8678 // equal faces; remove an object one
8679 mcIdType refFaceID = MEDCouplingImpl::encodeID( facesByEdge[ i1 ], 1 );
8680 if ( refFaceID == inputFaceID )
8683 if ( std::find( equalFaces.begin(),
8684 equalFaces.end(), objFaceID ) == equalFaces.end() )
8685 equalFaces.push_back( objFaceID );
8687 facesByEdge[ i0 ] = theUndefID;
8689 facesByEdge[ i1 ] = theUndefID;
8694 facesByEdge[ i0 ] = theUndefID;
8699 nbF = facesByEdge.size();
8700 for ( size_t i = 0; i < facesByEdge.size(); ++i )
8702 if ( facesByEdge[ i ] != theUndefID )
8704 facesByEdge[ i ] = MEDCouplingImpl::encodeID( facesByEdge[ i ], i >= prevNbF );
8705 if ( facesByEdge[ i ] == inputFaceID )
8706 facesByEdge[ i ] = theUndefID;
8708 nbF -= ( facesByEdge[ i ] == theUndefID );
8712 return; // non-manifold
8716 facesByEdge.clear();
8718 else // nbF == 1, set a found face first
8720 if ( facesByEdge[ 0 ] == theUndefID )
8722 for ( size_t i = 1; i < facesByEdge.size(); ++i )
8723 if ( facesByEdge[ i ] != theUndefID )
8725 facesByEdge[ 0 ] = facesByEdge[ i ];
8729 facesByEdge.resize( 1 );
8734 //================================================================================
8736 * \brief Remove a face from nodal reversed connectivity
8737 * \param [in] node - a node of the face
8738 * \param [in] face - the face
8739 * \param [in.out] revNodal - reverse nodal connectivity
8740 * \param [in,out] revNodalIndx - reverse nodal connectivity index
8742 //================================================================================
8744 void removeFromRevNodal( mcIdType node,
8746 MCAuto<DataArrayIdType>& revNodal,
8747 MCAuto<DataArrayIdType>& revNodalIndx)
8749 mcIdType* fBeg = revNodal->getPointer() + revNodalIndx->getIJ( node, 0 );
8750 mcIdType* fEnd = revNodal->getPointer() + revNodalIndx->getIJ( node + 1, 0);
8751 auto it = std::find( fBeg, fEnd, face );
8754 for ( auto it2 = it + 1; it2 < fEnd; ++it2 ) // keep faces sorted
8755 *( it2 - 1 ) = *it2;
8757 *( fEnd - 1 ) = theUndefID;
8761 //================================================================================
8763 * \brief Check order of two nodes in a given face
8764 * \param [inout] n0 - node 1
8765 * \param [inout] n1 - node 2
8766 * \param [inout] iFEnc - face
8767 * \param [inout] mesh - mesh
8768 * \return bool - true if the nodes are in [ .., n1, n0, ..] order in face
8770 //================================================================================
8772 bool isReverseOrder( mcIdType n0,
8775 MEDCouplingUMesh* mesh[] )
8778 mcIdType iF = decodeID( iFEnc, iMesh );
8780 const mcIdType *conn = mesh[ iMesh ]->getNodalConnectivity()->getConstPointer();
8781 const mcIdType *connI = mesh[ iMesh ]->getNodalConnectivityIndex()->getConstPointer();
8783 auto it0 = std::find( conn + connI[ iF ] + 1,
8784 conn + connI[ iF + 1 ],
8786 auto it1 = std::find( conn + connI[ iF ] + 1,
8787 conn + connI[ iF + 1 ],
8789 long i0 = it0 - conn;
8790 long i1 = it1 - conn;
8792 bool isRev = ( std::abs( i1 - i0 ) == 1 ) ? i1 < i0 : i0 < i1;
8796 //================================================================================
8798 * \brief Change orientation of a face in one of given meshes
8799 * \param [in] iFEnc - face ID also encoding a mesh index
8800 * \param [in,out] mesh - object and reference meshes
8802 //================================================================================
8804 void reverseFace( mcIdType iFEnc, MEDCouplingUMesh* mesh[] )
8807 mcIdType face = decodeID( iFEnc, iMesh );
8809 mcIdType *conn = mesh[ iMesh ]->getNodalConnectivity()->getPointer();
8810 mcIdType *connI = mesh[ iMesh ]->getNodalConnectivityIndex()->getPointer();
8812 const INTERP_KERNEL::CellModel& cm =
8813 INTERP_KERNEL::CellModel::GetCellModel( mesh[iMesh]->getTypeOfCell( face ));
8815 cm.changeOrientationOf2D( conn + connI[ face ] + 1,
8816 (unsigned int)( connI[ face + 1 ] - connI[ face ] - 1 ));
8823 //================================================================================
8825 * \brief Orient cells of \a this 2D mesh equally to \a refFaces
8826 * \param [in] refFaces - 2D mesh containing correctly oriented faces. It is optional.
8827 * If there are no cells in \a refFaces or it is nullptr, then any face
8828 * in \a this mesh is used as a reference
8829 * \throw If \a this mesh is not well defined.
8830 * \throw If \a this mesh or \refFaces are not 2D.
8831 * \throw If \a this mesh and \refFaces do not share nodes.
8832 * \throw If \a refFaces are not equally oriented.
8833 * \throw If \a this mesh plus \a refFaces together form a non-manifold mesh.
8835 * \if ENABLE_EXAMPLES
8836 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
8837 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
8840 //================================================================================
8842 void MEDCouplingUMesh::orientCorrectly2DCells(const MEDCouplingUMesh* refFaces)
8844 checkConsistencyLight();
8845 if ( getMeshDimension() != 2 )
8846 throw INTERP_KERNEL::Exception("The mesh dimension must be 2");
8849 refFaces->checkConsistencyLight();
8850 if ( refFaces->getMeshDimension() != 2 )
8851 throw INTERP_KERNEL::Exception("The reference mesh dimension must be 2");
8852 if ( getCoords() != refFaces->getCoords() )
8853 throw INTERP_KERNEL::Exception("Object and reference meshes must share nodes ");
8854 if ( refFaces->getNumberOfCells() == 0 )
8857 if ( getNumberOfCells() == 0 )
8860 enum { _OBJ, _REF };
8861 MEDCouplingUMesh* mesh[2] = { this, const_cast< MEDCouplingUMesh* >( refFaces ) };
8862 MCAuto<MEDCouplingUMesh> meshPtr;
8865 meshPtr = mesh[_REF] = MEDCouplingUMesh::New();
8866 mesh[_REF]->setCoords( mesh[_OBJ]->getCoords() );
8867 mesh[_REF]->allocateCells(0);
8868 mesh[_REF]->finishInsertingCells();
8870 mcIdType nbFacesToCheck[2] = { mesh[_OBJ]->getNumberOfCells(),
8871 mesh[_REF]->getNumberOfCells() };
8872 std::vector< bool > isFaceQueued[ 2 ]; // enqueued faces of 2 meshes
8873 isFaceQueued[_OBJ].resize( nbFacesToCheck[_OBJ] );
8874 isFaceQueued[_REF].resize( nbFacesToCheck[_REF] );
8876 MCAuto<DataArrayIdType> revNodal [2] = { DataArrayIdType::New(), DataArrayIdType::New() };
8877 MCAuto<DataArrayIdType> revNodalIndx[2] = { DataArrayIdType::New(), DataArrayIdType::New() };
8878 mesh[_OBJ]->getReverseNodalConnectivity( revNodal[_OBJ], revNodalIndx[_OBJ] );
8879 mesh[_REF]->getReverseNodalConnectivity( revNodal[_REF], revNodalIndx[_REF] );
8881 std::vector< mcIdType > faceNodes(4);
8882 std::vector< mcIdType > facesByEdge(4), equalFaces;
8883 std::vector< mcIdType > faceQueue; // starting faces with IDs counted from 1; negative ID mean a face in ref mesh
8885 while ( nbFacesToCheck[_OBJ] + nbFacesToCheck[_REF] > 0 ) // until all faces checked
8887 if ( faceQueue.empty() ) // all neighbors checked, find more faces to check
8889 for ( int iMesh = 1; iMesh >= 0; --iMesh ) // on [ _REF, _OBJ ]
8890 if ( nbFacesToCheck[iMesh] > 0 )
8891 for ( mcIdType f = 0, nbF = mesh[iMesh]->getNumberOfCells(); f < nbF; ++f )
8892 if ( !isFaceQueued[iMesh][f] )
8894 faceQueue.push_back( MEDCouplingImpl::encodeID( f, iMesh ));
8895 isFaceQueued[ iMesh ][ f ] = true;
8899 if ( faceQueue.empty() )
8903 mcIdType fID = faceQueue.back();
8904 faceQueue.pop_back();
8907 mcIdType refFace = MEDCouplingImpl::decodeID( fID, iMesh );
8909 nbFacesToCheck[iMesh]--;
8913 mesh[iMesh]->getNodeIdsOfCell( refFace, faceNodes );
8914 const INTERP_KERNEL::CellModel& cm = INTERP_KERNEL::CellModel::GetCellModel( mesh[iMesh]->getTypeOfCell( refFace ));
8915 const int nbEdges = cm.getNumberOfSons();
8917 // loop on edges of the refFace
8918 mcIdType n0 = faceNodes[ nbEdges - 1 ]; // 1st node of edge
8919 for ( int edge = 0; edge < nbEdges; ++edge )
8921 mcIdType n1 = faceNodes[ edge ]; // 2nd node of edge
8923 // get faces sharing the edge
8924 MEDCouplingImpl::getFacesOfEdge( n0, n1, fID, mesh, revNodal, revNodalIndx,
8925 facesByEdge, equalFaces );
8927 if ( facesByEdge.size() > 1 )
8928 THROW_IK_EXCEPTION("Non-manifold mesh at edge " << n0+1 << " - " << n1+1);
8930 if ( facesByEdge.size() == 1 )
8932 // compare orientation of two faces
8934 if ( !MEDCouplingImpl::isReverseOrder( n0, n1, facesByEdge[0], mesh ))
8936 if ( facesByEdge[0] < 0 ) // in the ref mesh
8937 throw INTERP_KERNEL::Exception("Different orientation of reference faces");
8939 MEDCouplingImpl::reverseFace( facesByEdge[0], mesh );
8941 mcIdType face2 = MEDCouplingImpl::decodeID( facesByEdge[0], iMesh2 );
8942 if ( !isFaceQueued[iMesh2][face2] )
8944 isFaceQueued[iMesh2][face2] = true;
8945 faceQueue.push_back( facesByEdge[0] );
8951 // remove face and equalFaces from revNodal in order not to treat them again
8952 equalFaces.push_back( fID );
8953 for ( mcIdType face : equalFaces )
8955 mcIdType f = MEDCouplingImpl::decodeID( face, iMesh2 );
8956 const mcIdType *conn = mesh[iMesh2]->getNodalConnectivity()->getConstPointer();
8957 const mcIdType *connI = mesh[iMesh2]->getNodalConnectivityIndex()->getConstPointer();
8958 mcIdType nbNodes = connI[ f + 1 ] - connI[ f ] - 1;
8959 for ( const mcIdType* n = conn + connI[ f ] + 1, *nEnd = n + nbNodes; n < nEnd; ++n )
8961 MEDCouplingImpl::removeFromRevNodal( *n, f, // not to treat f again
8962 revNodal[ iMesh2 ], revNodalIndx[ iMesh2 ] );
8965 } // while() until all faces checked