1 // Copyright (C) 2007-2022 CEA/DEN, EDF R&D
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 // Author : Anthony Geay (EDF R&D)
21 #include "MEDCouplingUMesh.txx"
22 #include "MEDCouplingCMesh.hxx"
23 #include "MEDCoupling1GTUMesh.hxx"
24 #include "MEDCouplingFieldDouble.hxx"
25 #include "MEDCouplingSkyLineArray.hxx"
26 #include "CellModel.hxx"
27 #include "VolSurfUser.txx"
28 #include "InterpolationUtils.hxx"
29 #include "PointLocatorAlgos.txx"
31 #include "BBTreeDst.txx"
32 #include "SplitterTetra.hxx"
33 #include "DiameterCalculator.hxx"
34 #include "DirectedBoundingBox.hxx"
35 #include "InterpKernelMatrixTools.hxx"
36 #include "InterpKernelMeshQuality.hxx"
37 #include "InterpKernelCellSimplify.hxx"
38 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
39 #include "InterpKernelAutoPtr.hxx"
40 #include "InterpKernelGeo2DNode.hxx"
41 #include "InterpKernelGeo2DEdgeLin.hxx"
42 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
43 #include "InterpKernelGeo2DQuadraticPolygon.hxx"
44 #include "OrientationInverter.hxx"
45 #include "MEDCouplingUMesh_internal.hxx"
55 using namespace MEDCoupling;
57 double MEDCouplingUMesh::EPS_FOR_POLYH_ORIENTATION=1.e-14;
61 const INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::MEDMEM_ORDER[N_MEDMEM_ORDER] = { INTERP_KERNEL::NORM_POINT1, INTERP_KERNEL::NORM_SEG2, INTERP_KERNEL::NORM_SEG3, INTERP_KERNEL::NORM_SEG4, INTERP_KERNEL::NORM_POLYL, INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4, INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_TRI7, INTERP_KERNEL::NORM_QUAD8, INTERP_KERNEL::NORM_QUAD9, INTERP_KERNEL::NORM_POLYGON, INTERP_KERNEL::NORM_QPOLYG, INTERP_KERNEL::NORM_TETRA4, INTERP_KERNEL::NORM_PYRA5, INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXA8, INTERP_KERNEL::NORM_HEXGP12, INTERP_KERNEL::NORM_TETRA10, INTERP_KERNEL::NORM_PYRA13, INTERP_KERNEL::NORM_PENTA15, INTERP_KERNEL::NORM_PENTA18, INTERP_KERNEL::NORM_HEXA20, INTERP_KERNEL::NORM_HEXA27, INTERP_KERNEL::NORM_POLYHED };
64 MEDCouplingUMesh *MEDCouplingUMesh::New()
66 return new MEDCouplingUMesh;
69 MEDCouplingUMesh *MEDCouplingUMesh::New(const std::string& meshName, int meshDim)
71 MEDCouplingUMesh *ret=new MEDCouplingUMesh;
72 ret->setName(meshName);
73 ret->setMeshDimension(meshDim);
78 * Returns a new MEDCouplingUMesh which is a full copy of \a this one. No data is shared
79 * between \a this and the new mesh.
80 * \return MEDCouplingUMesh * - a new instance of MEDCouplingMesh. The caller is to
81 * delete this mesh using decrRef() as it is no more needed.
83 MEDCouplingUMesh *MEDCouplingUMesh::deepCopy() const
90 * Returns a new MEDCouplingUMesh which is a copy of \a this one.
91 * \param [in] recDeepCpy - if \a true, the copy is deep, else all data arrays of \a
92 * this mesh are shared by the new mesh.
93 * \return MEDCouplingUMesh * - a new instance of MEDCouplingMesh. The caller is to
94 * delete this mesh using decrRef() as it is no more needed.
96 MEDCouplingUMesh *MEDCouplingUMesh::clone(bool recDeepCpy) const
98 return new MEDCouplingUMesh(*this,recDeepCpy);
102 * This method behaves mostly like MEDCouplingUMesh::deepCopy method, except that only nodal connectivity arrays are deeply copied.
103 * The coordinates are shared between \a this and the returned instance.
105 * \return MEDCouplingUMesh * - A new object instance holding the copy of \a this (deep for connectivity, shallow for coordiantes)
106 * \sa MEDCouplingUMesh::deepCopy
108 MEDCouplingUMesh *MEDCouplingUMesh::deepCopyConnectivityOnly() const
110 checkConnectivityFullyDefined();
111 MCAuto<MEDCouplingUMesh> ret=clone(false);
112 MCAuto<DataArrayIdType> c(getNodalConnectivity()->deepCopy()),ci(getNodalConnectivityIndex()->deepCopy());
113 ret->setConnectivity(c,ci);
117 void MEDCouplingUMesh::shallowCopyConnectivityFrom(const MEDCouplingPointSet *other)
120 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is null !");
121 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
123 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is not an MEDCouplingUMesh instance !");
124 MEDCouplingUMesh *otherC2=const_cast<MEDCouplingUMesh *>(otherC);//sorry :(
125 setConnectivity(otherC2->getNodalConnectivity(),otherC2->getNodalConnectivityIndex(),true);
128 std::size_t MEDCouplingUMesh::getHeapMemorySizeWithoutChildren() const
130 std::size_t ret(MEDCouplingPointSet::getHeapMemorySizeWithoutChildren());
134 std::vector<const BigMemoryObject *> MEDCouplingUMesh::getDirectChildrenWithNull() const
136 std::vector<const BigMemoryObject *> ret(MEDCouplingPointSet::getDirectChildrenWithNull());
137 ret.push_back(_nodal_connec);
138 ret.push_back(_nodal_connec_index);
142 void MEDCouplingUMesh::updateTime() const
144 MEDCouplingPointSet::updateTime();
147 updateTimeWith(*_nodal_connec);
149 if(_nodal_connec_index)
151 updateTimeWith(*_nodal_connec_index);
155 MEDCouplingUMesh::MEDCouplingUMesh():_mesh_dim(-2),_nodal_connec(0),_nodal_connec_index(0)
160 * Checks if \a this mesh is well defined. If no exception is thrown by this method,
161 * then \a this mesh is most probably is writable, exchangeable and available for most
162 * of algorithms. When a mesh is constructed from scratch, it is a good habit to call
163 * this method to check that all is in order with \a this mesh.
164 * \throw If the mesh dimension is not set.
165 * \throw If the coordinates array is not set (if mesh dimension != -1 ).
166 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
167 * \throw If the connectivity data array has more than one component.
168 * \throw If the connectivity data array has a named component.
169 * \throw If the connectivity index data array has more than one component.
170 * \throw If the connectivity index data array has a named component.
172 void MEDCouplingUMesh::checkConsistencyLight() const
175 throw INTERP_KERNEL::Exception("No mesh dimension specified !");
177 MEDCouplingPointSet::checkConsistencyLight();
178 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
180 if(ToIdType(INTERP_KERNEL::CellModel::GetCellModel(*iter).getDimension())!=_mesh_dim)
182 std::ostringstream message;
183 message << "Mesh invalid because dimension is " << _mesh_dim << " and there is presence of cell(s) with type " << (*iter);
184 throw INTERP_KERNEL::Exception(message.str().c_str());
189 if(_nodal_connec->getNumberOfComponents()!=1)
190 throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to be with number of components set to one !");
191 if(_nodal_connec->getInfoOnComponent(0)!="")
192 throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to have no info on its single component !");
196 throw INTERP_KERNEL::Exception("Nodal connectivity array is not defined !");
197 if(_nodal_connec_index)
199 if(_nodal_connec_index->getNumberOfComponents()!=1)
200 throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to be with number of components set to one !");
201 if(_nodal_connec_index->getInfoOnComponent(0)!="")
202 throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to have no info on its single component !");
206 throw INTERP_KERNEL::Exception("Nodal connectivity index array is not defined !");
210 * Checks if \a this mesh is well defined. If no exception is thrown by this method,
211 * then \a this mesh is informatically clean, most probably is writable, exchangeable and available for all
212 * algorithms. <br> In addition to the checks performed by checkConsistencyLight(), this
213 * method thoroughly checks the nodal connectivity. For more geometrical checking
214 * checkGeomConsistency method is better than this.
216 * \sa MEDCouplingUMesh::checkGeomConsistency
218 * \param [in] eps - a not used parameter.
219 * \throw If the mesh dimension is not set.
220 * \throw If the coordinates array is not set (if mesh dimension != -1 ).
221 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
222 * \throw If the connectivity data array has more than one component.
223 * \throw If the connectivity data array has a named component.
224 * \throw If the connectivity index data array has more than one component.
225 * \throw If the connectivity index data array has a named component.
226 * \throw If number of nodes defining an element does not correspond to the type of element.
227 * \throw If the nodal connectivity includes an invalid node id.
229 void MEDCouplingUMesh::checkConsistency(double eps) const
231 checkConsistencyLight();
234 int meshDim=getMeshDimension();
235 mcIdType nbOfNodes=getNumberOfNodes();
236 mcIdType nbOfCells=getNumberOfCells();
237 const mcIdType *ptr=_nodal_connec->getConstPointer();
238 const mcIdType *ptrI=_nodal_connec_index->getConstPointer();
239 for(mcIdType i=0;i<nbOfCells;i++)
241 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)ptr[ptrI[i]]);
242 if(ToIdType(cm.getDimension())!=meshDim)
244 std::ostringstream oss;
245 oss << "MEDCouplingUMesh::checkConsistency : cell << #" << i<< " with type Type " << cm.getRepr() << " in 'this' whereas meshdim == " << meshDim << " !";
246 throw INTERP_KERNEL::Exception(oss.str());
248 mcIdType nbOfNodesInCell=ptrI[i+1]-ptrI[i]-1;
250 if(nbOfNodesInCell!=ToIdType(cm.getNumberOfNodes()))
252 std::ostringstream oss;
253 oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with static Type '" << cm.getRepr() << "' has " << cm.getNumberOfNodes();
254 oss << " nodes whereas in connectivity there is " << nbOfNodesInCell << " nodes ! Looks very bad !";
255 throw INTERP_KERNEL::Exception(oss.str());
257 if(cm.isQuadratic() && cm.isDynamic() && meshDim == 2)
258 if (nbOfNodesInCell % 2 || nbOfNodesInCell < 4)
260 std::ostringstream oss;
261 oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with quadratic type '" << cm.getRepr() << "' has " << nbOfNodesInCell;
262 oss << " nodes. This should be even, and greater or equal than 4!! Looks very bad!";
263 throw INTERP_KERNEL::Exception(oss.str());
265 for(const mcIdType *w=ptr+ptrI[i]+1;w!=ptr+ptrI[i+1];w++)
270 if(nodeId>=nbOfNodes)
272 std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " whereas there are only " << nbOfNodes << " nodes in the mesh !";
273 throw INTERP_KERNEL::Exception(oss.str());
278 std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " in connectivity ! sounds bad !";
279 throw INTERP_KERNEL::Exception(oss.str());
283 if((INTERP_KERNEL::NormalizedCellType)(ptr[ptrI[i]])!=INTERP_KERNEL::NORM_POLYHED)
285 std::ostringstream oss; oss << "Cell #" << i << " is built with node #-1 in connectivity ! sounds bad !";
286 throw INTERP_KERNEL::Exception(oss.str());
294 * This method adds some geometrical checks in addition to the informatical check of checkConsistency method.
295 * This method in particular checks that a same node is not repeated several times in a cell.
297 * \throw If there is a presence a multiple same node ID in nodal connectivity of cell.
299 void MEDCouplingUMesh::checkGeomConsistency(double eps) const
301 this->checkConsistency(eps);
302 auto nbOfCells(getNumberOfCells());
303 const mcIdType *ptr(_nodal_connec->begin()),*ptrI(_nodal_connec_index->begin());
304 for(auto icell = 0 ; icell < nbOfCells ; ++icell)
306 std::set<mcIdType> s(ptr+ptrI[icell]+1,ptr+ptrI[icell+1]);
307 if(ToIdType(s.size())==ptrI[icell+1]-ptrI[icell]-1)
309 std::ostringstream oss; oss << "MEDCouplingUMesh::checkGeomConsistency : for cell #" << icell << " presence of multiple same nodeID !";
310 throw INTERP_KERNEL::Exception(oss.str());
316 * Sets dimension of \a this mesh. The mesh dimension in general depends on types of
317 * elements contained in the mesh. For more info on the mesh dimension see
318 * \ref MEDCouplingUMeshPage.
319 * \param [in] meshDim - a new mesh dimension.
320 * \throw If \a meshDim is invalid. A valid range is <em> -1 <= meshDim <= 3</em>.
322 void MEDCouplingUMesh::setMeshDimension(int meshDim)
324 if(meshDim<-1 || meshDim>3)
325 throw INTERP_KERNEL::Exception("Invalid meshDim specified ! Must be greater or equal to -1 and lower or equal to 3 !");
331 * Allocates memory to store an estimation of the given number of cells.
332 * The closer the estimation to the number of cells effectively inserted, the less need the library requires
333 * to reallocate memory. If the number of cells to be inserted is not known simply assign 0 to this parameter.
334 * If a nodal connectivity previously existed before the call of this method, it will be reset.
336 * \param [in] nbOfCells - estimation of the number of cell \a this mesh will contain.
338 * \if ENABLE_EXAMPLES
339 * \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
340 * \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
343 void MEDCouplingUMesh::allocateCells(mcIdType nbOfCells)
346 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::allocateCells : the input number of cells should be >= 0 !");
347 if(_nodal_connec_index)
349 _nodal_connec_index->decrRef();
353 _nodal_connec->decrRef();
355 _nodal_connec_index=DataArrayIdType::New();
356 _nodal_connec_index->reserve(nbOfCells+1);
357 _nodal_connec_index->pushBackSilent(0);
358 _nodal_connec=DataArrayIdType::New();
359 _nodal_connec->reserve(2*nbOfCells);
365 * Appends a cell to the connectivity array. For deeper understanding what is
366 * happening see \ref MEDCouplingUMeshNodalConnectivity.
367 * \param [in] type - type of cell to add.
368 * \param [in] size - number of nodes constituting this cell.
369 * \param [in] nodalConnOfCell - the connectivity of the cell to add.
371 * \if ENABLE_EXAMPLES
372 * \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
373 * \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
376 void MEDCouplingUMesh::insertNextCell(INTERP_KERNEL::NormalizedCellType type, mcIdType size, const mcIdType *nodalConnOfCell)
378 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
379 if(_nodal_connec_index==0)
380 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::insertNextCell : nodal connectivity not set ! invoke allocateCells before calling insertNextCell !");
381 if(ToIdType(cm.getDimension())==_mesh_dim)
384 if(size!=ToIdType(cm.getNumberOfNodes()))
386 std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : Trying to push a " << cm.getRepr() << " cell with a size of " << size;
387 oss << " ! Expecting " << cm.getNumberOfNodes() << " !";
388 throw INTERP_KERNEL::Exception(oss.str());
390 mcIdType idx=_nodal_connec_index->back();
391 mcIdType val=idx+size+1;
392 _nodal_connec_index->pushBackSilent(val);
393 _nodal_connec->writeOnPlace(idx,type,nodalConnOfCell,size);
398 std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : cell type " << cm.getRepr() << " has a dimension " << cm.getDimension();
399 oss << " whereas Mesh Dimension of current UMesh instance is set to " << _mesh_dim << " ! Please invoke \"setMeshDimension\" method before or invoke ";
400 oss << "\"MEDCouplingUMesh::New\" static method with 2 parameters name and meshDimension !";
401 throw INTERP_KERNEL::Exception(oss.str());
406 * Compacts data arrays to release unused memory. This method is to be called after
407 * finishing cell insertion using \a this->insertNextCell().
409 * \if ENABLE_EXAMPLES
410 * \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
411 * \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
414 void MEDCouplingUMesh::finishInsertingCells()
416 _nodal_connec->pack();
417 _nodal_connec_index->pack();
418 _nodal_connec->declareAsNew();
419 _nodal_connec_index->declareAsNew();
424 * Entry point for iteration over cells of this. Warning the returned cell iterator should be deallocated.
425 * Useful for python users.
427 MEDCouplingUMeshCellIterator *MEDCouplingUMesh::cellIterator()
429 return new MEDCouplingUMeshCellIterator(this);
433 * Entry point for iteration over cells groups geo types per geotypes. Warning the returned cell iterator should be deallocated.
434 * If \a this is not so that the cells are grouped by geo types, this method will throw an exception.
435 * In this case MEDCouplingUMesh::sortCellsInMEDFileFrmt or MEDCouplingUMesh::rearrange2ConsecutiveCellTypes methods for example can be called before invoking this method.
436 * Useful for python users.
438 MEDCouplingUMeshCellByTypeEntry *MEDCouplingUMesh::cellsByType()
440 if(!checkConsecutiveCellTypes())
441 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::cellsByType : this mesh is not sorted by type !");
442 return new MEDCouplingUMeshCellByTypeEntry(this);
446 * Returns a set of all cell types available in \a this mesh.
447 * \return std::set<INTERP_KERNEL::NormalizedCellType> - the set of cell types.
448 * \warning this method does not throw any exception even if \a this is not defined.
449 * \sa MEDCouplingUMesh::getAllGeoTypesSorted
451 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypes() const
457 * This method returns the sorted list of geometric types in \a this.
458 * Sorted means in the same order than the cells in \a this. A single entry in return vector means the maximal chunk of consecutive cells in \a this
459 * having the same geometric type. So a same geometric type can appear more than once if the cells are not sorted per geometric type.
461 * \throw if connectivity in \a this is not correctly defined.
463 * \sa MEDCouplingMesh::getAllGeoTypes
465 std::vector<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypesSorted() const
467 std::vector<INTERP_KERNEL::NormalizedCellType> ret;
468 checkConnectivityFullyDefined();
469 mcIdType nbOfCells=getNumberOfCells();
472 if(getNodalConnectivityArrayLen()<1)
473 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAllGeoTypesSorted : the connectivity in this seems invalid !");
474 const mcIdType *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin());
475 ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci++]);
476 for(mcIdType i=1;i<nbOfCells;i++,ci++)
477 if(ret.back()!=((INTERP_KERNEL::NormalizedCellType)c[*ci]))
478 ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci]);
483 * This method is a method that compares \a this and \a other.
484 * This method compares \b all attributes, even names and component names.
486 bool MEDCouplingUMesh::isEqualIfNotWhy(const MEDCouplingMesh *other, double prec, std::string& reason) const
489 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isEqualIfNotWhy : input other pointer is null !");
490 std::ostringstream oss; oss.precision(15);
491 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
494 reason="mesh given in input is not castable in MEDCouplingUMesh !";
497 if(!MEDCouplingPointSet::isEqualIfNotWhy(other,prec,reason))
499 if(_mesh_dim!=otherC->_mesh_dim)
501 oss << "umesh dimension mismatch : this mesh dimension=" << _mesh_dim << " other mesh dimension=" << otherC->_mesh_dim;
505 if(_types!=otherC->_types)
507 oss << "umesh geometric type mismatch :\nThis geometric types are :";
508 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
509 { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
510 oss << "\nOther geometric types are :";
511 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=otherC->_types.begin();iter!=otherC->_types.end();iter++)
512 { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
516 if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
517 if(_nodal_connec==0 || otherC->_nodal_connec==0)
519 reason="Only one UMesh between the two this and other has its nodal connectivity DataArrayInt defined !";
522 if(_nodal_connec!=otherC->_nodal_connec)
523 if(!_nodal_connec->isEqualIfNotWhy(*otherC->_nodal_connec,reason))
525 reason.insert(0,"Nodal connectivity DataArrayInt differ : ");
528 if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
529 if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
531 reason="Only one UMesh between the two this and other has its nodal connectivity index DataArrayInt defined !";
534 if(_nodal_connec_index!=otherC->_nodal_connec_index)
535 if(!_nodal_connec_index->isEqualIfNotWhy(*otherC->_nodal_connec_index,reason))
537 reason.insert(0,"Nodal connectivity index DataArrayInt differ : ");
544 * Checks if data arrays of this mesh (node coordinates, nodal
545 * connectivity of cells, etc) of two meshes are same. Textual data like name etc. are
547 * \param [in] other - the mesh to compare with.
548 * \param [in] prec - precision value used to compare node coordinates.
549 * \return bool - \a true if the two meshes are same.
551 bool MEDCouplingUMesh::isEqualWithoutConsideringStr(const MEDCouplingMesh *other, double prec) const
553 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
556 if(!MEDCouplingPointSet::isEqualWithoutConsideringStr(other,prec))
558 if(_mesh_dim!=otherC->_mesh_dim)
560 if(_types!=otherC->_types)
562 if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
563 if(_nodal_connec==0 || otherC->_nodal_connec==0)
565 if(_nodal_connec!=otherC->_nodal_connec)
566 if(!_nodal_connec->isEqualWithoutConsideringStr(*otherC->_nodal_connec))
568 if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
569 if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
571 if(_nodal_connec_index!=otherC->_nodal_connec_index)
572 if(!_nodal_connec_index->isEqualWithoutConsideringStr(*otherC->_nodal_connec_index))
578 * Checks if \a this and \a other meshes are geometrically equivalent with high
579 * probability, else an exception is thrown. The meshes are considered equivalent if
580 * (1) meshes contain the same number of nodes and the same number of elements of the
581 * same types (2) three cells of the two meshes (first, last and middle) are based
582 * on coincident nodes (with a specified precision).
583 * \param [in] other - the mesh to compare with.
584 * \param [in] prec - the precision used to compare nodes of the two meshes.
585 * \throw If the two meshes do not match.
587 void MEDCouplingUMesh::checkFastEquivalWith(const MEDCouplingMesh *other, double prec) const
589 MEDCouplingPointSet::checkFastEquivalWith(other,prec);
590 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
592 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkFastEquivalWith : Two meshes are not not unstructured !");
596 * Returns the reverse nodal connectivity. The reverse nodal connectivity enumerates
597 * cells each node belongs to.
598 * \warning For speed reasons, this method does not check if node ids in the nodal
599 * connectivity correspond to the size of node coordinates array.
600 * \param [in,out] revNodal - an array holding ids of cells sharing each node.
601 * \param [in,out] revNodalIndx - an array, of length \a this->getNumberOfNodes() + 1,
602 * dividing cell ids in \a revNodal into groups each referring to one
603 * node. Its every element (except the last one) is an index pointing to the
604 * first id of a group of cells. For example cells sharing the node #1 are
605 * described by following range of indices:
606 * [ \a revNodalIndx[1], \a revNodalIndx[2] ) and the cell ids are
607 * \a revNodal[ \a revNodalIndx[1] ], \a revNodal[ \a revNodalIndx[1] + 1], ...
608 * Number of cells sharing the *i*-th node is
609 * \a revNodalIndx[ *i*+1 ] - \a revNodalIndx[ *i* ].
610 * \throw If the coordinates array is not set.
611 * \throw If the nodal connectivity of cells is not defined.
613 * \if ENABLE_EXAMPLES
614 * \ref cpp_mcumesh_getReverseNodalConnectivity "Here is a C++ example".<br>
615 * \ref py_mcumesh_getReverseNodalConnectivity "Here is a Python example".
618 void MEDCouplingUMesh::getReverseNodalConnectivity(DataArrayIdType *revNodal, DataArrayIdType *revNodalIndx) const
621 mcIdType nbOfNodes(getNumberOfNodes());
622 mcIdType *revNodalIndxPtr=(mcIdType *)malloc((nbOfNodes+1)*sizeof(mcIdType));
623 revNodalIndx->useArray(revNodalIndxPtr,true,DeallocType::C_DEALLOC,nbOfNodes+1,1);
624 std::fill(revNodalIndxPtr,revNodalIndxPtr+nbOfNodes+1,0);
625 const mcIdType *conn(_nodal_connec->begin()),*connIndex(_nodal_connec_index->begin());
626 mcIdType nbOfCells(getNumberOfCells()),nbOfEltsInRevNodal(0);
627 for(mcIdType eltId=0;eltId<nbOfCells;eltId++)
629 const mcIdType *strtNdlConnOfCurCell(conn+connIndex[eltId]+1),*endNdlConnOfCurCell(conn+connIndex[eltId+1]);
630 for(const mcIdType *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
631 if(*iter>=0)//for polyhedrons
633 nbOfEltsInRevNodal++;
634 revNodalIndxPtr[(*iter)+1]++;
637 std::transform(revNodalIndxPtr+1,revNodalIndxPtr+nbOfNodes+1,revNodalIndxPtr,revNodalIndxPtr+1,std::plus<mcIdType>());
638 mcIdType *revNodalPtr=(mcIdType *)malloc(nbOfEltsInRevNodal*sizeof(mcIdType));
639 revNodal->useArray(revNodalPtr,true,DeallocType::C_DEALLOC,nbOfEltsInRevNodal,1);
640 std::fill(revNodalPtr,revNodalPtr+nbOfEltsInRevNodal,-1);
641 for(mcIdType eltId=0;eltId<nbOfCells;eltId++)
643 const mcIdType *strtNdlConnOfCurCell=conn+connIndex[eltId]+1;
644 const mcIdType *endNdlConnOfCurCell=conn+connIndex[eltId+1];
645 for(const mcIdType *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
646 if(*iter>=0)//for polyhedrons
647 *std::find_if(revNodalPtr+revNodalIndxPtr[*iter],revNodalPtr+revNodalIndxPtr[*iter+1],std::bind(std::equal_to<mcIdType>(),std::placeholders::_1,-1))=eltId;
652 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
653 * this->getMeshDimension(), that bound cells of \a this mesh. In addition arrays
654 * describing correspondence between cells of \a this and the result meshes are
655 * returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending connectivity,
656 * i.e. enumerate cells of the result mesh bounding each cell of \a this mesh. The
657 * arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
658 * i.e. enumerate cells of \a this mesh bounded by each cell of the result mesh.
659 * \warning For speed reasons, this method does not check if node ids in the nodal
660 * connectivity correspond to the size of node coordinates array.
661 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
662 * to write this mesh to the MED file, its cells must be sorted using
663 * sortCellsInMEDFileFrmt().
664 * \param [in,out] desc - the array containing cell ids of the result mesh bounding
665 * each cell of \a this mesh.
666 * \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
667 * dividing cell ids in \a desc into groups each referring to one
668 * cell of \a this mesh. Its every element (except the last one) is an index
669 * pointing to the first id of a group of cells. For example cells of the
670 * result mesh bounding the cell #1 of \a this mesh are described by following
672 * [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
673 * \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
674 * Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
675 * \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
676 * \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
677 * by each cell of the result mesh.
678 * \param [in,out] revDescIndx - the array, of length one more than number of cells
679 * in the result mesh,
680 * dividing cell ids in \a revDesc into groups each referring to one
681 * cell of the result mesh the same way as \a descIndx divides \a desc.
682 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is to
683 * delete this mesh using decrRef() as it is no more needed.
684 * \throw If the coordinates array is not set.
685 * \throw If the nodal connectivity of cells is node defined.
686 * \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
687 * revDescIndx == NULL.
689 * \if ENABLE_EXAMPLES
690 * \ref cpp_mcumesh_buildDescendingConnectivity "Here is a C++ example".<br>
691 * \ref py_mcumesh_buildDescendingConnectivity "Here is a Python example".
693 * \sa buildDescendingConnectivity2()
695 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
697 return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
701 * \a this has to have a mesh dimension equal to 3. If it is not the case an INTERP_KERNEL::Exception will be thrown.
702 * This behaves exactly as MEDCouplingUMesh::buildDescendingConnectivity does except that this method compute directly the transition from mesh dimension 3 to sub edges (dimension 1)
703 * in one shot. That is to say that this method is equivalent to 2 successive calls to MEDCouplingUMesh::buildDescendingConnectivity.
704 * This method returns 4 arrays and a mesh as MEDCouplingUMesh::buildDescendingConnectivity does.
705 * \sa MEDCouplingUMesh::buildDescendingConnectivity
707 MEDCouplingUMesh *MEDCouplingUMesh::explode3DMeshTo1D(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
710 if(getMeshDimension()!=3)
711 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explode3DMeshTo1D : This has to have a mesh dimension to 3 !");
712 return buildDescendingConnectivityGen<MinusTwoSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
716 * This method computes the micro edges constituting each cell in \a this. Micro edge is an edge for non quadratic cells. Micro edge is an half edge for quadratic cells.
717 * This method works for both meshes with mesh dimension equal to 2 or 3. Dynamical cells are not supported (polygons, polyhedrons...)
719 * \sa explode3DMeshTo1D, buildDescendingConnectiviy
721 MEDCouplingUMesh *MEDCouplingUMesh::explodeMeshIntoMicroEdges(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
724 switch(getMeshDimension())
727 return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
729 return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
731 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explodeMeshIntoMicroEdges : Only 2D and 3D supported !");
736 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
737 * this->getMeshDimension(), that bound cells of \a this mesh. In
738 * addition arrays describing correspondence between cells of \a this and the result
739 * meshes are returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending
740 * connectivity, i.e. enumerate cells of the result mesh bounding each cell of \a this
741 * mesh. This method differs from buildDescendingConnectivity() in that apart
742 * from cell ids, \a desc returns mutual orientation of cells in \a this and the
743 * result meshes. So a positive id means that order of nodes in corresponding cells
744 * of two meshes is same, and a negative id means a reverse order of nodes. Since a
745 * cell with id #0 can't be negative, the array \a desc returns ids in FORTRAN mode,
746 * i.e. cell ids are one-based.
747 * Arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
748 * i.e. enumerate cells of \a this mesh bounded by each cell of the result mesh.
749 * \warning For speed reasons, this method does not check if node ids in the nodal
750 * connectivity correspond to the size of node coordinates array.
751 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
752 * to write this mesh to the MED file, its cells must be sorted using
753 * sortCellsInMEDFileFrmt().
754 * \param [in,out] desc - the array containing cell ids of the result mesh bounding
755 * each cell of \a this mesh.
756 * \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
757 * dividing cell ids in \a desc into groups each referring to one
758 * cell of \a this mesh. Its every element (except the last one) is an index
759 * pointing to the first id of a group of cells. For example cells of the
760 * result mesh bounding the cell #1 of \a this mesh are described by following
762 * [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
763 * \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
764 * Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
765 * \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
766 * \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
767 * by each cell of the result mesh.
768 * \param [in,out] revDescIndx - the array, of length one more than number of cells
769 * in the result mesh,
770 * dividing cell ids in \a revDesc into groups each referring to one
771 * cell of the result mesh the same way as \a descIndx divides \a desc.
772 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This result mesh
773 * shares the node coordinates array with \a this mesh. The caller is to
774 * delete this mesh using decrRef() as it is no more needed.
775 * \throw If the coordinates array is not set.
776 * \throw If the nodal connectivity of cells is node defined.
777 * \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
778 * revDescIndx == NULL.
780 * \if ENABLE_EXAMPLES
781 * \ref cpp_mcumesh_buildDescendingConnectivity2 "Here is a C++ example".<br>
782 * \ref py_mcumesh_buildDescendingConnectivity2 "Here is a Python example".
784 * \sa buildDescendingConnectivity()
786 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity2(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
788 return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingOrientationSensitiveNbrer);
792 * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
793 * For speed reasons no check of this will be done. This method calls
794 * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
795 * This method lists for every cell in \b this its neighbor \b cells. To compute the result
796 * only connectivities are considered.
797 * The neighbor cells of a given cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
798 * The format of return is hence \ref numbering-indirect.
800 * \param [out] neighbors is an array storing all the neighbors of all cells in \b this. This array is newly
801 * allocated and should be dealt by the caller. \b neighborsIndx 2nd output
802 * parameter allows to select the right part in this array (\ref numbering-indirect). The number of tuples
803 * is equal to the last values in \b neighborsIndx.
804 * \param [out] neighborsIndx is an array of size this->getNumberOfCells()+1 newly allocated and should be
805 * dealt by the caller. This arrays allow to use the first output parameter \b neighbors (\ref numbering-indirect).
807 void MEDCouplingUMesh::computeNeighborsOfCells(DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIndx) const
809 MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
810 MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
811 MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
812 MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
813 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
815 ComputeNeighborsOfCellsAdv(desc,descIndx,revDesc,revDescIndx,neighbors,neighborsIndx);
819 * Given a set of identifiers indexed by the node IDs of the mesh (and given in the (\ref numbering-indirect format) ,
820 * re-arrange the data to produce a set indexed by cell IDs. The mapping between a node ID and a cell ID is done using the connectivity
821 * of the mesh (e.g. a triangular element will receive the information from its three vertices).
822 * Doublons are eliminated. If present in the inital dataset, the ID of the cell itself is also remooved.
824 * \param [in] nodeNeigh a set of identifiers (mcIdType) stored by node index (\ref numbering-indirect format)
825 * \param [in] nodeNeighI a set of identifiers (mcIdType) stored by node index (\ref numbering-indirect format)
826 * \param [out] cellNeigh This array is newly allocated and should be dealt by the caller. It contains the initial identifiers
827 * provided in the input parameters but stored now by cell index (See 2nd output parameter and \ref numbering-indirect).
828 * \param [out] cellNeighI is an array of size this->getNumberOfCells()+1 newly allocated and should be
829 * dealt by the caller. This arrays allow to use the first output parameter \b neighbors (\ref numbering-indirect).
831 * \raise if the number of tuples in nodeNeighI is not equal to the number of nodes in the mesh.
833 void MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne(const DataArrayIdType *nodeNeigh, const DataArrayIdType *nodeNeighI,
834 MCAuto<DataArrayIdType>& cellNeigh, MCAuto<DataArrayIdType>& cellNeighIndex) const
836 if(!nodeNeigh || !nodeNeighI)
837 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : null pointer !");
838 checkConsistencyLight();
839 nodeNeigh->checkAllocated(); nodeNeighI->checkAllocated();
840 nodeNeigh->checkNbOfComps(1,"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : node neigh");
841 nodeNeighI->checkNbOfComps(1,"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : node neigh index");
842 nodeNeighI->checkNbOfTuples(1+getNumberOfNodes(),"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : invalid length");
843 mcIdType nbCells=getNumberOfCells();
844 const mcIdType *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin()),*ne(nodeNeigh->begin()),*nei(nodeNeighI->begin());
845 cellNeigh=DataArrayIdType::New(); cellNeigh->alloc(0,1); cellNeighIndex=DataArrayIdType::New(); cellNeighIndex->alloc(1,1); cellNeighIndex->setIJ(0,0,0);
846 for(mcIdType i=0;i<nbCells;i++)
848 std::set<mcIdType> s;
849 for(const mcIdType *it=c+ci[i]+1;it!=c+ci[i+1];it++)
850 if(*it>=0) // avoid -1 in polygons or polyedrons
851 s.insert(ne+nei[*it],ne+nei[*it+1]);
853 cellNeigh->insertAtTheEnd(s.begin(),s.end());
854 cellNeighIndex->pushBackSilent(cellNeigh->getNumberOfTuples());
859 * This method is called by MEDCouplingUMesh::computeNeighborsOfCells. This methods performs the algorithm
860 * of MEDCouplingUMesh::computeNeighborsOfCells.
861 * This method is useful for users that want to reduce along a criterion the set of neighbours cell. This is
862 * typically the case to extract a set a neighbours,
863 * excluding a set of meshdim-1 cells in input descending connectivity.
864 * Typically \b desc, \b descIndx, \b revDesc and \b revDescIndx (\ref numbering-indirect) input params are
865 * the result of MEDCouplingUMesh::buildDescendingConnectivity.
866 * This method lists cell by cell in \b this which are its neighbors. To compute the result only connectivities
868 * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
870 * \param [in] desc descending connectivity array.
871 * \param [in] descIndx descending connectivity index array used to walk through \b desc (\ref numbering-indirect).
872 * \param [in] revDesc reverse descending connectivity array.
873 * \param [in] revDescIndx reverse descending connectivity index array used to walk through \b revDesc (\ref numbering-indirect).
874 * \param [out] neighbors is an array storing all the neighbors of all cells in \b this. This array is newly allocated and should be dealt by the caller. \b neighborsIndx 2nd output
875 * parameter allows to select the right part in this array. The number of tuples is equal to the last values in \b neighborsIndx.
876 * \param [out] neighborsIndx is an array of size this->getNumberOfCells()+1 newly allocated and should be dealt by the caller. This arrays allow to use the first output parameter \b neighbors.
878 void MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(const DataArrayIdType *desc, const DataArrayIdType *descIndx, const DataArrayIdType *revDesc, const DataArrayIdType *revDescIndx,
879 DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIndx)
881 if(!desc || !descIndx || !revDesc || !revDescIndx)
882 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeNeighborsOfCellsAdv some input array is empty !");
883 const mcIdType *descPtr=desc->begin();
884 const mcIdType *descIPtr=descIndx->begin();
885 const mcIdType *revDescPtr=revDesc->begin();
886 const mcIdType *revDescIPtr=revDescIndx->begin();
888 mcIdType nbCells=descIndx->getNumberOfTuples()-1;
889 MCAuto<DataArrayIdType> out0=DataArrayIdType::New();
890 MCAuto<DataArrayIdType> out1=DataArrayIdType::New(); out1->alloc(nbCells+1,1);
891 mcIdType *out1Ptr=out1->getPointer();
893 out0->reserve(desc->getNumberOfTuples());
894 for(mcIdType i=0;i<nbCells;i++,descIPtr++,out1Ptr++)
896 for(const mcIdType *w1=descPtr+descIPtr[0];w1!=descPtr+descIPtr[1];w1++)
898 std::set<mcIdType> s(revDescPtr+revDescIPtr[*w1],revDescPtr+revDescIPtr[(*w1)+1]);
900 out0->insertAtTheEnd(s.begin(),s.end());
902 *out1Ptr=out0->getNumberOfTuples();
904 neighbors=out0.retn();
905 neighborsIndx=out1.retn();
909 * Explodes \a this into edges whatever its dimension.
911 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::explodeIntoEdges(MCAuto<DataArrayIdType>& desc, MCAuto<DataArrayIdType>& descIndex, MCAuto<DataArrayIdType>& revDesc, MCAuto<DataArrayIdType>& revDescIndx) const
914 int mdim(getMeshDimension());
915 desc=DataArrayIdType::New(); descIndex=DataArrayIdType::New(); revDesc=DataArrayIdType::New(); revDescIndx=DataArrayIdType::New();
916 MCAuto<MEDCouplingUMesh> mesh1D;
921 mesh1D=explode3DMeshTo1D(desc,descIndex,revDesc,revDescIndx);
926 mesh1D=buildDescendingConnectivity(desc,descIndex,revDesc,revDescIndx);
931 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2] !");
938 * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
939 * For speed reasons no check of this will be done. This method calls
940 * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
941 * This method lists for every node in \b this its neighbor \b nodes. To compute the result
942 * only connectivities are considered.
943 * The neighbor nodes of node having id 'nodeId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
945 * \param [out] neighbors is an array storing all the neighbors of all nodes in \b this. This array
946 * is newly allocated and should be dealt by the caller. \b neighborsIndx 2nd output
947 * parameter allows to select the right part in this array (\ref numbering-indirect).
948 * The number of tuples is equal to the last values in \b neighborsIndx.
949 * \param [out] neighborsIdx is an array of size this->getNumberOfCells()+1 newly allocated and should
950 * be dealt by the caller. This arrays allow to use the first output parameter \b neighbors.
952 * \sa MEDCouplingUMesh::computeEnlargedNeighborsOfNodes
954 void MEDCouplingUMesh::computeNeighborsOfNodes(DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIdx) const
957 mcIdType mdim(getMeshDimension()),nbNodes(getNumberOfNodes());
958 MCAuto<DataArrayIdType> desc(DataArrayIdType::New()),descIndx(DataArrayIdType::New()),revDesc(DataArrayIdType::New()),revDescIndx(DataArrayIdType::New());
959 MCConstAuto<MEDCouplingUMesh> mesh1D;
964 mesh1D=explode3DMeshTo1D(desc,descIndx,revDesc,revDescIndx);
969 mesh1D=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
974 mesh1D.takeRef(this);
979 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2,1] !");
982 desc=DataArrayIdType::New(); descIndx=DataArrayIdType::New(); revDesc=0; revDescIndx=0;
983 mesh1D->getReverseNodalConnectivity(desc,descIndx);
984 MCAuto<DataArrayIdType> ret0(DataArrayIdType::New());
985 ret0->alloc(desc->getNumberOfTuples(),1);
986 mcIdType *r0Pt(ret0->getPointer());
987 const mcIdType *c1DPtr(mesh1D->getNodalConnectivity()->begin()),*rn(desc->begin()),*rni(descIndx->begin());
988 for(mcIdType i=0;i<nbNodes;i++,rni++)
990 for(const mcIdType *oneDCellIt=rn+rni[0];oneDCellIt!=rn+rni[1];oneDCellIt++)
991 *r0Pt++=c1DPtr[3*(*oneDCellIt)+1]==i?c1DPtr[3*(*oneDCellIt)+2]:c1DPtr[3*(*oneDCellIt)+1];
993 neighbors=ret0.retn();
994 neighborsIdx=descIndx.retn();
998 * Computes enlarged neighbors for each nodes in \a this. The behavior of this method is close to MEDCouplingUMesh::computeNeighborsOfNodes except that the neighborhood of each node is wider here.
999 * A node j is considered to be in the neighborhood of i if and only if there is a cell in \a this containing in its nodal connectivity both i and j.
1000 * This method is useful to find ghost cells of a part of a mesh with a code based on fields on nodes.
1002 * \sa MEDCouplingUMesh::computeNeighborsOfNodes
1004 void MEDCouplingUMesh::computeEnlargedNeighborsOfNodes(MCAuto<DataArrayIdType> &neighbors, MCAuto<DataArrayIdType>& neighborsIdx) const
1006 checkFullyDefined();
1007 mcIdType nbOfNodes(getNumberOfNodes());
1008 const mcIdType *conn(_nodal_connec->begin()),*connIndex(_nodal_connec_index->begin());
1009 mcIdType nbOfCells=getNumberOfCells();
1010 std::vector< std::set<mcIdType> > st0(nbOfNodes);
1011 for(mcIdType eltId=0;eltId<nbOfCells;eltId++)
1013 const mcIdType *strtNdlConnOfCurCell(conn+connIndex[eltId]+1),*endNdlConnOfCurCell(conn+connIndex[eltId+1]);
1014 std::set<mcIdType> s(strtNdlConnOfCurCell,endNdlConnOfCurCell); s.erase(-1); //for polyhedrons
1015 for(std::set<mcIdType>::const_iterator iter2=s.begin();iter2!=s.end();iter2++)
1016 st0[*iter2].insert(s.begin(),s.end());
1018 neighborsIdx=DataArrayIdType::New(); neighborsIdx->alloc(nbOfNodes+1,1); neighborsIdx->setIJ(0,0,0);
1020 mcIdType *neighIdx(neighborsIdx->getPointer());
1021 for(std::vector< std::set<mcIdType> >::const_iterator it=st0.begin();it!=st0.end();it++,neighIdx++)
1024 neighIdx[1]=neighIdx[0];
1026 neighIdx[1]=neighIdx[0]+ToIdType((*it).size())-1;
1029 neighbors=DataArrayIdType::New(); neighbors->alloc(neighborsIdx->back(),1);
1031 const mcIdType *neighIdx(neighborsIdx->begin());
1032 mcIdType *neigh(neighbors->getPointer()),nodeId(0);
1033 for(std::vector< std::set<mcIdType> >::const_iterator it=st0.begin();it!=st0.end();it++,neighIdx++,nodeId++)
1035 std::set<mcIdType> s(*it); s.erase(nodeId);
1036 std::copy(s.begin(),s.end(),neigh+*neighIdx);
1042 * Converts specified cells to either polygons (if \a this is a 2D mesh) or
1043 * polyhedrons (if \a this is a 3D mesh). The cells to convert are specified by an
1044 * array of cell ids. Pay attention that after conversion all algorithms work slower
1045 * with \a this mesh than before conversion. <br> If an exception is thrown during the
1046 * conversion due presence of invalid ids in the array of cells to convert, as a
1047 * result \a this mesh contains some already converted elements. In this case the 2D
1048 * mesh remains valid but 3D mesh becomes \b inconsistent!
1049 * \warning This method can significantly modify the order of geometric types in \a this,
1050 * hence, to write this mesh to the MED file, its cells must be sorted using
1051 * sortCellsInMEDFileFrmt().
1052 * \param [in] cellIdsToConvertBg - the array holding ids of cells to convert.
1053 * \param [in] cellIdsToConvertEnd - a pointer to the last-plus-one-th element of \a
1054 * cellIdsToConvertBg.
1055 * \throw If the coordinates array is not set.
1056 * \throw If the nodal connectivity of cells is node defined.
1057 * \throw If dimension of \a this mesh is not either 2 or 3.
1059 * \if ENABLE_EXAMPLES
1060 * \ref cpp_mcumesh_convertToPolyTypes "Here is a C++ example".<br>
1061 * \ref py_mcumesh_convertToPolyTypes "Here is a Python example".
1064 void MEDCouplingUMesh::convertToPolyTypes(const mcIdType *cellIdsToConvertBg, const mcIdType *cellIdsToConvertEnd)
1066 checkFullyDefined();
1067 int dim=getMeshDimension();
1069 throw INTERP_KERNEL::Exception("Invalid mesh dimension : must be 2 or 3 !");
1070 mcIdType nbOfCells=getNumberOfCells();
1073 const mcIdType *connIndex=_nodal_connec_index->begin();
1074 mcIdType *conn=_nodal_connec->getPointer();
1075 for(const mcIdType *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1077 if(*iter>=0 && *iter<nbOfCells)
1079 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*iter]]);
1080 if(!cm.isQuadratic())
1081 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_POLYGON;
1083 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_QPOLYG;
1087 std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1088 oss << " in range [0," << nbOfCells << ") !";
1089 throw INTERP_KERNEL::Exception(oss.str());
1095 mcIdType *connIndex(_nodal_connec_index->getPointer());
1096 const mcIdType *connOld(_nodal_connec->getConstPointer());
1097 MCAuto<DataArrayIdType> connNew(DataArrayIdType::New()),connNewI(DataArrayIdType::New()); connNew->alloc(0,1); connNewI->alloc(1,1); connNewI->setIJ(0,0,0);
1098 std::vector<bool> toBeDone(nbOfCells,false);
1099 for(const mcIdType *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1101 if(*iter>=0 && *iter<nbOfCells)
1102 toBeDone[*iter]=true;
1105 std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1106 oss << " in range [0," << nbOfCells << ") !";
1107 throw INTERP_KERNEL::Exception(oss.str());
1110 for(mcIdType cellId=0;cellId<nbOfCells;cellId++)
1112 mcIdType pos(connIndex[cellId]),posP1(connIndex[cellId+1]);
1113 mcIdType lgthOld(posP1-pos-1);
1114 if(toBeDone[cellId])
1116 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connOld[pos]);
1117 unsigned nbOfFaces(cm.getNumberOfSons2(connOld+pos+1,lgthOld));
1118 mcIdType *tmp(new mcIdType[nbOfFaces*lgthOld+1]);
1119 mcIdType *work=tmp; *work++=INTERP_KERNEL::NORM_POLYHED;
1120 for(unsigned j=0;j<nbOfFaces;j++)
1122 INTERP_KERNEL::NormalizedCellType type;
1123 unsigned offset=cm.fillSonCellNodalConnectivity2(j,connOld+pos+1,lgthOld,work,type);
1127 std::size_t newLgth(std::distance(tmp,work)-1);//-1 for last -1
1128 connNew->pushBackValsSilent(tmp,tmp+newLgth);
1129 connNewI->pushBackSilent(connNewI->back()+ToIdType(newLgth));
1134 connNew->pushBackValsSilent(connOld+pos,connOld+posP1);
1135 connNewI->pushBackSilent(connNewI->back()+posP1-pos);
1138 setConnectivity(connNew,connNewI,false);//false because computeTypes called just behind.
1144 * Converts all cells to either polygons (if \a this is a 2D mesh) or
1145 * polyhedrons (if \a this is a 3D mesh).
1146 * \warning As this method is purely for user-friendliness and no optimization is
1147 * done to avoid construction of a useless vector, this method can be costly
1149 * \throw If the coordinates array is not set.
1150 * \throw If the nodal connectivity of cells is node defined.
1151 * \throw If dimension of \a this mesh is not either 2 or 3.
1153 void MEDCouplingUMesh::convertAllToPoly()
1155 mcIdType nbOfCells=getNumberOfCells();
1156 std::vector<mcIdType> cellIds(nbOfCells);
1157 for(mcIdType i=0;i<nbOfCells;i++)
1159 convertToPolyTypes(&cellIds[0],&cellIds[0]+ToIdType(cellIds.size()));
1163 * Fixes nodal connectivity of invalid cells of type NORM_POLYHED. This method
1164 * expects that all NORM_POLYHED cells have connectivity similar to that of prismatic
1165 * volumes like NORM_HEXA8, NORM_PENTA6 etc., i.e. the first half of nodes describes a
1166 * base facet of the volume and the second half of nodes describes an opposite facet
1167 * having the same number of nodes as the base one. This method converts such
1168 * connectivity to a valid polyhedral format where connectivity of each facet is
1169 * explicitly described and connectivity of facets are separated by -1. If \a this mesh
1170 * contains a NORM_POLYHED cell with a valid connectivity, or an invalid connectivity is
1171 * not as expected, an exception is thrown and the mesh remains unchanged. Care of
1172 * a correct orientation of the first facet of a polyhedron, else orientation of a
1173 * corrected cell is reverse.<br>
1174 * This method is useful to build an extruded unstructured mesh with polyhedrons as
1175 * it releases the user from boring description of polyhedra connectivity in the valid
1177 * \throw If \a this->getMeshDimension() != 3.
1178 * \throw If \a this->getSpaceDimension() != 3.
1179 * \throw If the nodal connectivity of cells is not defined.
1180 * \throw If the coordinates array is not set.
1181 * \throw If \a this mesh contains polyhedrons with the valid connectivity.
1182 * \throw If \a this mesh contains polyhedrons with odd number of nodes.
1184 * \if ENABLE_EXAMPLES
1185 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
1186 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
1189 void MEDCouplingUMesh::convertExtrudedPolyhedra()
1191 checkFullyDefined();
1192 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1193 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertExtrudedPolyhedra works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
1194 mcIdType nbOfCells=getNumberOfCells();
1195 MCAuto<DataArrayIdType> newCi=DataArrayIdType::New();
1196 newCi->alloc(nbOfCells+1,1);
1197 mcIdType *newci=newCi->getPointer();
1198 const mcIdType *ci=_nodal_connec_index->getConstPointer();
1199 const mcIdType *c=_nodal_connec->getConstPointer();
1201 for(mcIdType i=0;i<nbOfCells;i++)
1203 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1204 if(type==INTERP_KERNEL::NORM_POLYHED)
1206 if(std::count(c+ci[i]+1,c+ci[i+1],-1)!=0)
1208 std::ostringstream oss; oss << "MEDCouplingUMesh::convertExtrudedPolyhedra : cell # " << i << " is a polhedron BUT it has NOT exactly 1 face !";
1209 throw INTERP_KERNEL::Exception(oss.str());
1211 std::size_t n2=std::distance(c+ci[i]+1,c+ci[i+1]);
1214 std::ostringstream oss; oss << "MEDCouplingUMesh::convertExtrudedPolyhedra : cell # " << i << " is a polhedron with 1 face but there is a mismatch of number of nodes in face should be even !";
1215 throw INTERP_KERNEL::Exception(oss.str());
1217 mcIdType n1=ToIdType(n2/2);
1218 newci[i+1]=7*n1+2+newci[i];//6*n1 (nodal length) + n1+2 (number of faces) - 1 (number of '-1' separator is equal to number of faces -1) + 1 (for cell type)
1221 newci[i+1]=(ci[i+1]-ci[i])+newci[i];
1223 MCAuto<DataArrayIdType> newC=DataArrayIdType::New();
1224 newC->alloc(newci[nbOfCells],1);
1225 mcIdType *newc=newC->getPointer();
1226 for(mcIdType i=0;i<nbOfCells;i++)
1228 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1229 if(type==INTERP_KERNEL::NORM_POLYHED)
1231 std::size_t n1=std::distance(c+ci[i]+1,c+ci[i+1])/2;
1232 newc=std::copy(c+ci[i],c+ci[i]+n1+1,newc);
1234 for(std::size_t j=0;j<n1;j++)
1236 newc[j]=c[ci[i]+1+n1+(n1-j)%n1];
1238 newc[n1+5*j+1]=c[ci[i]+1+j];
1239 newc[n1+5*j+2]=c[ci[i]+1+j+n1];
1240 newc[n1+5*j+3]=c[ci[i]+1+(j+1)%n1+n1];
1241 newc[n1+5*j+4]=c[ci[i]+1+(j+1)%n1];
1246 newc=std::copy(c+ci[i],c+ci[i+1],newc);
1248 _nodal_connec_index->decrRef(); _nodal_connec_index=newCi.retn();
1249 _nodal_connec->decrRef(); _nodal_connec=newC.retn();
1254 * Converts all polygons (if \a this is a 2D mesh) or polyhedrons (if \a this is a 3D
1255 * mesh) to cells of classical types. This method is opposite to convertToPolyTypes().
1256 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
1257 * to write this mesh to the MED file, its cells must be sorted using
1258 * sortCellsInMEDFileFrmt().
1259 * \warning Cells (and most notably polyhedrons) must be correctly oriented for this to work
1260 * properly. See orientCorrectlyPolyhedrons() and arePolyhedronsNotCorrectlyOriented().
1261 * \return \c true if at least one cell has been converted, \c false else. In the
1262 * last case the nodal connectivity remains unchanged.
1263 * \throw If the coordinates array is not set.
1264 * \throw If the nodal connectivity of cells is not defined.
1265 * \throw If \a this->getMeshDimension() < 0.
1267 bool MEDCouplingUMesh::unPolyze()
1269 checkFullyDefined();
1270 int mdim=getMeshDimension();
1272 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::unPolyze works on umeshes with meshdim equals to 0, 1 2 or 3 !");
1275 mcIdType nbOfCells=getNumberOfCells();
1278 mcIdType initMeshLgth=getNodalConnectivityArrayLen();
1279 mcIdType *conn=_nodal_connec->getPointer();
1280 mcIdType *index=_nodal_connec_index->getPointer();
1281 mcIdType posOfCurCell=0;
1283 mcIdType lgthOfCurCell;
1285 for(mcIdType i=0;i<nbOfCells;i++)
1287 lgthOfCurCell=index[i+1]-posOfCurCell;
1288 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
1289 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
1290 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::NORM_ERROR;
1294 switch(cm.getDimension())
1298 INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[lgthOfCurCell-1];
1299 std::copy(conn+posOfCurCell+1,conn+posOfCurCell+lgthOfCurCell,(mcIdType *)tmp);
1300 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly2D(cm.isQuadratic(),tmp,lgthOfCurCell-1,conn+newPos+1,newLgth);
1305 mcIdType nbOfFaces,lgthOfPolyhConn;
1306 INTERP_KERNEL::AutoPtr<mcIdType> zipFullReprOfPolyh=INTERP_KERNEL::CellSimplify::getFullPolyh3DCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,nbOfFaces,lgthOfPolyhConn);
1307 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly3D(zipFullReprOfPolyh,nbOfFaces,lgthOfPolyhConn,conn+newPos+1,newLgth);
1310 /* case 1: // Not supported yet
1312 newType=(lgthOfCurCell==3)?INTERP_KERNEL::NORM_SEG2:INTERP_KERNEL::NORM_POLYL;
1317 ret=ret || (newType!=type);
1318 conn[newPos]=newType;
1320 posOfCurCell=index[i+1];
1325 std::copy(conn+posOfCurCell,conn+posOfCurCell+lgthOfCurCell,conn+newPos);
1326 newPos+=lgthOfCurCell;
1327 posOfCurCell+=lgthOfCurCell;
1331 if(newPos!=initMeshLgth)
1332 _nodal_connec->reAlloc(newPos);
1339 * This method expects that spaceDimension is equal to 3 and meshDimension equal to 3.
1340 * This method performs operation only on polyhedrons in \b this. If no polyhedrons exists in \b this, \b this remains unchanged.
1341 * This method allows to merge if any coplanar 3DSurf cells that may appear in some polyhedrons cells.
1343 * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not. This epsilon is used to recenter around origin to have maximal
1346 void MEDCouplingUMesh::simplifyPolyhedra(double eps)
1348 checkFullyDefined();
1349 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1350 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplifyPolyhedra : works on meshdimension 3 and spaceDimension 3 !");
1351 MCAuto<DataArrayDouble> coords=getCoords()->deepCopy();
1352 coords->recenterForMaxPrecision(eps);
1354 mcIdType nbOfCells=getNumberOfCells();
1355 const mcIdType *conn=_nodal_connec->getConstPointer();
1356 const mcIdType *index=_nodal_connec_index->getConstPointer();
1357 MCAuto<DataArrayIdType> connINew=DataArrayIdType::New();
1358 connINew->alloc(nbOfCells+1,1);
1359 mcIdType *connINewPtr=connINew->getPointer(); *connINewPtr++=0;
1360 MCAuto<DataArrayIdType> connNew=DataArrayIdType::New(); connNew->alloc(0,1);
1361 MCAuto<DataArrayIdType> E_Fi(DataArrayIdType::New()), E_F(DataArrayIdType::New()), F_Ei(DataArrayIdType::New()), F_E(DataArrayIdType::New());
1362 MCAuto<MEDCouplingUMesh> m_faces(buildDescendingConnectivity(E_F, E_Fi, F_E, F_Ei));
1364 for(mcIdType i=0;i<nbOfCells;i++,connINewPtr++)
1366 if(conn[index[i]]==ToIdType(INTERP_KERNEL::NORM_POLYHED))
1368 SimplifyPolyhedronCell(eps,coords, i,connNew, m_faces, E_Fi, E_F, F_Ei, F_E);
1372 connNew->insertAtTheEnd(conn+index[i],conn+index[i+1]);
1373 *connINewPtr=connNew->getNumberOfTuples();
1376 setConnectivity(connNew,connINew,false);
1380 * This method returns all node ids used in the connectivity of \b this. The data array returned has to be dealt by the caller.
1381 * The returned node ids are sorted ascendingly. This method is close to MEDCouplingUMesh::getNodeIdsInUse except
1382 * the format of the returned DataArrayIdType instance.
1384 * \return a newly allocated DataArrayIdType sorted ascendingly of fetched node ids.
1385 * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1387 DataArrayIdType *MEDCouplingUMesh::computeFetchedNodeIds() const
1389 checkConnectivityFullyDefined();
1390 const mcIdType *maxEltPt(std::max_element(_nodal_connec->begin(),_nodal_connec->end()));
1391 mcIdType maxElt(maxEltPt==_nodal_connec->end()?0:std::abs(*maxEltPt)+1);
1392 std::vector<bool> retS(maxElt,false);
1393 computeNodeIdsAlg(retS);
1394 return DataArrayIdType::BuildListOfSwitchedOn(retS);
1398 * \param [in,out] nodeIdsInUse an array of size typically equal to nbOfNodes.
1399 * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1401 void MEDCouplingUMesh::computeNodeIdsAlg(std::vector<bool>& nodeIdsInUse) const
1403 mcIdType nbOfNodes=ToIdType(nodeIdsInUse.size()),
1404 nbOfCells=getNumberOfCells();
1405 const mcIdType *connIndex(_nodal_connec_index->getConstPointer()),*conn(_nodal_connec->getConstPointer());
1406 for(mcIdType i=0;i<nbOfCells;i++)
1407 for(mcIdType j=connIndex[i]+1;j<connIndex[i+1];j++)
1410 if(conn[j]<nbOfNodes)
1411 nodeIdsInUse[conn[j]]=true;
1414 std::ostringstream oss; oss << "MEDCouplingUMesh::computeNodeIdsAlg : In cell #" << i << " presence of node id " << conn[j] << " not in [0," << nbOfNodes << ") !";
1415 throw INTERP_KERNEL::Exception(oss.str());
1422 struct MEDCouplingAccVisit
1424 MEDCouplingAccVisit():_new_nb_of_nodes(0) { }
1425 mcIdType operator()(mcIdType val) { if(val!=-1) return _new_nb_of_nodes++; else return -1; }
1426 mcIdType _new_nb_of_nodes;
1432 * Finds nodes not used in any cell and returns an array giving a new id to every node
1433 * by excluding the unused nodes, for which the array holds -1. The result array is
1434 * a mapping in "Old to New" mode.
1435 * \param [out] nbrOfNodesInUse - number of node ids present in the nodal connectivity.
1436 * \return DataArrayIdType * - a new instance of DataArrayIdType. Its length is \a
1437 * this->getNumberOfNodes(). It holds for each node of \a this mesh either -1
1438 * if the node is unused or a new id else. The caller is to delete this
1439 * array using decrRef() as it is no more needed.
1440 * \throw If the coordinates array is not set.
1441 * \throw If the nodal connectivity of cells is not defined.
1442 * \throw If the nodal connectivity includes an invalid id.
1444 * \if ENABLE_EXAMPLES
1445 * \ref cpp_mcumesh_getNodeIdsInUse "Here is a C++ example".<br>
1446 * \ref py_mcumesh_getNodeIdsInUse "Here is a Python example".
1448 * \sa computeFetchedNodeIds, computeNodeIdsAlg()
1450 DataArrayIdType *MEDCouplingUMesh::getNodeIdsInUse(mcIdType& nbrOfNodesInUse) const
1453 mcIdType nbOfNodes(getNumberOfNodes());
1454 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1455 ret->alloc(nbOfNodes,1);
1456 mcIdType *traducer=ret->getPointer();
1457 std::fill(traducer,traducer+nbOfNodes,-1);
1458 mcIdType nbOfCells=getNumberOfCells();
1459 const mcIdType *connIndex=_nodal_connec_index->getConstPointer();
1460 const mcIdType *conn=_nodal_connec->getConstPointer();
1461 for(mcIdType i=0;i<nbOfCells;i++)
1462 for(mcIdType j=connIndex[i]+1;j<connIndex[i+1];j++)
1465 if(conn[j]<nbOfNodes)
1466 traducer[conn[j]]=1;
1469 std::ostringstream oss; oss << "MEDCouplingUMesh::getNodeIdsInUse : In cell #" << i << " presence of node id " << conn[j] << " not in [0," << nbOfNodes << ") !";
1470 throw INTERP_KERNEL::Exception(oss.str());
1473 nbrOfNodesInUse=ToIdType(std::count(traducer,traducer+nbOfNodes,1));
1474 std::transform(traducer,traducer+nbOfNodes,traducer,MEDCouplingAccVisit());
1479 * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1480 * For each cell in \b this the number of nodes constituting cell is computed.
1481 * For each polyhedron cell, the sum of the number of nodes of each face constituting polyhedron cell is returned.
1482 * So for pohyhedrons some nodes can be counted several times in the returned result.
1484 * \return a newly allocated array
1485 * \sa MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell
1487 DataArrayIdType *MEDCouplingUMesh::computeNbOfNodesPerCell() const
1489 checkConnectivityFullyDefined();
1490 mcIdType nbOfCells=getNumberOfCells();
1491 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1492 ret->alloc(nbOfCells,1);
1493 mcIdType *retPtr=ret->getPointer();
1494 const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1495 const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1496 for(mcIdType i=0;i<nbOfCells;i++,retPtr++)
1498 if(conn[connI[i]]!=ToIdType(INTERP_KERNEL::NORM_POLYHED))
1499 *retPtr=connI[i+1]-connI[i]-1;
1501 *retPtr=connI[i+1]-connI[i]-1-ToIdType(std::count(conn+connI[i]+1,conn+connI[i+1],-1));
1507 * This method computes effective number of nodes per cell. That is to say nodes appearing several times in nodal connectivity of a cell,
1508 * will be counted only once here whereas it will be counted several times in MEDCouplingUMesh::computeNbOfNodesPerCell method.
1510 * \return DataArrayIdType * - new object to be deallocated by the caller.
1511 * \sa MEDCouplingUMesh::computeNbOfNodesPerCell
1513 DataArrayIdType *MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell() const
1515 checkConnectivityFullyDefined();
1516 mcIdType nbOfCells=getNumberOfCells();
1517 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1518 ret->alloc(nbOfCells,1);
1519 mcIdType *retPtr=ret->getPointer();
1520 const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1521 const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1522 for(mcIdType i=0;i<nbOfCells;i++,retPtr++)
1524 std::set<mcIdType> s(conn+connI[i]+1,conn+connI[i+1]);
1525 if(conn[connI[i]]!=ToIdType(INTERP_KERNEL::NORM_POLYHED))
1526 *retPtr=ToIdType(s.size());
1530 *retPtr=ToIdType(s.size());
1537 * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1538 * For each cell in \b this the number of faces constituting (entity of dimension this->getMeshDimension()-1) cell is computed.
1540 * \return a newly allocated array
1542 DataArrayIdType *MEDCouplingUMesh::computeNbOfFacesPerCell() const
1544 checkConnectivityFullyDefined();
1545 mcIdType nbOfCells=getNumberOfCells();
1546 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1547 ret->alloc(nbOfCells,1);
1548 mcIdType *retPtr=ret->getPointer();
1549 const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1550 const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1551 for(mcIdType i=0;i<nbOfCells;i++,retPtr++,connI++)
1553 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]);
1554 *retPtr=cm.getNumberOfSons2(conn+connI[0]+1,connI[1]-connI[0]-1);
1560 * Removes unused nodes (the node coordinates array is shorten) and returns an array
1561 * mapping between new and old node ids in "Old to New" mode. -1 values in the returned
1562 * array mean that the corresponding old node is no more used.
1563 * \return DataArrayIdType * - a new instance of DataArrayIdType of length \a
1564 * this->getNumberOfNodes() before call of this method. The caller is to
1565 * delete this array using decrRef() as it is no more needed.
1566 * \throw If the coordinates array is not set.
1567 * \throw If the nodal connectivity of cells is not defined.
1568 * \throw If the nodal connectivity includes an invalid id.
1569 * \sa areAllNodesFetched
1571 * \if ENABLE_EXAMPLES
1572 * \ref cpp_mcumesh_zipCoordsTraducer "Here is a C++ example".<br>
1573 * \ref py_mcumesh_zipCoordsTraducer "Here is a Python example".
1576 DataArrayIdType *MEDCouplingUMesh::zipCoordsTraducer()
1578 return MEDCouplingPointSet::zipCoordsTraducer();
1582 * This method stands if 'cell1' and 'cell2' are equals regarding 'compType' policy.
1583 * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1585 int MEDCouplingUMesh::AreCellsEqual(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2, int compType)
1590 return AreCellsEqualPolicy0(conn,connI,cell1,cell2);
1592 return AreCellsEqualPolicy1(conn,connI,cell1,cell2);
1594 return AreCellsEqualPolicy2(conn,connI,cell1,cell2);
1596 return AreCellsEqualPolicy2NoType(conn,connI,cell1,cell2);
1598 return AreCellsEqualPolicy7(conn,connI,cell1,cell2);
1600 throw INTERP_KERNEL::Exception("Unknown comparison asked ! Must be in 0,1,2,3 or 7.");
1604 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 0.
1606 int MEDCouplingUMesh::AreCellsEqualPolicy0(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1608 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1609 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;
1614 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 1.
1616 int MEDCouplingUMesh::AreCellsEqualPolicy1(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1618 mcIdType sz=connI[cell1+1]-connI[cell1];
1619 if(sz==connI[cell2+1]-connI[cell2])
1621 if(conn[connI[cell1]]==conn[connI[cell2]])
1623 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1624 unsigned dim=cm.getDimension();
1629 mcIdType sz1=2*(sz-1);
1630 INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz1];
1631 mcIdType *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(mcIdType *)tmp);
1632 std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1633 work=std::search((mcIdType *)tmp,(mcIdType *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1634 return work!=tmp+sz1?1:0;
1637 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;//case of SEG2 and SEG3
1640 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy1 : not implemented yet for meshdim == 3 !");
1647 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 2.
1649 int MEDCouplingUMesh::AreCellsEqualPolicy2(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1651 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1653 if(conn[connI[cell1]]==conn[connI[cell2]])
1655 std::set<mcIdType> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1656 std::set<mcIdType> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1664 * This method is less restrictive than AreCellsEqualPolicy2. Here the geometric type is absolutely not taken into account !
1666 int MEDCouplingUMesh::AreCellsEqualPolicy2NoType(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1668 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1670 std::set<mcIdType> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1671 std::set<mcIdType> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1678 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 7.
1680 int MEDCouplingUMesh::AreCellsEqualPolicy7(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1682 mcIdType sz=connI[cell1+1]-connI[cell1];
1683 if(sz==connI[cell2+1]-connI[cell2])
1685 if(conn[connI[cell1]]==conn[connI[cell2]])
1687 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1688 unsigned dim=cm.getDimension();
1693 mcIdType sz1=2*(sz-1);
1694 INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz1];
1695 mcIdType *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(mcIdType *)tmp);
1696 std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1697 work=std::search((mcIdType *)tmp,(mcIdType *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1702 std::reverse_iterator<mcIdType *> it1((mcIdType *)tmp+sz1);
1703 std::reverse_iterator<mcIdType *> it2((mcIdType *)tmp);
1704 if(std::search(it1,it2,conn+connI[cell2]+1,conn+connI[cell2+1])!=it2)
1711 {//case of SEG2 and SEG3
1712 if(std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1))
1714 if(!cm.isQuadratic())
1716 std::reverse_iterator<const mcIdType *> it1(conn+connI[cell1+1]);
1717 std::reverse_iterator<const mcIdType *> it2(conn+connI[cell1]+1);
1718 if(std::equal(it1,it2,conn+connI[cell2]+1))
1724 if(conn[connI[cell1]+1]==conn[connI[cell2]+2] && conn[connI[cell1]+2]==conn[connI[cell2]+1] && conn[connI[cell1]+3]==conn[connI[cell2]+3])
1731 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy7 : not implemented yet for meshdim == 3 !");
1739 * This method find cells that are equal (regarding \a compType) in \a this. The comparison is specified by \a compType (see zipConnectivityTraducer).
1740 * This method keeps the coordinates of \a this. The comparison starts at rank \a startCellId cell id (included).
1741 * If \a startCellId is equal to 0 algorithm starts at cell #0 and for each cell candidates being searched have cell id higher than current cellId.
1742 * If \a startCellId is greater than 0 algorithm starts at cell #startCellId but for each cell all candidates are considered.
1743 * This method is time consuming.
1745 * \param [in] compType input specifying the technique used to compare cells each other.
1746 * - 0 : exactly. A cell is detected to be the same if and only if the connectivity is exactly the same without permutation and types same too. This is the strongest policy.
1747 * - 1 : permutation same orientation. cell1 and cell2 are considered equal if the connectivity of cell2 can be deduced by those of cell1 by direct permutation (with exactly the same orientation)
1748 * and their type equal. For 1D mesh the policy 1 is equivalent to 0.
1749 * - 2 : nodal. cell1 and cell2 are equal if and only if cell1 and cell2 have same type and have the same nodes constituting connectivity. This is the laziest policy. This policy
1750 * can be used for users not sensitive to orientation of cell
1751 * \param [in] startCellId specifies the cellId starting from which the equality computation will be carried out. By default it is 0, which it means that all cells in \a this will be scanned.
1752 * \param [out] commonCellsArr common cells ids (\ref numbering-indirect)
1753 * \param [out] commonCellsIArr common cells ids (\ref numbering-indirect)
1756 void MEDCouplingUMesh::findCommonCells(int compType, mcIdType startCellId, DataArrayIdType *& commonCellsArr, DataArrayIdType *& commonCellsIArr) const
1758 MCAuto<DataArrayIdType> revNodal=DataArrayIdType::New(),revNodalI=DataArrayIdType::New();
1759 getReverseNodalConnectivity(revNodal,revNodalI);
1760 FindCommonCellsAlg(compType,startCellId,_nodal_connec,_nodal_connec_index,revNodal,revNodalI,commonCellsArr,commonCellsIArr);
1763 void MEDCouplingUMesh::FindCommonCellsAlg(int compType, mcIdType startCellId, const DataArrayIdType *nodal, const DataArrayIdType *nodalI, const DataArrayIdType *revNodal, const DataArrayIdType *revNodalI,
1764 DataArrayIdType *& commonCellsArr, DataArrayIdType *& commonCellsIArr)
1766 MCAuto<DataArrayIdType> commonCells=DataArrayIdType::New(),commonCellsI=DataArrayIdType::New(); commonCells->alloc(0,1);
1767 mcIdType nbOfCells=nodalI->getNumberOfTuples()-1;
1768 commonCellsI->reserve(1); commonCellsI->pushBackSilent(0);
1769 const mcIdType *revNodalPtr=revNodal->getConstPointer(),*revNodalIPtr=revNodalI->getConstPointer();
1770 const mcIdType *connPtr=nodal->getConstPointer(),*connIPtr=nodalI->getConstPointer();
1771 std::vector<bool> isFetched(nbOfCells,false);
1774 for(mcIdType i=startCellId;i<nbOfCells;i++)
1778 const mcIdType *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind(std::not_equal_to<mcIdType>(),std::placeholders::_1,-1));
1779 std::vector<mcIdType> v,v2;
1780 if(connOfNode!=connPtr+connIPtr[i+1])
1782 const mcIdType *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1783 v2.insert(v2.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1]);
1786 for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1790 const mcIdType *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1791 std::vector<mcIdType>::iterator it=std::set_intersection(v.begin(),v.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1792 v2.resize(std::distance(v2.begin(),it));
1796 if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1798 mcIdType pos=commonCellsI->back();
1799 commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1800 for(const mcIdType *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1801 isFetched[*it]=true;
1809 for(mcIdType i=startCellId;i<nbOfCells;i++)
1813 const mcIdType *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind(std::not_equal_to<mcIdType>(),std::placeholders::_1,-1));
1814 // v2 contains the result of successive intersections using rev nodal on on each node of cell #i
1815 std::vector<mcIdType> v,v2;
1816 if(connOfNode!=connPtr+connIPtr[i+1])
1818 v2.insert(v2.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1]);
1821 for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1825 std::vector<mcIdType>::iterator it=std::set_intersection(v.begin(),v.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1826 v2.resize(std::distance(v2.begin(),it));
1828 // v2 contains now candidates. Problem candidates are sorted using id rank.
1833 auto it(std::find(v2.begin(),v2.end(),i));
1834 std::swap(*v2.begin(),*it);
1836 if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1838 mcIdType newPos(commonCells->getNumberOfTuples());
1839 mcIdType pos(commonCellsI->back());
1840 std::sort(commonCells->getPointerSilent()+pos,commonCells->getPointerSilent()+newPos);
1841 commonCellsI->pushBackSilent(newPos);
1842 for(const mcIdType *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1843 isFetched[*it]=true;
1849 commonCellsArr=commonCells.retn();
1850 commonCellsIArr=commonCellsI.retn();
1854 * Checks if \a this mesh includes all cells of an \a other mesh, and returns an array
1855 * giving for each cell of the \a other an id of a cell in \a this mesh. A value larger
1856 * than \a this->getNumberOfCells() in the returned array means that there is no
1857 * corresponding cell in \a this mesh.
1858 * It is expected that \a this and \a other meshes share the same node coordinates
1859 * array, if it is not so an exception is thrown.
1860 * \param [in] other - the mesh to compare with.
1861 * \param [in] compType - specifies a cell comparison technique. For meaning of its
1862 * valid values [0,1,2], see zipConnectivityTraducer().
1863 * \param [out] arr - a new instance of DataArrayIdType returning correspondence
1864 * between cells of the two meshes. It contains \a other->getNumberOfCells()
1865 * values. The caller is to delete this array using
1866 * decrRef() as it is no more needed.
1867 * \return bool - \c true if all cells of \a other mesh are present in the \a this
1870 * \if ENABLE_EXAMPLES
1871 * \ref cpp_mcumesh_areCellsIncludedIn "Here is a C++ example".<br>
1872 * \ref py_mcumesh_areCellsIncludedIn "Here is a Python example".
1874 * \sa checkDeepEquivalOnSameNodesWith()
1875 * \sa checkGeoEquivalWith()
1877 bool MEDCouplingUMesh::areCellsIncludedIn(const MEDCouplingUMesh *other, int compType, DataArrayIdType *& arr) const
1879 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1880 mcIdType nbOfCells=getNumberOfCells();
1881 static const int possibleCompType[]={0,1,2};
1882 if(std::find(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),compType)==possibleCompType+sizeof(possibleCompType)/sizeof(int))
1884 std::ostringstream oss; oss << "MEDCouplingUMesh::areCellsIncludedIn : only following policies are possible : ";
1885 std::copy(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),std::ostream_iterator<int>(oss," "));
1887 throw INTERP_KERNEL::Exception(oss.str());
1890 if(other->getNumberOfCells()==0)
1892 MCAuto<DataArrayIdType> dftRet(DataArrayIdType::New()); dftRet->alloc(0,1); arr=dftRet.retn(); arr->setName(other->getName());
1895 DataArrayIdType *commonCells(nullptr),*commonCellsI(nullptr);
1896 mesh->findCommonCells(compType,nbOfCells,commonCells,commonCellsI);
1897 MCAuto<DataArrayIdType> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1898 mcIdType newNbOfCells=-1;
1899 MCAuto<DataArrayIdType> o2n = DataArrayIdType::ConvertIndexArrayToO2N(ToIdType(mesh->getNumberOfCells()),commonCells->begin(),commonCellsI->begin(),commonCellsI->end(),newNbOfCells);
1900 MCAuto<DataArrayIdType> p0(o2n->selectByTupleIdSafeSlice(0,nbOfCells,1));
1901 mcIdType maxPart(p0->getMaxValueInArray());
1902 bool ret(maxPart==newNbOfCells-1);
1903 MCAuto<DataArrayIdType> p1(p0->invertArrayO2N2N2O(newNbOfCells));
1904 // fill p1 array in case of presence of cells in other not in this
1905 mcIdType *pt(p1->getPointer());
1906 for(mcIdType i = maxPart ; i < newNbOfCells-1 ; ++i )
1909 MCAuto<DataArrayIdType> p2(o2n->subArray(nbOfCells));
1910 p2->transformWithIndArr(p1->begin(),p1->end()); p2->setName(other->getName());
1916 * This method makes the assumption that \a this and \a other share the same coords. If not an exception will be thrown !
1917 * This method tries to determine if \b other is fully included in \b this.
1918 * The main difference is that this method is not expected to throw exception.
1919 * This method has two outputs :
1921 * \param other other mesh
1922 * \param arr is an output parameter that returns a \b newly created instance. This array is of size 'other->getNumberOfCells()'.
1923 * \return If \a other is fully included in 'this 'true is returned. If not false is returned.
1925 bool MEDCouplingUMesh::areCellsIncludedInPolicy7(const MEDCouplingUMesh *other, DataArrayIdType *& arr) const
1927 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1928 DataArrayIdType *commonCells=0,*commonCellsI=0;
1929 mcIdType thisNbCells=getNumberOfCells();
1930 mesh->findCommonCells(7,thisNbCells,commonCells,commonCellsI);
1931 MCAuto<DataArrayIdType> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1932 const mcIdType *commonCellsPtr=commonCells->getConstPointer(),*commonCellsIPtr=commonCellsI->getConstPointer();
1933 mcIdType otherNbCells=other->getNumberOfCells();
1934 MCAuto<DataArrayIdType> arr2=DataArrayIdType::New();
1935 arr2->alloc(otherNbCells,1);
1936 arr2->fillWithZero();
1937 mcIdType *arr2Ptr=arr2->getPointer();
1938 mcIdType nbOfCommon=commonCellsI->getNumberOfTuples()-1;
1939 for(mcIdType i=0;i<nbOfCommon;i++)
1941 mcIdType start=commonCellsPtr[commonCellsIPtr[i]];
1942 if(start<thisNbCells)
1944 for(mcIdType j=commonCellsIPtr[i]+1;j!=commonCellsIPtr[i+1];j++)
1946 mcIdType sig=commonCellsPtr[j]>0?1:-1;
1947 mcIdType val=std::abs(commonCellsPtr[j])-1;
1948 if(val>=thisNbCells)
1949 arr2Ptr[val-thisNbCells]=sig*(start+1);
1953 arr2->setName(other->getName());
1954 if(arr2->presenceOfValue(0))
1960 MEDCouplingUMesh *MEDCouplingUMesh::mergeMyselfWithOnSameCoords(const MEDCouplingPointSet *other) const
1963 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : input other is null !");
1964 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
1966 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : the input other mesh is not of type unstructured !");
1967 std::vector<const MEDCouplingUMesh *> ms(2);
1970 return MergeUMeshesOnSameCoords(ms);
1974 * Build a sub part of \b this lying or not on the same coordinates than \b this (regarding value of \b keepCoords).
1975 * By default coordinates are kept. This method is close to MEDCouplingUMesh::buildPartOfMySelf except that here input
1976 * cellIds is not given explicitly but by a range python like.
1978 * \param start starting ID
1979 * \param end end ID (excluded)
1980 * \param step step size
1981 * \param keepCoords that specifies if you want or not to keep coords as this or zip it (see MEDCoupling::MEDCouplingUMesh::zipCoords). If true zipCoords is \b NOT called, if false, zipCoords is called.
1982 * \return a newly allocated
1984 * \warning This method modifies can generate an unstructured mesh whose cells are not sorted by geometric type order.
1985 * In view of the MED file writing, a renumbering of cells of returned unstructured mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
1987 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfSlice(mcIdType start, mcIdType end, mcIdType step, bool keepCoords) const
1989 if(getMeshDimension()!=-1)
1990 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelfSlice(start,end,step,keepCoords));
1993 mcIdType newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfSlice for -1 dimension mesh ");
1995 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
1997 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
1999 return const_cast<MEDCouplingUMesh *>(this);
2004 * Creates a new MEDCouplingUMesh containing specified cells of \a this mesh.
2005 * The result mesh shares or not the node coordinates array with \a this mesh depending
2006 * on \a keepCoords parameter.
2007 * \warning Cells of the result mesh can be \b not sorted by geometric type, hence,
2008 * to write this mesh to the MED file, its cells must be sorted using
2009 * sortCellsInMEDFileFrmt().
2010 * \param [in] begin - an array of cell ids to include to the new mesh.
2011 * \param [in] end - a pointer to last-plus-one-th element of \a begin.
2012 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2013 * array of \a this mesh, else "free" nodes are removed from the result mesh
2014 * by calling zipCoords().
2015 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2016 * to delete this mesh using decrRef() as it is no more needed.
2017 * \throw If the coordinates array is not set.
2018 * \throw If the nodal connectivity of cells is not defined.
2019 * \throw If any cell id in the array \a begin is not valid.
2021 * \if ENABLE_EXAMPLES
2022 * \ref cpp_mcumesh_buildPartOfMySelf "Here is a C++ example".<br>
2023 * \ref py_mcumesh_buildPartOfMySelf "Here is a Python example".
2026 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelf(const mcIdType *begin, const mcIdType *end, bool keepCoords) const
2028 if(getMeshDimension()!=-1)
2029 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelf(begin,end,keepCoords));
2033 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
2035 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
2037 return const_cast<MEDCouplingUMesh *>(this);
2042 * This method operates only on nodal connectivity on \b this. Coordinates of \b this is completely ignored here.
2044 * This method allows to partially modify some cells in \b this (whose list is specified by [ \b cellIdsBg, \b cellIdsEnd ) ) with cells coming in \b otherOnSameCoordsThanThis.
2045 * Size of [ \b cellIdsBg, \b cellIdsEnd ) ) must be equal to the number of cells of otherOnSameCoordsThanThis.
2046 * The number of cells of \b this will remain the same with this method.
2048 * \param [in] cellIdsBg begin of cell ids (included) of cells in this to assign
2049 * \param [in] cellIdsEnd end of cell ids (excluded) of cells in this to assign
2050 * \param [in] otherOnSameCoordsThanThis an another mesh with same meshdimension than \b this with exactly the same number of cells than cell ids list in [\b cellIdsBg, \b cellIdsEnd ).
2051 * Coordinate pointer of \b this and those of \b otherOnSameCoordsThanThis must be the same
2053 void MEDCouplingUMesh::setPartOfMySelf(const mcIdType *cellIdsBg, const mcIdType *cellIdsEnd, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2055 checkConnectivityFullyDefined();
2056 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2057 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2058 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelf : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2059 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2061 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2062 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2063 throw INTERP_KERNEL::Exception(oss.str());
2065 mcIdType nbOfCellsToModify( ToIdType((std::distance(cellIdsBg,cellIdsEnd))));
2066 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2068 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2069 throw INTERP_KERNEL::Exception(oss.str());
2071 mcIdType nbOfCells(getNumberOfCells());
2072 bool easyAssign(true);
2073 const mcIdType *connI(_nodal_connec_index->begin());
2074 const mcIdType *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->begin();
2075 for(const mcIdType *it=cellIdsBg;it!=cellIdsEnd && easyAssign;it++,connIOther++)
2077 if(*it>=0 && *it<nbOfCells)
2079 easyAssign=(connIOther[1]-connIOther[0])==(connI[*it+1]-connI[*it]);
2083 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : On pos #" << std::distance(cellIdsBg,it) << " id is equal to " << *it << " which is not in [0," << nbOfCells << ") !";
2084 throw INTERP_KERNEL::Exception(oss.str());
2089 DataArrayIdType::SetPartOfIndexedArraysSameIdx(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2094 DataArrayIdType *arrOut=0,*arrIOut=0;
2095 DataArrayIdType::SetPartOfIndexedArrays(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2097 MCAuto<DataArrayIdType> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2098 setConnectivity(arrOut,arrIOut,true);
2102 void MEDCouplingUMesh::setPartOfMySelfSlice(mcIdType start, mcIdType end, mcIdType step, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2104 checkConnectivityFullyDefined();
2105 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2106 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2107 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelfSlice : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2108 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2110 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2111 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2112 throw INTERP_KERNEL::Exception(oss.str());
2114 mcIdType nbOfCellsToModify=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::setPartOfMySelfSlice : ");
2115 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2117 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2118 throw INTERP_KERNEL::Exception(oss.str());
2120 mcIdType nbOfCells=getNumberOfCells();
2121 bool easyAssign=true;
2122 const mcIdType *connI=_nodal_connec_index->getConstPointer();
2123 const mcIdType *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2125 for(mcIdType i=0;i<nbOfCellsToModify && easyAssign;i++,it+=step,connIOther++)
2127 if(it>=0 && it<nbOfCells)
2129 easyAssign=(connIOther[1]-connIOther[0])==(connI[it+1]-connI[it]);
2133 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : On pos #" << i << " id is equal to " << it << " which is not in [0," << nbOfCells << ") !";
2134 throw INTERP_KERNEL::Exception(oss.str());
2139 DataArrayIdType::SetPartOfIndexedArraysSameIdxSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2144 DataArrayIdType *arrOut=0,*arrIOut=0;
2145 DataArrayIdType::SetPartOfIndexedArraysSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2147 MCAuto<DataArrayIdType> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2148 setConnectivity(arrOut,arrIOut,true);
2154 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2155 * this->getMeshDimension(), that bound some cells of \a this mesh.
2156 * The cells of lower dimension to include to the result mesh are selected basing on
2157 * specified node ids and the value of \a fullyIn parameter. If \a fullyIn ==\c true, a
2158 * cell is copied if its all nodes are in the array \a begin of node ids. If \a fullyIn
2159 * ==\c false, a cell is copied if any its node is in the array of node ids. The
2160 * created mesh shares the node coordinates array with \a this mesh.
2161 * \param [in] begin - the array of node ids.
2162 * \param [in] end - a pointer to the (last+1)-th element of \a begin.
2163 * \param [in] fullyIn - if \c true, then cells whose all nodes are in the
2164 * array \a begin are added, else cells whose any node is in the
2165 * array \a begin are added.
2166 * \return MEDCouplingUMesh * - new instance of MEDCouplingUMesh. The caller is
2167 * to delete this mesh using decrRef() as it is no more needed.
2168 * \throw If the coordinates array is not set.
2169 * \throw If the nodal connectivity of cells is not defined.
2170 * \throw If any node id in \a begin is not valid.
2172 * \if ENABLE_EXAMPLES
2173 * \ref cpp_mcumesh_buildFacePartOfMySelfNode "Here is a C++ example".<br>
2174 * \ref py_mcumesh_buildFacePartOfMySelfNode "Here is a Python example".
2177 MEDCouplingUMesh *MEDCouplingUMesh::buildFacePartOfMySelfNode(const mcIdType *begin, const mcIdType *end, bool fullyIn) const
2179 MCAuto<DataArrayIdType> desc,descIndx,revDesc,revDescIndx;
2180 desc=DataArrayIdType::New(); descIndx=DataArrayIdType::New(); revDesc=DataArrayIdType::New(); revDescIndx=DataArrayIdType::New();
2181 MCAuto<MEDCouplingUMesh> subMesh=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2182 desc=0; descIndx=0; revDesc=0; revDescIndx=0;
2183 return static_cast<MEDCouplingUMesh*>(subMesh->buildPartOfMySelfNode(begin,end,fullyIn));
2187 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2188 * this->getMeshDimension(), which bound only one cell of \a this mesh.
2189 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2190 * array of \a this mesh, else "free" nodes are removed from the result mesh
2191 * by calling zipCoords().
2192 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2193 * to delete this mesh using decrRef() as it is no more needed.
2194 * \throw If the coordinates array is not set.
2195 * \throw If the nodal connectivity of cells is not defined.
2197 * \if ENABLE_EXAMPLES
2198 * \ref cpp_mcumesh_buildBoundaryMesh "Here is a C++ example".<br>
2199 * \ref py_mcumesh_buildBoundaryMesh "Here is a Python example".
2202 MEDCouplingUMesh *MEDCouplingUMesh::buildBoundaryMesh(bool keepCoords) const
2204 DataArrayIdType *desc=DataArrayIdType::New();
2205 DataArrayIdType *descIndx=DataArrayIdType::New();
2206 DataArrayIdType *revDesc=DataArrayIdType::New();
2207 DataArrayIdType *revDescIndx=DataArrayIdType::New();
2209 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2212 descIndx->decrRef();
2213 mcIdType nbOfCells=meshDM1->getNumberOfCells();
2214 const mcIdType *revDescIndxC=revDescIndx->getConstPointer();
2215 std::vector<mcIdType> boundaryCells;
2216 for(mcIdType i=0;i<nbOfCells;i++)
2217 if(revDescIndxC[i+1]-revDescIndxC[i]==1)
2218 boundaryCells.push_back(i);
2219 revDescIndx->decrRef();
2220 MEDCouplingUMesh *ret=meshDM1->buildPartOfMySelf(&boundaryCells[0],&boundaryCells[0]+boundaryCells.size(),keepCoords);
2225 * This method returns a newly created DataArrayIdType instance containing ids of cells located in boundary.
2226 * A cell is detected to be on boundary if it contains one or more than one face having only one father.
2227 * This method makes the assumption that \a this is fully defined (coords,connectivity). If not an exception will be thrown.
2229 DataArrayIdType *MEDCouplingUMesh::findCellIdsOnBoundary() const
2231 checkFullyDefined();
2232 MCAuto<DataArrayIdType> ret2(DataArrayIdType::New());
2234 if (getNumberOfCells() == 0)
2240 MCAuto<DataArrayIdType> desc(DataArrayIdType::New()), descIndx(DataArrayIdType::New()), revDesc(DataArrayIdType::New()), revDescIndx(DataArrayIdType::New());
2242 buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx)->decrRef();
2243 desc=(DataArrayIdType*)0; descIndx=(DataArrayIdType*)0;
2245 MCAuto<DataArrayIdType> tmp=revDescIndx->deltaShiftIndex();
2246 MCAuto<DataArrayIdType> faceIds=tmp->findIdsEqual(1); tmp=(DataArrayIdType*)0;
2247 const mcIdType *revDescPtr=revDesc->getConstPointer();
2248 const mcIdType *revDescIndxPtr=revDescIndx->getConstPointer();
2249 mcIdType nbOfCells=getNumberOfCells();
2250 std::vector<bool> ret1(nbOfCells,false);
2252 for(const mcIdType *pt=faceIds->begin();pt!=faceIds->end();pt++)
2253 if(!ret1[revDescPtr[revDescIndxPtr[*pt]]])
2254 { ret1[revDescPtr[revDescIndxPtr[*pt]]]=true; sz++; }
2257 mcIdType *ret2Ptr=ret2->getPointer();
2259 for(std::vector<bool>::const_iterator it=ret1.begin();it!=ret1.end();it++,sz++)
2262 ret2->setName("BoundaryCells");
2267 * This method finds in \b this the cell ids that lie on mesh \b otherDimM1OnSameCoords.
2268 * \b this and \b otherDimM1OnSameCoords have to lie on the same coordinate array pointer. The coherency of that coords array with connectivity
2269 * of \b this and \b otherDimM1OnSameCoords is not important here because this method works only on connectivity.
2270 * this->getMeshDimension() - 1 must be equal to otherDimM1OnSameCoords.getMeshDimension()
2272 * s0 is the cell ids set in \b this lying on at least one node in the fetched nodes in \b otherDimM1OnSameCoords.
2273 * 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
2274 * equals a cell in \b otherDimM1OnSameCoords.
2276 * \throw if \b otherDimM1OnSameCoords is not part of constituent of \b this, or if coordinate pointer of \b this and \b otherDimM1OnSameCoords
2277 * are not same, or if this->getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension()
2279 * \param [in] otherDimM1OnSameCoords other mesh
2280 * \param [out] cellIdsRk0 a newly allocated array containing the cell ids of s0 (which are cell ids of \b this) in the above algorithm.
2281 * \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
2282 * cellIdsRk1->transformWithIndArr(cellIdsRk0->begin(),cellIdsRk0->end());
2284 void MEDCouplingUMesh::findCellIdsLyingOn(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayIdType *&cellIdsRk0, DataArrayIdType *&cellIdsRk1) const
2286 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2287 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : coordinates pointer are not the same ! Use tryToShareSameCoords method !");
2288 checkConnectivityFullyDefined();
2289 otherDimM1OnSameCoords.checkConnectivityFullyDefined();
2290 if(getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension())
2291 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : invalid mesh dimension of input mesh regarding meshdimesion of this !");
2292 MCAuto<DataArrayIdType> fetchedNodeIds1=otherDimM1OnSameCoords.computeFetchedNodeIds();
2293 MCAuto<DataArrayIdType> s0arr=getCellIdsLyingOnNodes(fetchedNodeIds1->begin(),fetchedNodeIds1->end(),false);
2294 MCAuto<MEDCouplingUMesh> thisPart=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(s0arr->begin(),s0arr->end(),true));
2295 MCAuto<DataArrayIdType> descThisPart=DataArrayIdType::New(),descIThisPart=DataArrayIdType::New(),revDescThisPart=DataArrayIdType::New(),revDescIThisPart=DataArrayIdType::New();
2296 MCAuto<MEDCouplingUMesh> thisPartConsti=thisPart->buildDescendingConnectivity(descThisPart,descIThisPart,revDescThisPart,revDescIThisPart);
2297 const mcIdType *revDescThisPartPtr=revDescThisPart->getConstPointer(),*revDescIThisPartPtr=revDescIThisPart->getConstPointer();
2298 DataArrayIdType *idsOtherInConsti=0;
2299 bool b=thisPartConsti->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsOtherInConsti);
2300 MCAuto<DataArrayIdType> idsOtherInConstiAuto(idsOtherInConsti);
2302 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : the given mdim-1 mesh in other is not a constituent of this !");
2303 std::set<mcIdType> s1;
2304 for(const mcIdType *idOther=idsOtherInConsti->begin();idOther!=idsOtherInConsti->end();idOther++)
2305 s1.insert(revDescThisPartPtr+revDescIThisPartPtr[*idOther],revDescThisPartPtr+revDescIThisPartPtr[*idOther+1]);
2306 MCAuto<DataArrayIdType> s1arr_renum1=DataArrayIdType::New(); s1arr_renum1->alloc(s1.size(),1); std::copy(s1.begin(),s1.end(),s1arr_renum1->getPointer());
2307 s1arr_renum1->sort();
2308 cellIdsRk0=s0arr.retn();
2309 //cellIdsRk1=s_renum1.retn();
2310 cellIdsRk1=s1arr_renum1.retn();
2314 * 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
2315 * returned. This subpart of meshdim-1 mesh is built using meshdim-1 cells in it shared only one cell in \b this.
2317 * \return a newly allocated mesh lying on the same coordinates than \b this. The caller has to deal with returned mesh.
2319 MEDCouplingUMesh *MEDCouplingUMesh::computeSkin() const
2321 MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
2322 MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
2323 MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
2324 MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
2326 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2327 revDesc=0; desc=0; descIndx=0;
2328 MCAuto<DataArrayIdType> revDescIndx2=revDescIndx->deltaShiftIndex();
2329 MCAuto<DataArrayIdType> part=revDescIndx2->findIdsEqual(1);
2330 return static_cast<MEDCouplingUMesh *>(meshDM1->buildPartOfMySelf(part->begin(),part->end(),true));
2334 * Finds nodes lying on the boundary of \a this mesh.
2335 * \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of found
2336 * nodes. The caller is to delete this array using decrRef() as it is no
2338 * \throw If the coordinates array is not set.
2339 * \throw If the nodal connectivity of cells is node defined.
2341 * \if ENABLE_EXAMPLES
2342 * \ref cpp_mcumesh_findBoundaryNodes "Here is a C++ example".<br>
2343 * \ref py_mcumesh_findBoundaryNodes "Here is a Python example".
2346 DataArrayIdType *MEDCouplingUMesh::findBoundaryNodes() const
2348 MCAuto<MEDCouplingUMesh> skin=computeSkin();
2349 return skin->computeFetchedNodeIds();
2352 MEDCouplingUMesh *MEDCouplingUMesh::buildUnstructured() const
2355 return const_cast<MEDCouplingUMesh *>(this);
2359 * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2360 * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2361 * 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.
2362 * If a node is in the boundary of \b this \b and in the boundary of \b otherDimM1OnSameCoords, it will be duplicated.
2363 * 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.
2365 * \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
2366 * parameter is altered during the call.
2367 * \return node ids which need to be duplicated following the algorithm explained above.
2370 DataArrayIdType* MEDCouplingUMesh::findNodesToDuplicate(const MEDCouplingUMesh& crackingMesh) const
2372 // DEBUG NOTE: in case of issue with the algorithm in this method, see Python script in resources/dev
2373 // which mimicks the C++
2374 using DAInt = MCAuto<DataArrayIdType>;
2375 using MCUMesh = MCAuto<MEDCouplingUMesh>;
2377 checkFullyDefined();
2378 crackingMesh.checkFullyDefined();
2379 if(getCoords()!=crackingMesh.getCoords())
2380 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : meshes do not share the same coords array !");
2381 if(crackingMesh.getMeshDimension()!=getMeshDimension()-1)
2382 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the mesh given in other parameter must have this->getMeshDimension()-1 !");
2384 // 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!)
2385 MCUMesh m0skin = computeSkin();
2386 DataArrayIdType *idsToKeepP;
2387 m0skin->areCellsIncludedIn(&crackingMesh,2, idsToKeepP);
2388 DAInt idsToKeep(idsToKeepP);
2389 DAInt ids2 = idsToKeep->findIdsNotInRange(0, m0skin->getNumberOfCells()); // discard cells on the skin of M0
2390 MCUMesh otherDimM1OnSameCoords =static_cast<MEDCouplingUMesh *>(crackingMesh.buildPartOfMySelf(ids2->begin(), ids2->end(), true));
2392 if (!otherDimM1OnSameCoords->getNumberOfCells())
2393 return MCAuto<DataArrayIdType>(DataArrayIdType::New()).retn();
2395 // Checking star-shaped M1 group:
2396 DAInt dt0=DataArrayIdType::New(),dit0=DataArrayIdType::New(),rdt0=DataArrayIdType::New(),rdit0=DataArrayIdType::New();
2397 MCUMesh meshM2 = otherDimM1OnSameCoords->buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); // 2D: a mesh of points, 3D: a mesh of segs
2398 DAInt dsi = rdit0->deltaShiftIndex();
2399 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.
2400 if(idsTmp0->getNumberOfTuples())
2401 throw INTERP_KERNEL::Exception("MEDFileUMesh::buildInnerBoundaryAlongM1Group: group is too complex: some points (or edges) have more than two connected segments (or faces)!");
2402 dt0=0; dit0=0; rdt0=0; rdit0=0; idsTmp0=0;
2404 // Get extreme nodes from the group (they won't be duplicated except if they also lie on bound of M0 -- see below),
2405 // ie nodes belonging to the boundary "cells" (might be points) of M1
2406 DAInt xtremIdsM2 = dsi->findIdsEqual(1); dsi = 0;
2407 MCUMesh meshM2Part = static_cast<MEDCouplingUMesh *>(meshM2->buildPartOfMySelf(xtremIdsM2->begin(), xtremIdsM2->end(),true));
2408 DAInt xtrem = meshM2Part->computeFetchedNodeIds();
2409 // Remove from the list points on the boundary of the M0 mesh (those need duplication!).
2410 // 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)
2411 // 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
2412 // although they are technically on the skin of the cube.
2413 DAInt fNodes = m0skin->computeFetchedNodeIds();
2415 if (getMeshDimension() == 3)
2417 DAInt dnu1=DataArrayIdType::New(), dnu2=DataArrayIdType::New(), dnu3=DataArrayIdType::New(), dnu4=DataArrayIdType::New();
2418 MCUMesh m0skinDesc = m0skin->buildDescendingConnectivity(dnu1, dnu2, dnu3, dnu4); // all segments of the skin of the 3D (M0) mesh
2419 dnu1=0;dnu2=0;dnu3=0;dnu4=0;
2420 DataArrayIdType * corresp=0;
2421 meshM2->areCellsIncludedIn(m0skinDesc,2,corresp);
2422 // validIds is the list of segments which are on both the skin of *this*, and in the segments of the M1 group
2423 // In the cube example above, this is a U-shaped polyline.
2424 DAInt validIds = corresp->findIdsInRange(0, meshM2->getNumberOfCells());
2426 if (validIds->getNumberOfTuples())
2428 // 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:
2429 // (the U-shaped polyline described above)
2430 MCUMesh m1IntersecSkin = static_cast<MEDCouplingUMesh *>(m0skinDesc->buildPartOfMySelf(validIds->begin(), validIds->end(), true));
2431 // Its boundary nodes should no be duplicated (this is for example the tip of the crack inside the cube described above)
2432 DAInt notDuplSkin = m1IntersecSkin->findBoundaryNodes();
2433 DAInt fNodes1 = fNodes->buildSubstraction(notDuplSkin);
2435 // Specific logic to handle singular points :
2436 // - a point on this U-shape line used in a cell which has no face in common with M1 is deemed singular.
2437 // - indeed, if duplicated, such a point would lead to the duplication of a cell which has no face touching M1 ! The
2438 // algorithm would be duplicating too much ...
2439 // 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:
2440 dnu1=DataArrayIdType::New(), dnu2=DataArrayIdType::New(), dnu3=DataArrayIdType::New(), rdit0=DataArrayIdType::New();
2441 MCUMesh meshM2Desc = meshM2->buildDescendingConnectivity(dnu1, dnu2, dnu3, rdit0); // a mesh made of node cells
2442 dnu1=0;dnu2=0;dnu3=0;
2443 dsi = rdit0->deltaShiftIndex(); rdit0=0;
2444 DAInt singPoints = dsi->findIdsNotInRange(-1,4) ; dsi=0;// points connected to (strictly) more than 3 segments
2445 if (singPoints->getNumberOfTuples())
2447 DAInt boundNodes = m1IntersecSkin->computeFetchedNodeIds();
2448 // If a point on this U-shape line is connected to cells which do not share any face with M1, then it
2449 // should not be duplicated
2450 // 1. Extract N D cells touching U-shape line:
2451 DAInt cellsAroundBN = getCellIdsLyingOnNodes(boundNodes->begin(), boundNodes->end(), false); // false= take cell in, even if not all nodes are in dupl
2452 MCUMesh mAroundBN = static_cast<MEDCouplingUMesh *>(this->buildPartOfMySelf(cellsAroundBN->begin(), cellsAroundBN->end(), true));
2453 DAInt descBN=DataArrayIdType::New(), descIBN=DataArrayIdType::New(), revDescBN=DataArrayIdType::New(), revDescIBN=DataArrayIdType::New();
2454 MCUMesh mAroundBNDesc = mAroundBN->buildDescendingConnectivity(descBN,descIBN,revDescBN,revDescIBN);
2455 // 2. Identify cells in sub-mesh mAroundBN which have a face in common with M1
2456 DataArrayIdType *idsOfM1BNt;
2457 mAroundBNDesc->areCellsIncludedIn(otherDimM1OnSameCoords,2, idsOfM1BNt);
2458 DAInt idsOfM1BN(idsOfM1BNt);
2459 mcIdType nCells=mAroundBN->getNumberOfCells(), nCellsDesc=mAroundBNDesc->getNumberOfCells();
2460 DAInt idsTouch=DataArrayIdType::New(); idsTouch->alloc(0,1);
2461 const mcIdType *revDescIBNP=revDescIBN->begin(), *revDescBNP=revDescBN->begin();
2462 for(const auto& v: *idsOfM1BN)
2464 if (v >= nCellsDesc) // Keep valid match only
2466 mcIdType idx0 = revDescIBNP[v];
2467 // Keep the two cells on either side of the face v of M1:
2468 mcIdType c1=revDescBNP[idx0], c2=revDescBNP[idx0+1];
2469 idsTouch->pushBackSilent(c1); idsTouch->pushBackSilent(c2);
2471 // 3. Build complement
2472 DAInt idsTouchCompl = idsTouch->buildComplement(nCells);
2473 MCUMesh mAroundBNStrict = static_cast<MEDCouplingUMesh *>(mAroundBN->buildPartOfMySelf(idsTouchCompl->begin(), idsTouchCompl->end(), true));
2474 DAInt nod3 = mAroundBNStrict->computeFetchedNodeIds();
2475 DAInt inters = boundNodes->buildIntersection(nod3);
2476 fNodes1 = fNodes1->buildSubstraction(inters); // reminder: fNodes1 represent nodes that need dupl.
2478 notDup = xtrem->buildSubstraction(fNodes1);
2480 else // if (validIds-> ...)
2481 notDup = xtrem->buildSubstraction(fNodes);
2484 notDup = xtrem->buildSubstraction(fNodes);
2486 DAInt m1Nodes = otherDimM1OnSameCoords->computeFetchedNodeIds();
2487 DAInt dupl = m1Nodes->buildSubstraction(notDup);
2493 * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2494 * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2495 * This method is part of the MEDFileUMesh::buildInnerBoundaryAlongM1Group() algorithm.
2496 * Given a set of nodes to duplicate, this method identifies which cells should have their connectivity modified
2497 * to produce the inner boundary. It is typically called after findNodesToDuplicate().
2499 * \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.
2500 * \param [in] nodeIdsToDuplicateBg node ids needed to be duplicated, as returned by findNodesToDuplicate.
2501 * \param [in] nodeIdsToDuplicateEnd node ids needed to be duplicated, as returned by findNodesToDuplicate.
2502 * \param [out] cellIdsNeededToBeRenum cell ids in \b this in which the renumber of nodes should be performed.
2503 * \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.
2506 void MEDCouplingUMesh::findCellsToRenumber(const MEDCouplingUMesh& otherDimM1OnSameCoords, const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd,
2507 DataArrayIdType *& cellIdsNeededToBeRenum, DataArrayIdType *& cellIdsNotModified) const
2509 using DAInt = MCAuto<DataArrayIdType>;
2510 using MCUMesh = MCAuto<MEDCouplingUMesh>;
2512 checkFullyDefined();
2513 otherDimM1OnSameCoords.checkFullyDefined();
2514 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2515 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellsToRenumber: meshes do not share the same coords array !");
2516 if(otherDimM1OnSameCoords.getMeshDimension()!=getMeshDimension()-1)
2517 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellsToRenumber: the mesh given in other parameter must have this->getMeshDimension()-1 !");
2519 // Degenerated case - no nodes to duplicate
2520 if (nodeIdsToDuplicateBg == nodeIdsToDuplicateEnd)
2522 cellIdsNeededToBeRenum = DataArrayIdType::New(); cellIdsNeededToBeRenum->alloc(0,1);
2523 cellIdsNotModified = DataArrayIdType::New(); cellIdsNotModified->alloc(0,1);
2527 // Compute cell IDs of the mesh with cells that touch the M1 group with a least one node:
2528 DAInt cellsAroundGroupLarge = getCellIdsLyingOnNodes(nodeIdsToDuplicateBg, nodeIdsToDuplicateEnd, false); // false= take cell in, even if not all nodes are in dupl
2529 MCUMesh mAroundGrpLarge=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(cellsAroundGroupLarge->begin(),cellsAroundGroupLarge->end(),true));
2530 mcIdType nCellsLarge=cellsAroundGroupLarge->getNumberOfTuples();
2531 DAInt descL=DataArrayIdType::New(),descIL=DataArrayIdType::New(),revDescL=DataArrayIdType::New(),revDescIL=DataArrayIdType::New();
2532 MCUMesh mArGrpLargeDesc=mAroundGrpLarge->buildDescendingConnectivity(descL,descIL,revDescL,revDescIL);
2533 const mcIdType *descILP=descIL->begin(), *descLP=descL->begin();
2534 DataArrayIdType *idsOfM1t;
2535 mArGrpLargeDesc->areCellsIncludedIn(&otherDimM1OnSameCoords,2, idsOfM1t);
2536 DAInt idsOfM1Large(idsOfM1t);
2537 mcIdType nL = mArGrpLargeDesc->getNumberOfCells();
2539 // Computation of the neighbor information of the mesh WITH the crack (some neighbor links are removed):
2540 // In the neighbor information remove the connection between high dimension cells and its low level constituents which are part
2541 // of the frontier given in parameter (i.e. the cells of low dimension from the group delimiting the crack):
2542 DAInt descLTrunc = descL->deepCopy(), descILTrunc = descIL->deepCopy();
2543 DataArrayIdType::RemoveIdsFromIndexedArrays(idsOfM1Large->begin(), idsOfM1Large->end(),descLTrunc,descILTrunc);
2544 DataArrayIdType *neight=0, *neighIt=0;
2545 MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(descLTrunc,descILTrunc,revDescL,revDescIL, neight, neighIt);
2546 DAInt neighL(neight), neighIL(neighIt);
2548 DAInt hitCellsLarge = DataArrayIdType::New(); hitCellsLarge->alloc(nCellsLarge,1);
2549 hitCellsLarge->fillWithValue(0); // 0 : not hit, +1: one side of the crack, -1: other side of the crack,
2550 mcIdType* hitCellsLargeP = hitCellsLarge->rwBegin();
2552 // Now loop on the faces of the M1 group and fill spread zones on either side of the crack:
2553 const mcIdType *revDescILP=revDescIL->begin(), *revDescLP=revDescL->begin();
2554 for(const auto& v: *idsOfM1Large)
2556 if (v >= nL) continue; // Keep valid match only - see doc of areCellsIncludedIn()
2557 mcIdType idx0 = revDescILP[v];
2558 // Retrieve the two cells on either side of the face v of M1:
2559 mcIdType c1=revDescLP[idx0], c2=revDescLP[idx0+1];
2560 std::map<mcIdType, mcIdType> toOther = {{c1, c2}, {c2, c1}};
2561 // Handle the spread zones on the two sides of the crack:
2562 for (const auto c: {c1, c2})
2564 if (hitCellsLargeP[c]) continue;
2565 // Identify connex zone around this cell - if we find a value already assigned there, use it.
2567 DAInt spreadZone = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&c, &c+1, neighL,neighIL, -1, dnu);
2568 std::set<mcIdType> sv;
2569 for (const mcIdType& s: *spreadZone)
2570 if (hitCellsLargeP[s]) sv.insert(hitCellsLargeP[s]);
2572 // Strange: we find in the same spread zone a +1 and -1 !
2573 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellsToRenumber: internal error #0 - conflicting values - should not happen!");
2574 // If a valid value was found, use it:
2575 mcIdType val = sv.size()==1 ? *sv.begin() : 0;
2576 // Hopefully this does not conflict with an potential value on the other side:
2577 mcIdType other = toOther[c];
2578 if (hitCellsLargeP[other])
2580 if(val && hitCellsLargeP[other] != -val)
2581 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellsToRenumber: internal error #1 - conflicting values - should not happen!");;
2582 // We do not yet have a value, but other side has one. Use it!
2583 if(!val) val = -hitCellsLargeP[other];
2585 // Cover first initialisation:
2587 // And finally, fill the current spread zone:
2588 for(const mcIdType& s: *spreadZone) hitCellsLargeP[s] = val;
2592 DAInt cellsRet1 = hitCellsLarge->findIdsEqual(1);
2593 DAInt cellsRet2 = hitCellsLarge->findIdsEqual(-1);
2595 if (cellsRet1->getNumberOfTuples() + cellsRet2->getNumberOfTuples() != cellsAroundGroupLarge->getNumberOfTuples())
2597 DAInt nonHitCells = hitCellsLarge->findIdsEqual(0); // variable kept for debug ...
2598 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellsToRenumber: Some cells not hit - Internal error should not happen");
2600 cellsRet1->transformWithIndArr(cellsAroundGroupLarge->begin(),cellsAroundGroupLarge->end());
2601 cellsRet2->transformWithIndArr(cellsAroundGroupLarge->begin(),cellsAroundGroupLarge->end());
2603 cellIdsNeededToBeRenum=cellsRet1.retn();
2604 cellIdsNotModified=cellsRet2.retn();
2608 * This method operates a modification of the connectivity and coords in \b this.
2609 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2610 * its ids will be modified to id this->getNumberOfNodes()+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2611 * 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
2612 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id this->getNumberOfNodes()+0, node id nodeIdsToDuplicateBg[1] will have id this->getNumberOfNodes()+1,
2613 * node id nodeIdsToDuplicateBg[2] will have id this->getNumberOfNodes()+2...
2615 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2617 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2618 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2620 void MEDCouplingUMesh::duplicateNodes(const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd)
2622 mcIdType nbOfNodes=getNumberOfNodes();
2623 duplicateNodesInCoords(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd);
2624 duplicateNodesInConn(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,nbOfNodes);
2628 * This method renumbers only nodal connectivity in \a this. The renumbering is only an offset applied. So this method is a specialization of
2629 * \a renumberNodesInConn. \b WARNING, this method does not check that the resulting node ids in the nodal connectivity is in a valid range !
2631 * \param [in] offset - specifies the offset to be applied on each element of connectivity.
2633 * \sa renumberNodesInConn
2635 void MEDCouplingUMesh::renumberNodesWithOffsetInConn(mcIdType offset)
2637 checkConnectivityFullyDefined();
2638 mcIdType *conn(getNodalConnectivity()->getPointer());
2639 const mcIdType *connIndex(getNodalConnectivityIndex()->getConstPointer());
2640 mcIdType nbOfCells=getNumberOfCells();
2641 for(mcIdType i=0;i<nbOfCells;i++)
2642 for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2644 mcIdType& node=conn[iconn];
2645 if(node>=0)//avoid polyhedron separator
2650 _nodal_connec->declareAsNew();
2655 * Same than renumberNodesInConn(const mcIdType *) except that here the format of old-to-new traducer is using map instead
2656 * 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
2659 void MEDCouplingUMesh::renumberNodesInConn(const INTERP_KERNEL::HashMap<mcIdType,mcIdType>& newNodeNumbersO2N)
2661 this->renumberNodesInConnT< INTERP_KERNEL::HashMap<mcIdType,mcIdType> >(newNodeNumbersO2N);
2665 * Same than renumberNodesInConn(const mcIdType *) except that here the format of old-to-new traducer is using map instead
2666 * 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
2669 void MEDCouplingUMesh::renumberNodesInConn(const std::map<mcIdType,mcIdType>& newNodeNumbersO2N)
2671 this->renumberNodesInConnT< std::map<mcIdType,mcIdType> >(newNodeNumbersO2N);
2675 * Changes ids of nodes within the nodal connectivity arrays according to a permutation
2676 * array in "Old to New" mode. The node coordinates array is \b not changed by this method.
2677 * This method is a generalization of shiftNodeNumbersInConn().
2678 * \warning This method performs no check of validity of new ids. **Use it with care !**
2679 * \param [in] newNodeNumbersO2N - a permutation array, of length \a
2680 * this->getNumberOfNodes(), in "Old to New" mode.
2681 * See \ref numbering for more info on renumbering modes.
2682 * \throw If the nodal connectivity of cells is not defined.
2684 * \if ENABLE_EXAMPLES
2685 * \ref cpp_mcumesh_renumberNodesInConn "Here is a C++ example".<br>
2686 * \ref py_mcumesh_renumberNodesInConn "Here is a Python example".
2689 void MEDCouplingUMesh::renumberNodesInConn(const mcIdType *newNodeNumbersO2N)
2691 checkConnectivityFullyDefined();
2692 mcIdType *conn=getNodalConnectivity()->getPointer();
2693 const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2694 mcIdType nbOfCells=getNumberOfCells();
2695 for(mcIdType i=0;i<nbOfCells;i++)
2696 for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2698 mcIdType& node=conn[iconn];
2699 if(node>=0)//avoid polyhedron separator
2701 node=newNodeNumbersO2N[node];
2704 _nodal_connec->declareAsNew();
2709 * This method renumbers nodes \b in \b connectivity \b only \b without \b any \b reference \b to \b coords.
2710 * This method performs no check on the fact that new coordinate ids are valid. \b Use \b it \b with \b care !
2711 * This method is an specialization of \ref MEDCoupling::MEDCouplingUMesh::renumberNodesInConn "renumberNodesInConn method".
2713 * \param [in] delta specifies the shift size applied to nodeId in nodal connectivity in \b this.
2715 void MEDCouplingUMesh::shiftNodeNumbersInConn(mcIdType delta)
2717 checkConnectivityFullyDefined();
2718 mcIdType *conn=getNodalConnectivity()->getPointer();
2719 const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2720 mcIdType nbOfCells=getNumberOfCells();
2721 for(mcIdType i=0;i<nbOfCells;i++)
2722 for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2724 mcIdType& node=conn[iconn];
2725 if(node>=0)//avoid polyhedron separator
2730 _nodal_connec->declareAsNew();
2735 * This method operates a modification of the connectivity in \b this.
2736 * 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.
2737 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2738 * its ids will be modified to id offset+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2739 * 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
2740 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id offset+0, node id nodeIdsToDuplicateBg[1] will have id offset+1,
2741 * node id nodeIdsToDuplicateBg[2] will have id offset+2...
2743 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2744 * As an another consequense after the call of this method \b this can be transiently non cohrent.
2746 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2747 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2748 * \param [in] offset the offset applied to all node ids in connectivity that are in [ \a nodeIdsToDuplicateBg, \a nodeIdsToDuplicateEnd ).
2750 void MEDCouplingUMesh::duplicateNodesInConn(const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd, mcIdType offset)
2752 checkConnectivityFullyDefined();
2753 std::map<mcIdType,mcIdType> m;
2754 mcIdType val=offset;
2755 for(const mcIdType *work=nodeIdsToDuplicateBg;work!=nodeIdsToDuplicateEnd;work++,val++)
2757 mcIdType *conn=getNodalConnectivity()->getPointer();
2758 const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2759 mcIdType nbOfCells=getNumberOfCells();
2760 for(mcIdType i=0;i<nbOfCells;i++)
2761 for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2763 mcIdType& node=conn[iconn];
2764 if(node>=0)//avoid polyhedron separator
2766 std::map<mcIdType,mcIdType>::iterator it=m.find(node);
2775 * This method renumbers cells of \a this using the array specified by [old2NewBg;old2NewBg+getNumberOfCells())
2777 * Contrary to MEDCouplingPointSet::renumberNodes, this method makes a permutation without any fuse of cell.
2778 * After the call of this method the number of cells remains the same as before.
2780 * If 'check' equals true the method will check that any elements in [ \a old2NewBg; \a old2NewEnd ) is unique ; if not
2781 * an INTERP_KERNEL::Exception will be thrown. When 'check' equals true [ \a old2NewBg ; \a old2NewEnd ) is not expected to
2782 * be strictly in [0;this->getNumberOfCells()).
2784 * If 'check' equals false the method will not check the content of [ \a old2NewBg ; \a old2NewEnd ).
2785 * To avoid any throw of SIGSEGV when 'check' equals false, the elements in [ \a old2NewBg ; \a old2NewEnd ) should be unique and
2786 * should be contained in[0;this->getNumberOfCells()).
2788 * \param [in] old2NewBg is expected to be a dynamically allocated pointer of size at least equal to this->getNumberOfCells()
2789 * \param check whether to check content of old2NewBg
2791 void MEDCouplingUMesh::renumberCells(const mcIdType *old2NewBg, bool check)
2793 checkConnectivityFullyDefined();
2794 mcIdType nbCells=getNumberOfCells();
2795 const mcIdType *array=old2NewBg;
2797 array=DataArrayIdType::CheckAndPreparePermutation(old2NewBg,old2NewBg+nbCells);
2799 const mcIdType *conn=_nodal_connec->getConstPointer();
2800 const mcIdType *connI=_nodal_connec_index->getConstPointer();
2801 MCAuto<DataArrayIdType> o2n=DataArrayIdType::New(); o2n->useArray(array,false,DeallocType::C_DEALLOC,nbCells,1);
2802 MCAuto<DataArrayIdType> n2o=o2n->invertArrayO2N2N2O(nbCells);
2803 const mcIdType *n2oPtr=n2o->begin();
2804 MCAuto<DataArrayIdType> newConn=DataArrayIdType::New();
2805 newConn->alloc(_nodal_connec->getNumberOfTuples(),_nodal_connec->getNumberOfComponents());
2806 newConn->copyStringInfoFrom(*_nodal_connec);
2807 MCAuto<DataArrayIdType> newConnI=DataArrayIdType::New();
2808 newConnI->alloc(_nodal_connec_index->getNumberOfTuples(),_nodal_connec_index->getNumberOfComponents());
2809 newConnI->copyStringInfoFrom(*_nodal_connec_index);
2811 mcIdType *newC=newConn->getPointer();
2812 mcIdType *newCI=newConnI->getPointer();
2815 for(mcIdType i=0;i<nbCells;i++)
2817 mcIdType pos=n2oPtr[i];
2818 mcIdType nbOfElts=connI[pos+1]-connI[pos];
2819 newC=std::copy(conn+connI[pos],conn+connI[pos+1],newC);
2824 setConnectivity(newConn,newConnI);
2826 free(const_cast<mcIdType *>(array));
2830 * Finds cells whose bounding boxes intersect a given bounding box.
2831 * \param [in] bbox - an array defining the bounding box via coordinates of its
2832 * extremum points in "no interlace" mode, i.e. xMin, xMax, yMin, yMax, zMin,
2834 * \param [in] eps - a factor used to increase size of the bounding box of cell
2835 * before comparing it with \a bbox. This factor is multiplied by the maximal
2836 * extent of the bounding box of cell to produce an addition to this bounding box.
2837 * \return DataArrayIdType * - a new instance of DataArrayIdType holding ids for found
2838 * cells. The caller is to delete this array using decrRef() as it is no more
2840 * \throw If the coordinates array is not set.
2841 * \throw If the nodal connectivity of cells is not defined.
2843 * \if ENABLE_EXAMPLES
2844 * \ref cpp_mcumesh_getCellsInBoundingBox "Here is a C++ example".<br>
2845 * \ref py_mcumesh_getCellsInBoundingBox "Here is a Python example".
2848 DataArrayIdType *MEDCouplingUMesh::getCellsInBoundingBox(const double *bbox, double eps) const
2850 MCAuto<DataArrayIdType> elems=DataArrayIdType::New(); elems->alloc(0,1);
2851 if(getMeshDimension()==-1)
2853 elems->pushBackSilent(0);
2854 return elems.retn();
2856 int dim=getSpaceDimension();
2857 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2858 const mcIdType* conn = getNodalConnectivity()->getConstPointer();
2859 const mcIdType* conn_index= getNodalConnectivityIndex()->getConstPointer();
2860 const double* coords = getCoords()->getConstPointer();
2861 mcIdType nbOfCells=getNumberOfCells();
2862 for ( mcIdType ielem=0; ielem<nbOfCells;ielem++ )
2864 for (int i=0; i<dim; i++)
2866 elem_bb[i*2]=std::numeric_limits<double>::max();
2867 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2870 for (mcIdType inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2872 mcIdType node= conn[inode];
2873 if(node>=0)//avoid polyhedron separator
2875 for (int idim=0; idim<dim; idim++)
2877 if ( coords[node*dim+idim] < elem_bb[idim*2] )
2879 elem_bb[idim*2] = coords[node*dim+idim] ;
2881 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2883 elem_bb[idim*2+1] = coords[node*dim+idim] ;
2888 if (intersectsBoundingBox(elem_bb, bbox, dim, eps))
2889 elems->pushBackSilent(ielem);
2891 return elems.retn();
2895 * Given a boundary box 'bbox' returns elements 'elems' contained in this 'bbox' or touching 'bbox' (within 'eps' distance).
2896 * Warning 'elems' is incremented during the call so if elems is not empty before call returned elements will be
2897 * added in 'elems' parameter.
2899 DataArrayIdType *MEDCouplingUMesh::getCellsInBoundingBox(const INTERP_KERNEL::DirectedBoundingBox& bbox, double eps)
2901 MCAuto<DataArrayIdType> elems=DataArrayIdType::New(); elems->alloc(0,1);
2902 if(getMeshDimension()==-1)
2904 elems->pushBackSilent(0);
2905 return elems.retn();
2907 int dim=getSpaceDimension();
2908 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2909 const mcIdType* conn = getNodalConnectivity()->getConstPointer();
2910 const mcIdType* conn_index= getNodalConnectivityIndex()->getConstPointer();
2911 const double* coords = getCoords()->getConstPointer();
2912 mcIdType nbOfCells=getNumberOfCells();
2913 for ( mcIdType ielem=0; ielem<nbOfCells;ielem++ )
2915 for (int i=0; i<dim; i++)
2917 elem_bb[i*2]=std::numeric_limits<double>::max();
2918 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2921 for (mcIdType inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2923 mcIdType node= conn[inode];
2924 if(node>=0)//avoid polyhedron separator
2926 for (int idim=0; idim<dim; idim++)
2928 if ( coords[node*dim+idim] < elem_bb[idim*2] )
2930 elem_bb[idim*2] = coords[node*dim+idim] ;
2932 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2934 elem_bb[idim*2+1] = coords[node*dim+idim] ;
2939 if(intersectsBoundingBox(bbox, elem_bb, dim, eps))
2940 elems->pushBackSilent(ielem);
2942 return elems.retn();
2946 * Returns a type of a cell by its id.
2947 * \param [in] cellId - the id of the cell of interest.
2948 * \return INTERP_KERNEL::NormalizedCellType - enumeration item describing the cell type.
2949 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2951 INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::getTypeOfCell(mcIdType cellId) const
2953 const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
2954 if(cellId<_nodal_connec_index->getNbOfElems()-1)
2955 return (INTERP_KERNEL::NormalizedCellType) pt[ptI[cellId]];
2958 std::ostringstream oss; oss << "MEDCouplingUMesh::getTypeOfCell : Requesting type of cell #" << cellId << " but it should be in [0," << _nodal_connec_index->getNbOfElems()-1 << ") !";
2959 throw INTERP_KERNEL::Exception(oss.str());
2964 * This method returns a newly allocated array containing cell ids (ascendingly sorted) whose geometric type are equal to type.
2965 * This method does not throw exception if geometric type \a type is not in \a this.
2966 * This method throws an INTERP_KERNEL::Exception if meshdimension of \b this is not equal to those of \b type.
2967 * The coordinates array is not considered here.
2969 * \param [in] type the geometric type
2970 * \return cell ids in this having geometric type \a type.
2972 DataArrayIdType *MEDCouplingUMesh::giveCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2975 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
2977 checkConnectivityFullyDefined();
2978 mcIdType nbCells=getNumberOfCells();
2979 int mdim=getMeshDimension();
2980 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
2981 if(mdim!=ToIdType(cm.getDimension()))
2982 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::giveCellsWithType : Mismatch between mesh dimension and dimension of the cell !");
2983 const mcIdType *ptI=_nodal_connec_index->getConstPointer();
2984 const mcIdType *pt=_nodal_connec->getConstPointer();
2985 for(mcIdType i=0;i<nbCells;i++)
2987 if((INTERP_KERNEL::NormalizedCellType)pt[ptI[i]]==type)
2988 ret->pushBackSilent(i);
2994 * Returns nb of cells having the geometric type \a type. No throw if no cells in \a this has the geometric type \a type.
2996 mcIdType MEDCouplingUMesh::getNumberOfCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2998 const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
2999 mcIdType nbOfCells(getNumberOfCells()),ret(0);
3000 for(mcIdType i=0;i<nbOfCells;i++)
3001 if((INTERP_KERNEL::NormalizedCellType) pt[ptI[i]]==type)
3007 * Returns the nodal connectivity of a given cell.
3008 * The separator of faces within polyhedron connectivity (-1) is not returned, thus
3009 * all returned node ids can be used in getCoordinatesOfNode().
3010 * \param [in] cellId - an id of the cell of interest.
3011 * \param [in,out] conn - a vector where the node ids are appended. It is not
3012 * cleared before the appending.
3013 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
3015 void MEDCouplingUMesh::getNodeIdsOfCell(mcIdType cellId, std::vector<mcIdType>& conn) const
3017 const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
3018 for(const mcIdType *w=pt+ptI[cellId]+1;w!=pt+ptI[cellId+1];w++)
3023 std::string MEDCouplingUMesh::simpleRepr() const
3025 static const char msg0[]="No coordinates specified !";
3026 std::ostringstream ret;
3027 ret << "Unstructured mesh with name : \"" << getName() << "\"\n";
3028 ret << "Description of mesh : \"" << getDescription() << "\"\n";
3030 double tt=getTime(tmpp1,tmpp2);
3031 ret << "Time attached to the mesh [unit] : " << tt << " [" << getTimeUnit() << "]\n";
3032 ret << "Iteration : " << tmpp1 << " Order : " << tmpp2 << "\n";
3034 { ret << "Mesh dimension : " << _mesh_dim << "\nSpace dimension : "; }
3036 { ret << " Mesh dimension has not been set or is invalid !"; }
3039 const int spaceDim=getSpaceDimension();
3040 ret << spaceDim << "\nInfo attached on space dimension : ";
3041 for(int i=0;i<spaceDim;i++)
3042 ret << "\"" << _coords->getInfoOnComponent(i) << "\" ";
3046 ret << msg0 << "\n";
3047 ret << "Number of nodes : ";
3049 ret << getNumberOfNodes() << "\n";
3051 ret << msg0 << "\n";
3052 ret << "Number of cells : ";
3053 if(_nodal_connec!=0 && _nodal_connec_index!=0)
3054 ret << getNumberOfCells() << "\n";
3056 ret << "No connectivity specified !" << "\n";
3057 ret << "Cell types present : ";
3058 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
3060 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter);
3061 ret << cm.getRepr() << " ";
3067 std::string MEDCouplingUMesh::advancedRepr() const
3069 std::ostringstream ret;
3070 ret << simpleRepr();
3071 ret << "\nCoordinates array : \n___________________\n\n";
3073 _coords->reprWithoutNameStream(ret);
3075 ret << "No array set !\n";
3076 ret << "\n\nConnectivity arrays : \n_____________________\n\n";
3077 reprConnectivityOfThisLL(ret);
3082 * This method returns a C++ code that is a dump of \a this.
3083 * This method will throw if this is not fully defined.
3085 std::string MEDCouplingUMesh::cppRepr() const
3087 static const char coordsName[]="coords";
3088 static const char connName[]="conn";
3089 static const char connIName[]="connI";
3090 checkFullyDefined();
3091 std::ostringstream ret; ret << "// coordinates" << std::endl;
3092 _coords->reprCppStream(coordsName,ret); ret << std::endl << "// connectivity" << std::endl;
3093 _nodal_connec->reprCppStream(connName,ret); ret << std::endl;
3094 _nodal_connec_index->reprCppStream(connIName,ret); ret << std::endl;
3095 ret << "MEDCouplingUMesh *mesh=MEDCouplingUMesh::New(\"" << getName() << "\"," << getMeshDimension() << ");" << std::endl;
3096 ret << "mesh->setCoords(" << coordsName << ");" << std::endl;
3097 ret << "mesh->setConnectivity(" << connName << "," << connIName << ",true);" << std::endl;
3098 ret << coordsName << "->decrRef(); " << connName << "->decrRef(); " << connIName << "->decrRef();" << std::endl;
3102 std::string MEDCouplingUMesh::reprConnectivityOfThis() const
3104 std::ostringstream ret;
3105 reprConnectivityOfThisLL(ret);
3110 * This method builds a newly allocated instance (with the same name than \a this) that the caller has the responsibility to deal with.
3111 * This method returns an instance with all arrays allocated (connectivity, connectivity index, coordinates)
3112 * but with length of these arrays set to 0. It allows to define an "empty" mesh (with nor cells nor nodes but compliant with
3115 * This method expects that \a this has a mesh dimension set and higher or equal to 0. If not an exception will be thrown.
3116 * 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
3117 * with number of tuples set to 0, if not the array is taken as this in the returned instance.
3119 MEDCouplingUMesh *MEDCouplingUMesh::buildSetInstanceFromThis(std::size_t spaceDim) const
3121 int mdim=getMeshDimension();
3123 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSetInstanceFromThis : invalid mesh dimension ! Should be >= 0 !");
3124 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
3125 MCAuto<DataArrayIdType> tmp1,tmp2;
3126 bool needToCpyCT=true;
3129 tmp1=DataArrayIdType::New(); tmp1->alloc(0,1);
3137 if(!_nodal_connec_index)
3139 tmp2=DataArrayIdType::New(); tmp2->alloc(1,1); tmp2->setIJ(0,0,0);
3144 tmp2=_nodal_connec_index;
3147 ret->setConnectivity(tmp1,tmp2,false);
3152 MCAuto<DataArrayDouble> coords=DataArrayDouble::New(); coords->alloc(0,spaceDim);
3153 ret->setCoords(coords);
3156 ret->setCoords(_coords);
3160 mcIdType MEDCouplingUMesh::getNumberOfNodesInCell(mcIdType cellId) const
3162 const mcIdType *ptI=_nodal_connec_index->getConstPointer();
3163 const mcIdType *pt=_nodal_connec->getConstPointer();
3164 if(pt[ptI[cellId]]!=INTERP_KERNEL::NORM_POLYHED)
3165 return ptI[cellId+1]-ptI[cellId]-1;
3167 return ToIdType(std::count_if(pt+ptI[cellId]+1,pt+ptI[cellId+1],std::bind(std::not_equal_to<mcIdType>(),std::placeholders::_1,-1)));
3171 * Returns types of cells of the specified part of \a this mesh.
3172 * This method avoids computing sub-mesh explicitly to get its types.
3173 * \param [in] begin - an array of cell ids of interest.
3174 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3175 * \return std::set<INTERP_KERNEL::NormalizedCellType> - a set of enumeration items
3176 * describing the cell types.
3177 * \throw If the coordinates array is not set.
3178 * \throw If the nodal connectivity of cells is not defined.
3179 * \sa getAllGeoTypes()
3181 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getTypesOfPart(const mcIdType *begin, const mcIdType *end) const
3183 checkFullyDefined();
3184 std::set<INTERP_KERNEL::NormalizedCellType> ret;
3185 const mcIdType *conn=_nodal_connec->getConstPointer();
3186 const mcIdType *connIndex=_nodal_connec_index->getConstPointer();
3187 for(const mcIdType *w=begin;w!=end;w++)
3188 ret.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]);
3193 * Defines the nodal connectivity using given connectivity arrays in \ref numbering-indirect format.
3194 * Optionally updates
3195 * a set of types of cells constituting \a this mesh.
3196 * This method is for advanced users having prepared their connectivity before. For
3197 * more info on using this method see \ref MEDCouplingUMeshAdvBuild.
3198 * \param [in] conn - the nodal connectivity array.
3199 * \param [in] connIndex - the nodal connectivity index array.
3200 * \param [in] isComputingTypes - if \c true, the set of types constituting \a this
3203 void MEDCouplingUMesh::setConnectivity(DataArrayIdType *conn, DataArrayIdType *connIndex, bool isComputingTypes)
3205 DataArrayIdType::SetArrayIn(conn,_nodal_connec);
3206 DataArrayIdType::SetArrayIn(connIndex,_nodal_connec_index);
3207 if(isComputingTypes)
3213 * Copy constructor. If 'deepCopy' is false \a this is a shallow copy of other.
3214 * If 'deeCpy' is true all arrays (coordinates and connectivities) are deeply copied.
3216 MEDCouplingUMesh::MEDCouplingUMesh(const MEDCouplingUMesh& other, bool deepCpy):MEDCouplingPointSet(other,deepCpy),_mesh_dim(other._mesh_dim),
3217 _nodal_connec(0),_nodal_connec_index(0),
3218 _types(other._types)
3220 if(other._nodal_connec)
3221 _nodal_connec=other._nodal_connec->performCopyOrIncrRef(deepCpy);
3222 if(other._nodal_connec_index)
3223 _nodal_connec_index=other._nodal_connec_index->performCopyOrIncrRef(deepCpy);
3226 MEDCouplingUMesh::~MEDCouplingUMesh()
3229 _nodal_connec->decrRef();
3230 if(_nodal_connec_index)
3231 _nodal_connec_index->decrRef();
3235 * Recomputes a set of cell types of \a this mesh. For more info see
3236 * \ref MEDCouplingUMeshNodalConnectivity.
3238 void MEDCouplingUMesh::computeTypes()
3240 ComputeAllTypesInternal(_types,_nodal_connec,_nodal_connec_index);
3245 * Returns a number of cells constituting \a this mesh.
3246 * \return mcIdType - the number of cells in \a this mesh.
3247 * \throw If the nodal connectivity of cells is not defined.
3249 mcIdType MEDCouplingUMesh::getNumberOfCells() const
3251 if(_nodal_connec_index)
3252 return _nodal_connec_index->getNumberOfTuples()-1;
3257 throw INTERP_KERNEL::Exception("Unable to get number of cells because no connectivity specified !");
3261 * Returns a dimension of \a this mesh, i.e. a dimension of cells constituting \a this
3262 * mesh. For more info see \ref meshes.
3263 * \return int - the dimension of \a this mesh.
3264 * \throw If the mesh dimension is not defined using setMeshDimension().
3266 int MEDCouplingUMesh::getMeshDimension() const
3269 throw INTERP_KERNEL::Exception("No mesh dimension specified !");
3274 * Returns a length of the nodal connectivity array.
3275 * This method is for test reason. Normally the integer returned is not useable by
3276 * user. For more info see \ref MEDCouplingUMeshNodalConnectivity.
3277 * \return mcIdType - the length of the nodal connectivity array.
3279 mcIdType MEDCouplingUMesh::getNodalConnectivityArrayLen() const
3281 return _nodal_connec->getNbOfElems();
3285 * First step of serialization process. Used by ParaMEDMEM and MEDCouplingCorba to transfert data between process.
3287 void MEDCouplingUMesh::getTinySerializationInformation(std::vector<double>& tinyInfoD, std::vector<mcIdType>& tinyInfo, std::vector<std::string>& littleStrings) const
3289 MEDCouplingPointSet::getTinySerializationInformation(tinyInfoD,tinyInfo,littleStrings);
3290 tinyInfo.push_back(ToIdType(getMeshDimension()));
3291 tinyInfo.push_back(getNumberOfCells());
3293 tinyInfo.push_back(getNodalConnectivityArrayLen());
3295 tinyInfo.push_back(-1);
3299 * First step of unserialization process.
3301 bool MEDCouplingUMesh::isEmptyMesh(const std::vector<mcIdType>& tinyInfo) const
3303 return tinyInfo[6]<=0;
3307 * Second step of serialization process.
3308 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3309 * \param a1 DataArrayDouble
3310 * \param a2 DataArrayDouble
3311 * \param littleStrings string vector
3313 void MEDCouplingUMesh::resizeForUnserialization(const std::vector<mcIdType>& tinyInfo, DataArrayIdType *a1, DataArrayDouble *a2, std::vector<std::string>& littleStrings) const
3315 MEDCouplingPointSet::resizeForUnserialization(tinyInfo,a1,a2,littleStrings);
3317 a1->alloc(tinyInfo[7]+tinyInfo[6]+1,1);
3321 * Third and final step of serialization process.
3323 void MEDCouplingUMesh::serialize(DataArrayIdType *&a1, DataArrayDouble *&a2) const
3325 MEDCouplingPointSet::serialize(a1,a2);
3326 if(getMeshDimension()>-1)
3328 a1=DataArrayIdType::New();
3329 a1->alloc(getNodalConnectivityArrayLen()+getNumberOfCells()+1,1);
3330 mcIdType *ptA1=a1->getPointer();
3331 const mcIdType *conn=getNodalConnectivity()->getConstPointer();
3332 const mcIdType *index=getNodalConnectivityIndex()->getConstPointer();
3333 ptA1=std::copy(index,index+getNumberOfCells()+1,ptA1);
3334 std::copy(conn,conn+getNodalConnectivityArrayLen(),ptA1);
3341 * Second and final unserialization process.
3342 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3344 void MEDCouplingUMesh::unserialization(const std::vector<double>& tinyInfoD, const std::vector<mcIdType>& tinyInfo, const DataArrayIdType *a1, DataArrayDouble *a2, const std::vector<std::string>& littleStrings)
3346 MEDCouplingPointSet::unserialization(tinyInfoD,tinyInfo,a1,a2,littleStrings);
3347 setMeshDimension(FromIdType<int>(tinyInfo[5]));
3351 const mcIdType *recvBuffer=a1->getConstPointer();
3352 MCAuto<DataArrayIdType> myConnecIndex=DataArrayIdType::New();
3353 myConnecIndex->alloc(tinyInfo[6]+1,1);
3354 std::copy(recvBuffer,recvBuffer+tinyInfo[6]+1,myConnecIndex->getPointer());
3355 MCAuto<DataArrayIdType> myConnec=DataArrayIdType::New();
3356 myConnec->alloc(tinyInfo[7],1);
3357 std::copy(recvBuffer+tinyInfo[6]+1,recvBuffer+tinyInfo[6]+1+tinyInfo[7],myConnec->getPointer());
3358 setConnectivity(myConnec, myConnecIndex);
3365 * Returns a new MEDCouplingFieldDouble containing volumes of cells constituting \a this
3367 * For 1D cells, the returned field contains lengths.<br>
3368 * For 2D cells, the returned field contains areas.<br>
3369 * For 3D cells, the returned field contains volumes.
3370 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3371 * orientation, i.e. the volume is always positive.
3372 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on cells
3373 * and one time . The caller is to delete this field using decrRef() as it is no
3376 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureField(bool isAbs) const
3378 std::string name="MeasureOfMesh_";
3380 mcIdType nbelem=getNumberOfCells();
3381 MCAuto<MEDCouplingFieldDouble> field=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3382 field->setName(name);
3383 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3384 array->alloc(nbelem,1);
3385 double *area_vol=array->getPointer();
3386 field->setArray(array) ; array=0;
3387 field->setMesh(const_cast<MEDCouplingUMesh *>(this));
3388 field->synchronizeTimeWithMesh();
3389 if(getMeshDimension()!=-1)
3392 INTERP_KERNEL::NormalizedCellType type;
3393 int dim_space=getSpaceDimension();
3394 const double *coords=getCoords()->getConstPointer();
3395 const mcIdType *connec=getNodalConnectivity()->getConstPointer();
3396 const mcIdType *connec_index=getNodalConnectivityIndex()->getConstPointer();
3397 for(mcIdType iel=0;iel<nbelem;iel++)
3399 ipt=connec_index[iel];
3400 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3401 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);
3404 std::transform(area_vol,area_vol+nbelem,area_vol,[](double c){return fabs(c);});
3408 area_vol[0]=std::numeric_limits<double>::max();
3410 return field.retn();
3414 * Returns a new DataArrayDouble containing volumes of specified cells of \a this
3416 * For 1D cells, the returned array contains lengths.<br>
3417 * For 2D cells, the returned array contains areas.<br>
3418 * For 3D cells, the returned array contains volumes.
3419 * This method avoids building explicitly a part of \a this mesh to perform the work.
3420 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3421 * orientation, i.e. the volume is always positive.
3422 * \param [in] begin - an array of cell ids of interest.
3423 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3424 * \return DataArrayDouble * - a new instance of DataArrayDouble. The caller is to
3425 * delete this array using decrRef() as it is no more needed.
3427 * \if ENABLE_EXAMPLES
3428 * \ref cpp_mcumesh_getPartMeasureField "Here is a C++ example".<br>
3429 * \ref py_mcumesh_getPartMeasureField "Here is a Python example".
3431 * \sa getMeasureField()
3433 DataArrayDouble *MEDCouplingUMesh::getPartMeasureField(bool isAbs, const mcIdType *begin, const mcIdType *end) const
3435 std::string name="PartMeasureOfMesh_";
3437 std::size_t nbelem=std::distance(begin,end);
3438 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3439 array->setName(name);
3440 array->alloc(nbelem,1);
3441 double *area_vol=array->getPointer();
3442 if(getMeshDimension()!=-1)
3445 INTERP_KERNEL::NormalizedCellType type;
3446 int dim_space=getSpaceDimension();
3447 const double *coords=getCoords()->getConstPointer();
3448 const mcIdType *connec=getNodalConnectivity()->getConstPointer();
3449 const mcIdType *connec_index=getNodalConnectivityIndex()->getConstPointer();
3450 for(const mcIdType *iel=begin;iel!=end;iel++)
3452 ipt=connec_index[*iel];
3453 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3454 *area_vol++=INTERP_KERNEL::computeVolSurfOfCell2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,connec+ipt+1,connec_index[*iel+1]-ipt-1,coords,dim_space);
3457 std::transform(array->getPointer(),area_vol,array->getPointer(),[](double c){return fabs(c);});
3461 area_vol[0]=std::numeric_limits<double>::max();
3463 return array.retn();
3467 * Returns a new MEDCouplingFieldDouble containing volumes of cells of a dual mesh of
3468 * \a this one. The returned field contains the dual cell volume for each corresponding
3469 * node in \a this mesh. In other words, the field returns the getMeasureField() of
3470 * the dual mesh in P1 sens of \a this.<br>
3471 * For 1D cells, the returned field contains lengths.<br>
3472 * For 2D cells, the returned field contains areas.<br>
3473 * For 3D cells, the returned field contains volumes.
3474 * This method is useful to check "P1*" conservative interpolators.
3475 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3476 * orientation, i.e. the volume is always positive.
3477 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3478 * nodes and one time. The caller is to delete this array using decrRef() as
3479 * it is no more needed.
3481 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureFieldOnNode(bool isAbs) const
3483 MCAuto<MEDCouplingFieldDouble> tmp=getMeasureField(isAbs);
3484 std::string name="MeasureOnNodeOfMesh_";
3486 mcIdType nbNodes=getNumberOfNodes();
3487 MCAuto<DataArrayDouble> nnpc;
3489 MCAuto<DataArrayIdType> tmp2(computeNbOfNodesPerCell());
3490 nnpc=tmp2->convertToDblArr();
3492 std::for_each(nnpc->rwBegin(),nnpc->rwEnd(),[](double& v) { v=1./v; });
3493 const double *nnpcPtr(nnpc->begin());
3494 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_NODES);
3495 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3496 array->alloc(nbNodes,1);
3497 double *valsToFill=array->getPointer();
3498 std::fill(valsToFill,valsToFill+nbNodes,0.);
3499 const double *values=tmp->getArray()->getConstPointer();
3500 MCAuto<DataArrayIdType> da=DataArrayIdType::New();
3501 MCAuto<DataArrayIdType> daInd=DataArrayIdType::New();
3502 getReverseNodalConnectivity(da,daInd);
3503 const mcIdType *daPtr=da->getConstPointer();
3504 const mcIdType *daIPtr=daInd->getConstPointer();
3505 for(mcIdType i=0;i<nbNodes;i++)
3506 for(const mcIdType *cell=daPtr+daIPtr[i];cell!=daPtr+daIPtr[i+1];cell++)
3507 valsToFill[i]+=nnpcPtr[*cell]*values[*cell];
3509 ret->setArray(array);
3514 * Returns a new MEDCouplingFieldDouble holding normal vectors to cells of \a this
3515 * mesh. The returned normal vectors to each cell have a norm2 equal to 1.
3516 * The computed vectors have <em> this->getMeshDimension()+1 </em> components
3517 * and are normalized.
3518 * <br> \a this can be either
3519 * - a 2D mesh in 2D or 3D space or
3520 * - an 1D mesh in 2D space.
3522 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3523 * cells and one time. The caller is to delete this field using decrRef() as
3524 * it is no more needed.
3525 * \throw If the nodal connectivity of cells is not defined.
3526 * \throw If the coordinates array is not set.
3527 * \throw If the mesh dimension is not set.
3528 * \throw If the mesh and space dimension is not as specified above.
3530 MEDCouplingFieldDouble *MEDCouplingUMesh::buildOrthogonalField() const
3532 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3533 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3534 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3535 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3536 mcIdType nbOfCells=getNumberOfCells();
3537 int nbComp=getMeshDimension()+1;
3538 array->alloc(nbOfCells,nbComp);
3539 double *vals=array->getPointer();
3540 const mcIdType *connI=_nodal_connec_index->getConstPointer();
3541 const mcIdType *conn=_nodal_connec->getConstPointer();
3542 const double *coords=_coords->getConstPointer();
3543 if(getMeshDimension()==2)
3545 if(getSpaceDimension()==3)
3547 MCAuto<DataArrayDouble> loc=computeCellCenterOfMass();
3548 const double *locPtr=loc->getConstPointer();
3549 for(mcIdType i=0;i<nbOfCells;i++,vals+=3)
3551 mcIdType offset=connI[i];
3552 INTERP_KERNEL::crossprod<3>(locPtr+3*i,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3553 double n=INTERP_KERNEL::norm<3>(vals);
3554 std::transform(vals,vals+3,vals,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3559 MCAuto<MEDCouplingFieldDouble> isAbs=getMeasureField(false);
3560 const double *isAbsPtr=isAbs->getArray()->begin();
3561 for(mcIdType i=0;i<nbOfCells;i++,isAbsPtr++)
3562 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=*isAbsPtr>0.?1.:-1.; }
3565 else//meshdimension==1
3568 for(mcIdType i=0;i<nbOfCells;i++)
3570 mcIdType offset=connI[i];
3571 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3572 double n=INTERP_KERNEL::norm<2>(tmp);
3573 std::transform(tmp,tmp+2,tmp,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3578 ret->setArray(array);
3580 ret->synchronizeTimeWithSupport();
3585 * Returns a new MEDCouplingFieldDouble holding normal vectors to specified cells of
3586 * \a this mesh. The computed vectors have <em> this->getMeshDimension()+1 </em> components
3587 * and are normalized.
3588 * <br> \a this can be either
3589 * - a 2D mesh in 2D or 3D space or
3590 * - an 1D mesh in 2D space.
3592 * This method avoids building explicitly a part of \a this mesh to perform the work.
3593 * \param [in] begin - an array of cell ids of interest.
3594 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3595 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3596 * cells and one time. The caller is to delete this field using decrRef() as
3597 * it is no more needed.
3598 * \throw If the nodal connectivity of cells is not defined.
3599 * \throw If the coordinates array is not set.
3600 * \throw If the mesh dimension is not set.
3601 * \throw If the mesh and space dimension is not as specified above.
3602 * \sa buildOrthogonalField()
3604 * \if ENABLE_EXAMPLES
3605 * \ref cpp_mcumesh_buildPartOrthogonalField "Here is a C++ example".<br>
3606 * \ref py_mcumesh_buildPartOrthogonalField "Here is a Python example".
3609 MEDCouplingFieldDouble *MEDCouplingUMesh::buildPartOrthogonalField(const mcIdType *begin, const mcIdType *end) const
3611 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3612 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3613 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3614 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3615 std::size_t nbelems=std::distance(begin,end);
3616 int nbComp=getMeshDimension()+1;
3617 array->alloc(nbelems,nbComp);
3618 double *vals=array->getPointer();
3619 const mcIdType *connI=_nodal_connec_index->getConstPointer();
3620 const mcIdType *conn=_nodal_connec->getConstPointer();
3621 const double *coords=_coords->getConstPointer();
3622 if(getMeshDimension()==2)
3624 if(getSpaceDimension()==3)
3626 MCAuto<DataArrayDouble> loc=getPartBarycenterAndOwner(begin,end);
3627 const double *locPtr=loc->getConstPointer();
3628 for(const mcIdType *i=begin;i!=end;i++,vals+=3,locPtr+=3)
3630 mcIdType offset=connI[*i];
3631 INTERP_KERNEL::crossprod<3>(locPtr,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3632 double n=INTERP_KERNEL::norm<3>(vals);
3633 std::transform(vals,vals+3,vals,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3638 for(std::size_t i=0;i<nbelems;i++)
3639 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=1.; }
3642 else//meshdimension==1
3645 for(const mcIdType *i=begin;i!=end;i++)
3647 mcIdType offset=connI[*i];
3648 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3649 double n=INTERP_KERNEL::norm<2>(tmp);
3650 std::transform(tmp,tmp+2,tmp,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3655 ret->setArray(array);
3657 ret->synchronizeTimeWithSupport();
3662 * Returns a new MEDCouplingFieldDouble holding a direction vector for each SEG2 in \a
3663 * this 1D mesh. The computed vectors have <em> this->getSpaceDimension() </em> components
3664 * and are \b not normalized.
3665 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3666 * cells and one time. The caller is to delete this field using decrRef() as
3667 * it is no more needed.
3668 * \throw If the nodal connectivity of cells is not defined.
3669 * \throw If the coordinates array is not set.
3670 * \throw If \a this->getMeshDimension() != 1.
3671 * \throw If \a this mesh includes cells of type other than SEG2.
3673 MEDCouplingFieldDouble *MEDCouplingUMesh::buildDirectionVectorField() const
3675 if(getMeshDimension()!=1)
3676 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for buildDirectionVectorField !");
3677 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3678 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for buildDirectionVectorField !");
3679 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3680 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3681 mcIdType nbOfCells=getNumberOfCells();
3682 int spaceDim=getSpaceDimension();
3683 array->alloc(nbOfCells,spaceDim);
3684 double *pt=array->getPointer();
3685 const double *coo=getCoords()->getConstPointer();
3686 std::vector<mcIdType> conn;
3688 for(mcIdType i=0;i<nbOfCells;i++)
3691 getNodeIdsOfCell(i,conn);
3692 pt=std::transform(coo+conn[1]*spaceDim,coo+(conn[1]+1)*spaceDim,coo+conn[0]*spaceDim,pt,std::minus<double>());
3694 ret->setArray(array);
3696 ret->synchronizeTimeWithSupport();
3701 * Creates a 2D mesh by cutting \a this 3D mesh with a plane. In addition to the mesh,
3702 * returns a new DataArrayIdType, of length equal to the number of 2D cells in the result
3703 * mesh, holding, for each cell in the result mesh, an id of a 3D cell it comes
3704 * from. If a result face is shared by two 3D cells, then the face in included twice in
3706 * \param [in] origin - 3 components of a point defining location of the plane.
3707 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3708 * must be greater than 1e-6.
3709 * \param [in] eps - half-thickness of the plane.
3710 * \param [out] cellIds - a new instance of DataArrayIdType holding ids of 3D cells
3711 * producing correspondent 2D cells. The caller is to delete this array
3712 * using decrRef() as it is no more needed.
3713 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This mesh does
3714 * not share the node coordinates array with \a this mesh. The caller is to
3715 * delete this mesh using decrRef() as it is no more needed.
3716 * \throw If the coordinates array is not set.
3717 * \throw If the nodal connectivity of cells is not defined.
3718 * \throw If \a this->getMeshDimension() != 3 or \a this->getSpaceDimension() != 3.
3719 * \throw If magnitude of \a vec is less than 1e-6.
3720 * \throw If the plane does not intersect any 3D cell of \a this mesh.
3721 * \throw If \a this includes quadratic cells.
3723 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3D(const double *origin, const double *vec, double eps, DataArrayIdType *&cellIds) const
3725 checkFullyDefined();
3726 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3727 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3728 MCAuto<DataArrayIdType> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3729 if(candidates->empty())
3730 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane considering bounding boxes !");
3731 std::vector<mcIdType> nodes;
3732 DataArrayIdType *cellIds1D=0;
3733 MCAuto<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3734 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3735 MCAuto<DataArrayIdType> desc1=DataArrayIdType::New(),desc2=DataArrayIdType::New();
3736 MCAuto<DataArrayIdType> descIndx1=DataArrayIdType::New(),descIndx2=DataArrayIdType::New();
3737 MCAuto<DataArrayIdType> revDesc1=DataArrayIdType::New(),revDesc2=DataArrayIdType::New();
3738 MCAuto<DataArrayIdType> revDescIndx1=DataArrayIdType::New(),revDescIndx2=DataArrayIdType::New();
3739 MCAuto<MEDCouplingUMesh> mDesc2=subMesh->buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2);//meshDim==2 spaceDim==3
3740 revDesc2=0; revDescIndx2=0;
3741 MCAuto<MEDCouplingUMesh> mDesc1=mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3742 revDesc1=0; revDescIndx1=0;
3743 //Marking all 1D cells that contained at least one node located on the plane
3744 //the intersection between those cells and the plane, which consist of the nodes previously tagged, thus don't need to be computed afterwards
3745 //(if said intersection is computed in MEDCouplingUMesh::split3DCurveWithPlane, then we might create additional nodes
3746 //due to accuracy errors when the needed nodes already exist)
3747 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),false,cellIds1D);
3748 MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3750 std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3751 for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3753 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3754 std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(mDesc2->getNumberOfCells());
3755 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->getConstPointer(),mDesc2->getNodalConnectivityIndex()->getConstPointer(),
3756 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3757 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3758 MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New()),cellIds2(DataArrayIdType::New());
3759 connI->pushBackSilent(0); conn->alloc(0,1); cellIds2->alloc(0,1);
3760 subMesh->assemblyForSplitFrom3DSurf(cut3DSurf,desc2->getConstPointer(),descIndx2->getConstPointer(),conn,connI,cellIds2);
3761 if(cellIds2->empty())
3762 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3763 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3D",2);
3764 ret->setCoords(mDesc1->getCoords());
3765 ret->setConnectivity(conn,connI,true);
3766 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3771 * Creates an 1D mesh by cutting \a this 2D mesh in 3D space with a plane. In
3772 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
3773 from. If a result segment is shared by two 2D cells, then the segment in included twice in
3775 * \param [in] origin - 3 components of a point defining location of the plane.
3776 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3777 * must be greater than 1e-6.
3778 * \param [in] eps - half-thickness of the plane.
3779 * \param [out] cellIds - a new instance of DataArrayIdType holding ids of faces
3780 * producing correspondent segments. The caller is to delete this array
3781 * using decrRef() as it is no more needed.
3782 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This is an 1D
3783 * mesh in 3D space. This mesh does not share the node coordinates array with
3784 * \a this mesh. The caller is to delete this mesh using decrRef() as it is
3786 * \throw If the coordinates array is not set.
3787 * \throw If the nodal connectivity of cells is not defined.
3788 * \throw If \a this->getMeshDimension() != 2 or \a this->getSpaceDimension() != 3.
3789 * \throw If magnitude of \a vec is less than 1e-6.
3790 * \throw If the plane does not intersect any 2D cell of \a this mesh.
3791 * \throw If \a this includes quadratic cells.
3793 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3DSurf(const double *origin, const double *vec, double eps, DataArrayIdType *&cellIds) const
3795 checkFullyDefined();
3796 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
3797 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf works on umeshes with meshdim equal to 2 and spaceDim equal to 3 !");
3798 MCAuto<DataArrayIdType> candidates(getCellIdsCrossingPlane(origin,vec,eps));
3799 if(candidates->empty())
3800 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3D surf cells in this intercepts the specified plane considering bounding boxes !");
3801 std::vector<mcIdType> nodes;
3802 DataArrayIdType *cellIds1D(0);
3803 MCAuto<MEDCouplingUMesh> subMesh(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3804 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3805 MCAuto<DataArrayIdType> desc1(DataArrayIdType::New()),descIndx1(DataArrayIdType::New()),revDesc1(DataArrayIdType::New()),revDescIndx1(DataArrayIdType::New());
3806 MCAuto<MEDCouplingUMesh> mDesc1(subMesh->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3807 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3808 MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3810 std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3811 for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3813 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3814 mcIdType ncellsSub=subMesh->getNumberOfCells();
3815 std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(ncellsSub);
3816 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,subMesh->getNodalConnectivity()->getConstPointer(),subMesh->getNodalConnectivityIndex()->getConstPointer(),
3817 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3818 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3819 MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New()),cellIds2(DataArrayIdType::New()); connI->pushBackSilent(0);
3821 const mcIdType *nodal=subMesh->getNodalConnectivity()->getConstPointer();
3822 const mcIdType *nodalI=subMesh->getNodalConnectivityIndex()->getConstPointer();
3823 for(mcIdType i=0;i<ncellsSub;i++)
3825 if(cut3DSurf[i].first!=-1 && cut3DSurf[i].second!=-1)
3827 if(cut3DSurf[i].first!=-2)
3829 conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_SEG2)); conn->pushBackSilent(cut3DSurf[i].first); conn->pushBackSilent(cut3DSurf[i].second);
3830 connI->pushBackSilent(conn->getNumberOfTuples());
3831 cellIds2->pushBackSilent(i);
3835 mcIdType cellId3DSurf=cut3DSurf[i].second;
3836 mcIdType offset=nodalI[cellId3DSurf]+1;
3837 mcIdType nbOfEdges=nodalI[cellId3DSurf+1]-offset;
3838 for(mcIdType j=0;j<nbOfEdges;j++)
3840 conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_SEG2)); conn->pushBackSilent(nodal[offset+j]); conn->pushBackSilent(nodal[offset+(j+1)%nbOfEdges]);
3841 connI->pushBackSilent(conn->getNumberOfTuples());
3842 cellIds2->pushBackSilent(cellId3DSurf);
3847 if(cellIds2->empty())
3848 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3DSurf cells in this intercepts the specified plane !");
3849 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3DSurf",1);
3850 ret->setCoords(mDesc1->getCoords());
3851 ret->setConnectivity(conn,connI,true);
3852 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3856 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::clipSingle3DCellByPlane(const double origin[3], const double vec[3], double eps) const
3858 checkFullyDefined();
3859 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3860 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3861 if(getNumberOfCells()!=1)
3862 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works only on mesh containing exactly one cell !");
3864 std::vector<mcIdType> nodes;
3865 findNodesOnPlane(origin,vec,eps,nodes);
3866 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());
3867 MCAuto<MEDCouplingUMesh> mDesc2(buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2));//meshDim==2 spaceDim==3
3868 revDesc2=0; revDescIndx2=0;
3869 MCAuto<MEDCouplingUMesh> mDesc1(mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3870 revDesc1=0; revDescIndx1=0;
3871 DataArrayIdType *cellIds1D(0);
3872 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3873 MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3874 std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3875 for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3879 mcIdType oldNbNodes(mDesc1->getNumberOfNodes());
3880 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3881 sameNbNodes=(mDesc1->getNumberOfNodes()==oldNbNodes);
3883 std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(mDesc2->getNumberOfCells());
3884 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->begin(),mDesc2->getNodalConnectivityIndex()->begin(),
3885 mDesc1->getNodalConnectivity()->begin(),mDesc1->getNodalConnectivityIndex()->begin(),
3886 desc1->begin(),descIndx1->begin(),cut3DSurf);
3887 MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New());
3888 connI->pushBackSilent(0); conn->alloc(0,1);
3890 MCAuto<DataArrayIdType> cellIds2(DataArrayIdType::New()); cellIds2->alloc(0,1);
3891 assemblyForSplitFrom3DSurf(cut3DSurf,desc2->begin(),descIndx2->begin(),conn,connI,cellIds2);
3892 if(cellIds2->empty())
3893 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3895 std::vector<std::vector<mcIdType> > res;
3896 buildSubCellsFromCut(cut3DSurf,desc2->begin(),descIndx2->begin(),mDesc1->getCoords()->begin(),eps,res);
3897 std::size_t sz(res.size());
3898 if(ToIdType(res.size())==mDesc1->getNumberOfCells() && sameNbNodes)
3899 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane : cell is not clipped !");
3900 for(std::size_t i=0;i<sz;i++)
3902 conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYGON));
3903 conn->insertAtTheEnd(res[i].begin(),res[i].end());
3904 connI->pushBackSilent(conn->getNumberOfTuples());
3906 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
3907 ret->setCoords(mDesc1->getCoords());
3908 ret->setConnectivity(conn,connI,true);
3909 mcIdType nbCellsRet(ret->getNumberOfCells());
3911 MCAuto<DataArrayDouble> vec2(DataArrayDouble::New()); vec2->alloc(1,3); std::copy(vec,vec+3,vec2->getPointer());
3912 MCAuto<MEDCouplingFieldDouble> ortho(ret->buildOrthogonalField());
3913 MCAuto<DataArrayDouble> ortho2(ortho->getArray()->selectByTupleIdSafeSlice(0,1,1));
3914 MCAuto<DataArrayDouble> dott(DataArrayDouble::Dot(ortho2,vec2));
3915 MCAuto<DataArrayDouble> ccm(ret->computeCellCenterOfMass());
3916 MCAuto<DataArrayDouble> occm;
3918 MCAuto<DataArrayDouble> pt(DataArrayDouble::New()); pt->alloc(1,3); std::copy(origin,origin+3,pt->getPointer());
3919 occm=DataArrayDouble::Substract(ccm,pt);
3921 vec2=DataArrayDouble::New(); vec2->alloc(nbCellsRet,3);
3922 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);
3923 MCAuto<DataArrayDouble> dott2(DataArrayDouble::Dot(occm,vec2));
3925 const mcIdType *cPtr(ret->getNodalConnectivity()->begin()),*ciPtr(ret->getNodalConnectivityIndex()->begin());
3926 MCAuto<MEDCouplingUMesh> ret2(MEDCouplingUMesh::New("Clip3D",3));
3927 ret2->setCoords(mDesc1->getCoords());
3928 MCAuto<DataArrayIdType> conn2(DataArrayIdType::New()),conn2I(DataArrayIdType::New());
3929 conn2I->pushBackSilent(0); conn2->alloc(0,1);
3930 std::vector<mcIdType> cell0(1,ToIdType(INTERP_KERNEL::NORM_POLYHED));
3931 std::vector<mcIdType> cell1(1,ToIdType(INTERP_KERNEL::NORM_POLYHED));
3932 if(dott->getIJ(0,0)>0)
3934 cell0.insert(cell0.end(),cPtr+1,cPtr+ciPtr[1]);
3935 std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell1,cell1.end()));
3939 cell1.insert(cell1.end(),cPtr+1,cPtr+ciPtr[1]);
3940 std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell0,cell0.end()));
3942 for(mcIdType i=1;i<nbCellsRet;i++)
3944 if(dott2->getIJ(i,0)<0)
3946 if(ciPtr[i+1]-ciPtr[i]>=4)
3948 cell0.push_back(-1);
3949 cell0.insert(cell0.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
3954 if(ciPtr[i+1]-ciPtr[i]>=4)
3956 cell1.push_back(-1);
3957 cell1.insert(cell1.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
3961 conn2->insertAtTheEnd(cell0.begin(),cell0.end());
3962 conn2I->pushBackSilent(conn2->getNumberOfTuples());
3963 conn2->insertAtTheEnd(cell1.begin(),cell1.end());
3964 conn2I->pushBackSilent(conn2->getNumberOfTuples());
3965 ret2->setConnectivity(conn2,conn2I,true);
3966 ret2->checkConsistencyLight();
3967 ret2->orientCorrectlyPolyhedrons();
3972 * Finds cells whose bounding boxes intersect a given plane.
3973 * \param [in] origin - 3 components of a point defining location of the plane.
3974 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3975 * must be greater than 1e-6.
3976 * \param [in] eps - half-thickness of the plane.
3977 * \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of the found
3978 * cells. The caller is to delete this array using decrRef() as it is no more
3980 * \throw If the coordinates array is not set.
3981 * \throw If the nodal connectivity of cells is not defined.
3982 * \throw If \a this->getSpaceDimension() != 3.
3983 * \throw If magnitude of \a vec is less than 1e-6.
3984 * \sa buildSlice3D()
3986 DataArrayIdType *MEDCouplingUMesh::getCellIdsCrossingPlane(const double *origin, const double *vec, double eps) const
3988 checkFullyDefined();
3989 if(getSpaceDimension()!=3)
3990 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with spaceDim equal to 3 !");
3991 double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
3993 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellIdsCrossingPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
3995 vec2[0]=vec[1]; vec2[1]=-vec[0]; vec2[2]=0.;//vec2 is the result of cross product of vec with (0,0,1)
3996 double angle=acos(vec[2]/normm);
3997 MCAuto<DataArrayIdType> cellIds;
4001 MCAuto<DataArrayDouble> coo=_coords->deepCopy();
4002 double normm2(sqrt(vec2[0]*vec2[0]+vec2[1]*vec2[1]+vec2[2]*vec2[2]));
4003 if(normm2/normm>1e-6)
4004 DataArrayDouble::Rotate3DAlg(origin,vec2,angle,coo->getNumberOfTuples(),coo->getPointer(),coo->getPointer());
4005 MCAuto<MEDCouplingUMesh> mw=clone(false);//false -> shallow copy
4007 mw->getBoundingBox(bbox);
4008 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
4009 cellIds=mw->getCellsInBoundingBox(bbox,eps);
4013 getBoundingBox(bbox);
4014 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
4015 cellIds=getCellsInBoundingBox(bbox,eps);
4017 return cellIds.retn();
4021 * This method checks that \a this is a contiguous mesh. The user is expected to call this method on a mesh with meshdim==1.
4022 * If not an exception will thrown. If this is an empty mesh with no cell an exception will be thrown too.
4023 * No consideration of coordinate is done by this method.
4024 * 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)
4025 * If not false is returned. In case that false is returned a call to MEDCoupling::MEDCouplingUMesh::mergeNodes could be useful.
4027 bool MEDCouplingUMesh::isContiguous1D() const
4029 if(getMeshDimension()!=1)
4030 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense only for 1D mesh !");
4031 mcIdType nbCells=getNumberOfCells();
4033 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense for non empty mesh !");
4034 const mcIdType *connI(_nodal_connec_index->begin()),*conn(_nodal_connec->begin());
4035 mcIdType ref=conn[connI[0]+2];
4036 for(mcIdType i=1;i<nbCells;i++)
4038 if(conn[connI[i]+1]!=ref)
4040 ref=conn[connI[i]+2];
4046 * This method is only callable on mesh with meshdim == 1 containing only SEG2 and spaceDim==3.
4047 * This method projects this on the 3D line defined by (pt,v). This methods first checks that all SEG2 are along v vector.
4048 * \param pt reference point of the line
4049 * \param v normalized director vector of the line
4050 * \param eps max precision before throwing an exception
4051 * \param res output of size this->getNumberOfCells
4053 void MEDCouplingUMesh::project1D(const double *pt, const double *v, double eps, double *res) const
4055 if(getMeshDimension()!=1)
4056 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for project1D !");
4057 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
4058 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for project1D !");
4059 if(getSpaceDimension()!=3)
4060 throw INTERP_KERNEL::Exception("Expected a umesh with spaceDim==3 for project1D !");
4061 MCAuto<MEDCouplingFieldDouble> f=buildDirectionVectorField();
4062 const double *fPtr=f->getArray()->getConstPointer();
4064 for(mcIdType i=0;i<getNumberOfCells();i++)
4066 const double *tmp1=fPtr+3*i;
4067 tmp[0]=tmp1[1]*v[2]-tmp1[2]*v[1];
4068 tmp[1]=tmp1[2]*v[0]-tmp1[0]*v[2];
4069 tmp[2]=tmp1[0]*v[1]-tmp1[1]*v[0];
4070 double n1=INTERP_KERNEL::norm<3>(tmp);
4071 n1/=INTERP_KERNEL::norm<3>(tmp1);
4073 throw INTERP_KERNEL::Exception("UMesh::Projection 1D failed !");
4075 const double *coo=getCoords()->getConstPointer();
4076 for(mcIdType i=0;i<getNumberOfNodes();i++)
4078 std::transform(coo+i*3,coo+i*3+3,pt,tmp,std::minus<double>());
4079 std::transform(tmp,tmp+3,v,tmp,std::multiplies<double>());
4080 res[i]=std::accumulate(tmp,tmp+3,0.);
4085 * 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.
4086 * \a this is expected to be a mesh so that its space dimension is equal to its
4087 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4088 * 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).
4090 * 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
4091 * 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).
4092 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4094 * So this method is more accurate (so, more costly) than simply searching for the closest point in \a this.
4095 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4097 * \param [in] ptBg the start pointer (included) of the coordinates of the point
4098 * \param [in] ptEnd the end pointer (not included) of the coordinates of the point
4099 * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4100 * \return the positive value of the distance.
4101 * \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
4103 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoints
4105 double MEDCouplingUMesh::distanceToPoint(const double *ptBg, const double *ptEnd, mcIdType& cellId) const
4107 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4108 if(meshDim!=spaceDim-1)
4109 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint works only for spaceDim=meshDim+1 !");
4110 if(meshDim!=2 && meshDim!=1)
4111 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint : only mesh dimension 2 and 1 are implemented !");
4112 checkFullyDefined();
4113 if(ToIdType(std::distance(ptBg,ptEnd))!=spaceDim)
4114 { 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()); }
4115 DataArrayIdType *ret1=0;
4116 MCAuto<DataArrayDouble> pts=DataArrayDouble::New(); pts->useArray(ptBg,false,DeallocType::C_DEALLOC,1,spaceDim);
4117 MCAuto<DataArrayDouble> ret0=distanceToPoints(pts,ret1);
4118 MCAuto<DataArrayIdType> ret1Safe(ret1);
4119 cellId=*ret1Safe->begin();
4120 return *ret0->begin();
4124 * This method computes the distance from each point of points serie \a pts (stored in a DataArrayDouble in which each tuple represents a point)
4125 * to \a this and the first \a cellId in \a this corresponding to the returned distance.
4126 * 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
4127 * 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).
4128 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4130 * \a this is expected to be a mesh so that its space dimension is equal to its
4131 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4132 * 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).
4134 * So this method is more accurate (so, more costly) than simply searching for each point in \a pts the closest point in \a this.
4135 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4137 * \param [in] pts the list of points in which each tuple represents a point
4138 * \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.
4139 * \return a newly allocated object to be dealed by the caller that tells for each point in \a pts the distance to \a this.
4140 * \throw if number of components of \a pts is not equal to the space dimension.
4141 * \throw if mesh dimension of \a this is not equal to space dimension - 1.
4142 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoint
4144 DataArrayDouble *MEDCouplingUMesh::distanceToPoints(const DataArrayDouble *pts, DataArrayIdType *& cellIds) const
4147 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : input points pointer is NULL !");
4148 pts->checkAllocated();
4149 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4150 if(meshDim!=spaceDim-1)
4151 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints works only for spaceDim=meshDim+1 !");
4152 if(meshDim!=2 && meshDim!=1)
4153 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only mesh dimension 2 and 1 are implemented !");
4154 if(ToIdType(pts->getNumberOfComponents())!=spaceDim)
4156 std::ostringstream oss; oss << "MEDCouplingUMesh::distanceToPoints : input pts DataArrayDouble has " << pts->getNumberOfComponents() << " components whereas it should be equal to " << spaceDim << " (mesh spaceDimension) !";
4157 throw INTERP_KERNEL::Exception(oss.str());
4159 checkFullyDefined();
4160 mcIdType nbCells=getNumberOfCells();
4162 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : no cells in this !");
4163 mcIdType nbOfPts=pts->getNumberOfTuples();
4164 MCAuto<DataArrayDouble> ret0=DataArrayDouble::New(); ret0->alloc(nbOfPts,1);
4165 MCAuto<DataArrayIdType> ret1=DataArrayIdType::New(); ret1->alloc(nbOfPts,1);
4166 const mcIdType *nc=_nodal_connec->begin(),*ncI=_nodal_connec_index->begin(); const double *coords=_coords->begin();
4167 double *ret0Ptr=ret0->getPointer(); mcIdType *ret1Ptr=ret1->getPointer(); const double *ptsPtr=pts->begin();
4168 MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree());
4169 const double *bbox(bboxArr->begin());
4174 BBTreeDst<3> myTree(bbox,0,0,nbCells);
4175 for(mcIdType i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=3)
4177 double x=std::numeric_limits<double>::max();
4178 std::vector<mcIdType> elems;
4179 myTree.getMinDistanceOfMax(ptsPtr,x);
4180 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4181 DistanceToPoint3DSurfAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4187 BBTreeDst<2> myTree(bbox,0,0,nbCells);
4188 for(mcIdType i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=2)
4190 double x=std::numeric_limits<double>::max();
4191 std::vector<mcIdType> elems;
4192 myTree.getMinDistanceOfMax(ptsPtr,x);
4193 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4194 DistanceToPoint2DCurveAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4199 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only spacedim 2 and 3 supported !");
4201 cellIds=ret1.retn();
4210 * Finds cells in contact with a ball (i.e. a point with precision).
4211 * 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.
4212 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4214 * \warning This method is suitable if the caller intends to evaluate only one
4215 * point, for more points getCellsContainingPoints() is recommended as it is
4217 * \param [in] pos - array of coordinates of the ball central point.
4218 * \param [in] eps - ball radius.
4219 * \return mcIdType - a smallest id of cells being in contact with the ball, -1 in case
4220 * if there are no such cells.
4221 * \throw If the coordinates array is not set.
4222 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4224 mcIdType MEDCouplingUMesh::getCellContainingPoint(const double *pos, double eps) const
4226 std::vector<mcIdType> elts;
4227 getCellsContainingPoint(pos,eps,elts);
4230 return elts.front();
4234 * Finds cells in contact with a ball (i.e. a point with precision).
4235 * 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.
4236 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4237 * \warning This method is suitable if the caller intends to evaluate only one
4238 * point, for more points getCellsContainingPoints() is recommended as it is
4240 * \param [in] pos - array of coordinates of the ball central point.
4241 * \param [in] eps - ball radius.
4242 * \param [out] elts - vector returning ids of the found cells. It is cleared
4243 * before inserting ids.
4244 * \throw If the coordinates array is not set.
4245 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4247 * \if ENABLE_EXAMPLES
4248 * \ref cpp_mcumesh_getCellsContainingPoint "Here is a C++ example".<br>
4249 * \ref py_mcumesh_getCellsContainingPoint "Here is a Python example".
4252 void MEDCouplingUMesh::getCellsContainingPoint(const double *pos, double eps, std::vector<mcIdType>& elts) const
4254 MCAuto<DataArrayIdType> eltsUg,eltsIndexUg;
4255 getCellsContainingPoints(pos,1,eps,eltsUg,eltsIndexUg);
4256 elts.clear(); elts.insert(elts.end(),eltsUg->begin(),eltsUg->end());
4259 void MEDCouplingUMesh::getCellsContainingPointsZeAlg(const double *pos, mcIdType nbOfPoints, double eps,
4260 MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex,
4261 std::function<bool(INTERP_KERNEL::NormalizedCellType,mcIdType)> sensibilityTo2DQuadraticLinearCellsFunc) const
4263 int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
4268 const double *coords=_coords->getConstPointer();
4269 getCellsContainingPointsAlg<3>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4272 throw INTERP_KERNEL::Exception("For spaceDim==3 only meshDim==3 implemented for getelementscontainingpoints !");
4274 else if(spaceDim==2)
4278 const double *coords=_coords->getConstPointer();
4279 getCellsContainingPointsAlg<2>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4282 throw INTERP_KERNEL::Exception("For spaceDim==2 only meshDim==2 implemented for getelementscontainingpoints !");
4284 else if(spaceDim==1)
4288 const double *coords=_coords->getConstPointer();
4289 getCellsContainingPointsAlg<1>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4292 throw INTERP_KERNEL::Exception("For spaceDim==1 only meshDim==1 implemented for getelementscontainingpoints !");
4295 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPoints : not managed for mdim not in [1,2,3] !");
4299 * Finds cells in contact with several balls (i.e. points with precision).
4300 * This method is an extension of getCellContainingPoint() and
4301 * getCellsContainingPoint() for the case of multiple points.
4302 * 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.
4303 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4304 * \param [in] pos - an array of coordinates of points in full interlace mode :
4305 * X0,Y0,Z0,X1,Y1,Z1,... Size of the array must be \a
4306 * this->getSpaceDimension() * \a nbOfPoints
4307 * \param [in] nbOfPoints - number of points to locate within \a this mesh.
4308 * \param [in] eps - radius of balls (i.e. the precision).
4309 * \param [out] elts - vector returning ids of found cells.
4310 * \param [out] eltsIndex - an array, of length \a nbOfPoints + 1,
4311 * dividing cell ids in \a elts into groups each referring to one
4312 * point. Its every element (except the last one) is an index pointing to the
4313 * first id of a group of cells. For example cells in contact with the *i*-th
4314 * point are described by following range of indices:
4315 * [ \a eltsIndex[ *i* ], \a eltsIndex[ *i*+1 ] ) and the cell ids are
4316 * \a elts[ \a eltsIndex[ *i* ]], \a elts[ \a eltsIndex[ *i* ] + 1 ], ...
4317 * Number of cells in contact with the *i*-th point is
4318 * \a eltsIndex[ *i*+1 ] - \a eltsIndex[ *i* ].
4319 * \throw If the coordinates array is not set.
4320 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4322 * \if ENABLE_EXAMPLES
4323 * \ref cpp_mcumesh_getCellsContainingPoints "Here is a C++ example".<br>
4324 * \ref py_mcumesh_getCellsContainingPoints "Here is a Python example".
4327 void MEDCouplingUMesh::getCellsContainingPoints(const double *pos, mcIdType nbOfPoints, double eps,
4328 MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex) const
4330 auto yesImSensibleTo2DQuadraticLinearCellsFunc([](INTERP_KERNEL::NormalizedCellType ct, int mdim) { return INTERP_KERNEL::CellModel::GetCellModel(ct).isQuadratic() && mdim == 2; } );
4331 this->getCellsContainingPointsZeAlg(pos,nbOfPoints,eps,elts,eltsIndex,yesImSensibleTo2DQuadraticLinearCellsFunc);
4335 * Behaves like MEDCouplingMesh::getCellsContainingPoints for cells in \a this that are linear.
4336 * For quadratic cells in \a this, this method behaves by just considering linear part of cells.
4337 * This method is here only for backward compatibility (interpolation GaussPoints to GaussPoints).
4339 * \sa MEDCouplingUMesh::getCellsContainingPoints, MEDCouplingRemapper::prepareNotInterpKernelOnlyGaussGauss
4341 void MEDCouplingUMesh::getCellsContainingPointsLinearPartOnlyOnNonDynType(const double *pos, mcIdType nbOfPoints, double eps, MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex) const
4343 auto noImNotSensibleTo2DQuadraticLinearCellsFunc([](INTERP_KERNEL::NormalizedCellType,mcIdType) { return false; } );
4344 this->getCellsContainingPointsZeAlg(pos,nbOfPoints,eps,elts,eltsIndex,noImNotSensibleTo2DQuadraticLinearCellsFunc);
4348 * Finds butterfly cells in \a this mesh. A 2D cell is considered to be butterfly if at
4349 * least two its edges intersect each other anywhere except their extremities. An
4350 * INTERP_KERNEL::NORM_NORI3 cell can \b not be butterfly.
4351 * \param [in,out] cells - a vector returning ids of the found cells. It is not
4352 * cleared before filling in.
4353 * \param [in] eps - precision.
4354 * \throw If \a this->getMeshDimension() != 2.
4355 * \throw If \a this->getSpaceDimension() != 2 && \a this->getSpaceDimension() != 3.
4357 void MEDCouplingUMesh::checkButterflyCells(std::vector<mcIdType>& cells, double eps) const
4359 const char msg[]="Butterfly detection work only for 2D cells with spaceDim==2 or 3!";
4360 if(getMeshDimension()!=2)
4361 throw INTERP_KERNEL::Exception(msg);
4362 int spaceDim=getSpaceDimension();
4363 if(spaceDim!=2 && spaceDim!=3)
4364 throw INTERP_KERNEL::Exception(msg);
4365 const mcIdType *conn=_nodal_connec->getConstPointer();
4366 const mcIdType *connI=_nodal_connec_index->getConstPointer();
4367 mcIdType nbOfCells=getNumberOfCells();
4368 std::vector<double> cell2DinS2;
4369 for(mcIdType i=0;i<nbOfCells;i++)
4371 mcIdType offset=connI[i];
4372 mcIdType nbOfNodesForCell=connI[i+1]-offset-1;
4373 if(nbOfNodesForCell<=3)
4375 bool isQuad=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[offset]).isQuadratic();
4376 project2DCellOnXY(conn+offset+1,conn+connI[i+1],cell2DinS2);
4377 if(isButterfly2DCell(cell2DinS2,isQuad,eps))
4384 * This method is typically requested to unbutterfly 2D linear cells in \b this.
4386 * 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.
4387 * 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.
4389 * For each 2D linear cell in \b this, this method builds the convex envelop (or the convex hull) of the current cell.
4390 * This convex envelop is computed using Jarvis march algorithm.
4391 * The coordinates and the number of cells of \b this remain unchanged on invocation of this method.
4392 * 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)
4393 * 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.
4395 * \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.
4396 * \sa MEDCouplingUMesh::colinearize2D
4398 DataArrayIdType *MEDCouplingUMesh::convexEnvelop2D()
4400 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
4401 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convexEnvelop2D works only for meshDim=2 and spaceDim=2 !");
4402 checkFullyDefined();
4403 const double *coords=getCoords()->getConstPointer();
4404 mcIdType nbOfCells=getNumberOfCells();
4405 MCAuto<DataArrayIdType> nodalConnecIndexOut=DataArrayIdType::New();
4406 nodalConnecIndexOut->alloc(nbOfCells+1,1);
4407 MCAuto<DataArrayIdType> nodalConnecOut(DataArrayIdType::New());
4408 mcIdType *workIndexOut=nodalConnecIndexOut->getPointer();
4410 const mcIdType *nodalConnecIn=_nodal_connec->getConstPointer();
4411 const mcIdType *nodalConnecIndexIn=_nodal_connec_index->getConstPointer();
4412 std::set<INTERP_KERNEL::NormalizedCellType> types;
4413 MCAuto<DataArrayIdType> isChanged(DataArrayIdType::New());
4414 isChanged->alloc(0,1);
4415 for(mcIdType i=0;i<nbOfCells;i++,workIndexOut++)
4417 mcIdType pos=nodalConnecOut->getNumberOfTuples();
4418 if(BuildConvexEnvelopOf2DCellJarvis(coords,nodalConnecIn+nodalConnecIndexIn[i],nodalConnecIn+nodalConnecIndexIn[i+1],nodalConnecOut))
4419 isChanged->pushBackSilent(i);
4420 types.insert((INTERP_KERNEL::NormalizedCellType)nodalConnecOut->getIJ(pos,0));
4421 workIndexOut[1]=nodalConnecOut->getNumberOfTuples();
4423 if(isChanged->empty())
4425 setConnectivity(nodalConnecOut,nodalConnecIndexOut,false);
4427 return isChanged.retn();
4431 * This method is \b NOT const because it can modify \a this.
4432 * \a this is expected to be an unstructured mesh with meshDim==2 and spaceDim==3. If not an exception will be thrown.
4433 * \param mesh1D is an unstructured mesh with MeshDim==1 and spaceDim==3. If not an exception will be thrown.
4434 * \param policy specifies the type of extrusion chosen:
4435 * - \b 0 for translation only (most simple): the cells of the 1D mesh represent the vectors along which the 2D mesh
4436 * will be repeated to build each level
4437 * - \b 1 for translation and rotation: the translation is done as above. For each level, an arc of circle is fitted on
4438 * 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
4439 * 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
4441 * \return an unstructured mesh with meshDim==3 and spaceDim==3. The returned mesh has the same coords than \a this.
4443 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMesh(const MEDCouplingUMesh *mesh1D, int policy)
4445 checkFullyDefined();
4446 mesh1D->checkFullyDefined();
4447 if(!mesh1D->isContiguous1D())
4448 throw INTERP_KERNEL::Exception("buildExtrudedMesh : 1D mesh passed in parameter is not contiguous !");
4449 if(getSpaceDimension()!=mesh1D->getSpaceDimension())
4450 throw INTERP_KERNEL::Exception("Invalid call to buildExtrudedMesh this and mesh1D must have same space dimension !");
4451 if((getMeshDimension()!=2 || getSpaceDimension()!=3) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
4452 throw INTERP_KERNEL::Exception("Invalid 'this' for buildExtrudedMesh method : must be (meshDim==2 and spaceDim==3) or (meshDim==1 and spaceDim==2) !");
4453 if(mesh1D->getMeshDimension()!=1)
4454 throw INTERP_KERNEL::Exception("Invalid 'mesh1D' for buildExtrudedMesh method : must be meshDim==1 !");
4456 if(isPresenceOfQuadratic())
4458 if(mesh1D->isFullyQuadratic())
4461 throw INTERP_KERNEL::Exception("Invalid 2D mesh and 1D mesh because 2D mesh has quadratic cells and 1D is not fully quadratic !");
4463 mcIdType oldNbOfNodes(getNumberOfNodes());
4464 MCAuto<DataArrayDouble> newCoords;
4469 newCoords=fillExtCoordsUsingTranslation(mesh1D,isQuad);
4474 newCoords=fillExtCoordsUsingTranslAndAutoRotation(mesh1D,isQuad);
4478 throw INTERP_KERNEL::Exception("Not implemented extrusion policy : must be in (0) !");
4480 setCoords(newCoords);
4481 MCAuto<MEDCouplingUMesh> ret(buildExtrudedMeshFromThisLowLev(oldNbOfNodes,isQuad));
4488 * Checks if \a this mesh is constituted by only quadratic cells.
4489 * \return bool - \c true if there are only quadratic cells in \a this mesh.
4490 * \throw If the coordinates array is not set.
4491 * \throw If the nodal connectivity of cells is not defined.
4493 bool MEDCouplingUMesh::isFullyQuadratic() const
4495 checkFullyDefined();
4497 mcIdType nbOfCells=getNumberOfCells();
4498 for(mcIdType i=0;i<nbOfCells && ret;i++)
4500 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4501 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4502 ret=cm.isQuadratic();
4508 * Checks if \a this mesh includes any quadratic cell.
4509 * \return bool - \c true if there is at least one quadratic cells in \a this mesh.
4510 * \throw If the coordinates array is not set.
4511 * \throw If the nodal connectivity of cells is not defined.
4513 bool MEDCouplingUMesh::isPresenceOfQuadratic() const
4515 checkFullyDefined();
4517 mcIdType nbOfCells=getNumberOfCells();
4518 for(mcIdType i=0;i<nbOfCells && !ret;i++)
4520 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4521 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4522 ret=cm.isQuadratic();
4528 * Converts all quadratic cells to linear ones. If there are no quadratic cells in \a
4529 * this mesh, it remains unchanged.
4530 * \throw If the coordinates array is not set.
4531 * \throw If the nodal connectivity of cells is not defined.
4533 void MEDCouplingUMesh::convertQuadraticCellsToLinear()
4535 checkFullyDefined();
4536 mcIdType nbOfCells=getNumberOfCells();
4538 const mcIdType *iciptr=_nodal_connec_index->begin();
4539 for(mcIdType i=0;i<nbOfCells;i++)
4541 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4542 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4543 if(cm.isQuadratic())
4545 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4546 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4547 if(!cml.isDynamic())
4548 delta+=cm.getNumberOfNodes()-cml.getNumberOfNodes();
4550 delta+=(iciptr[i+1]-iciptr[i]-1)/2;
4555 MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()),newConnI(DataArrayIdType::New());
4556 const mcIdType *icptr(_nodal_connec->begin());
4557 newConn->alloc(getNodalConnectivityArrayLen()-delta,1);
4558 newConnI->alloc(nbOfCells+1,1);
4559 mcIdType *ocptr(newConn->getPointer()),*ociptr(newConnI->getPointer());
4562 for(mcIdType i=0;i<nbOfCells;i++,ociptr++)
4564 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)icptr[iciptr[i]];
4565 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4566 if(!cm.isQuadratic())
4568 _types.insert(type);
4569 ocptr=std::copy(icptr+iciptr[i],icptr+iciptr[i+1],ocptr);
4570 ociptr[1]=ociptr[0]+iciptr[i+1]-iciptr[i];
4574 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4575 _types.insert(typel);
4576 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4577 mcIdType newNbOfNodes=cml.getNumberOfNodes();
4579 newNbOfNodes=(iciptr[i+1]-iciptr[i]-1)/2;
4580 *ocptr++=ToIdType(typel);
4581 ocptr=std::copy(icptr+iciptr[i]+1,icptr+iciptr[i]+newNbOfNodes+1,ocptr);
4582 ociptr[1]=ociptr[0]+newNbOfNodes+1;
4585 setConnectivity(newConn,newConnI,false);
4589 * This method converts all linear cell in \a this to quadratic one.
4590 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, here it is needed to specify the target
4591 * 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)
4592 * 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.
4593 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, the coordinates in \a this can be become bigger. All created nodes will be put at the
4594 * end of the existing coordinates.
4596 * \param [in] conversionType specifies the type of conversion expected. Only 0 (default) and 1 are supported presently. 0 those that creates the 'most' simple
4597 * corresponding quadratic cells. 1 is those creating the 'most' complex.
4598 * \return a newly created DataArrayIdType instance that the caller should deal with containing cell ids of converted cells.
4600 * \throw if \a this is not fully defined. It throws too if \a conversionType is not in [0,1].
4602 * \sa MEDCouplingUMesh::convertQuadraticCellsToLinear
4604 DataArrayIdType *MEDCouplingUMesh::convertLinearCellsToQuadratic(int conversionType)
4606 DataArrayIdType *conn=0,*connI=0;
4607 DataArrayDouble *coords=0;
4608 std::set<INTERP_KERNEL::NormalizedCellType> types;
4609 checkFullyDefined();
4610 MCAuto<DataArrayIdType> ret,connSafe,connISafe;
4611 MCAuto<DataArrayDouble> coordsSafe;
4612 int meshDim=getMeshDimension();
4613 switch(conversionType)
4619 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);
4620 connSafe=conn; connISafe=connI; coordsSafe=coords;
4623 ret=convertLinearCellsToQuadratic2D0(conn,connI,coords,types);
4624 connSafe=conn; connISafe=connI; coordsSafe=coords;
4627 ret=convertLinearCellsToQuadratic3D0(conn,connI,coords,types);
4628 connSafe=conn; connISafe=connI; coordsSafe=coords;
4631 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 0 mesh dimensions available are [1,2,3] !");
4639 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);//it is not a bug. In 1D policy 0 and 1 are equals
4640 connSafe=conn; connISafe=connI; coordsSafe=coords;
4643 ret=convertLinearCellsToQuadratic2D1(conn,connI,coords,types);
4644 connSafe=conn; connISafe=connI; coordsSafe=coords;
4647 ret=convertLinearCellsToQuadratic3D1(conn,connI,coords,types);
4648 connSafe=conn; connISafe=connI; coordsSafe=coords;
4651 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 1 mesh dimensions available are [1,2,3] !");
4656 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion type available are 0 (default, the simplest) and 1 (the most complex) !");
4658 setConnectivity(connSafe,connISafe,false);
4660 setCoords(coordsSafe);
4665 * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
4666 * so that the number of cells remains the same. Quadratic faces are converted to
4667 * polygons. This method works only for 2D meshes in
4668 * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
4669 * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
4670 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
4671 * \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
4672 * a polylinized edge constituting the input polygon.
4673 * \throw If the coordinates array is not set.
4674 * \throw If the nodal connectivity of cells is not defined.
4675 * \throw If \a this->getMeshDimension() != 2.
4676 * \throw If \a this->getSpaceDimension() != 2.
4678 void MEDCouplingUMesh::tessellate2D(double eps)
4680 int meshDim(getMeshDimension()),spaceDim(getSpaceDimension());
4682 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : works only with space dimension equal to 2 !");
4686 return tessellate2DCurveInternal(eps);
4688 return tessellate2DInternal(eps);
4690 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : mesh dimension must be in [1,2] !");
4696 * This method only works if \a this has spaceDimension equal to 2 and meshDimension also equal to 2.
4697 * This method allows to modify connectivity of cells in \a this that shares some edges in \a edgeIdsToBeSplit.
4698 * The nodes to be added in those 2D cells are defined by the pair of \a nodeIdsToAdd and \a nodeIdsIndexToAdd.
4699 * Length of \a nodeIdsIndexToAdd is expected to equal to length of \a edgeIdsToBeSplit + 1.
4700 * The node ids in \a nodeIdsToAdd should be valid. Those nodes have to be sorted exactly following exactly the direction of the edge.
4701 * This method can be seen as the opposite method of colinearize2D.
4702 * 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
4703 * to avoid to modify the numbering of existing nodes.
4705 * \param [in] nodeIdsToAdd - the list of node ids to be added (\a nodeIdsIndexToAdd array allows to walk on this array)
4706 * \param [in] nodeIdsIndexToAdd - the entry point of \a nodeIdsToAdd to point to the corresponding nodes to be added.
4707 * \param [in] mesh1Desc - 1st output of buildDescendingConnectivity2 on \a this.
4708 * \param [in] desc - 2nd output of buildDescendingConnectivity2 on \a this.
4709 * \param [in] descI - 3rd output of buildDescendingConnectivity2 on \a this.
4710 * \param [in] revDesc - 4th output of buildDescendingConnectivity2 on \a this.
4711 * \param [in] revDescI - 5th output of buildDescendingConnectivity2 on \a this.
4713 * \sa buildDescendingConnectivity2
4715 void MEDCouplingUMesh::splitSomeEdgesOf2DMesh(const DataArrayIdType *nodeIdsToAdd, const DataArrayIdType *nodeIdsIndexToAdd, const DataArrayIdType *edgeIdsToBeSplit,
4716 const MEDCouplingUMesh *mesh1Desc, const DataArrayIdType *desc, const DataArrayIdType *descI, const DataArrayIdType *revDesc, const DataArrayIdType *revDescI)
4718 if(!nodeIdsToAdd || !nodeIdsIndexToAdd || !edgeIdsToBeSplit || !mesh1Desc || !desc || !descI || !revDesc || !revDescI)
4719 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : input pointers must be not NULL !");
4720 nodeIdsToAdd->checkAllocated(); nodeIdsIndexToAdd->checkAllocated(); edgeIdsToBeSplit->checkAllocated(); desc->checkAllocated(); descI->checkAllocated(); revDesc->checkAllocated(); revDescI->checkAllocated();
4721 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
4722 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : this must have spacedim=meshdim=2 !");
4723 if(mesh1Desc->getSpaceDimension()!=2 || mesh1Desc->getMeshDimension()!=1)
4724 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : mesh1Desc must be the explosion of this with spaceDim=2 and meshDim = 1 !");
4725 //DataArrayIdType *out0(0),*outi0(0);
4726 //MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
4727 //MCAuto<DataArrayIdType> out0s(out0),outi0s(outi0);
4728 //out0s=out0s->buildUnique(); out0s->sort(true);
4734 * Divides every cell of \a this mesh into simplices (triangles in 2D and tetrahedra in 3D).
4735 * In addition, returns an array mapping new cells to old ones. <br>
4736 * This method typically increases the number of cells in \a this mesh
4737 * but the number of nodes remains \b unchanged.
4738 * That's why the 3D splitting policies
4739 * INTERP_KERNEL::GENERAL_24 and INTERP_KERNEL::GENERAL_48 are not available here.
4740 * \param [in] policy - specifies a pattern used for splitting.
4741 * The semantic of \a policy is:
4742 * - 0 - to split QUAD4 by cutting it along 0-2 diagonal (for 2D mesh only).
4743 * - 1 - to split QUAD4 by cutting it along 1-3 diagonal (for 2D mesh only).
4744 * - INTERP_KERNEL::PLANAR_FACE_5 - to split HEXA8 into 5 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4745 * - INTERP_KERNEL::PLANAR_FACE_6 - to split HEXA8 into 6 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4748 * \return DataArrayIdType * - a new instance of DataArrayIdType holding, for each new cell,
4749 * an id of old cell producing it. The caller is to delete this array using
4750 * decrRef() as it is no more needed.
4752 * \throw If \a policy is 0 or 1 and \a this->getMeshDimension() != 2.
4753 * \throw If \a policy is INTERP_KERNEL::PLANAR_FACE_5 or INTERP_KERNEL::PLANAR_FACE_6
4754 * and \a this->getMeshDimension() != 3.
4755 * \throw If \a policy is not one of the four discussed above.
4756 * \throw If the nodal connectivity of cells is not defined.
4757 * \sa MEDCouplingUMesh::tetrahedrize, MEDCoupling1SGTUMesh::sortHexa8EachOther
4759 DataArrayIdType *MEDCouplingUMesh::simplexize(int policy)
4764 return simplexizePol0();
4766 return simplexizePol1();
4767 case INTERP_KERNEL::PLANAR_FACE_5:
4768 return simplexizePlanarFace5();
4769 case INTERP_KERNEL::PLANAR_FACE_6:
4770 return simplexizePlanarFace6();
4772 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)");
4777 * Checks if \a this mesh is constituted by simplex cells only. Simplex cells are:
4778 * - 1D: INTERP_KERNEL::NORM_SEG2
4779 * - 2D: INTERP_KERNEL::NORM_TRI3
4780 * - 3D: INTERP_KERNEL::NORM_TETRA4.
4782 * This method is useful for users that need to use P1 field services as
4783 * MEDCouplingFieldDouble::getValueOn(), MEDCouplingField::buildMeasureField() etc.
4784 * All these methods need mesh support containing only simplex cells.
4785 * \return bool - \c true if there are only simplex cells in \a this mesh.
4786 * \throw If the coordinates array is not set.
4787 * \throw If the nodal connectivity of cells is not defined.
4788 * \throw If \a this->getMeshDimension() < 1.
4790 bool MEDCouplingUMesh::areOnlySimplexCells() const
4792 checkFullyDefined();
4793 int mdim=getMeshDimension();
4794 if(mdim<1 || mdim>3)
4795 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::areOnlySimplexCells : only available with meshes having a meshdim 1, 2 or 3 !");
4796 mcIdType nbCells=getNumberOfCells();
4797 const mcIdType *conn=_nodal_connec->begin();
4798 const mcIdType *connI=_nodal_connec_index->begin();
4799 for(mcIdType i=0;i<nbCells;i++)
4801 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4811 * Converts degenerated 2D or 3D linear cells of \a this mesh into cells of simpler
4812 * type. For example an INTERP_KERNEL::NORM_QUAD4 cell having only three unique nodes in
4813 * its connectivity is transformed into an INTERP_KERNEL::NORM_TRI3 cell.
4814 * Quadratic cells in 2D are also handled. In those cells edges where start=end=midpoint are removed.
4815 * This method does \b not perform geometrical checks and checks only nodal connectivity of cells,
4816 * so it can be useful to call mergeNodes() before calling this method.
4817 * \throw If \a this->getMeshDimension() <= 1.
4818 * \throw If the coordinates array is not set.
4819 * \throw If the nodal connectivity of cells is not defined.
4821 void MEDCouplingUMesh::convertDegeneratedCells()
4823 checkFullyDefined();
4824 if(getMeshDimension()<=1)
4825 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4826 mcIdType nbOfCells=getNumberOfCells();
4829 mcIdType initMeshLgth=getNodalConnectivityArrayLen();
4830 mcIdType *conn=_nodal_connec->getPointer();
4831 mcIdType *index=_nodal_connec_index->getPointer();
4832 mcIdType posOfCurCell=0;
4834 mcIdType lgthOfCurCell;
4835 for(mcIdType i=0;i<nbOfCells;i++)
4837 lgthOfCurCell=index[i+1]-posOfCurCell;
4838 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4840 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
4841 conn+newPos+1,newLgth);
4842 conn[newPos]=newType;
4844 posOfCurCell=index[i+1];
4847 if(newPos!=initMeshLgth)
4848 _nodal_connec->reAlloc(newPos);
4853 * Same as MEDCouplingUMesh::convertDegeneratedCells() plus deletion of the flat cells.
4854 * A cell is flat in the following cases:
4855 * - for a linear cell, all points in the connectivity are equal
4856 * - for a quadratic cell, either the above, or a quadratic polygon with two (linear) points and two
4857 * identical quadratic points
4858 * \return a new instance of DataArrayIdType holding ids of removed cells. The caller is to delete
4859 * this array using decrRef() as it is no more needed.
4861 DataArrayIdType *MEDCouplingUMesh::convertDegeneratedCellsAndRemoveFlatOnes()
4863 checkFullyDefined();
4864 if(getMeshDimension()<=1)
4865 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4866 mcIdType nbOfCells=getNumberOfCells();
4867 MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(0,1);
4870 mcIdType initMeshLgth=getNodalConnectivityArrayLen();
4871 mcIdType *conn=_nodal_connec->getPointer();
4872 mcIdType *index=_nodal_connec_index->getPointer();
4873 mcIdType posOfCurCell=0;
4875 mcIdType lgthOfCurCell, nbDelCells(0);
4876 for(mcIdType i=0;i<nbOfCells;i++)
4878 lgthOfCurCell=index[i+1]-posOfCurCell;
4879 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4881 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
4882 conn+newPos+1,newLgth);
4883 // Shall we delete the cell if it is completely degenerated:
4884 bool delCell=INTERP_KERNEL::CellSimplify::isFlatCell(conn, newPos, newLgth, newType);
4888 ret->pushBackSilent(i);
4890 else //if the cell is to be deleted, simply stay at the same place
4892 conn[newPos]=newType;
4895 posOfCurCell=index[i+1];
4896 index[i+1-nbDelCells]=newPos;
4898 if(newPos!=initMeshLgth)
4899 _nodal_connec->reAlloc(newPos);
4900 const mcIdType nCellDel=ret->getNumberOfTuples();
4902 _nodal_connec_index->reAlloc(nbOfCells-nCellDel+1);
4908 * This method remove null 1D cells from \a this. A 1D cell is considered null if start node is equal to end node.
4909 * Only connectivity is considered here.
4911 bool MEDCouplingUMesh::removeDegenerated1DCells()
4913 checkConnectivityFullyDefined();
4914 if(getMeshDimension()!=1)
4915 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::removeDegenerated1DCells works on umeshes with meshdim equals to 1 !");
4916 std::size_t nbCells(getNumberOfCells()),newSize(0),newSize2(0);
4917 const mcIdType *conn(getNodalConnectivity()->begin()),*conni(getNodalConnectivityIndex()->begin());
4919 for(std::size_t i=0;i<nbCells;i++)
4921 INTERP_KERNEL::NormalizedCellType ct((INTERP_KERNEL::NormalizedCellType)conn[conni[i]]);
4922 if(ct==INTERP_KERNEL::NORM_SEG2 || ct==INTERP_KERNEL::NORM_SEG3)
4924 if(conn[conni[i]+1]!=conn[conni[i]+2])
4927 newSize2+=conni[i+1]-conni[i];
4932 std::ostringstream oss; oss << "MEDCouplingUMesh::removeDegenerated1DCells : cell #" << i << " in this is not of type SEG2/SEG3 !";
4933 throw INTERP_KERNEL::Exception(oss.str());
4937 if(newSize==nbCells)//no cells has been removed -> do nothing
4939 MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()),newConnI(DataArrayIdType::New()); newConnI->alloc(newSize+1,1); newConn->alloc(newSize2,1);
4940 mcIdType *newConnPtr(newConn->getPointer()),*newConnIPtr(newConnI->getPointer()); newConnIPtr[0]=0;
4941 for(std::size_t i=0;i<nbCells;i++)
4943 if(conn[conni[i]+1]!=conn[conni[i]+2])
4945 newConnIPtr[1]=newConnIPtr[0]+conni[i+1]-conni[i];
4946 newConnPtr=std::copy(conn+conni[i],conn+conni[i+1],newConnPtr);
4950 setConnectivity(newConn,newConnI,true);
4955 * Finds incorrectly oriented cells of this 2D mesh in 3D space.
4956 * A cell is considered to be oriented correctly if an angle between its
4957 * normal vector and a given vector is less than \c PI / \c 2.
4958 * \param [in] vec - 3 components of the vector specifying the correct orientation of
4960 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
4962 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
4963 * is not cleared before filling in.
4964 * \throw If \a this->getMeshDimension() != 2.
4965 * \throw If \a this->getSpaceDimension() != 3.
4967 * \if ENABLE_EXAMPLES
4968 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
4969 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
4972 void MEDCouplingUMesh::are2DCellsNotCorrectlyOriented(const double *vec, bool polyOnly, std::vector<mcIdType>& cells) const
4974 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
4975 throw INTERP_KERNEL::Exception("Invalid mesh to apply are2DCellsNotCorrectlyOriented on it : must be meshDim==2 and spaceDim==3 !");
4976 mcIdType nbOfCells=getNumberOfCells();
4977 const mcIdType *conn=_nodal_connec->begin();
4978 const mcIdType *connI=_nodal_connec_index->begin();
4979 const double *coordsPtr=_coords->begin();
4980 for(mcIdType i=0;i<nbOfCells;i++)
4982 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4983 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
4985 bool isQuadratic=INTERP_KERNEL::CellModel::GetCellModel(type).isQuadratic();
4986 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4993 * Reverse connectivity of 2D cells whose orientation is not correct. A cell is
4994 * considered to be oriented correctly if an angle between its normal vector and a
4995 * given vector is less than \c PI / \c 2.
4996 * \param [in] vec - 3 components of the vector specifying the correct orientation of
4998 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
5000 * \throw If \a this->getMeshDimension() != 2.
5001 * \throw If \a this->getSpaceDimension() != 3.
5003 * \if ENABLE_EXAMPLES
5004 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
5005 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
5008 * \sa changeOrientationOfCells
5010 void MEDCouplingUMesh::orientCorrectly2DCells(const double *vec, bool polyOnly)
5012 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
5013 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectly2DCells on it : must be meshDim==2 and spaceDim==3 !");
5014 mcIdType nbOfCells=getNumberOfCells();
5015 mcIdType *conn(_nodal_connec->getPointer());
5016 const mcIdType *connI(_nodal_connec_index->begin());
5017 const double *coordsPtr(_coords->begin());
5018 bool isModified(false);
5019 for(mcIdType i=0;i<nbOfCells;i++)
5021 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5022 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
5024 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
5025 bool isQuadratic(cm.isQuadratic());
5026 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5029 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
5034 _nodal_connec->declareAsNew();
5039 * This method change the orientation of cells in \a this without any consideration of coordinates. Only connectivity is impacted.
5041 * \sa orientCorrectly2DCells
5043 void MEDCouplingUMesh::changeOrientationOfCells()
5045 int mdim(getMeshDimension());
5046 if(mdim!=2 && mdim!=1)
5047 throw INTERP_KERNEL::Exception("Invalid mesh to apply changeOrientationOfCells on it : must be meshDim==2 or meshDim==1 !");
5048 mcIdType nbOfCells=getNumberOfCells();
5049 mcIdType *conn(_nodal_connec->getPointer());
5050 const mcIdType *connI(_nodal_connec_index->begin());
5053 for(mcIdType i=0;i<nbOfCells;i++)
5055 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5056 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
5057 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
5062 for(mcIdType i=0;i<nbOfCells;i++)
5064 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5065 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
5066 cm.changeOrientationOf1D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
5072 * Finds incorrectly oriented polyhedral cells, i.e. polyhedrons having correctly
5073 * oriented facets. The normal vector of the facet should point out of the cell.
5074 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
5075 * is not cleared before filling in.
5076 * \throw If \a this->getMeshDimension() != 3.
5077 * \throw If \a this->getSpaceDimension() != 3.
5078 * \throw If the coordinates array is not set.
5079 * \throw If the nodal connectivity of cells is not defined.
5081 * \if ENABLE_EXAMPLES
5082 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
5083 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
5086 void MEDCouplingUMesh::arePolyhedronsNotCorrectlyOriented(std::vector<mcIdType>& cells) const
5088 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
5089 throw INTERP_KERNEL::Exception("Invalid mesh to apply arePolyhedronsNotCorrectlyOriented on it : must be meshDim==3 and spaceDim==3 !");
5090 mcIdType nbOfCells=getNumberOfCells();
5091 const mcIdType *conn=_nodal_connec->begin();
5092 const mcIdType *connI=_nodal_connec_index->begin();
5093 const double *coordsPtr=_coords->begin();
5094 for(mcIdType i=0;i<nbOfCells;i++)
5096 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5097 if(type==INTERP_KERNEL::NORM_POLYHED)
5099 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5106 * Tries to fix connectivity of polyhedra, so that normal vector of all facets to point
5108 * \throw If \a this->getMeshDimension() != 3.
5109 * \throw If \a this->getSpaceDimension() != 3.
5110 * \throw If the coordinates array is not set.
5111 * \throw If the nodal connectivity of cells is not defined.
5112 * \throw If the reparation fails.
5114 * \if ENABLE_EXAMPLES
5115 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
5116 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
5118 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
5120 void MEDCouplingUMesh::orientCorrectlyPolyhedrons()
5122 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
5123 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectlyPolyhedrons on it : must be meshDim==3 and spaceDim==3 !");
5124 mcIdType nbOfCells=getNumberOfCells();
5125 mcIdType *conn=_nodal_connec->getPointer();
5126 const mcIdType *connI=_nodal_connec_index->begin();
5127 const double *coordsPtr=_coords->begin();
5128 for(mcIdType i=0;i<nbOfCells;i++)
5130 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5131 if(type==INTERP_KERNEL::NORM_POLYHED)
5135 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5136 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
5138 catch(INTERP_KERNEL::Exception& e)
5140 std::ostringstream oss; oss << "Something wrong in polyhedron #" << i << " : " << e.what();
5141 throw INTERP_KERNEL::Exception(oss.str());
5149 * This method invert orientation of all cells in \a this.
5150 * After calling this method the absolute value of measure of cells in \a this are the same than before calling.
5151 * This method only operates on the connectivity so coordinates are not touched at all.
5153 void MEDCouplingUMesh::invertOrientationOfAllCells()
5155 checkConnectivityFullyDefined();
5156 std::set<INTERP_KERNEL::NormalizedCellType> gts(getAllGeoTypes());
5157 mcIdType *conn(_nodal_connec->getPointer());
5158 const mcIdType *conni(_nodal_connec_index->begin());
5159 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator gt=gts.begin();gt!=gts.end();gt++)
5161 INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::OrientationInverter> oi(INTERP_KERNEL::OrientationInverter::BuildInstanceFrom(*gt));
5162 MCAuto<DataArrayIdType> cwt(giveCellsWithType(*gt));
5163 for(const mcIdType *it=cwt->begin();it!=cwt->end();it++)
5164 oi->operate(conn+conni[*it]+1,conn+conni[*it+1]);
5170 * Finds and fixes incorrectly oriented linear extruded volumes (INTERP_KERNEL::NORM_HEXA8,
5171 * INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXGP12 etc) to respect the MED convention
5172 * according to which the first facet of the cell should be oriented to have the normal vector
5173 * pointing out of cell.
5174 * \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of fixed
5175 * cells. The caller is to delete this array using decrRef() as it is no more
5177 * \throw If \a this->getMeshDimension() != 3.
5178 * \throw If \a this->getSpaceDimension() != 3.
5179 * \throw If the coordinates array is not set.
5180 * \throw If the nodal connectivity of cells is not defined.
5182 * \if ENABLE_EXAMPLES
5183 * \ref cpp_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a C++ example".<br>
5184 * \ref py_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a Python example".
5186 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
5188 DataArrayIdType *MEDCouplingUMesh::findAndCorrectBadOriented3DExtrudedCells()
5190 const char msg[]="check3DCellsWellOriented detection works only for 3D cells !";
5191 if(getMeshDimension()!=3)
5192 throw INTERP_KERNEL::Exception(msg);
5193 int spaceDim=getSpaceDimension();
5195 throw INTERP_KERNEL::Exception(msg);
5197 mcIdType nbOfCells=getNumberOfCells();
5198 mcIdType *conn=_nodal_connec->getPointer();
5199 const mcIdType *connI=_nodal_connec_index->begin();
5200 const double *coo=getCoords()->begin();
5201 MCAuto<DataArrayIdType> cells(DataArrayIdType::New()); cells->alloc(0,1);
5202 for(mcIdType i=0;i<nbOfCells;i++)
5204 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5205 if(cm.isExtruded() && !cm.isDynamic() && !cm.isQuadratic())
5207 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coo))
5209 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
5210 cells->pushBackSilent(i);
5214 return cells.retn();
5218 * This method is a faster method to correct orientation of all 3D cells in \a this.
5219 * 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.
5220 * This method makes the hypothesis that \a this a coherent that is to say MEDCouplingUMesh::checkConsistency should throw no exception.
5222 * \return a newly allocated mcIdType array with one components containing cell ids renumbered to fit the convention of MED (MED file and MEDCoupling)
5223 * \sa MEDCouplingUMesh::orientCorrectlyPolyhedrons,
5225 DataArrayIdType *MEDCouplingUMesh::findAndCorrectBadOriented3DCells()
5227 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
5228 throw INTERP_KERNEL::Exception("Invalid mesh to apply findAndCorrectBadOriented3DCells on it : must be meshDim==3 and spaceDim==3 !");
5229 mcIdType nbOfCells=getNumberOfCells();
5230 mcIdType *conn=_nodal_connec->getPointer();
5231 const mcIdType *connI=_nodal_connec_index->begin();
5232 const double *coordsPtr=_coords->begin();
5233 MCAuto<DataArrayIdType> ret=DataArrayIdType::New(); ret->alloc(0,1);
5234 for(mcIdType i=0;i<nbOfCells;i++)
5236 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5239 case INTERP_KERNEL::NORM_TETRA4:
5241 if(!IsTetra4WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5243 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+3));
5244 ret->pushBackSilent(i);
5248 case INTERP_KERNEL::NORM_PYRA5:
5250 if(!IsPyra5WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5252 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+4));
5253 ret->pushBackSilent(i);
5257 case INTERP_KERNEL::NORM_PENTA6:
5258 case INTERP_KERNEL::NORM_HEXA8:
5259 case INTERP_KERNEL::NORM_HEXGP12:
5261 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5263 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
5264 ret->pushBackSilent(i);
5268 case INTERP_KERNEL::NORM_POLYHED:
5270 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5272 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
5273 ret->pushBackSilent(i);
5278 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 !");
5286 * This method has a sense for meshes with spaceDim==3 and meshDim==2.
5287 * If it is not the case an exception will be thrown.
5288 * This method is fast because the first cell of \a this is used to compute the plane.
5289 * \param vec output of size at least 3 used to store the normal vector (with norm equal to Area ) of searched plane.
5290 * \param pos output of size at least 3 used to store a point owned of searched plane.
5292 void MEDCouplingUMesh::getFastAveragePlaneOfThis(double *vec, double *pos) const
5294 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
5295 throw INTERP_KERNEL::Exception("Invalid mesh to apply getFastAveragePlaneOfThis on it : must be meshDim==2 and spaceDim==3 !");
5296 const mcIdType *conn=_nodal_connec->begin();
5297 const mcIdType *connI=_nodal_connec_index->begin();
5298 const double *coordsPtr=_coords->begin();
5299 INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(conn+1,connI[1]-connI[0]-1,coordsPtr,vec);
5300 std::copy(coordsPtr+3*conn[1],coordsPtr+3*conn[1]+3,pos);
5304 * Creates a new MEDCouplingFieldDouble holding Edge Ratio values of all
5305 * cells. Currently cells of the following types are treated:
5306 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5307 * For a cell of other type an exception is thrown.
5308 * Space dimension of a 2D mesh can be either 2 or 3.
5309 * The Edge Ratio of a cell \f$t\f$ is:
5310 * \f$\frac{|t|_\infty}{|t|_0}\f$,
5311 * where \f$|t|_\infty\f$ and \f$|t|_0\f$ respectively denote the greatest and
5312 * the smallest edge lengths of \f$t\f$.
5313 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5314 * cells and one time, lying on \a this mesh. The caller is to delete this
5315 * field using decrRef() as it is no more needed.
5316 * \throw If the coordinates array is not set.
5317 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5318 * \throw If the connectivity data array has more than one component.
5319 * \throw If the connectivity data array has a named component.
5320 * \throw If the connectivity index data array has more than one component.
5321 * \throw If the connectivity index data array has a named component.
5322 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
5323 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5324 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5326 MEDCouplingFieldDouble *MEDCouplingUMesh::getEdgeRatioField() const
5328 checkConsistencyLight();
5329 int spaceDim=getSpaceDimension();
5330 int meshDim=getMeshDimension();
5331 if(spaceDim!=2 && spaceDim!=3)
5332 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : SpaceDimension must be equal to 2 or 3 !");
5333 if(meshDim!=2 && meshDim!=3)
5334 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : MeshDimension must be equal to 2 or 3 !");
5335 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5337 mcIdType nbOfCells=getNumberOfCells();
5338 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5339 arr->alloc(nbOfCells,1);
5340 double *pt=arr->getPointer();
5341 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5342 const mcIdType *conn=_nodal_connec->begin();
5343 const mcIdType *connI=_nodal_connec_index->begin();
5344 const double *coo=_coords->begin();
5346 for(mcIdType i=0;i<nbOfCells;i++,pt++)
5348 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5351 case INTERP_KERNEL::NORM_TRI3:
5353 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5354 *pt=INTERP_KERNEL::triEdgeRatio(tmp);
5357 case INTERP_KERNEL::NORM_QUAD4:
5359 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5360 *pt=INTERP_KERNEL::quadEdgeRatio(tmp);
5363 case INTERP_KERNEL::NORM_TETRA4:
5365 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5366 *pt=INTERP_KERNEL::tetraEdgeRatio(tmp);
5370 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5372 conn+=connI[i+1]-connI[i];
5374 ret->setName("EdgeRatio");
5375 ret->synchronizeTimeWithSupport();
5380 * Creates a new MEDCouplingFieldDouble holding Aspect Ratio values of all
5381 * cells. Currently cells of the following types are treated:
5382 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5383 * For a cell of other type an exception is thrown.
5384 * Space dimension of a 2D mesh can be either 2 or 3.
5385 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5386 * cells and one time, lying on \a this mesh. The caller is to delete this
5387 * field using decrRef() as it is no more needed.
5388 * \throw If the coordinates array is not set.
5389 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5390 * \throw If the connectivity data array has more than one component.
5391 * \throw If the connectivity data array has a named component.
5392 * \throw If the connectivity index data array has more than one component.
5393 * \throw If the connectivity index data array has a named component.
5394 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
5395 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5396 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5398 MEDCouplingFieldDouble *MEDCouplingUMesh::getAspectRatioField() const
5400 checkConsistencyLight();
5401 int spaceDim=getSpaceDimension();
5402 int meshDim=getMeshDimension();
5403 if(spaceDim!=2 && spaceDim!=3)
5404 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : SpaceDimension must be equal to 2 or 3 !");
5405 if(meshDim!=2 && meshDim!=3)
5406 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : MeshDimension must be equal to 2 or 3 !");
5407 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5409 mcIdType nbOfCells=getNumberOfCells();
5410 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5411 arr->alloc(nbOfCells,1);
5412 double *pt=arr->getPointer();
5413 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5414 const mcIdType *conn=_nodal_connec->begin();
5415 const mcIdType *connI=_nodal_connec_index->begin();
5416 const double *coo=_coords->begin();
5418 for(mcIdType i=0;i<nbOfCells;i++,pt++)
5420 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5423 case INTERP_KERNEL::NORM_TRI3:
5425 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5426 *pt=INTERP_KERNEL::triAspectRatio(tmp);
5429 case INTERP_KERNEL::NORM_QUAD4:
5431 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5432 *pt=INTERP_KERNEL::quadAspectRatio(tmp);
5435 case INTERP_KERNEL::NORM_TETRA4:
5437 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5438 *pt=INTERP_KERNEL::tetraAspectRatio(tmp);
5442 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5444 conn+=connI[i+1]-connI[i];
5446 ret->setName("AspectRatio");
5447 ret->synchronizeTimeWithSupport();
5452 * Creates a new MEDCouplingFieldDouble holding Warping factor values of all
5453 * cells of \a this 2D mesh in 3D space. It is a measure of the "planarity" of 2D cell
5454 * in 3D space. Currently only cells of the following types are
5455 * treated: INTERP_KERNEL::NORM_QUAD4.
5456 * For a cell of other type an exception is thrown.
5457 * The warp field is computed as follows: let (a,b,c,d) be the points of the quad.
5459 * \f$t=\vec{da}\times\vec{ab}\f$,
5460 * \f$u=\vec{ab}\times\vec{bc}\f$
5461 * \f$v=\vec{bc}\times\vec{cd}\f$
5462 * \f$w=\vec{cd}\times\vec{da}\f$, the warp is defined as \f$W^3\f$ with
5464 * W=min(\frac{t}{|t|}\cdot\frac{v}{|v|}, \frac{u}{|u|}\cdot\frac{w}{|w|})
5466 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5467 * cells and one time, lying on \a this mesh. The caller is to delete this
5468 * field using decrRef() as it is no more needed.
5469 * \throw If the coordinates array is not set.
5470 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5471 * \throw If the connectivity data array has more than one component.
5472 * \throw If the connectivity data array has a named component.
5473 * \throw If the connectivity index data array has more than one component.
5474 * \throw If the connectivity index data array has a named component.
5475 * \throw If \a this->getMeshDimension() != 2.
5476 * \throw If \a this->getSpaceDimension() != 3.
5477 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5479 MEDCouplingFieldDouble *MEDCouplingUMesh::getWarpField() const
5481 checkConsistencyLight();
5482 int spaceDim=getSpaceDimension();
5483 int meshDim=getMeshDimension();
5485 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : SpaceDimension must be equal to 3 !");
5487 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : MeshDimension must be equal to 2 !");
5488 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5490 mcIdType nbOfCells=getNumberOfCells();
5491 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5492 arr->alloc(nbOfCells,1);
5493 double *pt=arr->getPointer();
5494 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5495 const mcIdType *conn=_nodal_connec->begin();
5496 const mcIdType *connI=_nodal_connec_index->begin();
5497 const double *coo=_coords->begin();
5499 for(mcIdType i=0;i<nbOfCells;i++,pt++)
5501 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5504 case INTERP_KERNEL::NORM_QUAD4:
5506 FillInCompact3DMode(3,4,conn+1,coo,tmp);
5507 *pt=INTERP_KERNEL::quadWarp(tmp);
5511 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : A cell with not manged type (NORM_QUAD4) has been detected !");
5513 conn+=connI[i+1]-connI[i];
5515 ret->setName("Warp");
5516 ret->synchronizeTimeWithSupport();
5522 * Creates a new MEDCouplingFieldDouble holding Skew factor values of all
5523 * cells of \a this 2D mesh in 3D space. Currently cells of the following types are
5524 * treated: INTERP_KERNEL::NORM_QUAD4.
5525 * The skew is computed as follow for a quad with points (a,b,c,d): let
5526 * \f$u=\vec{ab}+\vec{dc}\f$ and \f$v=\vec{ac}+\vec{bd}\f$
5527 * then the skew is computed as:
5529 * s=\frac{u}{|u|}\cdot\frac{v}{|v|}
5532 * For a cell of other type an exception is thrown.
5533 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5534 * cells and one time, lying on \a this mesh. The caller is to delete this
5535 * field using decrRef() as it is no more needed.
5536 * \throw If the coordinates array is not set.
5537 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5538 * \throw If the connectivity data array has more than one component.
5539 * \throw If the connectivity data array has a named component.
5540 * \throw If the connectivity index data array has more than one component.
5541 * \throw If the connectivity index data array has a named component.
5542 * \throw If \a this->getMeshDimension() != 2.
5543 * \throw If \a this->getSpaceDimension() != 3.
5544 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5546 MEDCouplingFieldDouble *MEDCouplingUMesh::getSkewField() const
5548 checkConsistencyLight();
5549 int spaceDim=getSpaceDimension();
5550 int meshDim=getMeshDimension();
5552 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : SpaceDimension must be equal to 3 !");
5554 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : MeshDimension must be equal to 2 !");
5555 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5557 mcIdType nbOfCells=getNumberOfCells();
5558 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5559 arr->alloc(nbOfCells,1);
5560 double *pt=arr->getPointer();
5561 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5562 const mcIdType *conn=_nodal_connec->begin();
5563 const mcIdType *connI=_nodal_connec_index->begin();
5564 const double *coo=_coords->begin();
5566 for(mcIdType i=0;i<nbOfCells;i++,pt++)
5568 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5571 case INTERP_KERNEL::NORM_QUAD4:
5573 FillInCompact3DMode(3,4,conn+1,coo,tmp);
5574 *pt=INTERP_KERNEL::quadSkew(tmp);
5578 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : A cell with not manged type (NORM_QUAD4) has been detected !");
5580 conn+=connI[i+1]-connI[i];
5582 ret->setName("Skew");
5583 ret->synchronizeTimeWithSupport();
5588 * 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.
5590 * \return a new instance of field containing the result. The returned instance has to be deallocated by the caller.
5592 * \sa getSkewField, getWarpField, getAspectRatioField, getEdgeRatioField
5594 MEDCouplingFieldDouble *MEDCouplingUMesh::computeDiameterField() const
5596 checkConsistencyLight();
5597 MCAuto<MEDCouplingFieldDouble> ret(MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME));
5599 std::set<INTERP_KERNEL::NormalizedCellType> types;
5600 ComputeAllTypesInternal(types,_nodal_connec,_nodal_connec_index);
5601 int spaceDim(getSpaceDimension());
5602 mcIdType nbCells(getNumberOfCells());
5603 MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
5604 arr->alloc(nbCells,1);
5605 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++)
5607 INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::DiameterCalculator> dc(INTERP_KERNEL::CellModel::GetCellModel(*it).buildInstanceOfDiameterCalulator(spaceDim));
5608 MCAuto<DataArrayIdType> cellIds(giveCellsWithType(*it));
5609 dc->computeForListOfCellIdsUMeshFrmt(cellIds->begin(),cellIds->end(),_nodal_connec_index->begin(),_nodal_connec->begin(),getCoords()->begin(),arr->getPointer());
5612 ret->setName("Diameter");
5617 * This method aggregate the bbox of each cell and put it into bbox parameter (xmin,xmax,ymin,ymax,zmin,zmax).
5619 * \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)
5620 * For all other cases this input parameter is ignored.
5621 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5623 * \throw If \a this is not fully set (coordinates and connectivity).
5624 * \throw If a cell in \a this has no valid nodeId.
5625 * \sa MEDCouplingUMesh::getBoundingBoxForBBTreeFast, MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5627 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree(double arcDetEps) const
5629 int mDim(getMeshDimension()),sDim(getSpaceDimension());
5630 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.
5631 return getBoundingBoxForBBTreeFast();
5632 if((mDim==2 && sDim==2) || (mDim==1 && sDim==2))
5634 bool presenceOfQuadratic(false);
5635 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=_types.begin();it!=_types.end();it++)
5637 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(*it));
5638 if(cm.isQuadratic())
5639 presenceOfQuadratic=true;
5641 if(!presenceOfQuadratic)
5642 return getBoundingBoxForBBTreeFast();
5643 if(mDim==2 && sDim==2)
5644 return getBoundingBoxForBBTree2DQuadratic(arcDetEps);
5646 return getBoundingBoxForBBTree1DQuadratic(arcDetEps);
5648 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) !");
5652 * This method aggregate the bbox of each cell only considering the nodes constituting each cell and put it into bbox parameter.
5653 * So meshes having quadratic cells the computed bounding boxes can be invalid !
5655 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5657 * \throw If \a this is not fully set (coordinates and connectivity).
5658 * \throw If a cell in \a this has no valid nodeId.
5660 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTreeFast() const
5662 checkFullyDefined();
5663 int spaceDim(getSpaceDimension());
5664 mcIdType nbOfCells(getNumberOfCells()), nbOfNodes(getNumberOfNodes());
5665 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5666 double *bbox(ret->getPointer());
5667 for(mcIdType i=0;i<nbOfCells*spaceDim;i++)
5669 bbox[2*i]=std::numeric_limits<double>::max();
5670 bbox[2*i+1]=-std::numeric_limits<double>::max();
5672 const double *coordsPtr(_coords->begin());
5673 const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5674 for(mcIdType i=0;i<nbOfCells;i++)
5676 mcIdType offset=connI[i]+1;
5677 mcIdType nbOfNodesForCell(connI[i+1]-offset),kk(0);
5678 for(mcIdType j=0;j<nbOfNodesForCell;j++)
5680 mcIdType nodeId=conn[offset+j];
5681 if(nodeId>=0 && nodeId<nbOfNodes)
5683 for(int k=0;k<spaceDim;k++)
5685 bbox[2*spaceDim*i+2*k]=std::min(bbox[2*spaceDim*i+2*k],coordsPtr[spaceDim*nodeId+k]);
5686 bbox[2*spaceDim*i+2*k+1]=std::max(bbox[2*spaceDim*i+2*k+1],coordsPtr[spaceDim*nodeId+k]);
5693 std::ostringstream oss; oss << "MEDCouplingUMesh::getBoundingBoxForBBTree : cell #" << i << " contains no valid nodeId !";
5694 throw INTERP_KERNEL::Exception(oss.str());
5701 * This method aggregates the bbox of each 2D cell in \a this considering the whole shape. This method is particularly
5702 * useful for 2D meshes having quadratic cells
5703 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5704 * the two extremities of the arc of circle).
5706 * \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)
5707 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5708 * \throw If \a this is not fully defined.
5709 * \throw If \a this is not a mesh with meshDimension equal to 2.
5710 * \throw If \a this is not a mesh with spaceDimension equal to 2.
5711 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic
5713 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic(double arcDetEps) const
5715 checkFullyDefined();
5716 INTERP_KERNEL::QuadraticPlanarPrecision arcPrec(arcDetEps);
5718 int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
5719 mcIdType nbOfCells=getNumberOfCells();
5720 if(spaceDim!=2 || mDim!=2)
5721 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!");
5722 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5723 double *bbox(ret->getPointer());
5724 const double *coords(_coords->begin());
5725 const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5726 for(mcIdType i=0;i<nbOfCells;i++,bbox+=4,connI++)
5728 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5729 mcIdType sz(connI[1]-connI[0]-1);
5730 std::vector<INTERP_KERNEL::Node *> nodes(sz);
5731 INTERP_KERNEL::QuadraticPolygon *pol(0);
5732 for(mcIdType j=0;j<sz;j++)
5734 mcIdType nodeId(conn[*connI+1+j]);
5735 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5737 if(!cm.isQuadratic())
5738 pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
5740 pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
5741 INTERP_KERNEL::Bounds b; b.prepareForAggregation(); pol->fillBounds(b); delete pol;
5742 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax();
5748 * This method aggregates the bbox of each 1D cell in \a this considering the whole shape. This method is particularly
5749 * useful for 2D meshes having quadratic cells
5750 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5751 * the two extremities of the arc of circle).
5753 * \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)
5754 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5755 * \throw If \a this is not fully defined.
5756 * \throw If \a this is not a mesh with meshDimension equal to 1.
5757 * \throw If \a this is not a mesh with spaceDimension equal to 2.
5758 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5760 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic(double arcDetEps) const
5762 checkFullyDefined();
5763 int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
5764 mcIdType nbOfCells=getNumberOfCells();
5765 if(spaceDim!=2 || mDim!=1)
5766 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!");
5767 INTERP_KERNEL::QuadraticPlanarPrecision arcPrec(arcDetEps);
5768 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5769 double *bbox(ret->getPointer());
5770 const double *coords(_coords->begin());
5771 const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5772 for(mcIdType i=0;i<nbOfCells;i++,bbox+=4,connI++)
5774 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5775 mcIdType sz(connI[1]-connI[0]-1);
5776 std::vector<INTERP_KERNEL::Node *> nodes(sz);
5777 INTERP_KERNEL::Edge *edge(0);
5778 for(mcIdType j=0;j<sz;j++)
5780 mcIdType nodeId(conn[*connI+1+j]);
5781 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5783 if(!cm.isQuadratic())
5784 edge=INTERP_KERNEL::QuadraticPolygon::BuildLinearEdge(nodes);
5786 edge=INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(nodes);
5787 const INTERP_KERNEL::Bounds& b(edge->getBounds());
5788 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax(); edge->decrRef();
5795 namespace MEDCouplingImpl
5800 ConnReader(const mcIdType *c, mcIdType val):_conn(c),_val(val) { }
5801 bool operator() (const mcIdType& pos) { return _conn[pos]!=_val; }
5803 const mcIdType *_conn;
5810 ConnReader2(const mcIdType *c, mcIdType val):_conn(c),_val(val) { }
5811 bool operator() (const mcIdType& pos) { return _conn[pos]==_val; }
5813 const mcIdType *_conn;
5821 * This method expects that \a this is sorted by types. If not an exception will be thrown.
5822 * This method returns in the same format as code (see MEDCouplingUMesh::checkTypeConsistencyAndContig or MEDCouplingUMesh::splitProfilePerType) how
5823 * \a this is composed in cell types.
5824 * The returned array is of size 3*n where n is the number of different types present in \a this.
5825 * For every k in [0,n] ret[3*k+2]==-1 because it has no sense here.
5826 * This parameter is kept only for compatibility with other method listed above.
5828 std::vector<mcIdType> MEDCouplingUMesh::getDistributionOfTypes() const
5830 checkConnectivityFullyDefined();
5831 const mcIdType *conn=_nodal_connec->begin();
5832 const mcIdType *connI=_nodal_connec_index->begin();
5833 const mcIdType *work=connI;
5834 mcIdType nbOfCells=getNumberOfCells();
5835 std::size_t n=getAllGeoTypes().size();
5836 std::vector<mcIdType> ret(3*n,-1); //ret[3*k+2]==-1 because it has no sense here
5837 std::set<INTERP_KERNEL::NormalizedCellType> types;
5838 for(std::size_t i=0;work!=connI+nbOfCells;i++)
5840 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn[*work];
5841 if(types.find(typ)!=types.end())
5843 std::ostringstream oss; oss << "MEDCouplingUMesh::getDistributionOfTypes : Type " << INTERP_KERNEL::CellModel::GetCellModel(typ).getRepr();
5844 oss << " is not contiguous !";
5845 throw INTERP_KERNEL::Exception(oss.str());
5849 const mcIdType *work2=std::find_if(work+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,typ));
5850 ret[3*i+1]=ToIdType(std::distance(work,work2));
5857 * This method is used to check that this has contiguous cell type in same order than described in \a code.
5858 * only for types cell, type node is not managed.
5859 * Format of \a code is the following. \a code should be of size 3*n and non empty. If not an exception is thrown.
5860 * foreach k in [0,n) on 3*k pos represent the geometric type and 3*k+1 number of elements of type 3*k.
5861 * 3*k+2 refers if different from -1 the pos in 'idsPerType' to get the corresponding array.
5862 * If 2 or more same geometric type is in \a code and exception is thrown too.
5864 * This method firstly checks
5865 * If it exists k so that 3*k geometric type is not in geometric types of this an exception will be thrown.
5866 * If it exists k so that 3*k geometric type exists but the number of consecutive cell types does not match,
5867 * an exception is thrown too.
5869 * If all geometric types in \a code are exactly those in \a this null pointer is returned.
5870 * If it exists a geometric type in \a this \b not in \a code \b no exception is thrown
5871 * and a DataArrayIdType instance is returned that the user has the responsibility to deallocate.
5873 DataArrayIdType *MEDCouplingUMesh::checkTypeConsistencyAndContig(const std::vector<mcIdType>& code, const std::vector<const DataArrayIdType *>& idsPerType) const
5876 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code is empty, should not !");
5877 std::size_t sz=code.size();
5880 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code size is NOT %3 !");
5881 std::vector<INTERP_KERNEL::NormalizedCellType> types;
5883 bool isNoPflUsed=true;
5884 for(std::size_t i=0;i<n;i++)
5885 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)code[3*i])==types.end())
5887 types.push_back((INTERP_KERNEL::NormalizedCellType)code[3*i]);
5889 if(_types.find((INTERP_KERNEL::NormalizedCellType)code[3*i])==_types.end())
5890 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : expected geo types not in this !");
5891 isNoPflUsed=isNoPflUsed && (code[3*i+2]==-1);
5894 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code contains duplication of types in unstructured mesh !");
5897 if(!checkConsecutiveCellTypesAndOrder(&types[0],&types[0]+types.size()))
5898 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : non contiguous type !");
5899 if(types.size()==_types.size())
5902 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
5904 mcIdType *retPtr=ret->getPointer();
5905 const mcIdType *connI=_nodal_connec_index->begin();
5906 const mcIdType *conn=_nodal_connec->begin();
5907 mcIdType nbOfCells=getNumberOfCells();
5908 const mcIdType *i=connI;
5910 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++,kk++)
5912 i=std::find_if(i,connI+nbOfCells,MEDCouplingImpl::ConnReader2(conn,ToIdType((*it))));
5913 mcIdType offset=ToIdType(std::distance(connI,i));
5914 const mcIdType *j=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType((*it))));
5915 mcIdType nbOfCellsOfCurType=ToIdType(std::distance(i,j));
5916 if(code[3*kk+2]==-1)
5917 for(mcIdType k=0;k<nbOfCellsOfCurType;k++)
5921 mcIdType idInIdsPerType=code[3*kk+2];
5922 if(idInIdsPerType>=0 && idInIdsPerType<ToIdType(idsPerType.size()))
5924 const DataArrayIdType *zePfl=idsPerType[idInIdsPerType];
5927 zePfl->checkAllocated();
5928 if(zePfl->getNumberOfComponents()==1)
5930 for(const mcIdType *k=zePfl->begin();k!=zePfl->end();k++,retPtr++)
5932 if(*k>=0 && *k<nbOfCellsOfCurType)
5933 *retPtr=(*k)+offset;
5936 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : the section " << kk << " points to the profile #" << idInIdsPerType;
5937 oss << ", and this profile contains a value " << *k << " should be in [0," << nbOfCellsOfCurType << ") !";
5938 throw INTERP_KERNEL::Exception(oss.str());
5943 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of a profile with nb of compo != 1 !");
5946 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of null profile !");
5950 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : at section " << kk << " of code it points to the array #" << idInIdsPerType;
5951 oss << " should be in [0," << idsPerType.size() << ") !";
5952 throw INTERP_KERNEL::Exception(oss.str());
5961 * This method makes the hypothesis that \a this is sorted by type. If not an exception will be thrown.
5962 * 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.
5963 * 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.
5964 * This method has 1 input \a profile and 3 outputs \a code \a idsInPflPerType and \a idsPerType.
5966 * \param [in] profile list of IDs constituing the profile
5967 * \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.
5968 * \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,
5969 * \a idsInPflPerType[i] stores the tuple ids in \a profile that correspond to the geometric type code[3*i+0]
5970 * \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.
5971 * This vector can be empty in case of all geometric type cells are fully covered in ascending in the given input \a profile.
5972 * \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
5974 void MEDCouplingUMesh::splitProfilePerType(const DataArrayIdType *profile, std::vector<mcIdType>& code, std::vector<DataArrayIdType *>& idsInPflPerType, std::vector<DataArrayIdType *>& idsPerType, bool smartPflKiller) const
5977 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile is NULL !");
5978 if(profile->getNumberOfComponents()!=1)
5979 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile should have exactly one component !");
5980 checkConnectivityFullyDefined();
5981 const mcIdType *conn=_nodal_connec->begin();
5982 const mcIdType *connI=_nodal_connec_index->begin();
5983 mcIdType nbOfCells=getNumberOfCells();
5984 std::vector<INTERP_KERNEL::NormalizedCellType> types;
5985 std::vector<mcIdType> typeRangeVals(1);
5986 for(const mcIdType *i=connI;i!=connI+nbOfCells;)
5988 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5989 if(std::find(types.begin(),types.end(),curType)!=types.end())
5991 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : current mesh is not sorted by type !");
5993 types.push_back(curType);
5994 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
5995 typeRangeVals.push_back(ToIdType(std::distance(connI,i)));
5998 DataArrayIdType *castArr=0,*rankInsideCast=0,*castsPresent=0;
5999 profile->splitByValueRange(&typeRangeVals[0],&typeRangeVals[0]+typeRangeVals.size(),castArr,rankInsideCast,castsPresent);
6000 MCAuto<DataArrayIdType> tmp0=castArr;
6001 MCAuto<DataArrayIdType> tmp1=rankInsideCast;
6002 MCAuto<DataArrayIdType> tmp2=castsPresent;
6004 mcIdType nbOfCastsFinal=castsPresent->getNumberOfTuples();
6005 code.resize(3*nbOfCastsFinal);
6006 std::vector< MCAuto<DataArrayIdType> > idsInPflPerType2;
6007 std::vector< MCAuto<DataArrayIdType> > idsPerType2;
6008 for(mcIdType i=0;i<nbOfCastsFinal;i++)
6010 mcIdType castId=castsPresent->getIJ(i,0);
6011 MCAuto<DataArrayIdType> tmp3=castArr->findIdsEqual(castId);
6012 idsInPflPerType2.push_back(tmp3);
6013 code[3*i]=ToIdType(types[castId]);
6014 code[3*i+1]=tmp3->getNumberOfTuples();
6015 MCAuto<DataArrayIdType> tmp4=rankInsideCast->selectByTupleId(tmp3->begin(),tmp3->begin()+tmp3->getNumberOfTuples());
6016 if(!smartPflKiller || !tmp4->isIota(typeRangeVals[castId+1]-typeRangeVals[castId]))
6018 tmp4->copyStringInfoFrom(*profile);
6019 idsPerType2.push_back(tmp4);
6020 code[3*i+2]=ToIdType(idsPerType2.size())-1;
6027 std::size_t sz2=idsInPflPerType2.size();
6028 idsInPflPerType.resize(sz2);
6029 for(std::size_t i=0;i<sz2;i++)
6031 DataArrayIdType *locDa=idsInPflPerType2[i];
6033 idsInPflPerType[i]=locDa;
6035 std::size_t sz=idsPerType2.size();
6036 idsPerType.resize(sz);
6037 for(std::size_t i=0;i<sz;i++)
6039 DataArrayIdType *locDa=idsPerType2[i];
6041 idsPerType[i]=locDa;
6046 * This method is here too emulate the MEDMEM behaviour on BDC (buildDescendingConnectivity). Hoping this method becomes deprecated very soon.
6047 * This method make the assumption that \a this and 'nM1LevMesh' mesh lyies on same coords (same pointer) as MED and MEDMEM does.
6048 * The following equality should be verified 'nM1LevMesh->getMeshDimension()==this->getMeshDimension()-1'
6049 * 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.
6051 MEDCouplingUMesh *MEDCouplingUMesh::emulateMEDMEMBDC(const MEDCouplingUMesh *nM1LevMesh, DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *&revDesc, DataArrayIdType *&revDescIndx, DataArrayIdType *& nM1LevMeshIds, DataArrayIdType *&meshnM1Old2New) const
6053 checkFullyDefined();
6054 nM1LevMesh->checkFullyDefined();
6055 if(getMeshDimension()-1!=nM1LevMesh->getMeshDimension())
6056 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : The mesh passed as first argument should have a meshDim equal to this->getMeshDimension()-1 !" );
6057 if(_coords!=nM1LevMesh->getCoords())
6058 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : 'this' and mesh in first argument should share the same coords : Use tryToShareSameCoords method !");
6059 MCAuto<DataArrayIdType> tmp0=DataArrayIdType::New();
6060 MCAuto<DataArrayIdType> tmp1=DataArrayIdType::New();
6061 MCAuto<MEDCouplingUMesh> ret1=buildDescendingConnectivity(desc,descIndx,tmp0,tmp1);
6062 MCAuto<DataArrayIdType> ret0=ret1->sortCellsInMEDFileFrmt();
6063 desc->transformWithIndArr(ret0->begin(),ret0->begin()+ret0->getNbOfElems());
6064 MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
6065 tmp->setConnectivity(tmp0,tmp1);
6066 tmp->renumberCells(ret0->begin(),false);
6067 revDesc=tmp->getNodalConnectivity();
6068 revDescIndx=tmp->getNodalConnectivityIndex();
6069 DataArrayIdType *ret=0;
6070 if(!ret1->areCellsIncludedIn(nM1LevMesh,2,ret))
6073 ret->getMaxValue(tmp2);
6075 std::ostringstream oss; oss << "MEDCouplingUMesh::emulateMEDMEMBDC : input N-1 mesh present a cell not in descending mesh ... Id of cell is " << tmp2 << " !";
6076 throw INTERP_KERNEL::Exception(oss.str());
6081 revDescIndx->incrRef();
6084 meshnM1Old2New=ret0;
6089 * Permutes the nodal connectivity arrays so that the cells are sorted by type, which is
6090 * necessary for writing the mesh to MED file. Additionally returns a permutation array
6091 * in "Old to New" mode.
6092 * \return DataArrayIdType * - a new instance of DataArrayIdType. The caller is to delete
6093 * this array using decrRef() as it is no more needed.
6094 * \throw If the nodal connectivity of cells is not defined.
6096 DataArrayIdType *MEDCouplingUMesh::sortCellsInMEDFileFrmt()
6098 checkConnectivityFullyDefined();
6099 MCAuto<DataArrayIdType> ret=getRenumArrForMEDFileFrmt();
6100 renumberCells(ret->begin(),false);
6105 * This methods checks that cells are sorted by their types.
6106 * This method makes asumption (no check) that connectivity is correctly set before calling.
6108 bool MEDCouplingUMesh::checkConsecutiveCellTypes() const
6110 checkFullyDefined();
6111 const mcIdType *conn=_nodal_connec->begin();
6112 const mcIdType *connI=_nodal_connec_index->begin();
6113 mcIdType nbOfCells=getNumberOfCells();
6114 std::set<INTERP_KERNEL::NormalizedCellType> types;
6115 for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6117 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6118 if(types.find(curType)!=types.end())
6120 types.insert(curType);
6121 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6127 * This method is a specialization of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method that is called here.
6128 * The geometric type order is specified by MED file.
6130 * \sa MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder
6132 bool MEDCouplingUMesh::checkConsecutiveCellTypesForMEDFileFrmt() const
6134 return checkConsecutiveCellTypesAndOrder(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
6138 * This method performs the same job as checkConsecutiveCellTypes except that the order of types sequence is analyzed to check
6139 * that the order is specified in array defined by [ \a orderBg , \a orderEnd ).
6140 * If there is some geo types in \a this \b NOT in [ \a orderBg, \a orderEnd ) it is OK (return true) if contiguous.
6141 * If there is some geo types in [ \a orderBg, \a orderEnd ) \b NOT in \a this it is OK too (return true) if contiguous.
6143 bool MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
6145 checkFullyDefined();
6146 const mcIdType *conn=_nodal_connec->begin();
6147 const mcIdType *connI=_nodal_connec_index->begin();
6148 mcIdType nbOfCells=getNumberOfCells();
6151 mcIdType lastPos=-1;
6152 std::set<INTERP_KERNEL::NormalizedCellType> sg;
6153 for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6155 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6156 const INTERP_KERNEL::NormalizedCellType *isTypeExists=std::find(orderBg,orderEnd,curType);
6157 if(isTypeExists!=orderEnd)
6159 mcIdType pos=ToIdType(std::distance(orderBg,isTypeExists));
6163 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6167 if(sg.find(curType)==sg.end())
6169 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6180 * This method returns 2 newly allocated DataArrayIdType instances. The first is an array of size 'this->getNumberOfCells()' with one component,
6181 * 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
6182 * 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'.
6184 DataArrayIdType *MEDCouplingUMesh::getLevArrPerCellTypes(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd, DataArrayIdType *&nbPerType) const
6186 checkConnectivityFullyDefined();
6187 mcIdType nbOfCells=getNumberOfCells();
6188 const mcIdType *conn=_nodal_connec->begin();
6189 const mcIdType *connI=_nodal_connec_index->begin();
6190 MCAuto<DataArrayIdType> tmpa=DataArrayIdType::New();
6191 MCAuto<DataArrayIdType> tmpb=DataArrayIdType::New();
6192 tmpa->alloc(nbOfCells,1);
6193 tmpb->alloc(std::distance(orderBg,orderEnd),1);
6194 tmpb->fillWithZero();
6195 mcIdType *tmp=tmpa->getPointer();
6196 mcIdType *tmp2=tmpb->getPointer();
6197 for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6199 const INTERP_KERNEL::NormalizedCellType *where=std::find(orderBg,orderEnd,(INTERP_KERNEL::NormalizedCellType)conn[*i]);
6202 mcIdType pos=ToIdType(std::distance(orderBg,where));
6204 tmp[std::distance(connI,i)]=pos;
6208 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*i]);
6209 std::ostringstream oss; oss << "MEDCouplingUMesh::getLevArrPerCellTypes : Cell #" << std::distance(connI,i);
6210 oss << " has a type " << cm.getRepr() << " not in input array of type !";
6211 throw INTERP_KERNEL::Exception(oss.str());
6214 nbPerType=tmpb.retn();
6219 * This method behaves exactly as MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec but the order is those defined in MED file spec.
6221 * \return a new object containing the old to new correspondence.
6223 * \sa MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec, MEDCouplingUMesh::sortCellsInMEDFileFrmt.
6225 DataArrayIdType *MEDCouplingUMesh::getRenumArrForMEDFileFrmt() const
6227 return getRenumArrForConsecutiveCellTypesSpec(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
6231 * 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.
6232 * This method returns an array of size getNumberOfCells() that gives a renumber array old2New that can be used as input of MEDCouplingMesh::renumberCells.
6233 * The mesh after this call to MEDCouplingMesh::renumberCells will pass the test of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder with the same inputs.
6234 * The returned array minimizes the permutations that is to say the order of cells inside same geometric type remains the same.
6236 DataArrayIdType *MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
6238 DataArrayIdType *nbPerType=0;
6239 MCAuto<DataArrayIdType> tmpa=getLevArrPerCellTypes(orderBg,orderEnd,nbPerType);
6240 nbPerType->decrRef();
6241 return tmpa->buildPermArrPerLevel();
6245 * This method reorganize the cells of \a this so that the cells with same geometric types are put together.
6246 * The number of cells remains unchanged after the call of this method.
6247 * This method tries to minimizes the number of needed permutations. So, this method behaves not exactly as
6248 * MEDCouplingUMesh::sortCellsInMEDFileFrmt.
6250 * \return the array giving the correspondence old to new.
6252 DataArrayIdType *MEDCouplingUMesh::rearrange2ConsecutiveCellTypes()
6254 checkFullyDefined();
6256 const mcIdType *conn=_nodal_connec->begin();
6257 const mcIdType *connI=_nodal_connec_index->begin();
6258 mcIdType nbOfCells=getNumberOfCells();
6259 std::vector<INTERP_KERNEL::NormalizedCellType> types;
6260 for(const mcIdType *i=connI;i!=connI+nbOfCells && (types.size()!=_types.size());)
6261 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)conn[*i])==types.end())
6263 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6264 types.push_back(curType);
6265 for(i++;i!=connI+nbOfCells && (INTERP_KERNEL::NormalizedCellType)conn[*i]==curType;i++);
6267 DataArrayIdType *ret=DataArrayIdType::New();
6268 ret->alloc(nbOfCells,1);
6269 mcIdType *retPtr=ret->getPointer();
6270 std::fill(retPtr,retPtr+nbOfCells,-1);
6271 mcIdType newCellId=0;
6272 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
6274 for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6275 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
6276 retPtr[std::distance(connI,i)]=newCellId++;
6278 renumberCells(retPtr,false);
6283 * This method splits \a this into as mush as untructured meshes that consecutive set of same type cells.
6284 * So this method has typically a sense if MEDCouplingUMesh::checkConsecutiveCellTypes has a sense.
6285 * This method makes asumption that connectivity is correctly set before calling.
6287 std::vector<MEDCouplingUMesh *> MEDCouplingUMesh::splitByType() const
6289 checkConnectivityFullyDefined();
6290 const mcIdType *conn=_nodal_connec->begin();
6291 const mcIdType *connI=_nodal_connec_index->begin();
6292 mcIdType nbOfCells=getNumberOfCells();
6293 std::vector<MEDCouplingUMesh *> ret;
6294 for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6296 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6297 mcIdType beginCellId=ToIdType(std::distance(connI,i));
6298 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6299 mcIdType endCellId=ToIdType(std::distance(connI,i));
6300 mcIdType sz=endCellId-beginCellId;
6301 mcIdType *cells=new mcIdType[sz];
6302 for(mcIdType j=0;j<sz;j++)
6303 cells[j]=beginCellId+j;
6304 MEDCouplingUMesh *m=(MEDCouplingUMesh *)buildPartOfMySelf(cells,cells+sz,true);
6312 * This method performs the opposite operation than those in MEDCoupling1SGTUMesh::buildUnstructured.
6313 * If \a this is a single geometric type unstructured mesh, it will be converted into a more compact data structure,
6314 * MEDCoupling1GTUMesh instance. The returned instance will aggregate the same DataArrayDouble instance of coordinates than \a this.
6316 * \return a newly allocated instance, that the caller must manage.
6317 * \throw If \a this contains more than one geometric type.
6318 * \throw If the nodal connectivity of \a this is not fully defined.
6319 * \throw If the internal data is not coherent.
6321 MEDCoupling1GTUMesh *MEDCouplingUMesh::convertIntoSingleGeoTypeMesh() const
6323 checkConnectivityFullyDefined();
6324 if(_types.size()!=1)
6325 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6326 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6327 MCAuto<MEDCoupling1GTUMesh> ret=MEDCoupling1GTUMesh::New(getName(),typ);
6328 ret->setCoords(getCoords());
6329 MEDCoupling1SGTUMesh *retC=dynamic_cast<MEDCoupling1SGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6332 MCAuto<DataArrayIdType> c=convertNodalConnectivityToStaticGeoTypeMesh();
6333 retC->setNodalConnectivity(c);
6337 MEDCoupling1DGTUMesh *retD=dynamic_cast<MEDCoupling1DGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6339 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : Internal error !");
6340 DataArrayIdType *c=0,*ci=0;
6341 convertNodalConnectivityToDynamicGeoTypeMesh(c,ci);
6342 MCAuto<DataArrayIdType> cs(c),cis(ci);
6343 retD->setNodalConnectivity(cs,cis);
6348 DataArrayIdType *MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh() const
6350 checkConnectivityFullyDefined();
6351 if(_types.size()!=1)
6352 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6353 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6354 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6357 std::ostringstream oss; oss << "MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : this contains a single geo type (" << cm.getRepr() << ") but ";
6358 oss << "this type is dynamic ! Only static geometric type is possible for that type ! call convertNodalConnectivityToDynamicGeoTypeMesh instead !";
6359 throw INTERP_KERNEL::Exception(oss.str());
6361 mcIdType nbCells=getNumberOfCells();
6362 mcIdType typi=ToIdType(typ);
6363 mcIdType nbNodesPerCell=ToIdType(cm.getNumberOfNodes());
6364 MCAuto<DataArrayIdType> connOut=DataArrayIdType::New(); connOut->alloc(nbCells*nbNodesPerCell,1);
6365 mcIdType *outPtr=connOut->getPointer();
6366 const mcIdType *conn=_nodal_connec->begin();
6367 const mcIdType *connI=_nodal_connec_index->begin();
6369 for(mcIdType i=0;i<nbCells;i++,connI++)
6371 if(conn[connI[0]]==typi && connI[1]-connI[0]==nbNodesPerCell)
6372 outPtr=std::copy(conn+connI[0]+1,conn+connI[1],outPtr);
6375 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 << ") !";
6376 throw INTERP_KERNEL::Exception(oss.str());
6379 return connOut.retn();
6383 * Convert the nodal connectivity of the mesh so that all the cells are of dynamic types (polygon or quadratic
6384 * polygon). This returns the corresponding new nodal connectivity in \ref numbering-indirect format.
6385 * \param nodalConn nodal connectivity
6386 * \param nodalConnIndex nodal connectivity indices
6388 void MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh(DataArrayIdType *&nodalConn, DataArrayIdType *&nodalConnIndex) const
6390 static const char msg0[]="MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : nodal connectivity in this are invalid ! Call checkConsistency !";
6391 checkConnectivityFullyDefined();
6392 if(_types.size()!=1)
6393 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6394 mcIdType nbCells=getNumberOfCells(),
6395 lgth=_nodal_connec->getNumberOfTuples();
6397 throw INTERP_KERNEL::Exception(msg0);
6398 MCAuto<DataArrayIdType> c(DataArrayIdType::New()),ci(DataArrayIdType::New());
6399 c->alloc(lgth-nbCells,1); ci->alloc(nbCells+1,1);
6400 mcIdType *cp(c->getPointer()),*cip(ci->getPointer());
6401 const mcIdType *incp(_nodal_connec->begin()),*incip(_nodal_connec_index->begin());
6403 for(mcIdType i=0;i<nbCells;i++,cip++,incip++)
6405 mcIdType strt(incip[0]+1),stop(incip[1]);//+1 to skip geo type
6406 mcIdType delta(stop-strt);
6409 if((strt>=0 && strt<lgth) && (stop>=0 && stop<=lgth))
6410 cp=std::copy(incp+strt,incp+stop,cp);
6412 throw INTERP_KERNEL::Exception(msg0);
6415 throw INTERP_KERNEL::Exception(msg0);
6416 cip[1]=cip[0]+delta;
6418 nodalConn=c.retn(); nodalConnIndex=ci.retn();
6422 * This method takes in input a vector of MEDCouplingUMesh instances lying on the same coordinates with same mesh dimensions.
6423 * Each mesh in \b ms must be sorted by type with the same order (typically using MEDCouplingUMesh::sortCellsInMEDFileFrmt).
6424 * This method is particularly useful for MED file interaction. It allows to aggregate several meshes and keeping the type sorting
6425 * and the track of the permutation by chunk of same geotype cells to retrieve it. The traditional formats old2new and new2old
6426 * are not used here to avoid the build of big permutation array.
6428 * \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
6429 * those specified in MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6430 * \param [out] szOfCellGrpOfSameType is a newly allocated DataArrayIdType instance whose number of tuples is equal to the number of chunks of same geotype
6431 * in all meshes in \b ms. The accumulation of all values of this array is equal to the number of cells of returned mesh.
6432 * \param [out] idInMsOfCellGrpOfSameType is a newly allocated DataArrayIdType instance having the same size than \b szOfCellGrpOfSameType. This
6433 * output array gives for each chunck of same type the corresponding mesh id in \b ms.
6434 * \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
6435 * is sorted by type following the geo cell types order of MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6437 MEDCouplingUMesh *MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& ms,
6438 DataArrayIdType *&szOfCellGrpOfSameType,
6439 DataArrayIdType *&idInMsOfCellGrpOfSameType)
6441 std::vector<const MEDCouplingUMesh *> ms2;
6442 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms.begin();it!=ms.end();it++)
6445 (*it)->checkConnectivityFullyDefined();
6449 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : input vector is empty !");
6450 const DataArrayDouble *refCoo=ms2[0]->getCoords();
6451 int meshDim=ms2[0]->getMeshDimension();
6452 std::vector<const MEDCouplingUMesh *> m1ssm;
6453 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmAuto;
6455 std::vector<const MEDCouplingUMesh *> m1ssmSingle;
6456 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmSingleAuto;
6457 mcIdType fake=0,rk=0;
6458 MCAuto<DataArrayIdType> ret1(DataArrayIdType::New()),ret2(DataArrayIdType::New());
6459 ret1->alloc(0,1); ret2->alloc(0,1);
6460 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms2.begin();it!=ms2.end();it++,rk++)
6462 if(meshDim!=(*it)->getMeshDimension())
6463 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshdims mismatch !");
6464 if(refCoo!=(*it)->getCoords())
6465 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshes are not shared by a single coordinates coords !");
6466 std::vector<MEDCouplingUMesh *> sp=(*it)->splitByType();
6467 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<const MEDCouplingUMesh *> >(m1ssm));
6468 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<MCAuto<MEDCouplingUMesh> > >(m1ssmAuto));
6469 for(std::vector<MEDCouplingUMesh *>::const_iterator it2=sp.begin();it2!=sp.end();it2++)
6471 MEDCouplingUMesh *singleCell=static_cast<MEDCouplingUMesh *>((*it2)->buildPartOfMySelf(&fake,&fake+1,true));
6472 m1ssmSingleAuto.push_back(singleCell);
6473 m1ssmSingle.push_back(singleCell);
6474 ret1->pushBackSilent((*it2)->getNumberOfCells()); ret2->pushBackSilent(rk);
6477 MCAuto<MEDCouplingUMesh> m1ssmSingle2=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmSingle);
6478 MCAuto<DataArrayIdType> renum=m1ssmSingle2->sortCellsInMEDFileFrmt();
6479 std::vector<const MEDCouplingUMesh *> m1ssmfinal(m1ssm.size());
6480 for(mcIdType i=0;i<ToIdType(m1ssm.size());i++)
6481 m1ssmfinal[renum->getIJ(i,0)]=m1ssm[i];
6482 MCAuto<MEDCouplingUMesh> ret0=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmfinal);
6483 szOfCellGrpOfSameType=ret1->renumber(renum->begin());
6484 idInMsOfCellGrpOfSameType=ret2->renumber(renum->begin());
6489 * This method returns a newly created DataArrayIdType instance.
6490 * This method retrieves cell ids in [ \a begin, \a end ) that have the type \a type.
6492 DataArrayIdType *MEDCouplingUMesh::keepCellIdsByType(INTERP_KERNEL::NormalizedCellType type, const mcIdType *begin, const mcIdType *end) const
6494 checkFullyDefined();
6495 const mcIdType *conn=_nodal_connec->begin();
6496 const mcIdType *connIndex=_nodal_connec_index->begin();
6497 MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(0,1);
6498 for(const mcIdType *w=begin;w!=end;w++)
6499 if((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]==type)
6500 ret->pushBackSilent(*w);
6505 * This method makes the assumption that da->getNumberOfTuples()<this->getNumberOfCells(). This method makes the assumption that ids contained in 'da'
6506 * are in [0:getNumberOfCells())
6508 DataArrayIdType *MEDCouplingUMesh::convertCellArrayPerGeoType(const DataArrayIdType *da) const
6510 checkFullyDefined();
6511 const mcIdType *conn=_nodal_connec->begin();
6512 const mcIdType *connI=_nodal_connec_index->begin();
6513 mcIdType nbOfCells=getNumberOfCells();
6514 std::set<INTERP_KERNEL::NormalizedCellType> types(getAllGeoTypes());
6515 mcIdType *tmp=new mcIdType[nbOfCells];
6516 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
6519 for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6520 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
6521 tmp[std::distance(connI,i)]=j++;
6523 DataArrayIdType *ret=DataArrayIdType::New();
6524 ret->alloc(da->getNumberOfTuples(),da->getNumberOfComponents());
6525 ret->copyStringInfoFrom(*da);
6526 mcIdType *retPtr=ret->getPointer();
6527 const mcIdType *daPtr=da->begin();
6528 mcIdType nbOfElems=da->getNbOfElems();
6529 for(mcIdType k=0;k<nbOfElems;k++)
6530 retPtr[k]=tmp[daPtr[k]];
6536 * This method reduced number of cells of this by keeping cells whose type is different from 'type' and if type=='type'
6537 * This method \b works \b for mesh sorted by type.
6538 * cells whose ids is in 'idsPerGeoType' array.
6539 * This method conserves coords and name of mesh.
6541 MEDCouplingUMesh *MEDCouplingUMesh::keepSpecifiedCells(INTERP_KERNEL::NormalizedCellType type, const mcIdType *idsPerGeoTypeBg, const mcIdType *idsPerGeoTypeEnd) const
6543 std::vector<mcIdType> code=getDistributionOfTypes();
6544 std::size_t nOfTypesInThis=code.size()/3;
6545 mcIdType sz=0,szOfType=0;
6546 for(std::size_t i=0;i<nOfTypesInThis;i++)
6551 szOfType=code[3*i+1];
6553 for(const mcIdType *work=idsPerGeoTypeBg;work!=idsPerGeoTypeEnd;work++)
6554 if(*work<0 || *work>=szOfType)
6556 std::ostringstream oss; oss << "MEDCouplingUMesh::keepSpecifiedCells : Request on type " << type << " at place #" << std::distance(idsPerGeoTypeBg,work) << " value " << *work;
6557 oss << ". It should be in [0," << szOfType << ") !";
6558 throw INTERP_KERNEL::Exception(oss.str());
6560 MCAuto<DataArrayIdType> idsTokeep=DataArrayIdType::New(); idsTokeep->alloc(sz+std::distance(idsPerGeoTypeBg,idsPerGeoTypeEnd),1);
6561 mcIdType *idsPtr=idsTokeep->getPointer();
6563 for(std::size_t i=0;i<nOfTypesInThis;i++)
6566 for(mcIdType j=0;j<code[3*i+1];j++)
6569 idsPtr=std::transform(idsPerGeoTypeBg,idsPerGeoTypeEnd,idsPtr,std::bind(std::plus<mcIdType>(),std::placeholders::_1,offset));
6570 offset+=code[3*i+1];
6572 MCAuto<MEDCouplingUMesh> ret=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(idsTokeep->begin(),idsTokeep->end(),true));
6573 ret->copyTinyInfoFrom(this);
6578 * This method returns a vector of size 'this->getNumberOfCells()'.
6579 * This method retrieves for each cell in \a this if it is linear (false) or quadratic(true).
6581 std::vector<bool> MEDCouplingUMesh::getQuadraticStatus() const
6583 mcIdType ncell=getNumberOfCells();
6584 std::vector<bool> ret(ncell);
6585 const mcIdType *cI=getNodalConnectivityIndex()->begin();
6586 const mcIdType *c=getNodalConnectivity()->begin();
6587 for(mcIdType i=0;i<ncell;i++)
6589 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[i]];
6590 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6591 ret[i]=cm.isQuadratic();
6597 * Returns a newly created mesh (with ref count ==1) that contains merge of \a this and \a other.
6599 MEDCouplingMesh *MEDCouplingUMesh::mergeMyselfWith(const MEDCouplingMesh *other) const
6601 if(other->getType()!=UNSTRUCTURED)
6602 throw INTERP_KERNEL::Exception("Merge of umesh only available with umesh each other !");
6603 const MEDCouplingUMesh *otherC=static_cast<const MEDCouplingUMesh *>(other);
6604 return MergeUMeshes(this,otherC);
6608 * Returns a new DataArrayDouble holding barycenters of all cells. The barycenter is
6609 * computed by averaging coordinates of cell nodes, so this method is not a right
6610 * choice for degenerated meshes (not well oriented, cells with measure close to zero).
6611 * Beware also that for quadratic meshes, degenerated arc of circles are turned into linear edges for the computation.
6612 * This happens with a default detection precision of eps=1.0e-14. If you need control over this use computeCellCenterOfMassWithPrecision().
6613 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
6614 * this->getNumberOfCells() tuples per \a this->getSpaceDimension()
6615 * components. The caller is to delete this array using decrRef() as it is
6617 * \throw If the coordinates array is not set.
6618 * \throw If the nodal connectivity of cells is not defined.
6619 * \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
6620 * \sa MEDCouplingUMesh::computeCellCenterOfMassWithPrecision
6622 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMass() const
6624 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6625 int spaceDim=getSpaceDimension();
6626 mcIdType nbOfCells=getNumberOfCells();
6627 ret->alloc(nbOfCells,spaceDim);
6628 ret->copyStringInfoFrom(*getCoords());
6629 double *ptToFill=ret->getPointer();
6630 const mcIdType *nodal=_nodal_connec->begin();
6631 const mcIdType *nodalI=_nodal_connec_index->begin();
6632 const double *coor=_coords->begin();
6633 for(mcIdType i=0;i<nbOfCells;i++)
6635 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6636 INTERP_KERNEL::computeBarycenter2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[i]+1,nodalI[i+1]-nodalI[i]-1,coor,spaceDim,ptToFill);
6644 * See computeCellCenterOfMass().
6645 * \param eps a precision for the detection of degenerated arc of circles.
6646 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
6647 * this->getNumberOfCells() tuples per \a this->getSpaceDimension()
6648 * components. The caller is to delete this array using decrRef() as it is
6650 * \throw If the coordinates array is not set.
6651 * \throw If the nodal connectivity of cells is not defined.
6652 * \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
6653 * \sa MEDCouplingUMesh::computeCellCenterOfMassWithPrecision
6655 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMassWithPrecision(double eps) const
6657 INTERP_KERNEL::QuadraticPlanarPrecision prec(eps);
6658 MCAuto<DataArrayDouble> ret = computeCellCenterOfMass();
6664 * This method computes for each cell in \a this, the location of the iso barycenter of nodes constituting
6665 * the cell. Contrary to badly named MEDCouplingUMesh::computeCellCenterOfMass method that returns the center of inertia of the
6667 * \return a newly allocated DataArrayDouble instance that the caller has to deal with. The returned
6668 * DataArrayDouble instance will have \c this->getNumberOfCells() tuples and \c this->getSpaceDimension() components.
6670 * \sa MEDCouplingUMesh::computeCellCenterOfMass
6671 * \throw If \a this is not fully defined (coordinates and connectivity)
6672 * \throw If there is presence in nodal connectivity in \a this of node ids not in [0, \c this->getNumberOfNodes() )
6674 DataArrayDouble *MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell() const
6676 checkFullyDefined();
6677 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6678 int spaceDim=getSpaceDimension();
6679 mcIdType nbOfCells=getNumberOfCells();
6680 mcIdType nbOfNodes=getNumberOfNodes();
6681 ret->alloc(nbOfCells,spaceDim);
6682 double *ptToFill=ret->getPointer();
6683 const mcIdType *nodal=_nodal_connec->begin();
6684 const mcIdType *nodalI=_nodal_connec_index->begin();
6685 const double *coor=_coords->begin();
6686 for(mcIdType i=0;i<nbOfCells;i++,ptToFill+=spaceDim)
6688 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6689 std::fill(ptToFill,ptToFill+spaceDim,0.);
6690 if(type!=INTERP_KERNEL::NORM_POLYHED)
6692 for(const mcIdType *conn=nodal+nodalI[i]+1;conn!=nodal+nodalI[i+1];conn++)
6694 if(*conn>=0 && *conn<nbOfNodes)
6695 std::transform(coor+spaceDim*conn[0],coor+spaceDim*(conn[0]+1),ptToFill,ptToFill,std::plus<double>());
6698 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of nodeId #" << *conn << " should be in [0," << nbOfNodes << ") !";
6699 throw INTERP_KERNEL::Exception(oss.str());
6702 mcIdType nbOfNodesInCell=nodalI[i+1]-nodalI[i]-1;
6703 if(nbOfNodesInCell>0)
6704 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind(std::multiplies<double>(),std::placeholders::_1,1./(double)nbOfNodesInCell));
6707 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of cell with no nodes !";
6708 throw INTERP_KERNEL::Exception(oss.str());
6713 std::set<mcIdType> s(nodal+nodalI[i]+1,nodal+nodalI[i+1]);
6715 for(std::set<mcIdType>::const_iterator it=s.begin();it!=s.end();it++)
6717 if(*it>=0 && *it<nbOfNodes)
6718 std::transform(coor+spaceDim*(*it),coor+spaceDim*((*it)+1),ptToFill,ptToFill,std::plus<double>());
6721 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell polyhedron cell #" << i << " presence of nodeId #" << *it << " should be in [0," << nbOfNodes << ") !";
6722 throw INTERP_KERNEL::Exception(oss.str());
6726 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind(std::multiplies<double>(),std::placeholders::_1,1./(double)s.size()));
6729 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on polyhedron cell #" << i << " there are no nodes !";
6730 throw INTERP_KERNEL::Exception(oss.str());
6738 * Returns a new DataArrayDouble holding barycenters of specified cells. The
6739 * barycenter is computed by averaging coordinates of cell nodes. The cells to treat
6740 * are specified via an array of cell ids.
6741 * \warning Validity of the specified cell ids is not checked!
6742 * Valid range is [ 0, \a this->getNumberOfCells() ).
6743 * \param [in] begin - an array of cell ids of interest.
6744 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
6745 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size ( \a
6746 * end - \a begin ) tuples per \a this->getSpaceDimension() components. The
6747 * caller is to delete this array using decrRef() as it is no more needed.
6748 * \throw If the coordinates array is not set.
6749 * \throw If the nodal connectivity of cells is not defined.
6751 * \if ENABLE_EXAMPLES
6752 * \ref cpp_mcumesh_getPartBarycenterAndOwner "Here is a C++ example".<br>
6753 * \ref py_mcumesh_getPartBarycenterAndOwner "Here is a Python example".
6756 DataArrayDouble *MEDCouplingUMesh::getPartBarycenterAndOwner(const mcIdType *begin, const mcIdType *end) const
6758 DataArrayDouble *ret=DataArrayDouble::New();
6759 int spaceDim=getSpaceDimension();
6760 std::size_t nbOfTuple=std::distance(begin,end);
6761 ret->alloc(nbOfTuple,spaceDim);
6762 double *ptToFill=ret->getPointer();
6763 double *tmp=new double[spaceDim];
6764 const mcIdType *nodal=_nodal_connec->begin();
6765 const mcIdType *nodalI=_nodal_connec_index->begin();
6766 const double *coor=_coords->begin();
6767 for(const mcIdType *w=begin;w!=end;w++)
6769 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[*w]];
6770 INTERP_KERNEL::computeBarycenter2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[*w]+1,nodalI[*w+1]-nodalI[*w]-1,coor,spaceDim,ptToFill);
6778 * 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".
6779 * So the returned instance will have 4 components and \c this->getNumberOfCells() tuples.
6780 * So this method expects that \a this has a spaceDimension equal to 3 and meshDimension equal to 2.
6781 * The computation of the plane equation is done using each time the 3 first nodes of 2D cells.
6782 * This method is useful to detect 2D cells in 3D space that are not coplanar.
6784 * \return DataArrayDouble * - a new instance of DataArrayDouble having 4 components and a number of tuples equal to number of cells in \a this.
6785 * \throw If spaceDim!=3 or meshDim!=2.
6786 * \throw If connectivity of \a this is invalid.
6787 * \throw If connectivity of a cell in \a this points to an invalid node.
6789 DataArrayDouble *MEDCouplingUMesh::computePlaneEquationOf3DFaces() const
6791 MCAuto<DataArrayDouble> ret(DataArrayDouble::New());
6792 mcIdType nbOfCells=getNumberOfCells();
6793 mcIdType nbOfNodes(getNumberOfNodes());
6794 if(getSpaceDimension()!=3 || getMeshDimension()!=2)
6795 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computePlaneEquationOf3DFaces : This method must be applied on a mesh having meshDimension equal 2 and a spaceDimension equal to 3 !");
6796 ret->alloc(nbOfCells,4);
6797 double *retPtr(ret->getPointer());
6798 const mcIdType *nodal(_nodal_connec->begin()),*nodalI(_nodal_connec_index->begin());
6799 const double *coor(_coords->begin());
6800 for(mcIdType i=0;i<nbOfCells;i++,nodalI++,retPtr+=4)
6802 double matrix[16]={0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,0},matrix2[16];
6803 if(nodalI[1]-nodalI[0]>=4)
6805 double aa[3]={coor[nodal[nodalI[0]+1+1]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6806 coor[nodal[nodalI[0]+1+1]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6807 coor[nodal[nodalI[0]+1+1]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]}
6808 ,bb[3]={coor[nodal[nodalI[0]+1+2]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6809 coor[nodal[nodalI[0]+1+2]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6810 coor[nodal[nodalI[0]+1+2]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]};
6811 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]};
6812 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]));
6813 for(int j=0;j<3;j++)
6815 mcIdType nodeId(nodal[nodalI[0]+1+j]);
6816 if(nodeId>=0 && nodeId<nbOfNodes)
6817 std::copy(coor+nodeId*3,coor+(nodeId+1)*3,matrix+4*j);
6820 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! This cell points to an invalid nodeId : " << nodeId << " !";
6821 throw INTERP_KERNEL::Exception(oss.str());
6824 if(sqrt(cc[0]*cc[0]+cc[1]*cc[1]+cc[2]*cc[2])>(1e-3*aa_norm*bb_norm))
6826 INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6827 retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6831 if(nodalI[1]-nodalI[0]==4)
6833 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : cell" << i << " : Presence of The 3 colinear points !";
6834 throw INTERP_KERNEL::Exception(oss.str());
6837 double dd[3]={0.,0.,0.};
6838 for(mcIdType offset=nodalI[0]+1;offset<nodalI[1];offset++)
6839 std::transform(coor+3*nodal[offset],coor+3*(nodal[offset]+1),dd,dd,std::plus<double>());
6840 mcIdType nbOfNodesInCell(nodalI[1]-nodalI[0]-1);
6841 std::transform(dd,dd+3,dd,std::bind(std::multiplies<double>(),std::placeholders::_1,1./(double)nbOfNodesInCell));
6842 std::copy(dd,dd+3,matrix+4*2);
6843 INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6844 retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6849 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! Must be constitued by more than 3 nodes !";
6850 throw INTERP_KERNEL::Exception(oss.str());
6857 * This method expects as input a DataArrayDouble non nul instance 'da' that should be allocated. If not an exception is thrown.
6860 MEDCouplingUMesh *MEDCouplingUMesh::Build0DMeshFromCoords(DataArrayDouble *da)
6863 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build0DMeshFromCoords : instance of DataArrayDouble must be not null !");
6864 da->checkAllocated();
6865 std::string name(da->getName());
6866 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New(name,0));
6868 ret->setName("Mesh");
6870 mcIdType nbOfTuples(da->getNumberOfTuples());
6871 MCAuto<DataArrayIdType> c(DataArrayIdType::New()),cI(DataArrayIdType::New());
6872 c->alloc(2*nbOfTuples,1);
6873 cI->alloc(nbOfTuples+1,1);
6874 mcIdType *cp(c->getPointer()),*cip(cI->getPointer());
6876 for(mcIdType i=0;i<nbOfTuples;i++)
6878 *cp++=INTERP_KERNEL::NORM_POINT1;
6882 ret->setConnectivity(c,cI,true);
6886 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::Build1DMeshFromCoords(DataArrayDouble *da)
6889 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build01MeshFromCoords : instance of DataArrayDouble must be not null !");
6890 da->checkAllocated();
6891 std::string name(da->getName());
6892 MCAuto<MEDCouplingUMesh> ret;
6894 MCAuto<MEDCouplingCMesh> tmp(MEDCouplingCMesh::New());
6895 MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
6896 arr->alloc(da->getNumberOfTuples());
6897 tmp->setCoordsAt(0,arr);
6898 ret=tmp->buildUnstructured();
6902 ret->setName("Mesh");
6909 * Creates a new MEDCouplingUMesh by concatenating two given meshes of the same dimension.
6910 * Cells and nodes of
6911 * the first mesh precede cells and nodes of the second mesh within the result mesh.
6912 * \param [in] mesh1 - the first mesh.
6913 * \param [in] mesh2 - the second mesh.
6914 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6915 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6916 * is no more needed.
6917 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
6918 * \throw If the coordinates array is not set in none of the meshes.
6919 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
6920 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
6922 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
6924 std::vector<const MEDCouplingUMesh *> tmp(2);
6925 tmp[0]=const_cast<MEDCouplingUMesh *>(mesh1); tmp[1]=const_cast<MEDCouplingUMesh *>(mesh2);
6926 return MergeUMeshes(tmp);
6930 * Creates a new MEDCouplingUMesh by concatenating all given meshes of the same dimension.
6931 * Cells and nodes of
6932 * the *i*-th mesh precede cells and nodes of the (*i*+1)-th mesh within the result mesh.
6933 * \param [in] a - a vector of meshes (MEDCouplingUMesh) to concatenate.
6934 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6935 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6936 * is no more needed.
6937 * \throw If \a a.size() == 0.
6938 * \throw If \a a[ *i* ] == NULL.
6939 * \throw If the coordinates array is not set in none of the meshes.
6940 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
6941 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
6943 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const std::vector<const MEDCouplingUMesh *>& a)
6945 std::size_t sz=a.size();
6947 return MergeUMeshesLL(a);
6948 for(std::size_t ii=0;ii<sz;ii++)
6951 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshes : item #" << ii << " in input array of size "<< sz << " is empty !";
6952 throw INTERP_KERNEL::Exception(oss.str());
6954 std::vector< MCAuto<MEDCouplingUMesh> > bb(sz);
6955 std::vector< const MEDCouplingUMesh * > aa(sz);
6957 for(std::size_t i=0;i<sz && spaceDim==-3;i++)
6959 const MEDCouplingUMesh *cur=a[i];
6960 const DataArrayDouble *coo=cur->getCoords();
6962 spaceDim=int(coo->getNumberOfComponents());
6965 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : no spaceDim specified ! unable to perform merge !");
6966 for(std::size_t i=0;i<sz;i++)
6968 bb[i]=a[i]->buildSetInstanceFromThis(spaceDim);
6971 return MergeUMeshesLL(aa);
6975 * Creates a new MEDCouplingUMesh by concatenating cells of two given meshes of same
6976 * dimension and sharing the node coordinates array.
6977 * All cells of the first mesh precede all cells of the second mesh
6978 * within the result mesh.
6979 * \param [in] mesh1 - the first mesh.
6980 * \param [in] mesh2 - the second mesh.
6981 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6982 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6983 * is no more needed.
6984 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
6985 * \throw If the meshes do not share the node coordinates array.
6986 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
6987 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
6989 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
6991 std::vector<const MEDCouplingUMesh *> tmp(2);
6992 tmp[0]=mesh1; tmp[1]=mesh2;
6993 return MergeUMeshesOnSameCoords(tmp);
6997 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
6998 * dimension and sharing the node coordinates array.
6999 * All cells of the *i*-th mesh precede all cells of the
7000 * (*i*+1)-th mesh within the result mesh.
7001 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
7002 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7003 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7004 * is no more needed.
7005 * \throw If \a a.size() == 0.
7006 * \throw If \a a[ *i* ] == NULL.
7007 * \throw If the meshes do not share the node coordinates array.
7008 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
7009 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
7011 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes)
7014 throw INTERP_KERNEL::Exception("meshes input parameter is expected to be non empty.");
7015 for(std::size_t ii=0;ii<meshes.size();ii++)
7018 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshesOnSameCoords : item #" << ii << " in input array of size "<< meshes.size() << " is empty !";
7019 throw INTERP_KERNEL::Exception(oss.str());
7021 const DataArrayDouble *coords=meshes.front()->getCoords();
7022 int meshDim=meshes.front()->getMeshDimension();
7023 std::vector<const MEDCouplingUMesh *>::const_iterator iter=meshes.begin();
7024 mcIdType meshLgth=0;
7025 mcIdType meshIndexLgth=0;
7026 for(;iter!=meshes.end();iter++)
7028 if(coords!=(*iter)->getCoords())
7029 throw INTERP_KERNEL::Exception("meshes does not share the same coords ! Try using tryToShareSameCoords method !");
7030 if(meshDim!=(*iter)->getMeshDimension())
7031 throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, FuseUMeshesOnSameCoords impossible !");
7032 meshLgth+=(*iter)->getNodalConnectivityArrayLen();
7033 meshIndexLgth+=(*iter)->getNumberOfCells();
7035 MCAuto<DataArrayIdType> nodal=DataArrayIdType::New();
7036 nodal->alloc(meshLgth,1);
7037 mcIdType *nodalPtr=nodal->getPointer();
7038 MCAuto<DataArrayIdType> nodalIndex=DataArrayIdType::New();
7039 nodalIndex->alloc(meshIndexLgth+1,1);
7040 mcIdType *nodalIndexPtr=nodalIndex->getPointer();
7042 for(iter=meshes.begin();iter!=meshes.end();iter++)
7044 const mcIdType *nod=(*iter)->getNodalConnectivity()->begin();
7045 const mcIdType *index=(*iter)->getNodalConnectivityIndex()->begin();
7046 mcIdType nbOfCells=(*iter)->getNumberOfCells();
7047 mcIdType meshLgth2=(*iter)->getNodalConnectivityArrayLen();
7048 nodalPtr=std::copy(nod,nod+meshLgth2,nodalPtr);
7049 if(iter!=meshes.begin())
7050 nodalIndexPtr=std::transform(index+1,index+nbOfCells+1,nodalIndexPtr,std::bind(std::plus<mcIdType>(),std::placeholders::_1,offset));
7052 nodalIndexPtr=std::copy(index,index+nbOfCells+1,nodalIndexPtr);
7055 MEDCouplingUMesh *ret=MEDCouplingUMesh::New();
7056 ret->setName("merge");
7057 ret->setMeshDimension(meshDim);
7058 ret->setConnectivity(nodal,nodalIndex,true);
7059 ret->setCoords(coords);
7064 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
7065 * dimension and sharing the node coordinates array. Cells of the *i*-th mesh precede
7066 * cells of the (*i*+1)-th mesh within the result mesh. Duplicates of cells are
7067 * removed from \a this mesh and arrays mapping between new and old cell ids in "Old to
7068 * New" mode are returned for each input mesh.
7069 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
7070 * \param [in] compType - specifies a cell comparison technique. For meaning of its
7071 * valid values [0,1,2], see zipConnectivityTraducer().
7072 * \param [in,out] corr - an array of DataArrayIdType, of the same size as \a
7073 * meshes. The *i*-th array describes cell ids mapping for \a meshes[ *i* ]
7074 * mesh. The caller is to delete each of the arrays using decrRef() as it is
7076 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7077 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7078 * is no more needed.
7079 * \throw If \a meshes.size() == 0.
7080 * \throw If \a meshes[ *i* ] == NULL.
7081 * \throw If the meshes do not share the node coordinates array.
7082 * \throw If \a meshes[ *i* ]->getMeshDimension() < 0.
7083 * \throw If the \a meshes are of different dimension (getMeshDimension()).
7084 * \throw If the nodal connectivity of cells of any of \a meshes is not defined.
7085 * \throw If the nodal connectivity any of \a meshes includes an invalid id.
7087 MEDCouplingUMesh *MEDCouplingUMesh::FuseUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes, int compType, std::vector<DataArrayIdType *>& corr)
7089 //All checks are delegated to MergeUMeshesOnSameCoords
7090 MCAuto<MEDCouplingUMesh> ret=MergeUMeshesOnSameCoords(meshes);
7091 MCAuto<DataArrayIdType> o2n=ret->zipConnectivityTraducer(compType);
7092 corr.resize(meshes.size());
7093 std::size_t nbOfMeshes=meshes.size();
7095 const mcIdType *o2nPtr=o2n->begin();
7096 for(std::size_t i=0;i<nbOfMeshes;i++)
7098 DataArrayIdType *tmp=DataArrayIdType::New();
7099 mcIdType curNbOfCells=meshes[i]->getNumberOfCells();
7100 tmp->alloc(curNbOfCells,1);
7101 std::copy(o2nPtr+offset,o2nPtr+offset+curNbOfCells,tmp->getPointer());
7102 offset+=curNbOfCells;
7103 tmp->setName(meshes[i]->getName());
7110 * Makes all given meshes share the nodal connectivity array. The common connectivity
7111 * array is created by concatenating the connectivity arrays of all given meshes. All
7112 * the given meshes must be of the same space dimension but dimension of cells **can
7113 * differ**. This method is particularly useful in MEDLoader context to build a \ref
7114 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
7115 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
7116 * \param [in,out] meshes - a vector of meshes to update.
7117 * \throw If any of \a meshes is NULL.
7118 * \throw If the coordinates array is not set in any of \a meshes.
7119 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
7120 * \throw If \a meshes are of different space dimension.
7122 void MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords(const std::vector<MEDCouplingUMesh *>& meshes)
7124 std::size_t sz=meshes.size();
7127 std::vector< const DataArrayDouble * > coords(meshes.size());
7128 std::vector< const DataArrayDouble * >::iterator it2=coords.begin();
7129 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++,it2++)
7133 (*it)->checkConnectivityFullyDefined();
7134 const DataArrayDouble *coo=(*it)->getCoords();
7139 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
7140 oss << " has no coordinate array defined !";
7141 throw INTERP_KERNEL::Exception(oss.str());
7146 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
7147 oss << " is null !";
7148 throw INTERP_KERNEL::Exception(oss.str());
7151 MCAuto<DataArrayDouble> res=DataArrayDouble::Aggregate(coords);
7152 std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();
7153 mcIdType offset=(*it)->getNumberOfNodes();
7154 (*it++)->setCoords(res);
7155 for(;it!=meshes.end();it++)
7157 mcIdType oldNumberOfNodes=(*it)->getNumberOfNodes();
7158 (*it)->setCoords(res);
7159 (*it)->shiftNodeNumbersInConn(offset);
7160 offset+=oldNumberOfNodes;
7165 * Merges nodes coincident with a given precision within all given meshes that share
7166 * the nodal connectivity array. The given meshes **can be of different** mesh
7167 * dimension. This method is particularly useful in MEDLoader context to build a \ref
7168 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
7169 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
7170 * \param [in,out] meshes - a vector of meshes to update.
7171 * \param [in] eps - the precision used to detect coincident nodes (infinite norm).
7172 * \throw If any of \a meshes is NULL.
7173 * \throw If the \a meshes do not share the same node coordinates array.
7174 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
7176 void MEDCouplingUMesh::MergeNodesOnUMeshesSharingSameCoords(const std::vector<MEDCouplingUMesh *>& meshes, double eps)
7180 std::set<const DataArrayDouble *> s;
7181 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
7184 s.insert((*it)->getCoords());
7187 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 !";
7188 throw INTERP_KERNEL::Exception(oss.str());
7193 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 !";
7194 throw INTERP_KERNEL::Exception(oss.str());
7196 const DataArrayDouble *coo=*(s.begin());
7200 DataArrayIdType *comm,*commI;
7201 coo->findCommonTuples(eps,-1,comm,commI);
7202 MCAuto<DataArrayIdType> tmp1(comm),tmp2(commI);
7203 mcIdType oldNbOfNodes=coo->getNumberOfTuples();
7204 mcIdType newNbOfNodes;
7205 MCAuto<DataArrayIdType> o2n=DataArrayIdType::ConvertIndexArrayToO2N(oldNbOfNodes,comm->begin(),commI->begin(),commI->end(),newNbOfNodes);
7206 if(oldNbOfNodes==newNbOfNodes)
7208 MCAuto<DataArrayDouble> newCoords=coo->renumberAndReduce(o2n->begin(),newNbOfNodes);
7209 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
7211 (*it)->renumberNodesInConn(o2n->begin());
7212 (*it)->setCoords(newCoords);
7218 * This static operates only for coords in 3D. The polygon is specified by its connectivity nodes in [ \a begin , \a end ).
7220 bool MEDCouplingUMesh::IsPolygonWellOriented(bool isQuadratic, const double *vec, const mcIdType *begin, const mcIdType *end, const double *coords)
7223 double v[3]={0.,0.,0.};
7224 std::size_t sz=std::distance(begin,end);
7228 // Algorithm: sum in v the cross products of (e1, e2) where e_i it the vector between (0,0,0) and point i
7229 // and e2 is linear point directly following e1 in the connectivity. All points are used.
7230 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];
7231 v[1]+=coords[3*begin[i]+2]*coords[3*begin[(i+1)%sz]]-coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+2];
7232 v[2]+=coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+1]-coords[3*begin[i]+1]*coords[3*begin[(i+1)%sz]];
7236 // Same algorithm as above but also using intermediate quadratic points.
7237 // (taking only linear points might lead to issues if the linearized version of the
7238 // polygon is not convex or self-intersecting ... see testCellOrientation4)
7239 std::size_t hsz = sz/2;
7240 for(std::size_t j=0;j<sz;j++)
7242 if (j%2) // current point i is quadratic, next point i+1 is standard
7245 ip1 = ((j-1)/2 + 1)%hsz; // ip1 means "i+1", i.e. next point
7247 else // current point i is standard, next point i+1 is quadratic
7252 v[0]+=coords[3*begin[i]+1]*coords[3*begin[ip1]+2]-coords[3*begin[i]+2]*coords[3*begin[ip1]+1];
7253 v[1]+=coords[3*begin[i]+2]*coords[3*begin[ip1]]-coords[3*begin[i]]*coords[3*begin[ip1]+2];
7254 v[2]+=coords[3*begin[i]]*coords[3*begin[ip1]+1]-coords[3*begin[i]+1]*coords[3*begin[ip1]];
7257 double ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
7262 * The polyhedron is specified by its connectivity nodes in [ \a begin , \a end ).
7264 bool MEDCouplingUMesh::IsPolyhedronWellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7266 std::vector<std::pair<mcIdType,mcIdType> > edges;
7267 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
7268 const mcIdType *bgFace=begin;
7269 for(std::size_t i=0;i<nbOfFaces;i++)
7271 const mcIdType *endFace=std::find(bgFace+1,end,-1);
7272 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
7273 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7275 std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7276 if(std::find(edges.begin(),edges.end(),p1)!=edges.end())
7278 edges.push_back(p1);
7282 return INTERP_KERNEL::calculateVolumeForPolyh2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,ToIdType(std::distance(begin,end)),coords)>-EPS_FOR_POLYH_ORIENTATION;
7286 * The 3D extruded static cell (PENTA6,HEXA8,HEXAGP12...) its connectivity nodes in [ \a begin , \a end ).
7288 bool MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7290 double vec0[3],vec1[3];
7291 std::size_t sz=std::distance(begin,end);
7293 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented : the length of nodal connectivity of extruded cell is not even !");
7294 mcIdType nbOfNodes=ToIdType(sz/2);
7295 INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,nbOfNodes,coords,vec0);
7296 const double *pt0=coords+3*begin[0];
7297 const double *pt1=coords+3*begin[nbOfNodes];
7298 vec1[0]=pt1[0]-pt0[0]; vec1[1]=pt1[1]-pt0[1]; vec1[2]=pt1[2]-pt0[2];
7299 return (vec0[0]*vec1[0]+vec0[1]*vec1[1]+vec0[2]*vec1[2])<0.;
7302 void MEDCouplingUMesh::CorrectExtrudedStaticCell(mcIdType *begin, mcIdType *end)
7304 std::size_t sz=std::distance(begin,end);
7305 INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz];
7306 std::size_t nbOfNodes(sz/2);
7307 std::copy(begin,end,(mcIdType *)tmp);
7308 for(std::size_t j=1;j<nbOfNodes;j++)
7310 begin[j]=tmp[nbOfNodes-j];
7311 begin[j+nbOfNodes]=tmp[nbOfNodes+nbOfNodes-j];
7315 bool MEDCouplingUMesh::IsTetra4WellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7317 std::size_t sz=std::distance(begin,end);
7319 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsTetra4WellOriented : Tetra4 cell with not 4 nodes ! Call checkConsistency !");
7320 double vec0[3],vec1[3];
7321 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[1],*pt2=coords+3*begin[2],*pt3=coords+3*begin[3];
7322 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];
7323 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;
7326 bool MEDCouplingUMesh::IsPyra5WellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7328 std::size_t sz=std::distance(begin,end);
7330 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsPyra5WellOriented : Pyra5 cell with not 5 nodes ! Call checkConsistency !");
7332 INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,4,coords,vec0);
7333 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[4];
7334 return (vec0[0]*(pt1[0]-pt0[0])+vec0[1]*(pt1[1]-pt0[1])+vec0[2]*(pt1[2]-pt0[2]))<0.;
7338 * 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 )
7339 * 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
7342 * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not.
7343 * \param [in] coords the coordinates with nb of components exactly equal to 3
7344 * \param [in] index begin of the nodal connectivity (geometric type included) of a single polyhedron cell
7345 * \param [out] res the result is put at the end of the vector without any alteration of the data.
7347 void MEDCouplingUMesh::SimplifyPolyhedronCell(double eps, const DataArrayDouble *coords, mcIdType index, DataArrayIdType *res, MEDCouplingUMesh *faces,
7348 DataArrayIdType *E_Fi, DataArrayIdType *E_F, DataArrayIdType *F_Ei, DataArrayIdType *F_E)
7350 mcIdType nbFaces = E_Fi->getIJ(index + 1, 0) - E_Fi->getIJ(index, 0);
7351 MCAuto<DataArrayDouble> v=DataArrayDouble::New(); v->alloc(nbFaces,3);
7352 double *vPtr=v->getPointer();
7353 MCAuto<DataArrayDouble> p=DataArrayDouble::New(); p->alloc(nbFaces,2);
7354 double *pPtr=p->getPointer();
7355 mcIdType *e_fi = E_Fi->getPointer(), *e_f = E_F->getPointer(), *f_ei = F_Ei->getPointer(), *f_e = F_E->getPointer();
7356 const mcIdType *f_idx = faces->getNodalConnectivityIndex()->getPointer(), *f_cnn = faces->getNodalConnectivity()->getPointer();
7357 for(mcIdType i=0;i<nbFaces;i++,vPtr+=3,pPtr++)
7359 mcIdType face = e_f[e_fi[index] + i];
7360 ComputeVecAndPtOfFace(eps, coords->begin(), f_cnn + f_idx[face] + 1, f_cnn + f_idx[face + 1], vPtr, pPtr);
7361 // to differentiate faces going to different cells:
7363 for (mcIdType j = f_ei[face]; j < f_ei[face + 1]; j++)
7364 *pPtr += FromIdType<double>(f_e[j]);
7366 pPtr=p->getPointer(); vPtr=v->getPointer();
7367 DataArrayIdType *comm1=0,*commI1=0;
7368 v->findCommonTuples(eps,-1,comm1,commI1);
7369 for (mcIdType i = 0; i < nbFaces; i++)
7370 if (comm1->findIdFirstEqual(i) < 0)
7372 comm1->pushBackSilent(i);
7373 commI1->pushBackSilent(comm1->getNumberOfTuples());
7375 MCAuto<DataArrayIdType> comm1Auto(comm1),commI1Auto(commI1);
7376 const mcIdType *comm1Ptr=comm1->begin();
7377 const mcIdType *commI1Ptr=commI1->begin();
7378 mcIdType nbOfGrps1=commI1Auto->getNumberOfTuples()-1;
7379 res->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYHED));
7381 for(mcIdType i=0;i<nbOfGrps1;i++)
7383 mcIdType vecId=comm1Ptr[commI1Ptr[i]];
7384 MCAuto<DataArrayDouble> tmpgrp2=p->selectByTupleId(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7385 DataArrayIdType *comm2=0,*commI2=0;
7386 tmpgrp2->findCommonTuples(eps,-1,comm2,commI2);
7387 for (mcIdType j = 0; j < commI1Ptr[i+1] - commI1Ptr[i]; j++)
7388 if (comm2->findIdFirstEqual(j) < 0)
7390 comm2->pushBackSilent(j);
7391 commI2->pushBackSilent(comm2->getNumberOfTuples());
7393 MCAuto<DataArrayIdType> comm2Auto(comm2),commI2Auto(commI2);
7394 const mcIdType *comm2Ptr=comm2->begin();
7395 const mcIdType *commI2Ptr=commI2->begin();
7396 mcIdType nbOfGrps2=commI2Auto->getNumberOfTuples()-1;
7397 for(mcIdType j=0;j<nbOfGrps2;j++)
7399 if(commI2Ptr[j+1] == commI2Ptr[j] + 1)
7401 mcIdType face = e_f[e_fi[index] + comm1Ptr[commI1Ptr[i] + comm2Ptr[commI2Ptr[j]]]]; //hmmm
7402 res->insertAtTheEnd(f_cnn + f_idx[face] + 1, f_cnn + f_idx[face + 1]);
7403 res->pushBackSilent(-1);
7407 mcIdType pointId=comm1Ptr[commI1Ptr[i]+comm2Ptr[commI2Ptr[j]]];
7408 MCAuto<DataArrayIdType> ids2=comm2->selectByTupleIdSafeSlice(commI2Ptr[j],commI2Ptr[j+1],1);
7409 ids2->transformWithIndArr(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7410 ids2->transformWithIndArr(e_f + e_fi[index], e_f + e_fi[index + 1]);
7411 MCAuto<MEDCouplingUMesh> mm3=static_cast<MEDCouplingUMesh *>(faces->buildPartOfMySelf(ids2->begin(),ids2->end(),true));
7412 MCAuto<DataArrayIdType> idsNodeTmp=mm3->zipCoordsTraducer();
7413 MCAuto<DataArrayIdType> idsNode=idsNodeTmp->invertArrayO2N2N2O(mm3->getNumberOfNodes());
7414 const mcIdType *idsNodePtr=idsNode->begin();
7415 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];
7416 double vec[3]; vec[0]=vPtr[3*vecId+1]; vec[1]=-vPtr[3*vecId]; vec[2]=0.;
7417 double norm=vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2];
7418 if(std::abs(norm)>eps)
7420 double angle=INTERP_KERNEL::EdgeArcCircle::SafeAsin(norm);
7421 mm3->rotate(center,vec,angle);
7423 mm3->changeSpaceDimension(2);
7424 MCAuto<MEDCouplingUMesh> mm4=mm3->buildSpreadZonesWithPoly();
7425 const mcIdType *conn4=mm4->getNodalConnectivity()->begin();
7426 const mcIdType *connI4=mm4->getNodalConnectivityIndex()->begin();
7427 mcIdType nbOfCells=mm4->getNumberOfCells();
7428 for(mcIdType k=0;k<nbOfCells;k++)
7431 for(const mcIdType *work=conn4+connI4[k]+1;work!=conn4+connI4[k+1];work++,l++)
7432 res->pushBackSilent(idsNodePtr[*work]);
7433 res->pushBackSilent(-1);
7438 res->popBackSilent();
7442 * 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
7443 * through origin. The plane is defined by its nodal connectivity [ \b begin, \b end ).
7445 * \param [in] eps below that value the dot product of 2 vectors is considered as colinears
7446 * \param [in] coords coordinates expected to have 3 components.
7447 * \param [in] begin start of the nodal connectivity of the face.
7448 * \param [in] end end of the nodal connectivity (excluded) of the face.
7449 * \param [out] v the normalized vector of size 3
7450 * \param [out] p the pos of plane
7452 void MEDCouplingUMesh::ComputeVecAndPtOfFace(double eps, const double *coords, const mcIdType *begin, const mcIdType *end, double *v, double *p)
7454 std::size_t nbPoints=std::distance(begin,end);
7456 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeVecAndPtOfFace : < of 3 points in face ! not able to find a plane on that face !");
7457 double vec[3]={0.,0.,0.};
7459 bool refFound=false;
7460 for(;j<nbPoints-1 && !refFound;j++)
7462 vec[0]=coords[3*begin[j+1]]-coords[3*begin[j]];
7463 vec[1]=coords[3*begin[j+1]+1]-coords[3*begin[j]+1];
7464 vec[2]=coords[3*begin[j+1]+2]-coords[3*begin[j]+2];
7465 double norm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
7469 vec[0]/=norm; vec[1]/=norm; vec[2]/=norm;
7472 for(std::size_t i=j;i<nbPoints-1;i++)
7475 curVec[0]=coords[3*begin[i+1]]-coords[3*begin[i]];
7476 curVec[1]=coords[3*begin[i+1]+1]-coords[3*begin[i]+1];
7477 curVec[2]=coords[3*begin[i+1]+2]-coords[3*begin[i]+2];
7478 double norm=sqrt(curVec[0]*curVec[0]+curVec[1]*curVec[1]+curVec[2]*curVec[2]);
7481 curVec[0]/=norm; curVec[1]/=norm; curVec[2]/=norm;
7482 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];
7483 norm=sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
7486 v[0]/=norm; v[1]/=norm; v[2]/=norm;
7487 *p=v[0]*coords[3*begin[i]]+v[1]*coords[3*begin[i]+1]+v[2]*coords[3*begin[i]+2];
7491 throw INTERP_KERNEL::Exception("Not able to find a normal vector of that 3D face !");
7495 * This method tries to obtain a well oriented polyhedron.
7496 * If the algorithm fails, an exception will be thrown.
7498 void MEDCouplingUMesh::TryToCorrectPolyhedronOrientation(mcIdType *begin, mcIdType *end, const double *coords)
7500 std::list< std::pair<mcIdType,mcIdType> > edgesOK,edgesFinished;
7501 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
7502 std::vector<bool> isPerm(nbOfFaces,false);//field on faces False: I don't know, True : oriented
7504 mcIdType *bgFace=begin,*endFace=std::find(begin+1,end,-1);
7505 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
7506 for(std::size_t l=0;l<nbOfEdgesInFace;l++) { std::pair<mcIdType,mcIdType> p1(bgFace[l],bgFace[(l+1)%nbOfEdgesInFace]); edgesOK.push_back(p1); }
7508 while(std::find(isPerm.begin(),isPerm.end(),false)!=isPerm.end())
7511 std::size_t smthChanged=0;
7512 for(std::size_t i=0;i<nbOfFaces;i++)
7514 endFace=std::find(bgFace+1,end,-1);
7515 nbOfEdgesInFace=std::distance(bgFace,endFace);
7519 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7521 std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7522 std::pair<mcIdType,mcIdType> p2(p1.second,p1.first);
7523 bool b1=std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end();
7524 bool b2=std::find(edgesOK.begin(),edgesOK.end(),p2)!=edgesOK.end();
7525 if(b1 || b2) { b=b2; isPerm[i]=true; smthChanged++; break; }
7530 std::reverse(bgFace+1,endFace);
7531 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7533 std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7534 std::pair<mcIdType,mcIdType> p2(p1.second,p1.first);
7535 if(std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end())
7536 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7537 if(std::find(edgesFinished.begin(),edgesFinished.end(),p1)!=edgesFinished.end() || std::find(edgesFinished.begin(),edgesFinished.end(),p2)!=edgesFinished.end())
7538 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7539 std::list< std::pair<mcIdType,mcIdType> >::iterator it=std::find(edgesOK.begin(),edgesOK.end(),p2);
7540 if(it!=edgesOK.end())
7543 edgesFinished.push_back(p1);
7546 edgesOK.push_back(p1);
7553 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired !"); }
7555 if(!edgesOK.empty())
7556 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired : Some edges are shared only once !"); }
7557 if(INTERP_KERNEL::calculateVolumeForPolyh2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,ToIdType(std::distance(begin,end)),coords)<-EPS_FOR_POLYH_ORIENTATION)
7558 {//not lucky ! The first face was not correctly oriented : reorient all faces...
7560 for(std::size_t i=0;i<nbOfFaces;i++)
7562 endFace=std::find(bgFace+1,end,-1);
7563 std::reverse(bgFace+1,endFace);
7571 * This method makes the assumption spacedimension == meshdimension == 2.
7572 * This method works only for linear cells.
7574 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYGON in pos#0)
7576 DataArrayIdType *MEDCouplingUMesh::buildUnionOf2DMesh() const
7578 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
7579 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : meshdimension, spacedimension must be equal to 2 !");
7580 MCAuto<MEDCouplingUMesh> skin(computeSkin());
7581 mcIdType oldNbOfNodes(skin->getNumberOfNodes());
7582 MCAuto<DataArrayIdType> o2n(skin->zipCoordsTraducer());
7583 mcIdType nbOfNodesExpected(skin->getNumberOfNodes());
7584 MCAuto<DataArrayIdType> n2o(o2n->invertArrayO2N2N2O(oldNbOfNodes));
7585 mcIdType nbCells=skin->getNumberOfCells();
7586 if(nbCells==nbOfNodesExpected)
7587 return buildUnionOf2DMeshLinear(skin,n2o);
7588 else if(2*nbCells==nbOfNodesExpected)
7589 return buildUnionOf2DMeshQuadratic(skin,n2o);
7591 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : the mesh 2D in input appears to be not in a single part of a 2D mesh !");
7595 * This method makes the assumption spacedimension == meshdimension == 3.
7596 * This method works only for linear cells.
7598 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYHED in pos#0)
7600 DataArrayIdType *MEDCouplingUMesh::buildUnionOf3DMesh() const
7602 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
7603 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf3DMesh : meshdimension, spacedimension must be equal to 2 !");
7604 MCAuto<MEDCouplingUMesh> m=computeSkin();
7605 const mcIdType *conn=m->getNodalConnectivity()->begin();
7606 const mcIdType *connI=m->getNodalConnectivityIndex()->begin();
7607 mcIdType nbOfCells=m->getNumberOfCells();
7608 MCAuto<DataArrayIdType> ret=DataArrayIdType::New(); ret->alloc(m->getNodalConnectivity()->getNumberOfTuples(),1);
7609 mcIdType *work=ret->getPointer(); *work++=INTERP_KERNEL::NORM_POLYHED;
7612 work=std::copy(conn+connI[0]+1,conn+connI[1],work);
7613 for(mcIdType i=1;i<nbOfCells;i++)
7616 work=std::copy(conn+connI[i]+1,conn+connI[i+1],work);
7622 * \brief Creates a graph of cell neighbors
7623 * \return MEDCouplingSkyLineArray * - an sky line array the user should delete.
7624 * In the sky line array, graph arcs are stored in terms of (index,value) notation.
7626 * - index: 0 3 5 6 6
7627 * - value: 1 2 3 2 3 3
7628 * means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7629 * Arcs are not doubled but reflexive (1,1) arcs are present for each cell
7631 MEDCouplingSkyLineArray* MEDCouplingUMesh::generateGraph() const
7633 checkConnectivityFullyDefined();
7635 int meshDim = this->getMeshDimension();
7636 MEDCoupling::DataArrayIdType* indexr=MEDCoupling::DataArrayIdType::New();
7637 MEDCoupling::DataArrayIdType* revConn=MEDCoupling::DataArrayIdType::New();
7638 this->getReverseNodalConnectivity(revConn,indexr);
7639 const mcIdType* indexr_ptr=indexr->begin();
7640 const mcIdType* revConn_ptr=revConn->begin();
7642 const MEDCoupling::DataArrayIdType* index;
7643 const MEDCoupling::DataArrayIdType* conn;
7644 conn=this->getNodalConnectivity(); // it includes a type as the 1st element!!!
7645 index=this->getNodalConnectivityIndex();
7646 mcIdType nbCells=this->getNumberOfCells();
7647 const mcIdType* index_ptr=index->begin();
7648 const mcIdType* conn_ptr=conn->begin();
7650 //creating graph arcs (cell to cell relations)
7651 //arcs are stored in terms of (index,value) notation
7654 // means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7655 // in present version arcs are not doubled but reflexive (1,1) arcs are present for each cell
7657 //warning here one node have less than or equal effective number of cell with it
7658 //but cell could have more than effective nodes
7659 //because other equals nodes in other domain (with other global inode)
7660 std::vector <mcIdType> cell2cell_index(nbCells+1,0);
7661 std::vector <mcIdType> cell2cell;
7662 cell2cell.reserve(3*nbCells);
7664 for (mcIdType icell=0; icell<nbCells;icell++)
7666 std::map<mcIdType,mcIdType > counter;
7667 for (mcIdType iconn=index_ptr[icell]+1; iconn<index_ptr[icell+1];iconn++)
7669 mcIdType inode=conn_ptr[iconn];
7670 for (mcIdType iconnr=indexr_ptr[inode]; iconnr<indexr_ptr[inode+1];iconnr++)
7672 mcIdType icell2=revConn_ptr[iconnr];
7673 std::map<mcIdType,mcIdType>::iterator iter=counter.find(icell2);
7674 if (iter!=counter.end()) (iter->second)++;
7675 else counter.insert(std::make_pair(icell2,1));
7678 for (std::map<mcIdType,mcIdType>::const_iterator iter=counter.begin();
7679 iter!=counter.end(); iter++)
7680 if (iter->second >= meshDim)
7682 cell2cell_index[icell+1]++;
7683 cell2cell.push_back(iter->first);
7688 cell2cell_index[0]=0;
7689 for (mcIdType icell=0; icell<nbCells;icell++)
7690 cell2cell_index[icell+1]=cell2cell_index[icell]+cell2cell_index[icell+1];
7692 //filling up index and value to create skylinearray structure
7693 MEDCouplingSkyLineArray * array(MEDCouplingSkyLineArray::New(cell2cell_index,cell2cell));
7698 void MEDCouplingUMesh::writeVTKLL(std::ostream& ofs, const std::string& cellData, const std::string& pointData, DataArrayByte *byteData) const
7700 mcIdType nbOfCells=getNumberOfCells();
7702 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::writeVTK : the unstructured mesh has no cells !");
7703 ofs << " <" << getVTKDataSetType() << ">\n";
7704 ofs << " <Piece NumberOfPoints=\"" << getNumberOfNodes() << "\" NumberOfCells=\"" << nbOfCells << "\">\n";
7705 ofs << " <PointData>\n" << pointData << std::endl;
7706 ofs << " </PointData>\n";
7707 ofs << " <CellData>\n" << cellData << std::endl;
7708 ofs << " </CellData>\n";
7709 ofs << " <Points>\n";
7710 if(getSpaceDimension()==3)
7711 _coords->writeVTK(ofs,8,"Points",byteData);
7714 MCAuto<DataArrayDouble> coo=_coords->changeNbOfComponents(3,0.);
7715 coo->writeVTK(ofs,8,"Points",byteData);
7717 ofs << " </Points>\n";
7718 ofs << " <Cells>\n";
7719 const mcIdType *cPtr=_nodal_connec->begin();
7720 const mcIdType *cIPtr=_nodal_connec_index->begin();
7721 MCAuto<DataArrayIdType> faceoffsets=DataArrayIdType::New(); faceoffsets->alloc(nbOfCells,1);
7722 MCAuto<DataArrayIdType> types=DataArrayIdType::New(); types->alloc(nbOfCells,1);
7723 MCAuto<DataArrayIdType> offsets=DataArrayIdType::New(); offsets->alloc(nbOfCells,1);
7724 MCAuto<DataArrayIdType> connectivity=DataArrayIdType::New(); connectivity->alloc(_nodal_connec->getNumberOfTuples()-nbOfCells,1);
7725 mcIdType *w1=faceoffsets->getPointer(),*w2=types->getPointer(),*w3=offsets->getPointer(),*w4=connectivity->getPointer();
7726 mcIdType szFaceOffsets=0,szConn=0;
7727 for(mcIdType i=0;i<nbOfCells;i++,w1++,w2++,w3++)
7730 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]!=INTERP_KERNEL::NORM_POLYHED)
7733 *w3=szConn+cIPtr[i+1]-cIPtr[i]-1; szConn+=cIPtr[i+1]-cIPtr[i]-1;
7734 w4=std::copy(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],w4);
7738 mcIdType deltaFaceOffset=cIPtr[i+1]-cIPtr[i]+1;
7739 *w1=szFaceOffsets+deltaFaceOffset; szFaceOffsets+=deltaFaceOffset;
7740 std::set<mcIdType> c(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1]); c.erase(-1);
7741 *w3=szConn+ToIdType(c.size()); szConn+=ToIdType(c.size());
7742 w4=std::copy(c.begin(),c.end(),w4);
7745 std::unique_ptr<mcIdType[]> medcoupling2vtkTypeTraducer_mcIdType(new mcIdType[MEDCOUPLING2VTKTYPETRADUCER_LGTH]);
7746 for(auto ii = 0; ii<MEDCOUPLING2VTKTYPETRADUCER_LGTH ; ++ii)
7747 medcoupling2vtkTypeTraducer_mcIdType[ii] = MEDCOUPLING2VTKTYPETRADUCER[ii]!=MEDCOUPLING2VTKTYPETRADUCER_NONE?MEDCOUPLING2VTKTYPETRADUCER[ii] : -1;
7748 types->transformWithIndArr(medcoupling2vtkTypeTraducer_mcIdType.get(),medcoupling2vtkTypeTraducer_mcIdType.get()+MEDCOUPLING2VTKTYPETRADUCER_LGTH);
7749 types->writeVTK(ofs,8,"UInt8","types",byteData);
7750 std::string vtkTypeName = Traits<mcIdType>::VTKReprStr;
7751 offsets->writeVTK(ofs,8,vtkTypeName,"offsets",byteData);
7752 if(szFaceOffsets!=0)
7753 {//presence of Polyhedra
7754 connectivity->reAlloc(szConn);
7755 faceoffsets->writeVTK(ofs,8,vtkTypeName,"faceoffsets",byteData);
7756 MCAuto<DataArrayIdType> faces=DataArrayIdType::New(); faces->alloc(szFaceOffsets,1);
7757 w1=faces->getPointer();
7758 for(mcIdType i=0;i<nbOfCells;i++)
7759 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]==INTERP_KERNEL::NORM_POLYHED)
7761 mcIdType nbFaces=ToIdType(std::count(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],-1))+1;
7763 const mcIdType *w6=cPtr+cIPtr[i]+1,*w5=0;
7764 for(mcIdType j=0;j<nbFaces;j++)
7766 w5=std::find(w6,cPtr+cIPtr[i+1],-1);
7767 *w1++=ToIdType(std::distance(w6,w5));
7768 w1=std::copy(w6,w5,w1);
7772 faces->writeVTK(ofs,8,vtkTypeName,"faces",byteData);
7774 connectivity->writeVTK(ofs,8,vtkTypeName,"connectivity",byteData);
7775 ofs << " </Cells>\n";
7776 ofs << " </Piece>\n";
7777 ofs << " </" << getVTKDataSetType() << ">\n";
7780 void MEDCouplingUMesh::reprQuickOverview(std::ostream& stream) const
7782 stream << "MEDCouplingUMesh C++ instance at " << this << ". Name : \"" << getName() << "\".";
7784 { stream << " Not set !"; return ; }
7785 stream << " Mesh dimension : " << _mesh_dim << ".";
7789 { stream << " No coordinates set !"; return ; }
7790 if(!_coords->isAllocated())
7791 { stream << " Coordinates set but not allocated !"; return ; }
7792 stream << " Space dimension : " << _coords->getNumberOfComponents() << "." << std::endl;
7793 stream << "Number of nodes : " << _coords->getNumberOfTuples() << ".";
7794 if(!_nodal_connec_index)
7795 { stream << std::endl << "Nodal connectivity NOT set !"; return ; }
7796 if(!_nodal_connec_index->isAllocated())
7797 { stream << std::endl << "Nodal connectivity set but not allocated !"; return ; }
7798 mcIdType lgth=_nodal_connec_index->getNumberOfTuples();
7799 std::size_t cpt=_nodal_connec_index->getNumberOfComponents();
7800 if(cpt!=1 || lgth<1)
7802 stream << std::endl << "Number of cells : " << lgth-1 << ".";
7805 std::string MEDCouplingUMesh::getVTKDataSetType() const
7807 return std::string("UnstructuredGrid");
7810 std::string MEDCouplingUMesh::getVTKFileExtension() const
7812 return std::string("vtu");
7818 * Provides a renumbering of the cells of this (which has to be a piecewise connected 1D line), so that
7819 * the segments of the line are indexed in consecutive order (i.e. cells \a i and \a i+1 are neighbors).
7820 * This doesn't modify the mesh. This method only works using nodal connectivity consideration. Coordinates of nodes are ignored here.
7821 * The caller is to deal with the resulting DataArrayIdType.
7822 * \throw If the coordinate array is not set.
7823 * \throw If the nodal connectivity of the cells is not defined.
7824 * \throw If m1 is not a mesh of dimension 2, or m1 is not a mesh of dimension 1
7825 * \throw If m2 is not a (piecewise) line (i.e. if a point has more than 2 adjacent segments)
7827 * \sa DataArrayIdType::sortEachPairToMakeALinkedList
7829 DataArrayIdType *MEDCouplingUMesh::orderConsecutiveCells1D() const
7831 checkFullyDefined();
7832 if(getMeshDimension()!=1)
7833 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D works on unstructured mesh with meshdim = 1 !");
7835 // Check that this is a line (and not a more complex 1D mesh) - each point is used at most by 2 segments:
7836 MCAuto<DataArrayIdType> _d(DataArrayIdType::New()),_dI(DataArrayIdType::New());
7837 MCAuto<DataArrayIdType> _rD(DataArrayIdType::New()),_rDI(DataArrayIdType::New());
7838 MCAuto<MEDCouplingUMesh> m_points(buildDescendingConnectivity(_d, _dI, _rD, _rDI));
7839 const mcIdType *d(_d->begin()), *dI(_dI->begin());
7840 const mcIdType *rD(_rD->begin()), *rDI(_rDI->begin());
7841 MCAuto<DataArrayIdType> _dsi(_rDI->deltaShiftIndex());
7842 const mcIdType * dsi(_dsi->begin());
7843 MCAuto<DataArrayIdType> dsii = _dsi->findIdsNotInRange(0,3);
7845 if (dsii->getNumberOfTuples())
7846 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D only work with a mesh being a (piecewise) connected line!");
7848 mcIdType nc=getNumberOfCells();
7849 MCAuto<DataArrayIdType> result(DataArrayIdType::New());
7850 result->alloc(nc,1);
7852 // set of edges not used so far
7853 std::set<mcIdType> edgeSet;
7854 for (mcIdType i=0; i<nc; edgeSet.insert(i), i++);
7856 mcIdType startSeg=0;
7858 // while we have points with only one neighbor segments
7861 std::list<mcIdType> linePiece;
7862 // fills a list of consecutive segment linked to startSeg. This can go forward or backward.
7863 for (int direction=0;direction<2;direction++) // direction=0 --> forward, direction=1 --> backward
7865 // Fill the list forward (resp. backward) from the start segment:
7866 mcIdType activeSeg = startSeg;
7867 mcIdType prevPointId = -20;
7869 while (!edgeSet.empty())
7871 if (!(direction == 1 && prevPointId==-20)) // prevent adding twice startSeg
7874 linePiece.push_back(activeSeg);
7876 linePiece.push_front(activeSeg);
7877 edgeSet.erase(activeSeg);
7880 mcIdType ptId1 = d[dI[activeSeg]], ptId2 = d[dI[activeSeg]+1];
7881 ptId = direction ? (ptId1 == prevPointId ? ptId2 : ptId1) : (ptId2 == prevPointId ? ptId1 : ptId2);
7882 if (dsi[ptId] == 1) // hitting the end of the line
7886 mcIdType seg1 = rD[rDI[ptId]], seg2 = rD[rDI[ptId]+1];
7887 activeSeg = (seg1 == activeSeg) ? seg2 : seg1;
7889 //for piecewise meshes made up of closed parts
7890 bool segmentAlreadyTreated = (std::find(linePiece.begin(), linePiece.end(), activeSeg) != linePiece.end());
7891 if(segmentAlreadyTreated)
7895 // Done, save final piece into DA:
7896 std::copy(linePiece.begin(), linePiece.end(), result->getPointer()+newIdx);
7897 newIdx += ToIdType(linePiece.size());
7899 // identify next valid start segment (one which is not consumed)
7900 if(!edgeSet.empty())
7901 startSeg = *(edgeSet.begin());
7904 while (!edgeSet.empty());
7905 return result.retn();
7909 * This method split some of edges of 2D cells in \a this. The edges to be split are specified in \a subNodesInSeg
7910 * and in \a subNodesInSegI using \ref numbering-indirect storage mode.
7911 * To do the work this method can optionally needs information about middle of subedges for quadratic cases if
7912 * a minimal creation of new nodes is wanted.
7913 * So this method try to reduce at most the number of new nodes. The only case that can lead this method to add
7914 * nodes if a SEG3 is split without information of middle.
7915 * \b WARNING : is returned value is different from 0 a call to MEDCouplingUMesh::mergeNodes is necessary to
7916 * avoid to have a non conform mesh.
7918 * \return mcIdType - the number of new nodes created (in most of cases 0).
7920 * \throw If \a this is not coherent.
7921 * \throw If \a this has not spaceDim equal to 2.
7922 * \throw If \a this has not meshDim equal to 2.
7923 * \throw If some subcells needed to be split are orphan.
7924 * \sa MEDCouplingUMesh::conformize2D
7926 mcIdType MEDCouplingUMesh::split2DCells(const DataArrayIdType *desc, const DataArrayIdType *descI, const DataArrayIdType *subNodesInSeg, const DataArrayIdType *subNodesInSegI, const DataArrayIdType *midOpt, const DataArrayIdType *midOptI)
7928 if(!desc || !descI || !subNodesInSeg || !subNodesInSegI)
7929 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : the 4 first arrays must be not null !");
7930 desc->checkAllocated(); descI->checkAllocated(); subNodesInSeg->checkAllocated(); subNodesInSegI->checkAllocated();
7931 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
7932 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : This method only works for meshes with spaceDim=2 and meshDim=2 !");
7933 if(midOpt==0 && midOptI==0)
7935 split2DCellsLinear(desc,descI,subNodesInSeg,subNodesInSegI);
7938 else if(midOpt!=0 && midOptI!=0)
7939 return split2DCellsQuadratic(desc,descI,subNodesInSeg,subNodesInSegI,midOpt,midOptI);
7941 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : middle parameters must be set to null for all or not null for all.");
7945 * 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
7946 * 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
7947 * the geometric cell type set to INTERP_KERNEL::NORM_POLYGON.
7948 * 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
7949 * 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.
7951 * \return false if the input connectivity represents already the convex hull, true if the input cell needs to be reordered.
7953 bool MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis(const double *coords, const mcIdType *nodalConnBg, const mcIdType *nodalConnEnd, DataArrayIdType *nodalConnecOut)
7955 std::size_t sz=std::distance(nodalConnBg,nodalConnEnd);
7958 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)*nodalConnBg);
7959 if(cm.getDimension()==2)
7961 const mcIdType *node=nodalConnBg+1;
7962 mcIdType startNode=*node++;
7963 double refX=coords[2*startNode];
7964 for(;node!=nodalConnEnd;node++)
7966 if(coords[2*(*node)]<refX)
7969 refX=coords[2*startNode];
7972 std::vector<mcIdType> tmpOut; tmpOut.reserve(sz); tmpOut.push_back(startNode);
7976 double angle0=-M_PI/2;
7978 mcIdType nextNode=-1;
7979 mcIdType prevNode=-1;
7981 double angleNext=0.;
7982 while(nextNode!=startNode)
7986 for(node=nodalConnBg+1;node!=nodalConnEnd;node++)
7988 if(*node!=tmpOut.back() && *node!=prevNode)
7990 tmp2[0]=coords[2*(*node)]-coords[2*tmpOut.back()]; tmp2[1]=coords[2*(*node)+1]-coords[2*tmpOut.back()+1];
7991 double angleM=INTERP_KERNEL::EdgeArcCircle::GetAbsoluteAngle(tmp2,tmp1);
7996 res=angle0-angleM+2.*M_PI;
8005 if(nextNode!=startNode)
8007 angle0=angleNext-M_PI;
8010 prevNode=tmpOut.back();
8011 tmpOut.push_back(nextNode);
8014 std::vector<mcIdType> tmp3(2*(sz-1));
8015 std::vector<mcIdType>::iterator it=std::copy(nodalConnBg+1,nodalConnEnd,tmp3.begin());
8016 std::copy(nodalConnBg+1,nodalConnEnd,it);
8017 if(std::search(tmp3.begin(),tmp3.end(),tmpOut.begin(),tmpOut.end())!=tmp3.end())
8019 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
8022 if(std::search(tmp3.rbegin(),tmp3.rend(),tmpOut.begin(),tmpOut.end())!=tmp3.rend())
8024 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
8029 nodalConnecOut->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYGON));
8030 nodalConnecOut->insertAtTheEnd(tmpOut.begin(),tmpOut.end());
8035 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
8038 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
8042 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
8043 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
8044 * 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]].
8045 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
8046 * A negative value in \b arrIn means that it is ignored.
8047 * 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.
8049 * \param [in] arrIn arr origin array from which the extraction will be done.
8050 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
8051 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
8052 * \sa MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed, MEDCouplingUMesh::partitionBySpreadZone
8054 DataArrayIdType *MEDCouplingUMesh::ComputeSpreadZoneGradually(const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn)
8056 mcIdType seed=0,nbOfDepthPeelingPerformed=0;
8057 return ComputeSpreadZoneGraduallyFromSeed(&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfDepthPeelingPerformed);
8061 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
8062 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
8063 * 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]].
8064 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
8065 * A negative value in \b arrIn means that it is ignored.
8066 * 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.
8067 * \param [in] seedBg the begin pointer (included) of an array containing the seed of the search zone
8068 * \param [in] seedEnd the end pointer (not included) of an array containing the seed of the search zone
8069 * \param [in] arrIn arr origin array from which the extraction will be done.
8070 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
8071 * \param [in] nbOfDepthPeeling the max number of peels requested in search. By default -1, that is to say, no limit.
8072 * \param [out] nbOfDepthPeelingPerformed the number of peels effectively performed. May be different from \a nbOfDepthPeeling
8073 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
8074 * \sa MEDCouplingUMesh::partitionBySpreadZone
8076 DataArrayIdType *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(const mcIdType *seedBg, const mcIdType *seedEnd, const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn, mcIdType nbOfDepthPeeling, mcIdType& nbOfDepthPeelingPerformed)
8078 nbOfDepthPeelingPerformed=0;
8080 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed : arrIndxIn input pointer is NULL !");
8081 mcIdType nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
8084 DataArrayIdType *ret=DataArrayIdType::New(); ret->alloc(0,1);
8088 std::vector<bool> fetched(nbOfTuples,false);
8089 return ComputeSpreadZoneGraduallyFromSeedAlg(fetched,seedBg,seedEnd,arrIn,arrIndxIn,nbOfDepthPeeling,nbOfDepthPeelingPerformed);
8095 * \b this is expected to be a mesh fully defined whose spaceDim==meshDim.
8096 * It returns a new allocated mesh having the same mesh dimension and lying on same coordinates.
8097 * The returned mesh contains as poly cells as number of contiguous zone (regarding connectivity).
8098 * A spread contiguous zone is built using poly cells (polyhedra in 3D, polygons in 2D and polyline in 1D).
8099 * The sum of measure field of returned mesh is equal to the sum of measure field of this.
8101 * \return a newly allocated mesh lying on the same coords than \b this with same meshdimension than \b this.
8103 MEDCouplingUMesh *MEDCouplingUMesh::buildSpreadZonesWithPoly() const
8105 checkFullyDefined();
8106 int mdim=getMeshDimension();
8107 int spaceDim=getSpaceDimension();
8109 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension and spacedimension do not match !");
8110 std::vector<DataArrayIdType *> partition=partitionBySpreadZone();
8111 std::vector< MCAuto<DataArrayIdType> > partitionAuto; partitionAuto.reserve(partition.size());
8112 std::copy(partition.begin(),partition.end(),std::back_insert_iterator<std::vector< MCAuto<DataArrayIdType> > >(partitionAuto));
8113 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
8114 ret->setCoords(getCoords());
8115 ret->allocateCells(ToIdType(partition.size()));
8117 for(std::vector<DataArrayIdType *>::const_iterator it=partition.begin();it!=partition.end();it++)
8119 MCAuto<MEDCouplingUMesh> tmp=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf((*it)->begin(),(*it)->end(),true));
8120 MCAuto<DataArrayIdType> cell;
8124 cell=tmp->buildUnionOf2DMesh();
8127 cell=tmp->buildUnionOf3DMesh();
8130 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension supported are [2,3] ! Not implemented yet for others !");
8133 ret->insertNextCell((INTERP_KERNEL::NormalizedCellType)cell->getIJSafe(0,0),cell->getNumberOfTuples()-1,cell->begin()+1);
8136 ret->finishInsertingCells();
8141 * This method partitions \b this into contiguous zone.
8142 * This method only needs a well defined connectivity. Coordinates are not considered here.
8143 * This method returns a vector of \b newly allocated arrays that the caller has to deal with.
8145 std::vector<DataArrayIdType *> MEDCouplingUMesh::partitionBySpreadZone() const
8147 DataArrayIdType *neigh=0,*neighI=0;
8148 computeNeighborsOfCells(neigh,neighI);
8149 MCAuto<DataArrayIdType> neighAuto(neigh),neighIAuto(neighI);
8150 return PartitionBySpreadZone(neighAuto,neighIAuto);
8153 std::vector<DataArrayIdType *> MEDCouplingUMesh::PartitionBySpreadZone(const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn)
8155 if(!arrIn || !arrIndxIn)
8156 throw INTERP_KERNEL::Exception("PartitionBySpreadZone : null input pointers !");
8157 arrIn->checkAllocated(); arrIndxIn->checkAllocated();
8158 mcIdType nbOfTuples(arrIndxIn->getNumberOfTuples());
8159 if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1 || nbOfTuples<1)
8160 throw INTERP_KERNEL::Exception("PartitionBySpreadZone : invalid arrays in input !");
8161 mcIdType nbOfCellsCur(nbOfTuples-1);
8162 std::vector<DataArrayIdType *> ret;
8165 std::vector<bool> fetchedCells(nbOfCellsCur,false);
8166 std::vector< MCAuto<DataArrayIdType> > ret2;
8168 while(seed<nbOfCellsCur)
8170 mcIdType nbOfPeelPerformed=0;
8171 ret2.push_back(ComputeSpreadZoneGraduallyFromSeedAlg(fetchedCells,&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfPeelPerformed));
8172 seed=ToIdType(std::distance(fetchedCells.begin(),std::find(fetchedCells.begin()+seed,fetchedCells.end(),false)));
8174 for(std::vector< MCAuto<DataArrayIdType> >::iterator it=ret2.begin();it!=ret2.end();it++)
8175 ret.push_back((*it).retn());
8180 * This method returns given a distribution of cell type (returned for example by MEDCouplingUMesh::getDistributionOfTypes method and customized after) a
8181 * newly allocated DataArrayIdType instance with 2 components ready to be interpreted as input of DataArrayIdType::findRangeIdForEachTuple method.
8183 * \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.
8184 * \return a newly allocated DataArrayIdType to be managed by the caller.
8185 * \throw In case of \a code has not the right format (typically of size 3*n)
8187 DataArrayIdType *MEDCouplingUMesh::ComputeRangesFromTypeDistribution(const std::vector<mcIdType>& code)
8189 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
8190 std::size_t nb=code.size()/3;
8191 if(code.size()%3!=0)
8192 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeRangesFromTypeDistribution : invalid input code !");
8194 mcIdType *retPtr=ret->getPointer();
8195 for(std::size_t i=0;i<nb;i++,retPtr+=2)
8197 retPtr[0]=code[3*i+2];
8198 retPtr[1]=code[3*i+2]+code[3*i+1];
8204 * This method expects that \a this a 3D mesh (spaceDim=3 and meshDim=3) with all coordinates and connectivities set.
8205 * All cells in \a this are expected to be linear 3D cells.
8206 * This method will split **all** 3D cells in \a this into INTERP_KERNEL::NORM_TETRA4 cells and put them in the returned mesh.
8207 * It leads to an increase to number of cells.
8208 * This method contrary to MEDCouplingUMesh::simplexize can append coordinates in \a this to perform its work.
8209 * The \a nbOfAdditionalPoints returned value informs about it. If > 0, the coordinates array in returned mesh will have \a nbOfAdditionalPoints
8210 * more tuples (nodes) than in \a this. Anyway, all the nodes in \a this (with the same order) will be in the returned mesh.
8212 * \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.
8213 * For all other cells, the splitting policy will be ignored. See INTERP_KERNEL::SplittingPolicy for the images.
8214 * \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.
8215 * \param [out] n2oCells - A new instance of DataArrayIdType holding, for each new cell,
8216 * an id of old cell producing it. The caller is to delete this array using
8217 * decrRef() as it is no more needed.
8218 * \return MEDCoupling1SGTUMesh * - the mesh containing only INTERP_KERNEL::NORM_TETRA4 cells.
8220 * \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
8221 * the policy PLANAR_FACE_6 should be used on a mesh sorted with MEDCoupling1SGTUMesh::sortHexa8EachOther.
8223 * \throw If \a this is not a 3D mesh (spaceDim==3 and meshDim==3).
8224 * \throw If \a this is not fully constituted with linear 3D cells.
8225 * \sa MEDCouplingUMesh::simplexize, MEDCoupling1SGTUMesh::sortHexa8EachOther
8227 MEDCoupling1SGTUMesh *MEDCouplingUMesh::tetrahedrize(int policy, DataArrayIdType *& n2oCells, mcIdType& nbOfAdditionalPoints) const
8229 INTERP_KERNEL::SplittingPolicy pol((INTERP_KERNEL::SplittingPolicy)policy);
8230 checkConnectivityFullyDefined();
8231 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
8232 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tetrahedrize : only available for mesh with meshdim == 3 and spacedim == 3 !");
8233 mcIdType nbOfCells=getNumberOfCells();
8234 mcIdType nbNodes(getNumberOfNodes());
8235 MCAuto<MEDCoupling1SGTUMesh> ret0(MEDCoupling1SGTUMesh::New(getName(),INTERP_KERNEL::NORM_TETRA4));
8236 MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(nbOfCells,1);
8237 mcIdType *retPt(ret->getPointer());
8238 MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()); newConn->alloc(0,1);
8239 MCAuto<DataArrayDouble> addPts(DataArrayDouble::New()); addPts->alloc(0,1);
8240 const mcIdType *oldc(_nodal_connec->begin());
8241 const mcIdType *oldci(_nodal_connec_index->begin());
8242 const double *coords(_coords->begin());
8243 for(mcIdType i=0;i<nbOfCells;i++,oldci++,retPt++)
8245 std::vector<mcIdType> a; std::vector<double> b;
8246 INTERP_KERNEL::SplitIntoTetras(pol,(INTERP_KERNEL::NormalizedCellType)oldc[oldci[0]],oldc+oldci[0]+1,oldc+oldci[1],coords,a,b);
8247 std::size_t nbOfTet(a.size()/4); *retPt=ToIdType(nbOfTet);
8248 const mcIdType *aa(&a[0]);
8251 for(std::vector<mcIdType>::iterator it=a.begin();it!=a.end();it++)
8253 *it=(-(*(it))-1+nbNodes);
8254 addPts->insertAtTheEnd(b.begin(),b.end());
8255 nbNodes+=ToIdType(b.size()/3);
8257 for(std::size_t j=0;j<nbOfTet;j++,aa+=4)
8258 newConn->insertAtTheEnd(aa,aa+4);
8260 if(!addPts->empty())
8262 addPts->rearrange(3);
8263 nbOfAdditionalPoints=addPts->getNumberOfTuples();
8264 addPts=DataArrayDouble::Aggregate(getCoords(),addPts);
8265 ret0->setCoords(addPts);
8269 nbOfAdditionalPoints=0;
8270 ret0->setCoords(getCoords());
8272 ret0->setNodalConnectivity(newConn);
8274 ret->computeOffsetsFull();
8275 n2oCells=ret->buildExplicitArrOfSliceOnScaledArr(0,nbOfCells,1);
8279 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),
8280 _own_cell(true),_cell_id(-1),_nb_cell(0)
8285 _nb_cell=mesh->getNumberOfCells();
8289 MEDCouplingUMeshCellIterator::~MEDCouplingUMeshCellIterator()
8297 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh, MEDCouplingUMeshCell *itc, mcIdType bg, mcIdType end):_mesh(mesh),_cell(itc),
8298 _own_cell(false),_cell_id(bg-1),
8305 MEDCouplingUMeshCell *MEDCouplingUMeshCellIterator::nextt()
8308 if(_cell_id<_nb_cell)
8317 MEDCouplingUMeshCellByTypeEntry::MEDCouplingUMeshCellByTypeEntry(MEDCouplingUMesh *mesh):_mesh(mesh)
8323 MEDCouplingUMeshCellByTypeIterator *MEDCouplingUMeshCellByTypeEntry::iterator()
8325 return new MEDCouplingUMeshCellByTypeIterator(_mesh);
8328 MEDCouplingUMeshCellByTypeEntry::~MEDCouplingUMeshCellByTypeEntry()
8334 MEDCouplingUMeshCellEntry::MEDCouplingUMeshCellEntry(MEDCouplingUMesh *mesh, INTERP_KERNEL::NormalizedCellType type, MEDCouplingUMeshCell *itc, mcIdType bg, mcIdType end):_mesh(mesh),_type(type),
8342 MEDCouplingUMeshCellEntry::~MEDCouplingUMeshCellEntry()
8348 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCellEntry::getType() const
8353 mcIdType MEDCouplingUMeshCellEntry::getNumberOfElems() const
8358 MEDCouplingUMeshCellIterator *MEDCouplingUMeshCellEntry::iterator()
8360 return new MEDCouplingUMeshCellIterator(_mesh,_itc,_bg,_end);
8363 MEDCouplingUMeshCellByTypeIterator::MEDCouplingUMeshCellByTypeIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),_cell_id(0),_nb_cell(0)
8368 _nb_cell=mesh->getNumberOfCells();
8372 MEDCouplingUMeshCellByTypeIterator::~MEDCouplingUMeshCellByTypeIterator()
8379 MEDCouplingUMeshCellEntry *MEDCouplingUMeshCellByTypeIterator::nextt()
8381 const mcIdType *c=_mesh->getNodalConnectivity()->begin();
8382 const mcIdType *ci=_mesh->getNodalConnectivityIndex()->begin();
8383 if(_cell_id<_nb_cell)
8385 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[_cell_id]];
8386 mcIdType nbOfElems=ToIdType(std::distance(ci+_cell_id,std::find_if(ci+_cell_id,ci+_nb_cell,MEDCouplingImpl::ConnReader(c,type))));
8387 mcIdType startId=_cell_id;
8388 _cell_id+=nbOfElems;
8389 return new MEDCouplingUMeshCellEntry(_mesh,type,_cell,startId,_cell_id);
8395 MEDCouplingUMeshCell::MEDCouplingUMeshCell(MEDCouplingUMesh *mesh):_conn(0),_conn_indx(0),_conn_lgth(NOTICABLE_FIRST_VAL)
8399 _conn=mesh->getNodalConnectivity()->getPointer();
8400 _conn_indx=mesh->getNodalConnectivityIndex()->getPointer();
8404 void MEDCouplingUMeshCell::next()
8406 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8411 _conn_lgth=_conn_indx[1]-_conn_indx[0];
8414 std::string MEDCouplingUMeshCell::repr() const
8416 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8418 std::ostringstream oss; oss << "Cell Type " << INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)_conn[0]).getRepr();
8420 std::copy(_conn+1,_conn+_conn_lgth,std::ostream_iterator<mcIdType>(oss," "));
8424 return std::string("MEDCouplingUMeshCell::repr : Invalid pos");
8427 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCell::getType() const
8429 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8430 return (INTERP_KERNEL::NormalizedCellType)_conn[0];
8432 return INTERP_KERNEL::NORM_ERROR;
8435 const mcIdType *MEDCouplingUMeshCell::getAllConn(mcIdType& lgth) const
8438 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8446 namespace MEDCouplingImpl
8448 const mcIdType theUndefID = std::numeric_limits< mcIdType >::max(); //!< undefined cell id
8450 //================================================================================
8452 * \brief Encode a cell id and a mesh index into a code
8453 * \param [in] id - cell id
8454 * \param [in] iMesh - mesh index [0,1]
8455 * \return mcIdType - code
8457 //================================================================================
8459 mcIdType encodeID( mcIdType id, int iMesh )
8461 return ( id + 1 ) * ( iMesh ? -1 : 1 );
8463 //================================================================================
8465 * \brief Return cell id and mesh index by a given id
8466 * \param [in] id - code of a cell in a mesh
8467 * \param [out] iMesh - returned mesh index
8468 * \return mcIdType - cell id
8470 //================================================================================
8472 mcIdType decodeID( mcIdType id, int& iMesh )
8475 return std::abs( id ) - 1;
8478 //================================================================================
8480 * \brief return another face sharing two given nodes of a face edge
8481 * \param [in] n0 - 1st node of the edge
8482 * \param [in] n1 - 2nd node of the edge
8483 * \param [in] inputFaceID - face including \a n0 andf \a n2
8484 * \param [in] mesh - object and reference meshes
8485 * \param [in] revNodal - reverse nodal connectivity of the two meshes
8486 * \param [in] revNodalIndx - index of reverse nodal connectivity of the two meshes
8487 * \param [out] facesByEdge - return another face including \a n0 andf \a n2
8488 * \param [out] equalFaces - return faces equal to facesByEdge
8490 //================================================================================
8492 void getFacesOfEdge( mcIdType n0,
8494 mcIdType inputFaceID,
8495 MEDCouplingUMesh* mesh[],
8496 MCAuto<DataArrayIdType> revNodal[],
8497 MCAuto<DataArrayIdType> revNodalIndx[],
8498 std::vector< mcIdType >& facesByEdge,
8499 std::vector< mcIdType >& equalFaces)
8501 // find faces sharing the both nodes of edge
8503 facesByEdge.clear();
8504 size_t prevNbF; // nb faces found in 0-th mesh
8505 for ( int iM = 0; iM < 2; ++iM )
8507 const mcIdType * revInd = revNodalIndx[ iM ]->begin();
8508 const mcIdType * rev = revNodal [ iM ]->begin();
8510 mcIdType nbRevFaces0 = revInd[ n0 + 1 ] - revInd[ n0 ];
8511 mcIdType nbRevFaces1 = revInd[ n1 + 1 ] - revInd[ n1 ];
8513 prevNbF = facesByEdge.size();
8514 facesByEdge.resize( prevNbF + std::max( nbRevFaces0, nbRevFaces1 ));
8516 auto it = std::set_intersection( rev + revInd[ n0 ],
8517 rev + revInd[ n0 ] + nbRevFaces0,
8519 rev + revInd[ n1 ] + nbRevFaces1,
8520 facesByEdge.begin() + prevNbF );
8521 facesByEdge.resize( it - facesByEdge.begin() );
8524 // facesByEdge now contains at least the 'inputFaceID'
8525 // check if there are other faces
8527 size_t nbF = facesByEdge.size();
8530 if ( prevNbF > 0 && prevNbF < nbF ) // faces found in both meshes
8532 // remove from facesByEdge equal faces in different meshes
8533 const mcIdType *conn [2] = { mesh[0]->getNodalConnectivity()->getConstPointer(),
8534 mesh[1]->getNodalConnectivity()->getConstPointer() };
8535 const mcIdType *connI[2] = { mesh[0]->getNodalConnectivityIndex()->getConstPointer(),
8536 mesh[1]->getNodalConnectivityIndex()->getConstPointer() };
8537 for ( size_t i0 = 0; i0 < prevNbF; ++i0 )
8539 if ( facesByEdge[ i0 ] == theUndefID )
8541 mcIdType objFaceID = MEDCouplingImpl::encodeID( facesByEdge[ i0 ], 0 );
8542 bool isInputFace = ( objFaceID == inputFaceID );
8544 for ( size_t i1 = prevNbF; i1 < facesByEdge.size(); ++i1 )
8546 if ( facesByEdge[ i1 ] == theUndefID )
8549 mcIdType f0 = facesByEdge[ i0 ];
8550 mcIdType f1 = facesByEdge[ i1 ];
8551 size_t nbNodes0 = connI[0][ f0 + 1 ] - connI[0][ f0 ] - 1;
8552 size_t nbNodes1 = connI[1][ f1 + 1 ] - connI[1][ f1 ] - 1;
8553 if ( nbNodes0 != nbNodes1 )
8556 const mcIdType * fConn0 = conn[0] + connI[0][ f0 ] + 1;
8557 const mcIdType * fConn1 = conn[1] + connI[1][ f1 ] + 1;
8558 if ( std::equal( fConn0, fConn0 + nbNodes0, fConn1 ))
8560 // equal faces; remove an object one
8561 mcIdType refFaceID = MEDCouplingImpl::encodeID( facesByEdge[ i1 ], 1 );
8562 if ( refFaceID == inputFaceID )
8565 if ( std::find( equalFaces.begin(),
8566 equalFaces.end(), objFaceID ) == equalFaces.end() )
8567 equalFaces.push_back( objFaceID );
8569 facesByEdge[ i0 ] = theUndefID;
8571 facesByEdge[ i1 ] = theUndefID;
8576 facesByEdge[ i0 ] = theUndefID;
8581 nbF = facesByEdge.size();
8582 for ( size_t i = 0; i < facesByEdge.size(); ++i )
8584 if ( facesByEdge[ i ] != theUndefID )
8586 facesByEdge[ i ] = MEDCouplingImpl::encodeID( facesByEdge[ i ], i >= prevNbF );
8587 if ( facesByEdge[ i ] == inputFaceID )
8588 facesByEdge[ i ] = theUndefID;
8590 nbF -= ( facesByEdge[ i ] == theUndefID );
8594 return; // non-manifold
8598 facesByEdge.clear();
8600 else // nbF == 1, set a found face first
8602 if ( facesByEdge[ 0 ] == theUndefID )
8604 for ( size_t i = 1; i < facesByEdge.size(); ++i )
8605 if ( facesByEdge[ i ] != theUndefID )
8607 facesByEdge[ 0 ] = facesByEdge[ i ];
8611 facesByEdge.resize( 1 );
8616 //================================================================================
8618 * \brief Remove a face from nodal reversed connectivity
8619 * \param [in] node - a node of the face
8620 * \param [in] face - the face
8621 * \param [in.out] revNodal - reverse nodal connectivity
8622 * \param [in,out] revNodalIndx - reverse nodal connectivity index
8624 //================================================================================
8626 void removeFromRevNodal( mcIdType node,
8628 MCAuto<DataArrayIdType>& revNodal,
8629 MCAuto<DataArrayIdType>& revNodalIndx)
8631 mcIdType* fBeg = revNodal->getPointer() + revNodalIndx->getIJ( node, 0 );
8632 mcIdType* fEnd = revNodal->getPointer() + revNodalIndx->getIJ( node + 1, 0);
8633 auto it = std::find( fBeg, fEnd, face );
8636 for ( auto it2 = it + 1; it2 < fEnd; ++it2 ) // keep faces sorted
8637 *( it2 - 1 ) = *it2;
8639 *( fEnd - 1 ) = theUndefID;
8643 //================================================================================
8645 * \brief Check order of two nodes in a given face
8646 * \param [inout] n0 - node 1
8647 * \param [inout] n1 - node 2
8648 * \param [inout] iFEnc - face
8649 * \param [inout] mesh - mesh
8650 * \return bool - true if the nodes are in [ .., n1, n0, ..] order in face
8652 //================================================================================
8654 bool isReverseOrder( mcIdType n0,
8657 MEDCouplingUMesh* mesh[] )
8660 mcIdType iF = decodeID( iFEnc, iMesh );
8662 const mcIdType *conn = mesh[ iMesh ]->getNodalConnectivity()->getConstPointer();
8663 const mcIdType *connI = mesh[ iMesh ]->getNodalConnectivityIndex()->getConstPointer();
8665 auto it0 = std::find( conn + connI[ iF ] + 1,
8666 conn + connI[ iF + 1 ],
8668 auto it1 = std::find( conn + connI[ iF ] + 1,
8669 conn + connI[ iF + 1 ],
8671 long i0 = it0 - conn;
8672 long i1 = it1 - conn;
8674 bool isRev = ( std::abs( i1 - i0 ) == 1 ) ? i1 < i0 : i0 < i1;
8678 //================================================================================
8680 * \brief Change orientation of a face in one of given meshes
8681 * \param [in] iFEnc - face ID also encoding a mesh index
8682 * \param [in,out] mesh - object and reference meshes
8684 //================================================================================
8686 void reverseFace( mcIdType iFEnc, MEDCouplingUMesh* mesh[] )
8689 mcIdType face = decodeID( iFEnc, iMesh );
8691 mcIdType *conn = mesh[ iMesh ]->getNodalConnectivity()->getPointer();
8692 mcIdType *connI = mesh[ iMesh ]->getNodalConnectivityIndex()->getPointer();
8694 const INTERP_KERNEL::CellModel& cm =
8695 INTERP_KERNEL::CellModel::GetCellModel( mesh[iMesh]->getTypeOfCell( face ));
8697 cm.changeOrientationOf2D( conn + connI[ face ] + 1,
8698 (unsigned int)( connI[ face + 1 ] - connI[ face ] - 1 ));
8705 //================================================================================
8707 * \brief Orient cells of \a this 2D mesh equally to \a refFaces
8708 * \param [in] refFaces - 2D mesh containing correctly oriented faces. It is optional.
8709 * If there are no cells in \a refFaces or it is nullptr, then any face
8710 * in \a this mesh is used as a reference
8711 * \throw If \a this mesh is not well defined.
8712 * \throw If \a this mesh or \refFaces are not 2D.
8713 * \throw If \a this mesh and \refFaces do not share nodes.
8714 * \throw If \a refFaces are not equally oriented.
8715 * \throw If \a this mesh plus \a refFaces together form a non-manifold mesh.
8717 * \if ENABLE_EXAMPLES
8718 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
8719 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
8722 //================================================================================
8724 void MEDCouplingUMesh::orientCorrectly2DCells(const MEDCouplingUMesh* refFaces)
8726 checkConsistencyLight();
8727 if ( getMeshDimension() != 2 )
8728 throw INTERP_KERNEL::Exception("The mesh dimension must be 2");
8731 refFaces->checkConsistencyLight();
8732 if ( refFaces->getMeshDimension() != 2 )
8733 throw INTERP_KERNEL::Exception("The reference mesh dimension must be 2");
8734 if ( getCoords() != refFaces->getCoords() )
8735 throw INTERP_KERNEL::Exception("Object and reference meshes must share nodes ");
8736 if ( refFaces->getNumberOfCells() == 0 )
8739 if ( getNumberOfCells() == 0 )
8742 enum { _OBJ, _REF };
8743 MEDCouplingUMesh* mesh[2] = { this, const_cast< MEDCouplingUMesh* >( refFaces ) };
8744 MCAuto<MEDCouplingUMesh> meshPtr;
8747 meshPtr = mesh[_REF] = MEDCouplingUMesh::New();
8748 mesh[_REF]->setCoords( mesh[_OBJ]->getCoords() );
8749 mesh[_REF]->allocateCells(0);
8750 mesh[_REF]->finishInsertingCells();
8752 mcIdType nbFacesToCheck[2] = { mesh[_OBJ]->getNumberOfCells(),
8753 mesh[_REF]->getNumberOfCells() };
8754 std::vector< bool > isFaceQueued[ 2 ]; // enqueued faces of 2 meshes
8755 isFaceQueued[_OBJ].resize( nbFacesToCheck[_OBJ] );
8756 isFaceQueued[_REF].resize( nbFacesToCheck[_REF] );
8758 MCAuto<DataArrayIdType> revNodal [2] = { DataArrayIdType::New(), DataArrayIdType::New() };
8759 MCAuto<DataArrayIdType> revNodalIndx[2] = { DataArrayIdType::New(), DataArrayIdType::New() };
8760 mesh[_OBJ]->getReverseNodalConnectivity( revNodal[_OBJ], revNodalIndx[_OBJ] );
8761 mesh[_REF]->getReverseNodalConnectivity( revNodal[_REF], revNodalIndx[_REF] );
8763 std::vector< mcIdType > faceNodes(4);
8764 std::vector< mcIdType > facesByEdge(4), equalFaces;
8765 std::vector< mcIdType > faceQueue; // starting faces with IDs counted from 1; negative ID mean a face in ref mesh
8767 while ( nbFacesToCheck[_OBJ] + nbFacesToCheck[_REF] > 0 ) // until all faces checked
8769 if ( faceQueue.empty() ) // all neighbors checked, find more faces to check
8771 for ( int iMesh = 1; iMesh >= 0; --iMesh ) // on [ _REF, _OBJ ]
8772 if ( nbFacesToCheck[iMesh] > 0 )
8773 for ( mcIdType f = 0, nbF = mesh[iMesh]->getNumberOfCells(); f < nbF; ++f )
8774 if ( !isFaceQueued[iMesh][f] )
8776 faceQueue.push_back( MEDCouplingImpl::encodeID( f, iMesh ));
8777 isFaceQueued[ iMesh ][ f ] = true;
8781 if ( faceQueue.empty() )
8785 mcIdType fID = faceQueue.back();
8786 faceQueue.pop_back();
8789 mcIdType refFace = MEDCouplingImpl::decodeID( fID, iMesh );
8791 nbFacesToCheck[iMesh]--;
8795 mesh[iMesh]->getNodeIdsOfCell( refFace, faceNodes );
8796 const INTERP_KERNEL::CellModel& cm = INTERP_KERNEL::CellModel::GetCellModel( mesh[iMesh]->getTypeOfCell( refFace ));
8797 const int nbEdges = cm.getNumberOfSons();
8799 // loop on edges of the refFace
8800 mcIdType n0 = faceNodes[ nbEdges - 1 ]; // 1st node of edge
8801 for ( int edge = 0; edge < nbEdges; ++edge )
8803 mcIdType n1 = faceNodes[ edge ]; // 2nd node of edge
8805 // get faces sharing the edge
8806 MEDCouplingImpl::getFacesOfEdge( n0, n1, fID, mesh, revNodal, revNodalIndx,
8807 facesByEdge, equalFaces );
8809 if ( facesByEdge.size() > 1 )
8810 THROW_IK_EXCEPTION("Non-manifold mesh at edge " << n0+1 << " - " << n1+1);
8812 if ( facesByEdge.size() == 1 )
8814 // compare orientation of two faces
8816 if ( !MEDCouplingImpl::isReverseOrder( n0, n1, facesByEdge[0], mesh ))
8818 if ( facesByEdge[0] < 0 ) // in the ref mesh
8819 throw INTERP_KERNEL::Exception("Different orientation of reference faces");
8821 MEDCouplingImpl::reverseFace( facesByEdge[0], mesh );
8823 mcIdType face2 = MEDCouplingImpl::decodeID( facesByEdge[0], iMesh2 );
8824 if ( !isFaceQueued[iMesh2][face2] )
8826 isFaceQueued[iMesh2][face2] = true;
8827 faceQueue.push_back( facesByEdge[0] );
8833 // remove face and equalFaces from revNodal in order not to treat them again
8834 equalFaces.push_back( fID );
8835 for ( mcIdType face : equalFaces )
8837 mcIdType f = MEDCouplingImpl::decodeID( face, iMesh2 );
8838 const mcIdType *conn = mesh[iMesh2]->getNodalConnectivity()->getConstPointer();
8839 const mcIdType *connI = mesh[iMesh2]->getNodalConnectivityIndex()->getConstPointer();
8840 mcIdType nbNodes = connI[ f + 1 ] - connI[ f ] - 1;
8841 for ( const mcIdType* n = conn + connI[ f ] + 1, *nEnd = n + nbNodes; n < nEnd; ++n )
8843 MEDCouplingImpl::removeFromRevNodal( *n, f, // not to treat f again
8844 revNodal[ iMesh2 ], revNodalIndx[ iMesh2 ] );
8847 } // while() until all faces checked