1 // Copyright (C) 2007-2021 CEA/DEN, EDF R&D
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 // Author : Anthony Geay (EDF R&D)
21 #include "MEDCouplingUMesh.txx"
22 #include "MEDCouplingCMesh.hxx"
23 #include "MEDCoupling1GTUMesh.hxx"
24 #include "MEDCouplingFieldDouble.hxx"
25 #include "MEDCouplingSkyLineArray.hxx"
26 #include "CellModel.hxx"
27 #include "VolSurfUser.txx"
28 #include "InterpolationUtils.hxx"
29 #include "PointLocatorAlgos.txx"
31 #include "BBTreeDst.txx"
32 #include "SplitterTetra.hxx"
33 #include "DiameterCalculator.hxx"
34 #include "DirectedBoundingBox.hxx"
35 #include "InterpKernelMatrixTools.hxx"
36 #include "InterpKernelMeshQuality.hxx"
37 #include "InterpKernelCellSimplify.hxx"
38 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
39 #include "InterpKernelAutoPtr.hxx"
40 #include "InterpKernelGeo2DNode.hxx"
41 #include "InterpKernelGeo2DEdgeLin.hxx"
42 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
43 #include "InterpKernelGeo2DQuadraticPolygon.hxx"
44 #include "OrientationInverter.hxx"
45 #include "MEDCouplingUMesh_internal.hxx"
55 using namespace MEDCoupling;
57 double MEDCouplingUMesh::EPS_FOR_POLYH_ORIENTATION=1.e-14;
61 const INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::MEDMEM_ORDER[N_MEDMEM_ORDER] = { INTERP_KERNEL::NORM_POINT1, INTERP_KERNEL::NORM_SEG2, INTERP_KERNEL::NORM_SEG3, INTERP_KERNEL::NORM_SEG4, INTERP_KERNEL::NORM_POLYL, INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4, INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_TRI7, INTERP_KERNEL::NORM_QUAD8, INTERP_KERNEL::NORM_QUAD9, INTERP_KERNEL::NORM_POLYGON, INTERP_KERNEL::NORM_QPOLYG, INTERP_KERNEL::NORM_TETRA4, INTERP_KERNEL::NORM_PYRA5, INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXA8, INTERP_KERNEL::NORM_HEXGP12, INTERP_KERNEL::NORM_TETRA10, INTERP_KERNEL::NORM_PYRA13, INTERP_KERNEL::NORM_PENTA15, INTERP_KERNEL::NORM_PENTA18, INTERP_KERNEL::NORM_HEXA20, INTERP_KERNEL::NORM_HEXA27, INTERP_KERNEL::NORM_POLYHED };
64 MEDCouplingUMesh *MEDCouplingUMesh::New()
66 return new MEDCouplingUMesh;
69 MEDCouplingUMesh *MEDCouplingUMesh::New(const std::string& meshName, int meshDim)
71 MEDCouplingUMesh *ret=new MEDCouplingUMesh;
72 ret->setName(meshName);
73 ret->setMeshDimension(meshDim);
78 * Returns a new MEDCouplingUMesh which is a full copy of \a this one. No data is shared
79 * between \a this and the new mesh.
80 * \return MEDCouplingUMesh * - a new instance of MEDCouplingMesh. The caller is to
81 * delete this mesh using decrRef() as it is no more needed.
83 MEDCouplingUMesh *MEDCouplingUMesh::deepCopy() const
90 * Returns a new MEDCouplingUMesh which is a copy of \a this one.
91 * \param [in] recDeepCpy - if \a true, the copy is deep, else all data arrays of \a
92 * this mesh are shared by the new mesh.
93 * \return MEDCouplingUMesh * - a new instance of MEDCouplingMesh. The caller is to
94 * delete this mesh using decrRef() as it is no more needed.
96 MEDCouplingUMesh *MEDCouplingUMesh::clone(bool recDeepCpy) const
98 return new MEDCouplingUMesh(*this,recDeepCpy);
102 * This method behaves mostly like MEDCouplingUMesh::deepCopy method, except that only nodal connectivity arrays are deeply copied.
103 * The coordinates are shared between \a this and the returned instance.
105 * \return MEDCouplingUMesh * - A new object instance holding the copy of \a this (deep for connectivity, shallow for coordiantes)
106 * \sa MEDCouplingUMesh::deepCopy
108 MEDCouplingUMesh *MEDCouplingUMesh::deepCopyConnectivityOnly() const
110 checkConnectivityFullyDefined();
111 MCAuto<MEDCouplingUMesh> ret=clone(false);
112 MCAuto<DataArrayIdType> c(getNodalConnectivity()->deepCopy()),ci(getNodalConnectivityIndex()->deepCopy());
113 ret->setConnectivity(c,ci);
117 void MEDCouplingUMesh::shallowCopyConnectivityFrom(const MEDCouplingPointSet *other)
120 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is null !");
121 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
123 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is not an MEDCouplingUMesh instance !");
124 MEDCouplingUMesh *otherC2=const_cast<MEDCouplingUMesh *>(otherC);//sorry :(
125 setConnectivity(otherC2->getNodalConnectivity(),otherC2->getNodalConnectivityIndex(),true);
128 std::size_t MEDCouplingUMesh::getHeapMemorySizeWithoutChildren() const
130 std::size_t ret(MEDCouplingPointSet::getHeapMemorySizeWithoutChildren());
134 std::vector<const BigMemoryObject *> MEDCouplingUMesh::getDirectChildrenWithNull() const
136 std::vector<const BigMemoryObject *> ret(MEDCouplingPointSet::getDirectChildrenWithNull());
137 ret.push_back(_nodal_connec);
138 ret.push_back(_nodal_connec_index);
142 void MEDCouplingUMesh::updateTime() const
144 MEDCouplingPointSet::updateTime();
147 updateTimeWith(*_nodal_connec);
149 if(_nodal_connec_index)
151 updateTimeWith(*_nodal_connec_index);
155 MEDCouplingUMesh::MEDCouplingUMesh():_mesh_dim(-2),_nodal_connec(0),_nodal_connec_index(0)
160 * Checks if \a this mesh is well defined. If no exception is thrown by this method,
161 * then \a this mesh is most probably is writable, exchangeable and available for most
162 * of algorithms. When a mesh is constructed from scratch, it is a good habit to call
163 * this method to check that all is in order with \a this mesh.
164 * \throw If the mesh dimension is not set.
165 * \throw If the coordinates array is not set (if mesh dimension != -1 ).
166 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
167 * \throw If the connectivity data array has more than one component.
168 * \throw If the connectivity data array has a named component.
169 * \throw If the connectivity index data array has more than one component.
170 * \throw If the connectivity index data array has a named component.
172 void MEDCouplingUMesh::checkConsistencyLight() const
175 throw INTERP_KERNEL::Exception("No mesh dimension specified !");
177 MEDCouplingPointSet::checkConsistencyLight();
178 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
180 if(ToIdType(INTERP_KERNEL::CellModel::GetCellModel(*iter).getDimension())!=_mesh_dim)
182 std::ostringstream message;
183 message << "Mesh invalid because dimension is " << _mesh_dim << " and there is presence of cell(s) with type " << (*iter);
184 throw INTERP_KERNEL::Exception(message.str().c_str());
189 if(_nodal_connec->getNumberOfComponents()!=1)
190 throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to be with number of components set to one !");
191 if(_nodal_connec->getInfoOnComponent(0)!="")
192 throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to have no info on its single component !");
196 throw INTERP_KERNEL::Exception("Nodal connectivity array is not defined !");
197 if(_nodal_connec_index)
199 if(_nodal_connec_index->getNumberOfComponents()!=1)
200 throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to be with number of components set to one !");
201 if(_nodal_connec_index->getInfoOnComponent(0)!="")
202 throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to have no info on its single component !");
206 throw INTERP_KERNEL::Exception("Nodal connectivity index array is not defined !");
210 * Checks if \a this mesh is well defined. If no exception is thrown by this method,
211 * then \a this mesh is informatically clean, most probably is writable, exchangeable and available for all
212 * algorithms. <br> In addition to the checks performed by checkConsistencyLight(), this
213 * method thoroughly checks the nodal connectivity. For more geometrical checking
214 * checkGeomConsistency method is better than this.
216 * \sa MEDCouplingUMesh::checkGeomConsistency
218 * \param [in] eps - a not used parameter.
219 * \throw If the mesh dimension is not set.
220 * \throw If the coordinates array is not set (if mesh dimension != -1 ).
221 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
222 * \throw If the connectivity data array has more than one component.
223 * \throw If the connectivity data array has a named component.
224 * \throw If the connectivity index data array has more than one component.
225 * \throw If the connectivity index data array has a named component.
226 * \throw If number of nodes defining an element does not correspond to the type of element.
227 * \throw If the nodal connectivity includes an invalid node id.
229 void MEDCouplingUMesh::checkConsistency(double eps) const
231 checkConsistencyLight();
234 int meshDim=getMeshDimension();
235 mcIdType nbOfNodes=getNumberOfNodes();
236 mcIdType nbOfCells=getNumberOfCells();
237 const mcIdType *ptr=_nodal_connec->getConstPointer();
238 const mcIdType *ptrI=_nodal_connec_index->getConstPointer();
239 for(mcIdType i=0;i<nbOfCells;i++)
241 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)ptr[ptrI[i]]);
242 if(ToIdType(cm.getDimension())!=meshDim)
244 std::ostringstream oss;
245 oss << "MEDCouplingUMesh::checkConsistency : cell << #" << i<< " with type Type " << cm.getRepr() << " in 'this' whereas meshdim == " << meshDim << " !";
246 throw INTERP_KERNEL::Exception(oss.str());
248 mcIdType nbOfNodesInCell=ptrI[i+1]-ptrI[i]-1;
250 if(nbOfNodesInCell!=ToIdType(cm.getNumberOfNodes()))
252 std::ostringstream oss;
253 oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with static Type '" << cm.getRepr() << "' has " << cm.getNumberOfNodes();
254 oss << " nodes whereas in connectivity there is " << nbOfNodesInCell << " nodes ! Looks very bad !";
255 throw INTERP_KERNEL::Exception(oss.str());
257 if(cm.isQuadratic() && cm.isDynamic() && meshDim == 2)
258 if (nbOfNodesInCell % 2 || nbOfNodesInCell < 4)
260 std::ostringstream oss;
261 oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with quadratic type '" << cm.getRepr() << "' has " << nbOfNodesInCell;
262 oss << " nodes. This should be even, and greater or equal than 4!! Looks very bad!";
263 throw INTERP_KERNEL::Exception(oss.str());
265 for(const mcIdType *w=ptr+ptrI[i]+1;w!=ptr+ptrI[i+1];w++)
270 if(nodeId>=nbOfNodes)
272 std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " whereas there are only " << nbOfNodes << " nodes in the mesh !";
273 throw INTERP_KERNEL::Exception(oss.str());
278 std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " in connectivity ! sounds bad !";
279 throw INTERP_KERNEL::Exception(oss.str());
283 if((INTERP_KERNEL::NormalizedCellType)(ptr[ptrI[i]])!=INTERP_KERNEL::NORM_POLYHED)
285 std::ostringstream oss; oss << "Cell #" << i << " is built with node #-1 in connectivity ! sounds bad !";
286 throw INTERP_KERNEL::Exception(oss.str());
294 * This method adds some geometrical checks in addition to the informatical check of checkConsistency method.
295 * This method in particular checks that a same node is not repeated several times in a cell.
297 * \throw If there is a presence a multiple same node ID in nodal connectivity of cell.
299 void MEDCouplingUMesh::checkGeomConsistency(double eps) const
301 this->checkConsistency(eps);
302 auto nbOfCells(getNumberOfCells());
303 const mcIdType *ptr(_nodal_connec->begin()),*ptrI(_nodal_connec_index->begin());
304 for(auto icell = 0 ; icell < nbOfCells ; ++icell)
306 std::set<mcIdType> s(ptr+ptrI[icell]+1,ptr+ptrI[icell+1]);
307 if(ToIdType(s.size())==ptrI[icell+1]-ptrI[icell]-1)
309 std::ostringstream oss; oss << "MEDCouplingUMesh::checkGeomConsistency : for cell #" << icell << " presence of multiple same nodeID !";
310 throw INTERP_KERNEL::Exception(oss.str());
316 * Sets dimension of \a this mesh. The mesh dimension in general depends on types of
317 * elements contained in the mesh. For more info on the mesh dimension see
318 * \ref MEDCouplingUMeshPage.
319 * \param [in] meshDim - a new mesh dimension.
320 * \throw If \a meshDim is invalid. A valid range is <em> -1 <= meshDim <= 3</em>.
322 void MEDCouplingUMesh::setMeshDimension(int meshDim)
324 if(meshDim<-1 || meshDim>3)
325 throw INTERP_KERNEL::Exception("Invalid meshDim specified ! Must be greater or equal to -1 and lower or equal to 3 !");
331 * Allocates memory to store an estimation of the given number of cells.
332 * The closer the estimation to the number of cells effectively inserted, the less need the library requires
333 * to reallocate memory. If the number of cells to be inserted is not known simply assign 0 to this parameter.
334 * If a nodal connectivity previously existed before the call of this method, it will be reset.
336 * \param [in] nbOfCells - estimation of the number of cell \a this mesh will contain.
338 * \if ENABLE_EXAMPLES
339 * \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
340 * \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
343 void MEDCouplingUMesh::allocateCells(mcIdType nbOfCells)
346 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::allocateCells : the input number of cells should be >= 0 !");
347 if(_nodal_connec_index)
349 _nodal_connec_index->decrRef();
353 _nodal_connec->decrRef();
355 _nodal_connec_index=DataArrayIdType::New();
356 _nodal_connec_index->reserve(nbOfCells+1);
357 _nodal_connec_index->pushBackSilent(0);
358 _nodal_connec=DataArrayIdType::New();
359 _nodal_connec->reserve(2*nbOfCells);
365 * Appends a cell to the connectivity array. For deeper understanding what is
366 * happening see \ref MEDCouplingUMeshNodalConnectivity.
367 * \param [in] type - type of cell to add.
368 * \param [in] size - number of nodes constituting this cell.
369 * \param [in] nodalConnOfCell - the connectivity of the cell to add.
371 * \if ENABLE_EXAMPLES
372 * \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
373 * \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
376 void MEDCouplingUMesh::insertNextCell(INTERP_KERNEL::NormalizedCellType type, mcIdType size, const mcIdType *nodalConnOfCell)
378 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
379 if(_nodal_connec_index==0)
380 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::insertNextCell : nodal connectivity not set ! invoke allocateCells before calling insertNextCell !");
381 if(ToIdType(cm.getDimension())==_mesh_dim)
384 if(size!=ToIdType(cm.getNumberOfNodes()))
386 std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : Trying to push a " << cm.getRepr() << " cell with a size of " << size;
387 oss << " ! Expecting " << cm.getNumberOfNodes() << " !";
388 throw INTERP_KERNEL::Exception(oss.str());
390 mcIdType idx=_nodal_connec_index->back();
391 mcIdType val=idx+size+1;
392 _nodal_connec_index->pushBackSilent(val);
393 _nodal_connec->writeOnPlace(idx,type,nodalConnOfCell,size);
398 std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : cell type " << cm.getRepr() << " has a dimension " << cm.getDimension();
399 oss << " whereas Mesh Dimension of current UMesh instance is set to " << _mesh_dim << " ! Please invoke \"setMeshDimension\" method before or invoke ";
400 oss << "\"MEDCouplingUMesh::New\" static method with 2 parameters name and meshDimension !";
401 throw INTERP_KERNEL::Exception(oss.str());
406 * Compacts data arrays to release unused memory. This method is to be called after
407 * finishing cell insertion using \a this->insertNextCell().
409 * \if ENABLE_EXAMPLES
410 * \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
411 * \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
414 void MEDCouplingUMesh::finishInsertingCells()
416 _nodal_connec->pack();
417 _nodal_connec_index->pack();
418 _nodal_connec->declareAsNew();
419 _nodal_connec_index->declareAsNew();
424 * Entry point for iteration over cells of this. Warning the returned cell iterator should be deallocated.
425 * Useful for python users.
427 MEDCouplingUMeshCellIterator *MEDCouplingUMesh::cellIterator()
429 return new MEDCouplingUMeshCellIterator(this);
433 * Entry point for iteration over cells groups geo types per geotypes. Warning the returned cell iterator should be deallocated.
434 * If \a this is not so that the cells are grouped by geo types, this method will throw an exception.
435 * In this case MEDCouplingUMesh::sortCellsInMEDFileFrmt or MEDCouplingUMesh::rearrange2ConsecutiveCellTypes methods for example can be called before invoking this method.
436 * Useful for python users.
438 MEDCouplingUMeshCellByTypeEntry *MEDCouplingUMesh::cellsByType()
440 if(!checkConsecutiveCellTypes())
441 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::cellsByType : this mesh is not sorted by type !");
442 return new MEDCouplingUMeshCellByTypeEntry(this);
446 * Returns a set of all cell types available in \a this mesh.
447 * \return std::set<INTERP_KERNEL::NormalizedCellType> - the set of cell types.
448 * \warning this method does not throw any exception even if \a this is not defined.
449 * \sa MEDCouplingUMesh::getAllGeoTypesSorted
451 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypes() const
457 * This method returns the sorted list of geometric types in \a this.
458 * Sorted means in the same order than the cells in \a this. A single entry in return vector means the maximal chunk of consecutive cells in \a this
459 * having the same geometric type. So a same geometric type can appear more than once if the cells are not sorted per geometric type.
461 * \throw if connectivity in \a this is not correctly defined.
463 * \sa MEDCouplingMesh::getAllGeoTypes
465 std::vector<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypesSorted() const
467 std::vector<INTERP_KERNEL::NormalizedCellType> ret;
468 checkConnectivityFullyDefined();
469 mcIdType nbOfCells=getNumberOfCells();
472 if(getNodalConnectivityArrayLen()<1)
473 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAllGeoTypesSorted : the connectivity in this seems invalid !");
474 const mcIdType *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin());
475 ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci++]);
476 for(mcIdType i=1;i<nbOfCells;i++,ci++)
477 if(ret.back()!=((INTERP_KERNEL::NormalizedCellType)c[*ci]))
478 ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci]);
483 * This method is a method that compares \a this and \a other.
484 * This method compares \b all attributes, even names and component names.
486 bool MEDCouplingUMesh::isEqualIfNotWhy(const MEDCouplingMesh *other, double prec, std::string& reason) const
489 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isEqualIfNotWhy : input other pointer is null !");
490 std::ostringstream oss; oss.precision(15);
491 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
494 reason="mesh given in input is not castable in MEDCouplingUMesh !";
497 if(!MEDCouplingPointSet::isEqualIfNotWhy(other,prec,reason))
499 if(_mesh_dim!=otherC->_mesh_dim)
501 oss << "umesh dimension mismatch : this mesh dimension=" << _mesh_dim << " other mesh dimension=" << otherC->_mesh_dim;
505 if(_types!=otherC->_types)
507 oss << "umesh geometric type mismatch :\nThis geometric types are :";
508 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
509 { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
510 oss << "\nOther geometric types are :";
511 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=otherC->_types.begin();iter!=otherC->_types.end();iter++)
512 { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
516 if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
517 if(_nodal_connec==0 || otherC->_nodal_connec==0)
519 reason="Only one UMesh between the two this and other has its nodal connectivity DataArrayInt defined !";
522 if(_nodal_connec!=otherC->_nodal_connec)
523 if(!_nodal_connec->isEqualIfNotWhy(*otherC->_nodal_connec,reason))
525 reason.insert(0,"Nodal connectivity DataArrayInt differ : ");
528 if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
529 if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
531 reason="Only one UMesh between the two this and other has its nodal connectivity index DataArrayInt defined !";
534 if(_nodal_connec_index!=otherC->_nodal_connec_index)
535 if(!_nodal_connec_index->isEqualIfNotWhy(*otherC->_nodal_connec_index,reason))
537 reason.insert(0,"Nodal connectivity index DataArrayInt differ : ");
544 * Checks if data arrays of this mesh (node coordinates, nodal
545 * connectivity of cells, etc) of two meshes are same. Textual data like name etc. are
547 * \param [in] other - the mesh to compare with.
548 * \param [in] prec - precision value used to compare node coordinates.
549 * \return bool - \a true if the two meshes are same.
551 bool MEDCouplingUMesh::isEqualWithoutConsideringStr(const MEDCouplingMesh *other, double prec) const
553 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
556 if(!MEDCouplingPointSet::isEqualWithoutConsideringStr(other,prec))
558 if(_mesh_dim!=otherC->_mesh_dim)
560 if(_types!=otherC->_types)
562 if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
563 if(_nodal_connec==0 || otherC->_nodal_connec==0)
565 if(_nodal_connec!=otherC->_nodal_connec)
566 if(!_nodal_connec->isEqualWithoutConsideringStr(*otherC->_nodal_connec))
568 if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
569 if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
571 if(_nodal_connec_index!=otherC->_nodal_connec_index)
572 if(!_nodal_connec_index->isEqualWithoutConsideringStr(*otherC->_nodal_connec_index))
578 * Checks if \a this and \a other meshes are geometrically equivalent with high
579 * probability, else an exception is thrown. The meshes are considered equivalent if
580 * (1) meshes contain the same number of nodes and the same number of elements of the
581 * same types (2) three cells of the two meshes (first, last and middle) are based
582 * on coincident nodes (with a specified precision).
583 * \param [in] other - the mesh to compare with.
584 * \param [in] prec - the precision used to compare nodes of the two meshes.
585 * \throw If the two meshes do not match.
587 void MEDCouplingUMesh::checkFastEquivalWith(const MEDCouplingMesh *other, double prec) const
589 MEDCouplingPointSet::checkFastEquivalWith(other,prec);
590 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
592 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkFastEquivalWith : Two meshes are not not unstructured !");
596 * Returns the reverse nodal connectivity. The reverse nodal connectivity enumerates
597 * cells each node belongs to.
598 * \warning For speed reasons, this method does not check if node ids in the nodal
599 * connectivity correspond to the size of node coordinates array.
600 * \param [in,out] revNodal - an array holding ids of cells sharing each node.
601 * \param [in,out] revNodalIndx - an array, of length \a this->getNumberOfNodes() + 1,
602 * dividing cell ids in \a revNodal into groups each referring to one
603 * node. Its every element (except the last one) is an index pointing to the
604 * first id of a group of cells. For example cells sharing the node #1 are
605 * described by following range of indices:
606 * [ \a revNodalIndx[1], \a revNodalIndx[2] ) and the cell ids are
607 * \a revNodal[ \a revNodalIndx[1] ], \a revNodal[ \a revNodalIndx[1] + 1], ...
608 * Number of cells sharing the *i*-th node is
609 * \a revNodalIndx[ *i*+1 ] - \a revNodalIndx[ *i* ].
610 * \throw If the coordinates array is not set.
611 * \throw If the nodal connectivity of cells is not defined.
613 * \if ENABLE_EXAMPLES
614 * \ref cpp_mcumesh_getReverseNodalConnectivity "Here is a C++ example".<br>
615 * \ref py_mcumesh_getReverseNodalConnectivity "Here is a Python example".
618 void MEDCouplingUMesh::getReverseNodalConnectivity(DataArrayIdType *revNodal, DataArrayIdType *revNodalIndx) const
621 mcIdType nbOfNodes(getNumberOfNodes());
622 mcIdType *revNodalIndxPtr=(mcIdType *)malloc((nbOfNodes+1)*sizeof(mcIdType));
623 revNodalIndx->useArray(revNodalIndxPtr,true,DeallocType::C_DEALLOC,nbOfNodes+1,1);
624 std::fill(revNodalIndxPtr,revNodalIndxPtr+nbOfNodes+1,0);
625 const mcIdType *conn(_nodal_connec->begin()),*connIndex(_nodal_connec_index->begin());
626 mcIdType nbOfCells(getNumberOfCells()),nbOfEltsInRevNodal(0);
627 for(mcIdType eltId=0;eltId<nbOfCells;eltId++)
629 const mcIdType *strtNdlConnOfCurCell(conn+connIndex[eltId]+1),*endNdlConnOfCurCell(conn+connIndex[eltId+1]);
630 for(const mcIdType *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
631 if(*iter>=0)//for polyhedrons
633 nbOfEltsInRevNodal++;
634 revNodalIndxPtr[(*iter)+1]++;
637 std::transform(revNodalIndxPtr+1,revNodalIndxPtr+nbOfNodes+1,revNodalIndxPtr,revNodalIndxPtr+1,std::plus<mcIdType>());
638 mcIdType *revNodalPtr=(mcIdType *)malloc(nbOfEltsInRevNodal*sizeof(mcIdType));
639 revNodal->useArray(revNodalPtr,true,DeallocType::C_DEALLOC,nbOfEltsInRevNodal,1);
640 std::fill(revNodalPtr,revNodalPtr+nbOfEltsInRevNodal,-1);
641 for(mcIdType eltId=0;eltId<nbOfCells;eltId++)
643 const mcIdType *strtNdlConnOfCurCell=conn+connIndex[eltId]+1;
644 const mcIdType *endNdlConnOfCurCell=conn+connIndex[eltId+1];
645 for(const mcIdType *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
646 if(*iter>=0)//for polyhedrons
647 *std::find_if(revNodalPtr+revNodalIndxPtr[*iter],revNodalPtr+revNodalIndxPtr[*iter+1],std::bind(std::equal_to<mcIdType>(),std::placeholders::_1,-1))=eltId;
652 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
653 * this->getMeshDimension(), that bound cells of \a this mesh. In addition arrays
654 * describing correspondence between cells of \a this and the result meshes are
655 * returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending connectivity,
656 * i.e. enumerate cells of the result mesh bounding each cell of \a this mesh. The
657 * arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
658 * i.e. enumerate cells of \a this mesh bounded by each cell of the result mesh.
659 * \warning For speed reasons, this method does not check if node ids in the nodal
660 * connectivity correspond to the size of node coordinates array.
661 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
662 * to write this mesh to the MED file, its cells must be sorted using
663 * sortCellsInMEDFileFrmt().
664 * \param [in,out] desc - the array containing cell ids of the result mesh bounding
665 * each cell of \a this mesh.
666 * \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
667 * dividing cell ids in \a desc into groups each referring to one
668 * cell of \a this mesh. Its every element (except the last one) is an index
669 * pointing to the first id of a group of cells. For example cells of the
670 * result mesh bounding the cell #1 of \a this mesh are described by following
672 * [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
673 * \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
674 * Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
675 * \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
676 * \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
677 * by each cell of the result mesh.
678 * \param [in,out] revDescIndx - the array, of length one more than number of cells
679 * in the result mesh,
680 * dividing cell ids in \a revDesc into groups each referring to one
681 * cell of the result mesh the same way as \a descIndx divides \a desc.
682 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is to
683 * delete this mesh using decrRef() as it is no more needed.
684 * \throw If the coordinates array is not set.
685 * \throw If the nodal connectivity of cells is node defined.
686 * \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
687 * revDescIndx == NULL.
689 * \if ENABLE_EXAMPLES
690 * \ref cpp_mcumesh_buildDescendingConnectivity "Here is a C++ example".<br>
691 * \ref py_mcumesh_buildDescendingConnectivity "Here is a Python example".
693 * \sa buildDescendingConnectivity2()
695 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
697 return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
701 * \a this has to have a mesh dimension equal to 3. If it is not the case an INTERP_KERNEL::Exception will be thrown.
702 * This behaves exactly as MEDCouplingUMesh::buildDescendingConnectivity does except that this method compute directly the transition from mesh dimension 3 to sub edges (dimension 1)
703 * in one shot. That is to say that this method is equivalent to 2 successive calls to MEDCouplingUMesh::buildDescendingConnectivity.
704 * This method returns 4 arrays and a mesh as MEDCouplingUMesh::buildDescendingConnectivity does.
705 * \sa MEDCouplingUMesh::buildDescendingConnectivity
707 MEDCouplingUMesh *MEDCouplingUMesh::explode3DMeshTo1D(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
710 if(getMeshDimension()!=3)
711 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explode3DMeshTo1D : This has to have a mesh dimension to 3 !");
712 return buildDescendingConnectivityGen<MinusTwoSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
716 * This method computes the micro edges constituting each cell in \a this. Micro edge is an edge for non quadratic cells. Micro edge is an half edge for quadratic cells.
717 * This method works for both meshes with mesh dimension equal to 2 or 3. Dynamical cells are not supported (polygons, polyhedrons...)
719 * \sa explode3DMeshTo1D, buildDescendingConnectiviy
721 MEDCouplingUMesh *MEDCouplingUMesh::explodeMeshIntoMicroEdges(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
724 switch(getMeshDimension())
727 return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
729 return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
731 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explodeMeshIntoMicroEdges : Only 2D and 3D supported !");
736 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
737 * this->getMeshDimension(), that bound cells of \a this mesh. In
738 * addition arrays describing correspondence between cells of \a this and the result
739 * meshes are returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending
740 * connectivity, i.e. enumerate cells of the result mesh bounding each cell of \a this
741 * mesh. This method differs from buildDescendingConnectivity() in that apart
742 * from cell ids, \a desc returns mutual orientation of cells in \a this and the
743 * result meshes. So a positive id means that order of nodes in corresponding cells
744 * of two meshes is same, and a negative id means a reverse order of nodes. Since a
745 * cell with id #0 can't be negative, the array \a desc returns ids in FORTRAN mode,
746 * i.e. cell ids are one-based.
747 * Arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
748 * i.e. enumerate cells of \a this mesh bounded by each cell of the result mesh.
749 * \warning For speed reasons, this method does not check if node ids in the nodal
750 * connectivity correspond to the size of node coordinates array.
751 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
752 * to write this mesh to the MED file, its cells must be sorted using
753 * sortCellsInMEDFileFrmt().
754 * \param [in,out] desc - the array containing cell ids of the result mesh bounding
755 * each cell of \a this mesh.
756 * \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
757 * dividing cell ids in \a desc into groups each referring to one
758 * cell of \a this mesh. Its every element (except the last one) is an index
759 * pointing to the first id of a group of cells. For example cells of the
760 * result mesh bounding the cell #1 of \a this mesh are described by following
762 * [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
763 * \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
764 * Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
765 * \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
766 * \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
767 * by each cell of the result mesh.
768 * \param [in,out] revDescIndx - the array, of length one more than number of cells
769 * in the result mesh,
770 * dividing cell ids in \a revDesc into groups each referring to one
771 * cell of the result mesh the same way as \a descIndx divides \a desc.
772 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This result mesh
773 * shares the node coordinates array with \a this mesh. The caller is to
774 * delete this mesh using decrRef() as it is no more needed.
775 * \throw If the coordinates array is not set.
776 * \throw If the nodal connectivity of cells is node defined.
777 * \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
778 * revDescIndx == NULL.
780 * \if ENABLE_EXAMPLES
781 * \ref cpp_mcumesh_buildDescendingConnectivity2 "Here is a C++ example".<br>
782 * \ref py_mcumesh_buildDescendingConnectivity2 "Here is a Python example".
784 * \sa buildDescendingConnectivity()
786 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity2(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
788 return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingOrientationSensitiveNbrer);
792 * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
793 * For speed reasons no check of this will be done. This method calls
794 * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
795 * This method lists for every cell in \b this its neighbor \b cells. To compute the result
796 * only connectivities are considered.
797 * The neighbor cells of a given cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
798 * The format of return is hence \ref numbering-indirect.
800 * \param [out] neighbors is an array storing all the neighbors of all cells in \b this. This array is newly
801 * allocated and should be dealt by the caller. \b neighborsIndx 2nd output
802 * parameter allows to select the right part in this array (\ref numbering-indirect). The number of tuples
803 * is equal to the last values in \b neighborsIndx.
804 * \param [out] neighborsIndx is an array of size this->getNumberOfCells()+1 newly allocated and should be
805 * dealt by the caller. This arrays allow to use the first output parameter \b neighbors (\ref numbering-indirect).
807 void MEDCouplingUMesh::computeNeighborsOfCells(DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIndx) const
809 MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
810 MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
811 MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
812 MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
813 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
815 ComputeNeighborsOfCellsAdv(desc,descIndx,revDesc,revDescIndx,neighbors,neighborsIndx);
819 * Given a set of identifiers indexed by the node IDs of the mesh (and given in the (\ref numbering-indirect format) ,
820 * re-arrange the data to produce a set indexed by cell IDs. The mapping between a node ID and a cell ID is done using the connectivity
821 * of the mesh (e.g. a triangular element will receive the information from its three vertices).
822 * Doublons are eliminated. If present in the inital dataset, the ID of the cell itself is also remooved.
824 * \param [in] nodeNeigh a set of identifiers (mcIdType) stored by node index (\ref numbering-indirect format)
825 * \param [in] nodeNeighI a set of identifiers (mcIdType) stored by node index (\ref numbering-indirect format)
826 * \param [out] cellNeigh This array is newly allocated and should be dealt by the caller. It contains the initial identifiers
827 * provided in the input parameters but stored now by cell index (See 2nd output parameter and \ref numbering-indirect).
828 * \param [out] cellNeighI is an array of size this->getNumberOfCells()+1 newly allocated and should be
829 * dealt by the caller. This arrays allow to use the first output parameter \b neighbors (\ref numbering-indirect).
831 * \raise if the number of tuples in nodeNeighI is not equal to the number of nodes in the mesh.
833 void MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne(const DataArrayIdType *nodeNeigh, const DataArrayIdType *nodeNeighI,
834 MCAuto<DataArrayIdType>& cellNeigh, MCAuto<DataArrayIdType>& cellNeighIndex) const
836 if(!nodeNeigh || !nodeNeighI)
837 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : null pointer !");
838 checkConsistencyLight();
839 nodeNeigh->checkAllocated(); nodeNeighI->checkAllocated();
840 nodeNeigh->checkNbOfComps(1,"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : node neigh");
841 nodeNeighI->checkNbOfComps(1,"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : node neigh index");
842 nodeNeighI->checkNbOfTuples(1+getNumberOfNodes(),"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : invalid length");
843 mcIdType nbCells=getNumberOfCells();
844 const mcIdType *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin()),*ne(nodeNeigh->begin()),*nei(nodeNeighI->begin());
845 cellNeigh=DataArrayIdType::New(); cellNeigh->alloc(0,1); cellNeighIndex=DataArrayIdType::New(); cellNeighIndex->alloc(1,1); cellNeighIndex->setIJ(0,0,0);
846 for(mcIdType i=0;i<nbCells;i++)
848 std::set<mcIdType> s;
849 for(const mcIdType *it=c+ci[i]+1;it!=c+ci[i+1];it++)
850 if(*it>=0) // avoid -1 in polygons or polyedrons
851 s.insert(ne+nei[*it],ne+nei[*it+1]);
853 cellNeigh->insertAtTheEnd(s.begin(),s.end());
854 cellNeighIndex->pushBackSilent(cellNeigh->getNumberOfTuples());
859 * This method is called by MEDCouplingUMesh::computeNeighborsOfCells. This methods performs the algorithm
860 * of MEDCouplingUMesh::computeNeighborsOfCells.
861 * This method is useful for users that want to reduce along a criterion the set of neighbours cell. This is
862 * typically the case to extract a set a neighbours,
863 * excluding a set of meshdim-1 cells in input descending connectivity.
864 * Typically \b desc, \b descIndx, \b revDesc and \b revDescIndx (\ref numbering-indirect) input params are
865 * the result of MEDCouplingUMesh::buildDescendingConnectivity.
866 * This method lists cell by cell in \b this which are its neighbors. To compute the result only connectivities
868 * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
870 * \param [in] desc descending connectivity array.
871 * \param [in] descIndx descending connectivity index array used to walk through \b desc (\ref numbering-indirect).
872 * \param [in] revDesc reverse descending connectivity array.
873 * \param [in] revDescIndx reverse descending connectivity index array used to walk through \b revDesc (\ref numbering-indirect).
874 * \param [out] neighbors is an array storing all the neighbors of all cells in \b this. This array is newly allocated and should be dealt by the caller. \b neighborsIndx 2nd output
875 * parameter allows to select the right part in this array. The number of tuples is equal to the last values in \b neighborsIndx.
876 * \param [out] neighborsIndx is an array of size this->getNumberOfCells()+1 newly allocated and should be dealt by the caller. This arrays allow to use the first output parameter \b neighbors.
878 void MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(const DataArrayIdType *desc, const DataArrayIdType *descIndx, const DataArrayIdType *revDesc, const DataArrayIdType *revDescIndx,
879 DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIndx)
881 if(!desc || !descIndx || !revDesc || !revDescIndx)
882 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeNeighborsOfCellsAdv some input array is empty !");
883 const mcIdType *descPtr=desc->begin();
884 const mcIdType *descIPtr=descIndx->begin();
885 const mcIdType *revDescPtr=revDesc->begin();
886 const mcIdType *revDescIPtr=revDescIndx->begin();
888 mcIdType nbCells=descIndx->getNumberOfTuples()-1;
889 MCAuto<DataArrayIdType> out0=DataArrayIdType::New();
890 MCAuto<DataArrayIdType> out1=DataArrayIdType::New(); out1->alloc(nbCells+1,1);
891 mcIdType *out1Ptr=out1->getPointer();
893 out0->reserve(desc->getNumberOfTuples());
894 for(mcIdType i=0;i<nbCells;i++,descIPtr++,out1Ptr++)
896 for(const mcIdType *w1=descPtr+descIPtr[0];w1!=descPtr+descIPtr[1];w1++)
898 std::set<mcIdType> s(revDescPtr+revDescIPtr[*w1],revDescPtr+revDescIPtr[(*w1)+1]);
900 out0->insertAtTheEnd(s.begin(),s.end());
902 *out1Ptr=out0->getNumberOfTuples();
904 neighbors=out0.retn();
905 neighborsIndx=out1.retn();
909 * Explodes \a this into edges whatever its dimension.
911 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::explodeIntoEdges(MCAuto<DataArrayIdType>& desc, MCAuto<DataArrayIdType>& descIndex, MCAuto<DataArrayIdType>& revDesc, MCAuto<DataArrayIdType>& revDescIndx) const
914 int mdim(getMeshDimension());
915 desc=DataArrayIdType::New(); descIndex=DataArrayIdType::New(); revDesc=DataArrayIdType::New(); revDescIndx=DataArrayIdType::New();
916 MCAuto<MEDCouplingUMesh> mesh1D;
921 mesh1D=explode3DMeshTo1D(desc,descIndex,revDesc,revDescIndx);
926 mesh1D=buildDescendingConnectivity(desc,descIndex,revDesc,revDescIndx);
931 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2] !");
938 * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
939 * For speed reasons no check of this will be done. This method calls
940 * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
941 * This method lists for every node in \b this its neighbor \b nodes. To compute the result
942 * only connectivities are considered.
943 * The neighbor nodes of node having id 'nodeId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
945 * \param [out] neighbors is an array storing all the neighbors of all nodes in \b this. This array
946 * is newly allocated and should be dealt by the caller. \b neighborsIndx 2nd output
947 * parameter allows to select the right part in this array (\ref numbering-indirect).
948 * The number of tuples is equal to the last values in \b neighborsIndx.
949 * \param [out] neighborsIdx is an array of size this->getNumberOfCells()+1 newly allocated and should
950 * be dealt by the caller. This arrays allow to use the first output parameter \b neighbors.
952 * \sa MEDCouplingUMesh::computeEnlargedNeighborsOfNodes
954 void MEDCouplingUMesh::computeNeighborsOfNodes(DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIdx) const
957 mcIdType mdim(getMeshDimension()),nbNodes(getNumberOfNodes());
958 MCAuto<DataArrayIdType> desc(DataArrayIdType::New()),descIndx(DataArrayIdType::New()),revDesc(DataArrayIdType::New()),revDescIndx(DataArrayIdType::New());
959 MCConstAuto<MEDCouplingUMesh> mesh1D;
964 mesh1D=explode3DMeshTo1D(desc,descIndx,revDesc,revDescIndx);
969 mesh1D=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
974 mesh1D.takeRef(this);
979 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2,1] !");
982 desc=DataArrayIdType::New(); descIndx=DataArrayIdType::New(); revDesc=0; revDescIndx=0;
983 mesh1D->getReverseNodalConnectivity(desc,descIndx);
984 MCAuto<DataArrayIdType> ret0(DataArrayIdType::New());
985 ret0->alloc(desc->getNumberOfTuples(),1);
986 mcIdType *r0Pt(ret0->getPointer());
987 const mcIdType *c1DPtr(mesh1D->getNodalConnectivity()->begin()),*rn(desc->begin()),*rni(descIndx->begin());
988 for(mcIdType i=0;i<nbNodes;i++,rni++)
990 for(const mcIdType *oneDCellIt=rn+rni[0];oneDCellIt!=rn+rni[1];oneDCellIt++)
991 *r0Pt++=c1DPtr[3*(*oneDCellIt)+1]==i?c1DPtr[3*(*oneDCellIt)+2]:c1DPtr[3*(*oneDCellIt)+1];
993 neighbors=ret0.retn();
994 neighborsIdx=descIndx.retn();
998 * Computes enlarged neighbors for each nodes in \a this. The behavior of this method is close to MEDCouplingUMesh::computeNeighborsOfNodes except that the neighborhood of each node is wider here.
999 * A node j is considered to be in the neighborhood of i if and only if there is a cell in \a this containing in its nodal connectivity both i and j.
1000 * This method is useful to find ghost cells of a part of a mesh with a code based on fields on nodes.
1002 * \sa MEDCouplingUMesh::computeNeighborsOfNodes
1004 void MEDCouplingUMesh::computeEnlargedNeighborsOfNodes(MCAuto<DataArrayIdType> &neighbors, MCAuto<DataArrayIdType>& neighborsIdx) const
1006 checkFullyDefined();
1007 mcIdType nbOfNodes(getNumberOfNodes());
1008 const mcIdType *conn(_nodal_connec->begin()),*connIndex(_nodal_connec_index->begin());
1009 mcIdType nbOfCells=getNumberOfCells();
1010 std::vector< std::set<mcIdType> > st0(nbOfNodes);
1011 for(mcIdType eltId=0;eltId<nbOfCells;eltId++)
1013 const mcIdType *strtNdlConnOfCurCell(conn+connIndex[eltId]+1),*endNdlConnOfCurCell(conn+connIndex[eltId+1]);
1014 std::set<mcIdType> s(strtNdlConnOfCurCell,endNdlConnOfCurCell); s.erase(-1); //for polyhedrons
1015 for(std::set<mcIdType>::const_iterator iter2=s.begin();iter2!=s.end();iter2++)
1016 st0[*iter2].insert(s.begin(),s.end());
1018 neighborsIdx=DataArrayIdType::New(); neighborsIdx->alloc(nbOfNodes+1,1); neighborsIdx->setIJ(0,0,0);
1020 mcIdType *neighIdx(neighborsIdx->getPointer());
1021 for(std::vector< std::set<mcIdType> >::const_iterator it=st0.begin();it!=st0.end();it++,neighIdx++)
1024 neighIdx[1]=neighIdx[0];
1026 neighIdx[1]=neighIdx[0]+ToIdType((*it).size())-1;
1029 neighbors=DataArrayIdType::New(); neighbors->alloc(neighborsIdx->back(),1);
1031 const mcIdType *neighIdx(neighborsIdx->begin());
1032 mcIdType *neigh(neighbors->getPointer()),nodeId(0);
1033 for(std::vector< std::set<mcIdType> >::const_iterator it=st0.begin();it!=st0.end();it++,neighIdx++,nodeId++)
1035 std::set<mcIdType> s(*it); s.erase(nodeId);
1036 std::copy(s.begin(),s.end(),neigh+*neighIdx);
1042 * Converts specified cells to either polygons (if \a this is a 2D mesh) or
1043 * polyhedrons (if \a this is a 3D mesh). The cells to convert are specified by an
1044 * array of cell ids. Pay attention that after conversion all algorithms work slower
1045 * with \a this mesh than before conversion. <br> If an exception is thrown during the
1046 * conversion due presence of invalid ids in the array of cells to convert, as a
1047 * result \a this mesh contains some already converted elements. In this case the 2D
1048 * mesh remains valid but 3D mesh becomes \b inconsistent!
1049 * \warning This method can significantly modify the order of geometric types in \a this,
1050 * hence, to write this mesh to the MED file, its cells must be sorted using
1051 * sortCellsInMEDFileFrmt().
1052 * \param [in] cellIdsToConvertBg - the array holding ids of cells to convert.
1053 * \param [in] cellIdsToConvertEnd - a pointer to the last-plus-one-th element of \a
1054 * cellIdsToConvertBg.
1055 * \throw If the coordinates array is not set.
1056 * \throw If the nodal connectivity of cells is node defined.
1057 * \throw If dimension of \a this mesh is not either 2 or 3.
1059 * \if ENABLE_EXAMPLES
1060 * \ref cpp_mcumesh_convertToPolyTypes "Here is a C++ example".<br>
1061 * \ref py_mcumesh_convertToPolyTypes "Here is a Python example".
1064 void MEDCouplingUMesh::convertToPolyTypes(const mcIdType *cellIdsToConvertBg, const mcIdType *cellIdsToConvertEnd)
1066 checkFullyDefined();
1067 int dim=getMeshDimension();
1069 throw INTERP_KERNEL::Exception("Invalid mesh dimension : must be 2 or 3 !");
1070 mcIdType nbOfCells=getNumberOfCells();
1073 const mcIdType *connIndex=_nodal_connec_index->begin();
1074 mcIdType *conn=_nodal_connec->getPointer();
1075 for(const mcIdType *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1077 if(*iter>=0 && *iter<nbOfCells)
1079 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*iter]]);
1080 if(!cm.isQuadratic())
1081 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_POLYGON;
1083 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_QPOLYG;
1087 std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1088 oss << " in range [0," << nbOfCells << ") !";
1089 throw INTERP_KERNEL::Exception(oss.str());
1095 mcIdType *connIndex(_nodal_connec_index->getPointer());
1096 const mcIdType *connOld(_nodal_connec->getConstPointer());
1097 MCAuto<DataArrayIdType> connNew(DataArrayIdType::New()),connNewI(DataArrayIdType::New()); connNew->alloc(0,1); connNewI->alloc(1,1); connNewI->setIJ(0,0,0);
1098 std::vector<bool> toBeDone(nbOfCells,false);
1099 for(const mcIdType *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1101 if(*iter>=0 && *iter<nbOfCells)
1102 toBeDone[*iter]=true;
1105 std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1106 oss << " in range [0," << nbOfCells << ") !";
1107 throw INTERP_KERNEL::Exception(oss.str());
1110 for(mcIdType cellId=0;cellId<nbOfCells;cellId++)
1112 mcIdType pos(connIndex[cellId]),posP1(connIndex[cellId+1]);
1113 mcIdType lgthOld(posP1-pos-1);
1114 if(toBeDone[cellId])
1116 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connOld[pos]);
1117 unsigned nbOfFaces(cm.getNumberOfSons2(connOld+pos+1,lgthOld));
1118 mcIdType *tmp(new mcIdType[nbOfFaces*lgthOld+1]);
1119 mcIdType *work=tmp; *work++=INTERP_KERNEL::NORM_POLYHED;
1120 for(unsigned j=0;j<nbOfFaces;j++)
1122 INTERP_KERNEL::NormalizedCellType type;
1123 unsigned offset=cm.fillSonCellNodalConnectivity2(j,connOld+pos+1,lgthOld,work,type);
1127 std::size_t newLgth(std::distance(tmp,work)-1);//-1 for last -1
1128 connNew->pushBackValsSilent(tmp,tmp+newLgth);
1129 connNewI->pushBackSilent(connNewI->back()+ToIdType(newLgth));
1134 connNew->pushBackValsSilent(connOld+pos,connOld+posP1);
1135 connNewI->pushBackSilent(connNewI->back()+posP1-pos);
1138 setConnectivity(connNew,connNewI,false);//false because computeTypes called just behind.
1144 * Converts all cells to either polygons (if \a this is a 2D mesh) or
1145 * polyhedrons (if \a this is a 3D mesh).
1146 * \warning As this method is purely for user-friendliness and no optimization is
1147 * done to avoid construction of a useless vector, this method can be costly
1149 * \throw If the coordinates array is not set.
1150 * \throw If the nodal connectivity of cells is node defined.
1151 * \throw If dimension of \a this mesh is not either 2 or 3.
1153 void MEDCouplingUMesh::convertAllToPoly()
1155 mcIdType nbOfCells=getNumberOfCells();
1156 std::vector<mcIdType> cellIds(nbOfCells);
1157 for(mcIdType i=0;i<nbOfCells;i++)
1159 convertToPolyTypes(&cellIds[0],&cellIds[0]+ToIdType(cellIds.size()));
1163 * Fixes nodal connectivity of invalid cells of type NORM_POLYHED. This method
1164 * expects that all NORM_POLYHED cells have connectivity similar to that of prismatic
1165 * volumes like NORM_HEXA8, NORM_PENTA6 etc., i.e. the first half of nodes describes a
1166 * base facet of the volume and the second half of nodes describes an opposite facet
1167 * having the same number of nodes as the base one. This method converts such
1168 * connectivity to a valid polyhedral format where connectivity of each facet is
1169 * explicitly described and connectivity of facets are separated by -1. If \a this mesh
1170 * contains a NORM_POLYHED cell with a valid connectivity, or an invalid connectivity is
1171 * not as expected, an exception is thrown and the mesh remains unchanged. Care of
1172 * a correct orientation of the first facet of a polyhedron, else orientation of a
1173 * corrected cell is reverse.<br>
1174 * This method is useful to build an extruded unstructured mesh with polyhedrons as
1175 * it releases the user from boring description of polyhedra connectivity in the valid
1177 * \throw If \a this->getMeshDimension() != 3.
1178 * \throw If \a this->getSpaceDimension() != 3.
1179 * \throw If the nodal connectivity of cells is not defined.
1180 * \throw If the coordinates array is not set.
1181 * \throw If \a this mesh contains polyhedrons with the valid connectivity.
1182 * \throw If \a this mesh contains polyhedrons with odd number of nodes.
1184 * \if ENABLE_EXAMPLES
1185 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
1186 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
1189 void MEDCouplingUMesh::convertExtrudedPolyhedra()
1191 checkFullyDefined();
1192 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1193 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertExtrudedPolyhedra works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
1194 mcIdType nbOfCells=getNumberOfCells();
1195 MCAuto<DataArrayIdType> newCi=DataArrayIdType::New();
1196 newCi->alloc(nbOfCells+1,1);
1197 mcIdType *newci=newCi->getPointer();
1198 const mcIdType *ci=_nodal_connec_index->getConstPointer();
1199 const mcIdType *c=_nodal_connec->getConstPointer();
1201 for(mcIdType i=0;i<nbOfCells;i++)
1203 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1204 if(type==INTERP_KERNEL::NORM_POLYHED)
1206 if(std::count(c+ci[i]+1,c+ci[i+1],-1)!=0)
1208 std::ostringstream oss; oss << "MEDCouplingUMesh::convertExtrudedPolyhedra : cell # " << i << " is a polhedron BUT it has NOT exactly 1 face !";
1209 throw INTERP_KERNEL::Exception(oss.str());
1211 std::size_t n2=std::distance(c+ci[i]+1,c+ci[i+1]);
1214 std::ostringstream oss; oss << "MEDCouplingUMesh::convertExtrudedPolyhedra : cell # " << i << " is a polhedron with 1 face but there is a mismatch of number of nodes in face should be even !";
1215 throw INTERP_KERNEL::Exception(oss.str());
1217 mcIdType n1=ToIdType(n2/2);
1218 newci[i+1]=7*n1+2+newci[i];//6*n1 (nodal length) + n1+2 (number of faces) - 1 (number of '-1' separator is equal to number of faces -1) + 1 (for cell type)
1221 newci[i+1]=(ci[i+1]-ci[i])+newci[i];
1223 MCAuto<DataArrayIdType> newC=DataArrayIdType::New();
1224 newC->alloc(newci[nbOfCells],1);
1225 mcIdType *newc=newC->getPointer();
1226 for(mcIdType i=0;i<nbOfCells;i++)
1228 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1229 if(type==INTERP_KERNEL::NORM_POLYHED)
1231 std::size_t n1=std::distance(c+ci[i]+1,c+ci[i+1])/2;
1232 newc=std::copy(c+ci[i],c+ci[i]+n1+1,newc);
1234 for(std::size_t j=0;j<n1;j++)
1236 newc[j]=c[ci[i]+1+n1+(n1-j)%n1];
1238 newc[n1+5*j+1]=c[ci[i]+1+j];
1239 newc[n1+5*j+2]=c[ci[i]+1+j+n1];
1240 newc[n1+5*j+3]=c[ci[i]+1+(j+1)%n1+n1];
1241 newc[n1+5*j+4]=c[ci[i]+1+(j+1)%n1];
1246 newc=std::copy(c+ci[i],c+ci[i+1],newc);
1248 _nodal_connec_index->decrRef(); _nodal_connec_index=newCi.retn();
1249 _nodal_connec->decrRef(); _nodal_connec=newC.retn();
1254 * Converts all polygons (if \a this is a 2D mesh) or polyhedrons (if \a this is a 3D
1255 * mesh) to cells of classical types. This method is opposite to convertToPolyTypes().
1256 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
1257 * to write this mesh to the MED file, its cells must be sorted using
1258 * sortCellsInMEDFileFrmt().
1259 * \warning Cells (and most notably polyhedrons) must be correctly oriented for this to work
1260 * properly. See orientCorrectlyPolyhedrons() and arePolyhedronsNotCorrectlyOriented().
1261 * \return \c true if at least one cell has been converted, \c false else. In the
1262 * last case the nodal connectivity remains unchanged.
1263 * \throw If the coordinates array is not set.
1264 * \throw If the nodal connectivity of cells is not defined.
1265 * \throw If \a this->getMeshDimension() < 0.
1267 bool MEDCouplingUMesh::unPolyze()
1269 checkFullyDefined();
1270 int mdim=getMeshDimension();
1272 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::unPolyze works on umeshes with meshdim equals to 0, 1 2 or 3 !");
1275 mcIdType nbOfCells=getNumberOfCells();
1278 mcIdType initMeshLgth=getNodalConnectivityArrayLen();
1279 mcIdType *conn=_nodal_connec->getPointer();
1280 mcIdType *index=_nodal_connec_index->getPointer();
1281 mcIdType posOfCurCell=0;
1283 mcIdType lgthOfCurCell;
1285 for(mcIdType i=0;i<nbOfCells;i++)
1287 lgthOfCurCell=index[i+1]-posOfCurCell;
1288 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
1289 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
1290 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::NORM_ERROR;
1294 switch(cm.getDimension())
1298 INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[lgthOfCurCell-1];
1299 std::copy(conn+posOfCurCell+1,conn+posOfCurCell+lgthOfCurCell,(mcIdType *)tmp);
1300 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly2D(cm.isQuadratic(),tmp,lgthOfCurCell-1,conn+newPos+1,newLgth);
1305 mcIdType nbOfFaces,lgthOfPolyhConn;
1306 INTERP_KERNEL::AutoPtr<mcIdType> zipFullReprOfPolyh=INTERP_KERNEL::CellSimplify::getFullPolyh3DCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,nbOfFaces,lgthOfPolyhConn);
1307 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly3D(zipFullReprOfPolyh,nbOfFaces,lgthOfPolyhConn,conn+newPos+1,newLgth);
1310 /* case 1: // Not supported yet
1312 newType=(lgthOfCurCell==3)?INTERP_KERNEL::NORM_SEG2:INTERP_KERNEL::NORM_POLYL;
1317 ret=ret || (newType!=type);
1318 conn[newPos]=newType;
1320 posOfCurCell=index[i+1];
1325 std::copy(conn+posOfCurCell,conn+posOfCurCell+lgthOfCurCell,conn+newPos);
1326 newPos+=lgthOfCurCell;
1327 posOfCurCell+=lgthOfCurCell;
1331 if(newPos!=initMeshLgth)
1332 _nodal_connec->reAlloc(newPos);
1339 * This method expects that spaceDimension is equal to 3 and meshDimension equal to 3.
1340 * This method performs operation only on polyhedrons in \b this. If no polyhedrons exists in \b this, \b this remains unchanged.
1341 * This method allows to merge if any coplanar 3DSurf cells that may appear in some polyhedrons cells.
1343 * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not. This epsilon is used to recenter around origin to have maximal
1346 void MEDCouplingUMesh::simplifyPolyhedra(double eps)
1348 checkFullyDefined();
1349 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1350 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplifyPolyhedra : works on meshdimension 3 and spaceDimension 3 !");
1351 MCAuto<DataArrayDouble> coords=getCoords()->deepCopy();
1352 coords->recenterForMaxPrecision(eps);
1354 mcIdType nbOfCells=getNumberOfCells();
1355 const mcIdType *conn=_nodal_connec->getConstPointer();
1356 const mcIdType *index=_nodal_connec_index->getConstPointer();
1357 MCAuto<DataArrayIdType> connINew=DataArrayIdType::New();
1358 connINew->alloc(nbOfCells+1,1);
1359 mcIdType *connINewPtr=connINew->getPointer(); *connINewPtr++=0;
1360 MCAuto<DataArrayIdType> connNew=DataArrayIdType::New(); connNew->alloc(0,1);
1361 MCAuto<DataArrayIdType> E_Fi(DataArrayIdType::New()), E_F(DataArrayIdType::New()), F_Ei(DataArrayIdType::New()), F_E(DataArrayIdType::New());
1362 MCAuto<MEDCouplingUMesh> m_faces(buildDescendingConnectivity(E_F, E_Fi, F_E, F_Ei));
1364 for(mcIdType i=0;i<nbOfCells;i++,connINewPtr++)
1366 if(conn[index[i]]==ToIdType(INTERP_KERNEL::NORM_POLYHED))
1368 SimplifyPolyhedronCell(eps,coords, i,connNew, m_faces, E_Fi, E_F, F_Ei, F_E);
1372 connNew->insertAtTheEnd(conn+index[i],conn+index[i+1]);
1373 *connINewPtr=connNew->getNumberOfTuples();
1376 setConnectivity(connNew,connINew,false);
1380 * This method returns all node ids used in the connectivity of \b this. The data array returned has to be dealt by the caller.
1381 * The returned node ids are sorted ascendingly. This method is close to MEDCouplingUMesh::getNodeIdsInUse except
1382 * the format of the returned DataArrayIdType instance.
1384 * \return a newly allocated DataArrayIdType sorted ascendingly of fetched node ids.
1385 * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1387 DataArrayIdType *MEDCouplingUMesh::computeFetchedNodeIds() const
1389 checkConnectivityFullyDefined();
1390 const mcIdType *maxEltPt(std::max_element(_nodal_connec->begin(),_nodal_connec->end()));
1391 mcIdType maxElt(maxEltPt==_nodal_connec->end()?0:std::abs(*maxEltPt)+1);
1392 std::vector<bool> retS(maxElt,false);
1393 computeNodeIdsAlg(retS);
1394 return DataArrayIdType::BuildListOfSwitchedOn(retS);
1398 * \param [in,out] nodeIdsInUse an array of size typically equal to nbOfNodes.
1399 * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1401 void MEDCouplingUMesh::computeNodeIdsAlg(std::vector<bool>& nodeIdsInUse) const
1403 mcIdType nbOfNodes=ToIdType(nodeIdsInUse.size()),
1404 nbOfCells=getNumberOfCells();
1405 const mcIdType *connIndex(_nodal_connec_index->getConstPointer()),*conn(_nodal_connec->getConstPointer());
1406 for(mcIdType i=0;i<nbOfCells;i++)
1407 for(mcIdType j=connIndex[i]+1;j<connIndex[i+1];j++)
1410 if(conn[j]<nbOfNodes)
1411 nodeIdsInUse[conn[j]]=true;
1414 std::ostringstream oss; oss << "MEDCouplingUMesh::computeNodeIdsAlg : In cell #" << i << " presence of node id " << conn[j] << " not in [0," << nbOfNodes << ") !";
1415 throw INTERP_KERNEL::Exception(oss.str());
1422 struct MEDCouplingAccVisit
1424 MEDCouplingAccVisit():_new_nb_of_nodes(0) { }
1425 mcIdType operator()(mcIdType val) { if(val!=-1) return _new_nb_of_nodes++; else return -1; }
1426 mcIdType _new_nb_of_nodes;
1432 * Finds nodes not used in any cell and returns an array giving a new id to every node
1433 * by excluding the unused nodes, for which the array holds -1. The result array is
1434 * a mapping in "Old to New" mode.
1435 * \param [out] nbrOfNodesInUse - number of node ids present in the nodal connectivity.
1436 * \return DataArrayIdType * - a new instance of DataArrayIdType. Its length is \a
1437 * this->getNumberOfNodes(). It holds for each node of \a this mesh either -1
1438 * if the node is unused or a new id else. The caller is to delete this
1439 * array using decrRef() as it is no more needed.
1440 * \throw If the coordinates array is not set.
1441 * \throw If the nodal connectivity of cells is not defined.
1442 * \throw If the nodal connectivity includes an invalid id.
1444 * \if ENABLE_EXAMPLES
1445 * \ref cpp_mcumesh_getNodeIdsInUse "Here is a C++ example".<br>
1446 * \ref py_mcumesh_getNodeIdsInUse "Here is a Python example".
1448 * \sa computeFetchedNodeIds, computeNodeIdsAlg()
1450 DataArrayIdType *MEDCouplingUMesh::getNodeIdsInUse(mcIdType& nbrOfNodesInUse) const
1453 mcIdType nbOfNodes(getNumberOfNodes());
1454 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1455 ret->alloc(nbOfNodes,1);
1456 mcIdType *traducer=ret->getPointer();
1457 std::fill(traducer,traducer+nbOfNodes,-1);
1458 mcIdType nbOfCells=getNumberOfCells();
1459 const mcIdType *connIndex=_nodal_connec_index->getConstPointer();
1460 const mcIdType *conn=_nodal_connec->getConstPointer();
1461 for(mcIdType i=0;i<nbOfCells;i++)
1462 for(mcIdType j=connIndex[i]+1;j<connIndex[i+1];j++)
1465 if(conn[j]<nbOfNodes)
1466 traducer[conn[j]]=1;
1469 std::ostringstream oss; oss << "MEDCouplingUMesh::getNodeIdsInUse : In cell #" << i << " presence of node id " << conn[j] << " not in [0," << nbOfNodes << ") !";
1470 throw INTERP_KERNEL::Exception(oss.str());
1473 nbrOfNodesInUse=ToIdType(std::count(traducer,traducer+nbOfNodes,1));
1474 std::transform(traducer,traducer+nbOfNodes,traducer,MEDCouplingAccVisit());
1479 * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1480 * For each cell in \b this the number of nodes constituting cell is computed.
1481 * For each polyhedron cell, the sum of the number of nodes of each face constituting polyhedron cell is returned.
1482 * So for pohyhedrons some nodes can be counted several times in the returned result.
1484 * \return a newly allocated array
1485 * \sa MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell
1487 DataArrayIdType *MEDCouplingUMesh::computeNbOfNodesPerCell() const
1489 checkConnectivityFullyDefined();
1490 mcIdType nbOfCells=getNumberOfCells();
1491 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1492 ret->alloc(nbOfCells,1);
1493 mcIdType *retPtr=ret->getPointer();
1494 const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1495 const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1496 for(mcIdType i=0;i<nbOfCells;i++,retPtr++)
1498 if(conn[connI[i]]!=ToIdType(INTERP_KERNEL::NORM_POLYHED))
1499 *retPtr=connI[i+1]-connI[i]-1;
1501 *retPtr=connI[i+1]-connI[i]-1-ToIdType(std::count(conn+connI[i]+1,conn+connI[i+1],-1));
1507 * This method computes effective number of nodes per cell. That is to say nodes appearing several times in nodal connectivity of a cell,
1508 * will be counted only once here whereas it will be counted several times in MEDCouplingUMesh::computeNbOfNodesPerCell method.
1510 * \return DataArrayIdType * - new object to be deallocated by the caller.
1511 * \sa MEDCouplingUMesh::computeNbOfNodesPerCell
1513 DataArrayIdType *MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell() const
1515 checkConnectivityFullyDefined();
1516 mcIdType nbOfCells=getNumberOfCells();
1517 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1518 ret->alloc(nbOfCells,1);
1519 mcIdType *retPtr=ret->getPointer();
1520 const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1521 const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1522 for(mcIdType i=0;i<nbOfCells;i++,retPtr++)
1524 std::set<mcIdType> s(conn+connI[i]+1,conn+connI[i+1]);
1525 if(conn[connI[i]]!=ToIdType(INTERP_KERNEL::NORM_POLYHED))
1526 *retPtr=ToIdType(s.size());
1530 *retPtr=ToIdType(s.size());
1537 * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1538 * For each cell in \b this the number of faces constituting (entity of dimension this->getMeshDimension()-1) cell is computed.
1540 * \return a newly allocated array
1542 DataArrayIdType *MEDCouplingUMesh::computeNbOfFacesPerCell() const
1544 checkConnectivityFullyDefined();
1545 mcIdType nbOfCells=getNumberOfCells();
1546 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1547 ret->alloc(nbOfCells,1);
1548 mcIdType *retPtr=ret->getPointer();
1549 const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1550 const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1551 for(mcIdType i=0;i<nbOfCells;i++,retPtr++,connI++)
1553 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]);
1554 *retPtr=cm.getNumberOfSons2(conn+connI[0]+1,connI[1]-connI[0]-1);
1560 * Removes unused nodes (the node coordinates array is shorten) and returns an array
1561 * mapping between new and old node ids in "Old to New" mode. -1 values in the returned
1562 * array mean that the corresponding old node is no more used.
1563 * \return DataArrayIdType * - a new instance of DataArrayIdType of length \a
1564 * this->getNumberOfNodes() before call of this method. The caller is to
1565 * delete this array using decrRef() as it is no more needed.
1566 * \throw If the coordinates array is not set.
1567 * \throw If the nodal connectivity of cells is not defined.
1568 * \throw If the nodal connectivity includes an invalid id.
1569 * \sa areAllNodesFetched
1571 * \if ENABLE_EXAMPLES
1572 * \ref cpp_mcumesh_zipCoordsTraducer "Here is a C++ example".<br>
1573 * \ref py_mcumesh_zipCoordsTraducer "Here is a Python example".
1576 DataArrayIdType *MEDCouplingUMesh::zipCoordsTraducer()
1578 return MEDCouplingPointSet::zipCoordsTraducer();
1582 * This method stands if 'cell1' and 'cell2' are equals regarding 'compType' policy.
1583 * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1585 int MEDCouplingUMesh::AreCellsEqual(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2, int compType)
1590 return AreCellsEqualPolicy0(conn,connI,cell1,cell2);
1592 return AreCellsEqualPolicy1(conn,connI,cell1,cell2);
1594 return AreCellsEqualPolicy2(conn,connI,cell1,cell2);
1596 return AreCellsEqualPolicy2NoType(conn,connI,cell1,cell2);
1598 return AreCellsEqualPolicy7(conn,connI,cell1,cell2);
1600 throw INTERP_KERNEL::Exception("Unknown comparison asked ! Must be in 0,1,2,3 or 7.");
1604 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 0.
1606 int MEDCouplingUMesh::AreCellsEqualPolicy0(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1608 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1609 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;
1614 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 1.
1616 int MEDCouplingUMesh::AreCellsEqualPolicy1(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1618 mcIdType sz=connI[cell1+1]-connI[cell1];
1619 if(sz==connI[cell2+1]-connI[cell2])
1621 if(conn[connI[cell1]]==conn[connI[cell2]])
1623 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1624 unsigned dim=cm.getDimension();
1629 mcIdType sz1=2*(sz-1);
1630 INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz1];
1631 mcIdType *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(mcIdType *)tmp);
1632 std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1633 work=std::search((mcIdType *)tmp,(mcIdType *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1634 return work!=tmp+sz1?1:0;
1637 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;//case of SEG2 and SEG3
1640 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy1 : not implemented yet for meshdim == 3 !");
1647 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 2.
1649 int MEDCouplingUMesh::AreCellsEqualPolicy2(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1651 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1653 if(conn[connI[cell1]]==conn[connI[cell2]])
1655 std::set<mcIdType> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1656 std::set<mcIdType> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1664 * This method is less restrictive than AreCellsEqualPolicy2. Here the geometric type is absolutely not taken into account !
1666 int MEDCouplingUMesh::AreCellsEqualPolicy2NoType(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1668 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1670 std::set<mcIdType> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1671 std::set<mcIdType> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1678 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 7.
1680 int MEDCouplingUMesh::AreCellsEqualPolicy7(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1682 mcIdType sz=connI[cell1+1]-connI[cell1];
1683 if(sz==connI[cell2+1]-connI[cell2])
1685 if(conn[connI[cell1]]==conn[connI[cell2]])
1687 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1688 unsigned dim=cm.getDimension();
1693 mcIdType sz1=2*(sz-1);
1694 INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz1];
1695 mcIdType *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(mcIdType *)tmp);
1696 std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1697 work=std::search((mcIdType *)tmp,(mcIdType *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1702 std::reverse_iterator<mcIdType *> it1((mcIdType *)tmp+sz1);
1703 std::reverse_iterator<mcIdType *> it2((mcIdType *)tmp);
1704 if(std::search(it1,it2,conn+connI[cell2]+1,conn+connI[cell2+1])!=it2)
1711 {//case of SEG2 and SEG3
1712 if(std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1))
1714 if(!cm.isQuadratic())
1716 std::reverse_iterator<const mcIdType *> it1(conn+connI[cell1+1]);
1717 std::reverse_iterator<const mcIdType *> it2(conn+connI[cell1]+1);
1718 if(std::equal(it1,it2,conn+connI[cell2]+1))
1724 if(conn[connI[cell1]+1]==conn[connI[cell2]+2] && conn[connI[cell1]+2]==conn[connI[cell2]+1] && conn[connI[cell1]+3]==conn[connI[cell2]+3])
1731 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy7 : not implemented yet for meshdim == 3 !");
1739 * This method find cells that are equal (regarding \a compType) in \a this. The comparison is specified by \a compType (see zipConnectivityTraducer).
1740 * This method keeps the coordinates of \a this. The comparison starts at rank \a startCellId cell id (included).
1741 * If \a startCellId is equal to 0 algorithm starts at cell #0 and for each cell candidates being searched have cell id higher than current cellId.
1742 * If \a startCellId is greater than 0 algorithm starts at cell #startCellId but for each cell all candidates are considered.
1743 * This method is time consuming.
1745 * \param [in] compType input specifying the technique used to compare cells each other.
1746 * - 0 : exactly. A cell is detected to be the same if and only if the connectivity is exactly the same without permutation and types same too. This is the strongest policy.
1747 * - 1 : permutation same orientation. cell1 and cell2 are considered equal if the connectivity of cell2 can be deduced by those of cell1 by direct permutation (with exactly the same orientation)
1748 * and their type equal. For 1D mesh the policy 1 is equivalent to 0.
1749 * - 2 : nodal. cell1 and cell2 are equal if and only if cell1 and cell2 have same type and have the same nodes constituting connectivity. This is the laziest policy. This policy
1750 * can be used for users not sensitive to orientation of cell
1751 * \param [in] startCellId specifies the cellId starting from which the equality computation will be carried out. By default it is 0, which it means that all cells in \a this will be scanned.
1752 * \param [out] commonCellsArr common cells ids (\ref numbering-indirect)
1753 * \param [out] commonCellsIArr common cells ids (\ref numbering-indirect)
1756 void MEDCouplingUMesh::findCommonCells(int compType, mcIdType startCellId, DataArrayIdType *& commonCellsArr, DataArrayIdType *& commonCellsIArr) const
1758 MCAuto<DataArrayIdType> revNodal=DataArrayIdType::New(),revNodalI=DataArrayIdType::New();
1759 getReverseNodalConnectivity(revNodal,revNodalI);
1760 FindCommonCellsAlg(compType,startCellId,_nodal_connec,_nodal_connec_index,revNodal,revNodalI,commonCellsArr,commonCellsIArr);
1763 void MEDCouplingUMesh::FindCommonCellsAlg(int compType, mcIdType startCellId, const DataArrayIdType *nodal, const DataArrayIdType *nodalI, const DataArrayIdType *revNodal, const DataArrayIdType *revNodalI,
1764 DataArrayIdType *& commonCellsArr, DataArrayIdType *& commonCellsIArr)
1766 MCAuto<DataArrayIdType> commonCells=DataArrayIdType::New(),commonCellsI=DataArrayIdType::New(); commonCells->alloc(0,1);
1767 mcIdType nbOfCells=nodalI->getNumberOfTuples()-1;
1768 commonCellsI->reserve(1); commonCellsI->pushBackSilent(0);
1769 const mcIdType *revNodalPtr=revNodal->getConstPointer(),*revNodalIPtr=revNodalI->getConstPointer();
1770 const mcIdType *connPtr=nodal->getConstPointer(),*connIPtr=nodalI->getConstPointer();
1771 std::vector<bool> isFetched(nbOfCells,false);
1774 for(mcIdType i=startCellId;i<nbOfCells;i++)
1778 const mcIdType *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind(std::not_equal_to<mcIdType>(),std::placeholders::_1,-1));
1779 std::vector<mcIdType> v,v2;
1780 if(connOfNode!=connPtr+connIPtr[i+1])
1782 const mcIdType *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1783 v2.insert(v2.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1]);
1786 for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1790 const mcIdType *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1791 std::vector<mcIdType>::iterator it=std::set_intersection(v.begin(),v.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1792 v2.resize(std::distance(v2.begin(),it));
1796 if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1798 mcIdType pos=commonCellsI->back();
1799 commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1800 for(const mcIdType *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1801 isFetched[*it]=true;
1809 for(mcIdType i=startCellId;i<nbOfCells;i++)
1813 const mcIdType *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind(std::not_equal_to<mcIdType>(),std::placeholders::_1,-1));
1814 // v2 contains the result of successive intersections using rev nodal on on each node of cell #i
1815 std::vector<mcIdType> v,v2;
1816 if(connOfNode!=connPtr+connIPtr[i+1])
1818 v2.insert(v2.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1]);
1821 for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1825 std::vector<mcIdType>::iterator it=std::set_intersection(v.begin(),v.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1826 v2.resize(std::distance(v2.begin(),it));
1828 // v2 contains now candidates. Problem candidates are sorted using id rank.
1833 auto it(std::find(v2.begin(),v2.end(),i));
1834 std::swap(*v2.begin(),*it);
1836 if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1838 mcIdType newPos(commonCells->getNumberOfTuples());
1839 mcIdType pos(commonCellsI->back());
1840 std::sort(commonCells->getPointerSilent()+pos,commonCells->getPointerSilent()+newPos);
1841 commonCellsI->pushBackSilent(newPos);
1842 for(const mcIdType *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1843 isFetched[*it]=true;
1849 commonCellsArr=commonCells.retn();
1850 commonCellsIArr=commonCellsI.retn();
1854 * Checks if \a this mesh includes all cells of an \a other mesh, and returns an array
1855 * giving for each cell of the \a other an id of a cell in \a this mesh. A value larger
1856 * than \a this->getNumberOfCells() in the returned array means that there is no
1857 * corresponding cell in \a this mesh.
1858 * It is expected that \a this and \a other meshes share the same node coordinates
1859 * array, if it is not so an exception is thrown.
1860 * \param [in] other - the mesh to compare with.
1861 * \param [in] compType - specifies a cell comparison technique. For meaning of its
1862 * valid values [0,1,2], see zipConnectivityTraducer().
1863 * \param [out] arr - a new instance of DataArrayIdType returning correspondence
1864 * between cells of the two meshes. It contains \a other->getNumberOfCells()
1865 * values. The caller is to delete this array using
1866 * decrRef() as it is no more needed.
1867 * \return bool - \c true if all cells of \a other mesh are present in the \a this
1870 * \if ENABLE_EXAMPLES
1871 * \ref cpp_mcumesh_areCellsIncludedIn "Here is a C++ example".<br>
1872 * \ref py_mcumesh_areCellsIncludedIn "Here is a Python example".
1874 * \sa checkDeepEquivalOnSameNodesWith()
1875 * \sa checkGeoEquivalWith()
1877 bool MEDCouplingUMesh::areCellsIncludedIn(const MEDCouplingUMesh *other, int compType, DataArrayIdType *& arr) const
1879 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1880 mcIdType nbOfCells=getNumberOfCells();
1881 static const int possibleCompType[]={0,1,2};
1882 if(std::find(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),compType)==possibleCompType+sizeof(possibleCompType)/sizeof(int))
1884 std::ostringstream oss; oss << "MEDCouplingUMesh::areCellsIncludedIn : only following policies are possible : ";
1885 std::copy(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),std::ostream_iterator<int>(oss," "));
1887 throw INTERP_KERNEL::Exception(oss.str());
1890 if(other->getNumberOfCells()==0)
1892 MCAuto<DataArrayIdType> dftRet(DataArrayIdType::New()); dftRet->alloc(0,1); arr=dftRet.retn(); arr->setName(other->getName());
1895 DataArrayIdType *commonCells(nullptr),*commonCellsI(nullptr);
1896 mesh->findCommonCells(compType,nbOfCells,commonCells,commonCellsI);
1897 MCAuto<DataArrayIdType> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1898 mcIdType newNbOfCells=-1;
1899 MCAuto<DataArrayIdType> o2n = DataArrayIdType::ConvertIndexArrayToO2N(ToIdType(mesh->getNumberOfCells()),commonCells->begin(),commonCellsI->begin(),commonCellsI->end(),newNbOfCells);
1900 MCAuto<DataArrayIdType> p0(o2n->selectByTupleIdSafeSlice(0,nbOfCells,1));
1901 mcIdType maxPart(p0->getMaxValueInArray());
1902 bool ret(maxPart==newNbOfCells-1);
1903 MCAuto<DataArrayIdType> p1(p0->invertArrayO2N2N2O(newNbOfCells));
1904 // fill p1 array in case of presence of cells in other not in this
1905 mcIdType *pt(p1->getPointer());
1906 for(mcIdType i = maxPart ; i < newNbOfCells-1 ; ++i )
1909 MCAuto<DataArrayIdType> p2(o2n->subArray(nbOfCells));
1910 p2->transformWithIndArr(p1->begin(),p1->end()); p2->setName(other->getName());
1916 * This method makes the assumption that \a this and \a other share the same coords. If not an exception will be thrown !
1917 * This method tries to determine if \b other is fully included in \b this.
1918 * The main difference is that this method is not expected to throw exception.
1919 * This method has two outputs :
1921 * \param other other mesh
1922 * \param arr is an output parameter that returns a \b newly created instance. This array is of size 'other->getNumberOfCells()'.
1923 * \return If \a other is fully included in 'this 'true is returned. If not false is returned.
1925 bool MEDCouplingUMesh::areCellsIncludedInPolicy7(const MEDCouplingUMesh *other, DataArrayIdType *& arr) const
1927 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1928 DataArrayIdType *commonCells=0,*commonCellsI=0;
1929 mcIdType thisNbCells=getNumberOfCells();
1930 mesh->findCommonCells(7,thisNbCells,commonCells,commonCellsI);
1931 MCAuto<DataArrayIdType> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1932 const mcIdType *commonCellsPtr=commonCells->getConstPointer(),*commonCellsIPtr=commonCellsI->getConstPointer();
1933 mcIdType otherNbCells=other->getNumberOfCells();
1934 MCAuto<DataArrayIdType> arr2=DataArrayIdType::New();
1935 arr2->alloc(otherNbCells,1);
1936 arr2->fillWithZero();
1937 mcIdType *arr2Ptr=arr2->getPointer();
1938 mcIdType nbOfCommon=commonCellsI->getNumberOfTuples()-1;
1939 for(mcIdType i=0;i<nbOfCommon;i++)
1941 mcIdType start=commonCellsPtr[commonCellsIPtr[i]];
1942 if(start<thisNbCells)
1944 for(mcIdType j=commonCellsIPtr[i]+1;j!=commonCellsIPtr[i+1];j++)
1946 mcIdType sig=commonCellsPtr[j]>0?1:-1;
1947 mcIdType val=std::abs(commonCellsPtr[j])-1;
1948 if(val>=thisNbCells)
1949 arr2Ptr[val-thisNbCells]=sig*(start+1);
1953 arr2->setName(other->getName());
1954 if(arr2->presenceOfValue(0))
1960 MEDCouplingUMesh *MEDCouplingUMesh::mergeMyselfWithOnSameCoords(const MEDCouplingPointSet *other) const
1963 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : input other is null !");
1964 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
1966 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : the input other mesh is not of type unstructured !");
1967 std::vector<const MEDCouplingUMesh *> ms(2);
1970 return MergeUMeshesOnSameCoords(ms);
1974 * Build a sub part of \b this lying or not on the same coordinates than \b this (regarding value of \b keepCoords).
1975 * By default coordinates are kept. This method is close to MEDCouplingUMesh::buildPartOfMySelf except that here input
1976 * cellIds is not given explicitly but by a range python like.
1978 * \param start starting ID
1979 * \param end end ID (excluded)
1980 * \param step step size
1981 * \param keepCoords that specifies if you want or not to keep coords as this or zip it (see MEDCoupling::MEDCouplingUMesh::zipCoords). If true zipCoords is \b NOT called, if false, zipCoords is called.
1982 * \return a newly allocated
1984 * \warning This method modifies can generate an unstructured mesh whose cells are not sorted by geometric type order.
1985 * In view of the MED file writing, a renumbering of cells of returned unstructured mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
1987 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfSlice(mcIdType start, mcIdType end, mcIdType step, bool keepCoords) const
1989 if(getMeshDimension()!=-1)
1990 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelfSlice(start,end,step,keepCoords));
1993 mcIdType newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfSlice for -1 dimension mesh ");
1995 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
1997 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
1999 return const_cast<MEDCouplingUMesh *>(this);
2004 * Creates a new MEDCouplingUMesh containing specified cells of \a this mesh.
2005 * The result mesh shares or not the node coordinates array with \a this mesh depending
2006 * on \a keepCoords parameter.
2007 * \warning Cells of the result mesh can be \b not sorted by geometric type, hence,
2008 * to write this mesh to the MED file, its cells must be sorted using
2009 * sortCellsInMEDFileFrmt().
2010 * \param [in] begin - an array of cell ids to include to the new mesh.
2011 * \param [in] end - a pointer to last-plus-one-th element of \a begin.
2012 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2013 * array of \a this mesh, else "free" nodes are removed from the result mesh
2014 * by calling zipCoords().
2015 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2016 * to delete this mesh using decrRef() as it is no more needed.
2017 * \throw If the coordinates array is not set.
2018 * \throw If the nodal connectivity of cells is not defined.
2019 * \throw If any cell id in the array \a begin is not valid.
2021 * \if ENABLE_EXAMPLES
2022 * \ref cpp_mcumesh_buildPartOfMySelf "Here is a C++ example".<br>
2023 * \ref py_mcumesh_buildPartOfMySelf "Here is a Python example".
2026 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelf(const mcIdType *begin, const mcIdType *end, bool keepCoords) const
2028 if(getMeshDimension()!=-1)
2029 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelf(begin,end,keepCoords));
2033 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
2035 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
2037 return const_cast<MEDCouplingUMesh *>(this);
2042 * This method operates only on nodal connectivity on \b this. Coordinates of \b this is completely ignored here.
2044 * This method allows to partially modify some cells in \b this (whose list is specified by [ \b cellIdsBg, \b cellIdsEnd ) ) with cells coming in \b otherOnSameCoordsThanThis.
2045 * Size of [ \b cellIdsBg, \b cellIdsEnd ) ) must be equal to the number of cells of otherOnSameCoordsThanThis.
2046 * The number of cells of \b this will remain the same with this method.
2048 * \param [in] cellIdsBg begin of cell ids (included) of cells in this to assign
2049 * \param [in] cellIdsEnd end of cell ids (excluded) of cells in this to assign
2050 * \param [in] otherOnSameCoordsThanThis an another mesh with same meshdimension than \b this with exactly the same number of cells than cell ids list in [\b cellIdsBg, \b cellIdsEnd ).
2051 * Coordinate pointer of \b this and those of \b otherOnSameCoordsThanThis must be the same
2053 void MEDCouplingUMesh::setPartOfMySelf(const mcIdType *cellIdsBg, const mcIdType *cellIdsEnd, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2055 checkConnectivityFullyDefined();
2056 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2057 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2058 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelf : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2059 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2061 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2062 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2063 throw INTERP_KERNEL::Exception(oss.str());
2065 mcIdType nbOfCellsToModify( ToIdType((std::distance(cellIdsBg,cellIdsEnd))));
2066 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2068 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2069 throw INTERP_KERNEL::Exception(oss.str());
2071 mcIdType nbOfCells(getNumberOfCells());
2072 bool easyAssign(true);
2073 const mcIdType *connI(_nodal_connec_index->begin());
2074 const mcIdType *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->begin();
2075 for(const mcIdType *it=cellIdsBg;it!=cellIdsEnd && easyAssign;it++,connIOther++)
2077 if(*it>=0 && *it<nbOfCells)
2079 easyAssign=(connIOther[1]-connIOther[0])==(connI[*it+1]-connI[*it]);
2083 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : On pos #" << std::distance(cellIdsBg,it) << " id is equal to " << *it << " which is not in [0," << nbOfCells << ") !";
2084 throw INTERP_KERNEL::Exception(oss.str());
2089 DataArrayIdType::SetPartOfIndexedArraysSameIdx(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2094 DataArrayIdType *arrOut=0,*arrIOut=0;
2095 DataArrayIdType::SetPartOfIndexedArrays(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2097 MCAuto<DataArrayIdType> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2098 setConnectivity(arrOut,arrIOut,true);
2102 void MEDCouplingUMesh::setPartOfMySelfSlice(mcIdType start, mcIdType end, mcIdType step, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2104 checkConnectivityFullyDefined();
2105 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2106 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2107 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelfSlice : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2108 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2110 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2111 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2112 throw INTERP_KERNEL::Exception(oss.str());
2114 mcIdType nbOfCellsToModify=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::setPartOfMySelfSlice : ");
2115 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2117 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2118 throw INTERP_KERNEL::Exception(oss.str());
2120 mcIdType nbOfCells=getNumberOfCells();
2121 bool easyAssign=true;
2122 const mcIdType *connI=_nodal_connec_index->getConstPointer();
2123 const mcIdType *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2125 for(mcIdType i=0;i<nbOfCellsToModify && easyAssign;i++,it+=step,connIOther++)
2127 if(it>=0 && it<nbOfCells)
2129 easyAssign=(connIOther[1]-connIOther[0])==(connI[it+1]-connI[it]);
2133 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : On pos #" << i << " id is equal to " << it << " which is not in [0," << nbOfCells << ") !";
2134 throw INTERP_KERNEL::Exception(oss.str());
2139 DataArrayIdType::SetPartOfIndexedArraysSameIdxSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2144 DataArrayIdType *arrOut=0,*arrIOut=0;
2145 DataArrayIdType::SetPartOfIndexedArraysSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2147 MCAuto<DataArrayIdType> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2148 setConnectivity(arrOut,arrIOut,true);
2154 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2155 * this->getMeshDimension(), that bound some cells of \a this mesh.
2156 * The cells of lower dimension to include to the result mesh are selected basing on
2157 * specified node ids and the value of \a fullyIn parameter. If \a fullyIn ==\c true, a
2158 * cell is copied if its all nodes are in the array \a begin of node ids. If \a fullyIn
2159 * ==\c false, a cell is copied if any its node is in the array of node ids. The
2160 * created mesh shares the node coordinates array with \a this mesh.
2161 * \param [in] begin - the array of node ids.
2162 * \param [in] end - a pointer to the (last+1)-th element of \a begin.
2163 * \param [in] fullyIn - if \c true, then cells whose all nodes are in the
2164 * array \a begin are added, else cells whose any node is in the
2165 * array \a begin are added.
2166 * \return MEDCouplingUMesh * - new instance of MEDCouplingUMesh. The caller is
2167 * to delete this mesh using decrRef() as it is no more needed.
2168 * \throw If the coordinates array is not set.
2169 * \throw If the nodal connectivity of cells is not defined.
2170 * \throw If any node id in \a begin is not valid.
2172 * \if ENABLE_EXAMPLES
2173 * \ref cpp_mcumesh_buildFacePartOfMySelfNode "Here is a C++ example".<br>
2174 * \ref py_mcumesh_buildFacePartOfMySelfNode "Here is a Python example".
2177 MEDCouplingUMesh *MEDCouplingUMesh::buildFacePartOfMySelfNode(const mcIdType *begin, const mcIdType *end, bool fullyIn) const
2179 MCAuto<DataArrayIdType> desc,descIndx,revDesc,revDescIndx;
2180 desc=DataArrayIdType::New(); descIndx=DataArrayIdType::New(); revDesc=DataArrayIdType::New(); revDescIndx=DataArrayIdType::New();
2181 MCAuto<MEDCouplingUMesh> subMesh=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2182 desc=0; descIndx=0; revDesc=0; revDescIndx=0;
2183 return static_cast<MEDCouplingUMesh*>(subMesh->buildPartOfMySelfNode(begin,end,fullyIn));
2187 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2188 * this->getMeshDimension(), which bound only one cell of \a this mesh.
2189 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2190 * array of \a this mesh, else "free" nodes are removed from the result mesh
2191 * by calling zipCoords().
2192 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2193 * to delete this mesh using decrRef() as it is no more needed.
2194 * \throw If the coordinates array is not set.
2195 * \throw If the nodal connectivity of cells is not defined.
2197 * \if ENABLE_EXAMPLES
2198 * \ref cpp_mcumesh_buildBoundaryMesh "Here is a C++ example".<br>
2199 * \ref py_mcumesh_buildBoundaryMesh "Here is a Python example".
2202 MEDCouplingUMesh *MEDCouplingUMesh::buildBoundaryMesh(bool keepCoords) const
2204 DataArrayIdType *desc=DataArrayIdType::New();
2205 DataArrayIdType *descIndx=DataArrayIdType::New();
2206 DataArrayIdType *revDesc=DataArrayIdType::New();
2207 DataArrayIdType *revDescIndx=DataArrayIdType::New();
2209 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2212 descIndx->decrRef();
2213 mcIdType nbOfCells=meshDM1->getNumberOfCells();
2214 const mcIdType *revDescIndxC=revDescIndx->getConstPointer();
2215 std::vector<mcIdType> boundaryCells;
2216 for(mcIdType i=0;i<nbOfCells;i++)
2217 if(revDescIndxC[i+1]-revDescIndxC[i]==1)
2218 boundaryCells.push_back(i);
2219 revDescIndx->decrRef();
2220 MEDCouplingUMesh *ret=meshDM1->buildPartOfMySelf(&boundaryCells[0],&boundaryCells[0]+boundaryCells.size(),keepCoords);
2225 * This method returns a newly created DataArrayIdType instance containing ids of cells located in boundary.
2226 * A cell is detected to be on boundary if it contains one or more than one face having only one father.
2227 * This method makes the assumption that \a this is fully defined (coords,connectivity). If not an exception will be thrown.
2229 DataArrayIdType *MEDCouplingUMesh::findCellIdsOnBoundary() const
2231 checkFullyDefined();
2232 MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
2233 MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
2234 MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
2235 MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
2237 buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx)->decrRef();
2238 desc=(DataArrayIdType*)0; descIndx=(DataArrayIdType*)0;
2240 MCAuto<DataArrayIdType> tmp=revDescIndx->deltaShiftIndex();
2241 MCAuto<DataArrayIdType> faceIds=tmp->findIdsEqual(1); tmp=(DataArrayIdType*)0;
2242 const mcIdType *revDescPtr=revDesc->getConstPointer();
2243 const mcIdType *revDescIndxPtr=revDescIndx->getConstPointer();
2244 mcIdType nbOfCells=getNumberOfCells();
2245 std::vector<bool> ret1(nbOfCells,false);
2247 for(const mcIdType *pt=faceIds->begin();pt!=faceIds->end();pt++)
2248 if(!ret1[revDescPtr[revDescIndxPtr[*pt]]])
2249 { ret1[revDescPtr[revDescIndxPtr[*pt]]]=true; sz++; }
2251 DataArrayIdType *ret2=DataArrayIdType::New();
2253 mcIdType *ret2Ptr=ret2->getPointer();
2255 for(std::vector<bool>::const_iterator it=ret1.begin();it!=ret1.end();it++,sz++)
2258 ret2->setName("BoundaryCells");
2263 * This method finds in \b this the cell ids that lie on mesh \b otherDimM1OnSameCoords.
2264 * \b this and \b otherDimM1OnSameCoords have to lie on the same coordinate array pointer. The coherency of that coords array with connectivity
2265 * of \b this and \b otherDimM1OnSameCoords is not important here because this method works only on connectivity.
2266 * this->getMeshDimension() - 1 must be equal to otherDimM1OnSameCoords.getMeshDimension()
2268 * s0 is the cell ids set in \b this lying on at least one node in the fetched nodes in \b otherDimM1OnSameCoords.
2269 * This method also returns the cells ids set s1 which contains the cell ids in \b this for which one of the dim-1 constituent
2270 * equals a cell in \b otherDimM1OnSameCoords.
2272 * \throw if \b otherDimM1OnSameCoords is not part of constituent of \b this, or if coordinate pointer of \b this and \b otherDimM1OnSameCoords
2273 * are not same, or if this->getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension()
2275 * \param [in] otherDimM1OnSameCoords other mesh
2276 * \param [out] cellIdsRk0 a newly allocated array containing the cell ids of s0 (which are cell ids of \b this) in the above algorithm.
2277 * \param [out] cellIdsRk1 a newly allocated array containing the cell ids of s1 \b indexed into the \b cellIdsRk0 subset. To get the absolute ids of s1, simply invoke
2278 * cellIdsRk1->transformWithIndArr(cellIdsRk0->begin(),cellIdsRk0->end());
2280 void MEDCouplingUMesh::findCellIdsLyingOn(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayIdType *&cellIdsRk0, DataArrayIdType *&cellIdsRk1) const
2282 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2283 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : coordinates pointer are not the same ! Use tryToShareSameCoords method !");
2284 checkConnectivityFullyDefined();
2285 otherDimM1OnSameCoords.checkConnectivityFullyDefined();
2286 if(getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension())
2287 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : invalid mesh dimension of input mesh regarding meshdimesion of this !");
2288 MCAuto<DataArrayIdType> fetchedNodeIds1=otherDimM1OnSameCoords.computeFetchedNodeIds();
2289 MCAuto<DataArrayIdType> s0arr=getCellIdsLyingOnNodes(fetchedNodeIds1->begin(),fetchedNodeIds1->end(),false);
2290 MCAuto<MEDCouplingUMesh> thisPart=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(s0arr->begin(),s0arr->end(),true));
2291 MCAuto<DataArrayIdType> descThisPart=DataArrayIdType::New(),descIThisPart=DataArrayIdType::New(),revDescThisPart=DataArrayIdType::New(),revDescIThisPart=DataArrayIdType::New();
2292 MCAuto<MEDCouplingUMesh> thisPartConsti=thisPart->buildDescendingConnectivity(descThisPart,descIThisPart,revDescThisPart,revDescIThisPart);
2293 const mcIdType *revDescThisPartPtr=revDescThisPart->getConstPointer(),*revDescIThisPartPtr=revDescIThisPart->getConstPointer();
2294 DataArrayIdType *idsOtherInConsti=0;
2295 bool b=thisPartConsti->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsOtherInConsti);
2296 MCAuto<DataArrayIdType> idsOtherInConstiAuto(idsOtherInConsti);
2298 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : the given mdim-1 mesh in other is not a constituent of this !");
2299 std::set<mcIdType> s1;
2300 for(const mcIdType *idOther=idsOtherInConsti->begin();idOther!=idsOtherInConsti->end();idOther++)
2301 s1.insert(revDescThisPartPtr+revDescIThisPartPtr[*idOther],revDescThisPartPtr+revDescIThisPartPtr[*idOther+1]);
2302 MCAuto<DataArrayIdType> s1arr_renum1=DataArrayIdType::New(); s1arr_renum1->alloc(s1.size(),1); std::copy(s1.begin(),s1.end(),s1arr_renum1->getPointer());
2303 s1arr_renum1->sort();
2304 cellIdsRk0=s0arr.retn();
2305 //cellIdsRk1=s_renum1.retn();
2306 cellIdsRk1=s1arr_renum1.retn();
2310 * This method computes the skin of \b this. That is to say the consituting meshdim-1 mesh is built and only the boundary subpart is
2311 * returned. This subpart of meshdim-1 mesh is built using meshdim-1 cells in it shared only one cell in \b this.
2313 * \return a newly allocated mesh lying on the same coordinates than \b this. The caller has to deal with returned mesh.
2315 MEDCouplingUMesh *MEDCouplingUMesh::computeSkin() const
2317 MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
2318 MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
2319 MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
2320 MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
2322 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2323 revDesc=0; desc=0; descIndx=0;
2324 MCAuto<DataArrayIdType> revDescIndx2=revDescIndx->deltaShiftIndex();
2325 MCAuto<DataArrayIdType> part=revDescIndx2->findIdsEqual(1);
2326 return static_cast<MEDCouplingUMesh *>(meshDM1->buildPartOfMySelf(part->begin(),part->end(),true));
2330 * Finds nodes lying on the boundary of \a this mesh.
2331 * \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of found
2332 * nodes. The caller is to delete this array using decrRef() as it is no
2334 * \throw If the coordinates array is not set.
2335 * \throw If the nodal connectivity of cells is node defined.
2337 * \if ENABLE_EXAMPLES
2338 * \ref cpp_mcumesh_findBoundaryNodes "Here is a C++ example".<br>
2339 * \ref py_mcumesh_findBoundaryNodes "Here is a Python example".
2342 DataArrayIdType *MEDCouplingUMesh::findBoundaryNodes() const
2344 MCAuto<MEDCouplingUMesh> skin=computeSkin();
2345 return skin->computeFetchedNodeIds();
2348 MEDCouplingUMesh *MEDCouplingUMesh::buildUnstructured() const
2351 return const_cast<MEDCouplingUMesh *>(this);
2355 * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2356 * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2357 * This method searches for nodes needed to be duplicated. These nodes are nodes fetched by \b otherDimM1OnSameCoords which are not part of the boundary of \b otherDimM1OnSameCoords.
2358 * If a node is in the boundary of \b this \b and in the boundary of \b otherDimM1OnSameCoords this node is considered as needed to be duplicated.
2359 * When the set of node ids \b nodeIdsToDuplicate is computed, cell ids in \b this is searched so that their connectivity includes at least 1 node in \b nodeIdsToDuplicate.
2361 * \param [in] otherDimM1OnSameCoords a mesh lying on the same coords than \b this and with a mesh dimension equal to those of \b this minus 1. WARNING this input
2362 * parameter is altered during the call.
2363 * \param [out] nodeIdsToDuplicate node ids needed to be duplicated following the algorithm explain above.
2364 * \param [out] cellIdsNeededToBeRenum cell ids in \b this in which the renumber of nodes should be performed.
2365 * \param [out] cellIdsNotModified cell ids mcIdType \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.
2368 void MEDCouplingUMesh::findNodesToDuplicate(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayIdType *& nodeIdsToDuplicate,
2369 DataArrayIdType *& cellIdsNeededToBeRenum, DataArrayIdType *& cellIdsNotModified) const
2371 typedef MCAuto<DataArrayIdType> DAInt;
2372 typedef MCAuto<MEDCouplingUMesh> MCUMesh;
2374 checkFullyDefined();
2375 otherDimM1OnSameCoords.checkFullyDefined();
2376 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2377 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : meshes do not share the same coords array !");
2378 if(otherDimM1OnSameCoords.getMeshDimension()!=getMeshDimension()-1)
2379 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the mesh given in other parameter must have this->getMeshDimension()-1 !");
2381 // Checking star-shaped M1 group:
2382 DAInt dt0=DataArrayIdType::New(),dit0=DataArrayIdType::New(),rdt0=DataArrayIdType::New(),rdit0=DataArrayIdType::New();
2383 MCUMesh meshM2 = otherDimM1OnSameCoords.buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); // 2D: a mesh of points, 3D: a mesh of segs
2384 DAInt dsi = rdit0->deltaShiftIndex();
2385 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.
2386 if(idsTmp0->getNumberOfTuples())
2387 throw INTERP_KERNEL::Exception("MEDFileUMesh::buildInnerBoundaryAlongM1Group: group is too complex: some points (or edges) have more than two connected segments (or faces)!");
2388 dt0=0; dit0=0; rdt0=0; rdit0=0; idsTmp0=0;
2390 // Get extreme nodes from the group (they won't be duplicated except if they also lie on bound of M0 -- see below),
2391 // ie nodes belonging to the boundary "cells" (might be points) of M1
2392 DAInt xtremIdsM2 = dsi->findIdsEqual(1); dsi = 0;
2393 MCUMesh meshM2Part = static_cast<MEDCouplingUMesh *>(meshM2->buildPartOfMySelf(xtremIdsM2->begin(), xtremIdsM2->end(),true));
2394 DAInt xtrem = meshM2Part->computeFetchedNodeIds();
2395 // Remove from the list points on the boundary of the M0 mesh (those need duplication!)
2396 dt0=DataArrayIdType::New(),dit0=DataArrayIdType::New(),rdt0=DataArrayIdType::New(),rdit0=DataArrayIdType::New();
2397 MCUMesh m0desc = buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); dt0=0; dit0=0; rdt0=0;
2398 dsi = rdit0->deltaShiftIndex();
2399 DAInt boundSegs = dsi->findIdsEqual(1); dsi = 0; // boundary segs/faces of the M0 mesh
2400 MCUMesh m0descSkin = static_cast<MEDCouplingUMesh *>(m0desc->buildPartOfMySelf(boundSegs->begin(),boundSegs->end(), true));
2401 DAInt fNodes = m0descSkin->computeFetchedNodeIds();
2402 // 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)
2403 // 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
2404 // although they are technically on the skin of the cube.
2406 if (getMeshDimension() == 3)
2408 DAInt dnu1=DataArrayIdType::New(), dnu2=DataArrayIdType::New(), dnu3=DataArrayIdType::New(), dnu4=DataArrayIdType::New();
2409 MCUMesh m0descSkinDesc = m0descSkin->buildDescendingConnectivity(dnu1, dnu2, dnu3, dnu4); // all segments of the skin of the 3D (M0) mesh
2410 dnu1=0;dnu2=0;dnu3=0;dnu4=0;
2411 DataArrayIdType * corresp=0;
2412 meshM2->areCellsIncludedIn(m0descSkinDesc,2,corresp);
2413 DAInt validIds = corresp->findIdsInRange(0, meshM2->getNumberOfCells());
2415 if (validIds->getNumberOfTuples())
2417 // 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:
2418 MCUMesh m1IntersecSkin = static_cast<MEDCouplingUMesh *>(m0descSkinDesc->buildPartOfMySelf(validIds->begin(), validIds->end(), true));
2419 // Its boundary nodes should no be duplicated (this is for example the tip of the crack inside the cube described above)
2420 DAInt notDuplSkin = m1IntersecSkin->findBoundaryNodes();
2421 DAInt fNodes1 = fNodes->buildSubstraction(notDuplSkin);
2423 // Also, in this (segment) mesh, nodes connected to more than 3 segs should not be dup either (singular points - see testBuildInnerBoundary6())
2424 dt0=DataArrayIdType::New(),dit0=DataArrayIdType::New(),rdt0=DataArrayIdType::New(),rdit0=DataArrayIdType::New();
2425 MCUMesh meshM2Desc = meshM2->buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); dt0=0; dit0=0; rdt0=0; // a mesh made of node cells
2426 dsi = rdit0->deltaShiftIndex();
2427 DAInt singPoints = dsi->findIdsNotInRange(-1,4); // points connected to (strictly) more than 3 segments
2428 const mcIdType *cc = meshM2Desc->getNodalConnectivity()->begin(), *ccI = meshM2Desc->getNodalConnectivityIndex()->begin();
2429 mcIdType * singPointsP = singPoints->rwBegin();
2430 for (mcIdType j=0; j < singPoints->getNumberOfTuples(); j++) // replace ids in singPoints by real coordinate index (was index of cells in notDuplSkin)
2432 mcIdType nodeCellIdx = singPointsP[j];
2433 singPointsP[j] = cc[ccI[nodeCellIdx]+1]; // +1 to skip type
2435 DAInt fNodes2 = fNodes1->buildSubstraction(singPoints);
2436 notDup = xtrem->buildSubstraction(fNodes2);
2439 notDup = xtrem->buildSubstraction(fNodes);
2442 notDup = xtrem->buildSubstraction(fNodes);
2444 // Now compute cells around group (i.e. cells where we will do the propagation to identify the two sub-sets delimited by the group)
2445 DAInt m1Nodes = otherDimM1OnSameCoords.computeFetchedNodeIds();
2446 DAInt dupl = m1Nodes->buildSubstraction(notDup);
2447 DAInt cellsAroundGroup = getCellIdsLyingOnNodes(dupl->begin(), dupl->end(), false); // false= take cell in, even if not all nodes are in notDup
2450 MCUMesh m0Part2=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(cellsAroundGroup->begin(),cellsAroundGroup->end(),true));
2451 mcIdType nCells2 = m0Part2->getNumberOfCells();
2452 DAInt desc00=DataArrayIdType::New(),descI00=DataArrayIdType::New(),revDesc00=DataArrayIdType::New(),revDescI00=DataArrayIdType::New();
2453 MCUMesh m01=m0Part2->buildDescendingConnectivity(desc00,descI00,revDesc00,revDescI00);
2455 // Neighbor information of the mesh without considering the crack (serves to count how many connex pieces it is made of)
2456 DataArrayIdType *tmp00=0,*tmp11=0;
2457 MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00, tmp00, tmp11);
2458 DAInt neighInit00(tmp00);
2459 DAInt neighIInit00(tmp11);
2460 // Neighbor information of the mesh WITH the crack (some neighbors are removed):
2461 DataArrayIdType *idsTmp=0;
2462 m01->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsTmp);
2464 // In the neighbor information remove the connection between high dimension cells and its low level constituents which are part
2465 // of the frontier given in parameter (i.e. the cells of low dimension from the group delimiting the crack):
2466 DataArrayIdType::RemoveIdsFromIndexedArrays(ids->begin(),ids->end(),desc00,descI00);
2467 DataArrayIdType *tmp0=0,*tmp1=0;
2468 // Compute the neighbor of each cell in m0Part2, taking into account the broken link above. Two
2469 // cells on either side of the crack (defined by the mesh of low dimension) are not neighbor anymore.
2470 ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00,tmp0,tmp1);
2471 DAInt neigh00(tmp0);
2472 DAInt neighI00(tmp1);
2474 // For each initial connex part of the sub-mesh (or said differently for each independent crack):
2475 mcIdType seed = 0, nIter = 0;
2476 mcIdType nIterMax = nCells2+1; // Safety net for the loop
2477 DAInt hitCells = DataArrayIdType::New(); hitCells->alloc(nCells2);
2478 hitCells->fillWithValue(-1);
2479 DAInt cellsToModifyConn0_torenum = DataArrayIdType::New();
2480 cellsToModifyConn0_torenum->alloc(0,1);
2481 while (nIter < nIterMax)
2483 DAInt t = hitCells->findIdsEqual(-1);
2484 if (!t->getNumberOfTuples())
2486 // Connex zone without the crack (to compute the next seed really)
2488 DAInt connexCheck = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neighInit00,neighIInit00, -1, dnu);
2490 for (mcIdType * ptr = connexCheck->getPointer(); cnt < connexCheck->getNumberOfTuples(); ptr++, cnt++)
2491 hitCells->setIJ(*ptr,0,1);
2492 // Connex zone WITH the crack (to identify cells lying on either part of the crack)
2493 DAInt spreadZone = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neigh00,neighI00, -1, dnu);
2494 cellsToModifyConn0_torenum = DataArrayIdType::Aggregate(cellsToModifyConn0_torenum, spreadZone, 0);
2495 // Compute next seed, i.e. a cell in another connex part, which was not covered by the previous iterations
2496 DAInt comple = cellsToModifyConn0_torenum->buildComplement(nCells2);
2497 DAInt nonHitCells = hitCells->findIdsEqual(-1);
2498 DAInt intersec = nonHitCells->buildIntersection(comple);
2499 if (intersec->getNumberOfTuples())
2500 { seed = intersec->getIJ(0,0); }
2505 if (nIter >= nIterMax)
2506 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate(): internal error - too many iterations.");
2508 DAInt cellsToModifyConn1_torenum=cellsToModifyConn0_torenum->buildComplement(neighI00->getNumberOfTuples()-1);
2509 cellsToModifyConn0_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2510 cellsToModifyConn1_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2512 cellIdsNeededToBeRenum=cellsToModifyConn0_torenum.retn();
2513 cellIdsNotModified=cellsToModifyConn1_torenum.retn();
2514 nodeIdsToDuplicate=dupl.retn();
2518 * This method operates a modification of the connectivity and coords in \b this.
2519 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2520 * its ids will be modified to id this->getNumberOfNodes()+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2521 * 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
2522 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id this->getNumberOfNodes()+0, node id nodeIdsToDuplicateBg[1] will have id this->getNumberOfNodes()+1,
2523 * node id nodeIdsToDuplicateBg[2] will have id this->getNumberOfNodes()+2...
2525 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2527 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2528 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2530 void MEDCouplingUMesh::duplicateNodes(const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd)
2532 mcIdType nbOfNodes=getNumberOfNodes();
2533 duplicateNodesInCoords(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd);
2534 duplicateNodesInConn(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,nbOfNodes);
2538 * This method renumbers only nodal connectivity in \a this. The renumbering is only an offset applied. So this method is a specialization of
2539 * \a renumberNodesInConn. \b WARNING, this method does not check that the resulting node ids in the nodal connectivity is in a valid range !
2541 * \param [in] offset - specifies the offset to be applied on each element of connectivity.
2543 * \sa renumberNodesInConn
2545 void MEDCouplingUMesh::renumberNodesWithOffsetInConn(mcIdType offset)
2547 checkConnectivityFullyDefined();
2548 mcIdType *conn(getNodalConnectivity()->getPointer());
2549 const mcIdType *connIndex(getNodalConnectivityIndex()->getConstPointer());
2550 mcIdType nbOfCells=getNumberOfCells();
2551 for(mcIdType i=0;i<nbOfCells;i++)
2552 for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2554 mcIdType& node=conn[iconn];
2555 if(node>=0)//avoid polyhedron separator
2560 _nodal_connec->declareAsNew();
2565 * Same than renumberNodesInConn(const mcIdType *) except that here the format of old-to-new traducer is using map instead
2566 * 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
2569 void MEDCouplingUMesh::renumberNodesInConn(const INTERP_KERNEL::HashMap<mcIdType,mcIdType>& newNodeNumbersO2N)
2571 this->renumberNodesInConnT< INTERP_KERNEL::HashMap<mcIdType,mcIdType> >(newNodeNumbersO2N);
2575 * Same than renumberNodesInConn(const mcIdType *) except that here the format of old-to-new traducer is using map instead
2576 * 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
2579 void MEDCouplingUMesh::renumberNodesInConn(const std::map<mcIdType,mcIdType>& newNodeNumbersO2N)
2581 this->renumberNodesInConnT< std::map<mcIdType,mcIdType> >(newNodeNumbersO2N);
2585 * Changes ids of nodes within the nodal connectivity arrays according to a permutation
2586 * array in "Old to New" mode. The node coordinates array is \b not changed by this method.
2587 * This method is a generalization of shiftNodeNumbersInConn().
2588 * \warning This method performs no check of validity of new ids. **Use it with care !**
2589 * \param [in] newNodeNumbersO2N - a permutation array, of length \a
2590 * this->getNumberOfNodes(), in "Old to New" mode.
2591 * See \ref numbering for more info on renumbering modes.
2592 * \throw If the nodal connectivity of cells is not defined.
2594 * \if ENABLE_EXAMPLES
2595 * \ref cpp_mcumesh_renumberNodesInConn "Here is a C++ example".<br>
2596 * \ref py_mcumesh_renumberNodesInConn "Here is a Python example".
2599 void MEDCouplingUMesh::renumberNodesInConn(const mcIdType *newNodeNumbersO2N)
2601 checkConnectivityFullyDefined();
2602 mcIdType *conn=getNodalConnectivity()->getPointer();
2603 const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2604 mcIdType nbOfCells=getNumberOfCells();
2605 for(mcIdType i=0;i<nbOfCells;i++)
2606 for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2608 mcIdType& node=conn[iconn];
2609 if(node>=0)//avoid polyhedron separator
2611 node=newNodeNumbersO2N[node];
2614 _nodal_connec->declareAsNew();
2619 * This method renumbers nodes \b in \b connectivity \b only \b without \b any \b reference \b to \b coords.
2620 * This method performs no check on the fact that new coordinate ids are valid. \b Use \b it \b with \b care !
2621 * This method is an specialization of \ref MEDCoupling::MEDCouplingUMesh::renumberNodesInConn "renumberNodesInConn method".
2623 * \param [in] delta specifies the shift size applied to nodeId in nodal connectivity in \b this.
2625 void MEDCouplingUMesh::shiftNodeNumbersInConn(mcIdType delta)
2627 checkConnectivityFullyDefined();
2628 mcIdType *conn=getNodalConnectivity()->getPointer();
2629 const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2630 mcIdType nbOfCells=getNumberOfCells();
2631 for(mcIdType i=0;i<nbOfCells;i++)
2632 for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2634 mcIdType& node=conn[iconn];
2635 if(node>=0)//avoid polyhedron separator
2640 _nodal_connec->declareAsNew();
2645 * This method operates a modification of the connectivity in \b this.
2646 * 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.
2647 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2648 * its ids will be modified to id offset+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2649 * 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
2650 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id offset+0, node id nodeIdsToDuplicateBg[1] will have id offset+1,
2651 * node id nodeIdsToDuplicateBg[2] will have id offset+2...
2653 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2654 * As an another consequense after the call of this method \b this can be transiently non cohrent.
2656 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2657 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2658 * \param [in] offset the offset applied to all node ids in connectivity that are in [ \a nodeIdsToDuplicateBg, \a nodeIdsToDuplicateEnd ).
2660 void MEDCouplingUMesh::duplicateNodesInConn(const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd, mcIdType offset)
2662 checkConnectivityFullyDefined();
2663 std::map<mcIdType,mcIdType> m;
2664 mcIdType val=offset;
2665 for(const mcIdType *work=nodeIdsToDuplicateBg;work!=nodeIdsToDuplicateEnd;work++,val++)
2667 mcIdType *conn=getNodalConnectivity()->getPointer();
2668 const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2669 mcIdType nbOfCells=getNumberOfCells();
2670 for(mcIdType i=0;i<nbOfCells;i++)
2671 for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2673 mcIdType& node=conn[iconn];
2674 if(node>=0)//avoid polyhedron separator
2676 std::map<mcIdType,mcIdType>::iterator it=m.find(node);
2685 * This method renumbers cells of \a this using the array specified by [old2NewBg;old2NewBg+getNumberOfCells())
2687 * Contrary to MEDCouplingPointSet::renumberNodes, this method makes a permutation without any fuse of cell.
2688 * After the call of this method the number of cells remains the same as before.
2690 * If 'check' equals true the method will check that any elements in [ \a old2NewBg; \a old2NewEnd ) is unique ; if not
2691 * an INTERP_KERNEL::Exception will be thrown. When 'check' equals true [ \a old2NewBg ; \a old2NewEnd ) is not expected to
2692 * be strictly in [0;this->getNumberOfCells()).
2694 * If 'check' equals false the method will not check the content of [ \a old2NewBg ; \a old2NewEnd ).
2695 * To avoid any throw of SIGSEGV when 'check' equals false, the elements in [ \a old2NewBg ; \a old2NewEnd ) should be unique and
2696 * should be contained in[0;this->getNumberOfCells()).
2698 * \param [in] old2NewBg is expected to be a dynamically allocated pointer of size at least equal to this->getNumberOfCells()
2699 * \param check whether to check content of old2NewBg
2701 void MEDCouplingUMesh::renumberCells(const mcIdType *old2NewBg, bool check)
2703 checkConnectivityFullyDefined();
2704 mcIdType nbCells=getNumberOfCells();
2705 const mcIdType *array=old2NewBg;
2707 array=DataArrayIdType::CheckAndPreparePermutation(old2NewBg,old2NewBg+nbCells);
2709 const mcIdType *conn=_nodal_connec->getConstPointer();
2710 const mcIdType *connI=_nodal_connec_index->getConstPointer();
2711 MCAuto<DataArrayIdType> o2n=DataArrayIdType::New(); o2n->useArray(array,false,DeallocType::C_DEALLOC,nbCells,1);
2712 MCAuto<DataArrayIdType> n2o=o2n->invertArrayO2N2N2O(nbCells);
2713 const mcIdType *n2oPtr=n2o->begin();
2714 MCAuto<DataArrayIdType> newConn=DataArrayIdType::New();
2715 newConn->alloc(_nodal_connec->getNumberOfTuples(),_nodal_connec->getNumberOfComponents());
2716 newConn->copyStringInfoFrom(*_nodal_connec);
2717 MCAuto<DataArrayIdType> newConnI=DataArrayIdType::New();
2718 newConnI->alloc(_nodal_connec_index->getNumberOfTuples(),_nodal_connec_index->getNumberOfComponents());
2719 newConnI->copyStringInfoFrom(*_nodal_connec_index);
2721 mcIdType *newC=newConn->getPointer();
2722 mcIdType *newCI=newConnI->getPointer();
2725 for(mcIdType i=0;i<nbCells;i++)
2727 mcIdType pos=n2oPtr[i];
2728 mcIdType nbOfElts=connI[pos+1]-connI[pos];
2729 newC=std::copy(conn+connI[pos],conn+connI[pos+1],newC);
2734 setConnectivity(newConn,newConnI);
2736 free(const_cast<mcIdType *>(array));
2740 * Finds cells whose bounding boxes intersect a given bounding box.
2741 * \param [in] bbox - an array defining the bounding box via coordinates of its
2742 * extremum points in "no interlace" mode, i.e. xMin, xMax, yMin, yMax, zMin,
2744 * \param [in] eps - a factor used to increase size of the bounding box of cell
2745 * before comparing it with \a bbox. This factor is multiplied by the maximal
2746 * extent of the bounding box of cell to produce an addition to this bounding box.
2747 * \return DataArrayIdType * - a new instance of DataArrayIdType holding ids for found
2748 * cells. The caller is to delete this array using decrRef() as it is no more
2750 * \throw If the coordinates array is not set.
2751 * \throw If the nodal connectivity of cells is not defined.
2753 * \if ENABLE_EXAMPLES
2754 * \ref cpp_mcumesh_getCellsInBoundingBox "Here is a C++ example".<br>
2755 * \ref py_mcumesh_getCellsInBoundingBox "Here is a Python example".
2758 DataArrayIdType *MEDCouplingUMesh::getCellsInBoundingBox(const double *bbox, double eps) const
2760 MCAuto<DataArrayIdType> elems=DataArrayIdType::New(); elems->alloc(0,1);
2761 if(getMeshDimension()==-1)
2763 elems->pushBackSilent(0);
2764 return elems.retn();
2766 int dim=getSpaceDimension();
2767 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2768 const mcIdType* conn = getNodalConnectivity()->getConstPointer();
2769 const mcIdType* conn_index= getNodalConnectivityIndex()->getConstPointer();
2770 const double* coords = getCoords()->getConstPointer();
2771 mcIdType nbOfCells=getNumberOfCells();
2772 for ( mcIdType ielem=0; ielem<nbOfCells;ielem++ )
2774 for (int i=0; i<dim; i++)
2776 elem_bb[i*2]=std::numeric_limits<double>::max();
2777 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2780 for (mcIdType inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2782 mcIdType node= conn[inode];
2783 if(node>=0)//avoid polyhedron separator
2785 for (int idim=0; idim<dim; idim++)
2787 if ( coords[node*dim+idim] < elem_bb[idim*2] )
2789 elem_bb[idim*2] = coords[node*dim+idim] ;
2791 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2793 elem_bb[idim*2+1] = coords[node*dim+idim] ;
2798 if (intersectsBoundingBox(elem_bb, bbox, dim, eps))
2799 elems->pushBackSilent(ielem);
2801 return elems.retn();
2805 * Given a boundary box 'bbox' returns elements 'elems' contained in this 'bbox' or touching 'bbox' (within 'eps' distance).
2806 * Warning 'elems' is incremented during the call so if elems is not empty before call returned elements will be
2807 * added in 'elems' parameter.
2809 DataArrayIdType *MEDCouplingUMesh::getCellsInBoundingBox(const INTERP_KERNEL::DirectedBoundingBox& bbox, double eps)
2811 MCAuto<DataArrayIdType> elems=DataArrayIdType::New(); elems->alloc(0,1);
2812 if(getMeshDimension()==-1)
2814 elems->pushBackSilent(0);
2815 return elems.retn();
2817 int dim=getSpaceDimension();
2818 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2819 const mcIdType* conn = getNodalConnectivity()->getConstPointer();
2820 const mcIdType* conn_index= getNodalConnectivityIndex()->getConstPointer();
2821 const double* coords = getCoords()->getConstPointer();
2822 mcIdType nbOfCells=getNumberOfCells();
2823 for ( mcIdType ielem=0; ielem<nbOfCells;ielem++ )
2825 for (int i=0; i<dim; i++)
2827 elem_bb[i*2]=std::numeric_limits<double>::max();
2828 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2831 for (mcIdType inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2833 mcIdType node= conn[inode];
2834 if(node>=0)//avoid polyhedron separator
2836 for (int idim=0; idim<dim; idim++)
2838 if ( coords[node*dim+idim] < elem_bb[idim*2] )
2840 elem_bb[idim*2] = coords[node*dim+idim] ;
2842 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2844 elem_bb[idim*2+1] = coords[node*dim+idim] ;
2849 if(intersectsBoundingBox(bbox, elem_bb, dim, eps))
2850 elems->pushBackSilent(ielem);
2852 return elems.retn();
2856 * Returns a type of a cell by its id.
2857 * \param [in] cellId - the id of the cell of interest.
2858 * \return INTERP_KERNEL::NormalizedCellType - enumeration item describing the cell type.
2859 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2861 INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::getTypeOfCell(mcIdType cellId) const
2863 const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
2864 if(cellId<_nodal_connec_index->getNbOfElems()-1)
2865 return (INTERP_KERNEL::NormalizedCellType) pt[ptI[cellId]];
2868 std::ostringstream oss; oss << "MEDCouplingUMesh::getTypeOfCell : Requesting type of cell #" << cellId << " but it should be in [0," << _nodal_connec_index->getNbOfElems()-1 << ") !";
2869 throw INTERP_KERNEL::Exception(oss.str());
2874 * This method returns a newly allocated array containing cell ids (ascendingly sorted) whose geometric type are equal to type.
2875 * This method does not throw exception if geometric type \a type is not in \a this.
2876 * This method throws an INTERP_KERNEL::Exception if meshdimension of \b this is not equal to those of \b type.
2877 * The coordinates array is not considered here.
2879 * \param [in] type the geometric type
2880 * \return cell ids in this having geometric type \a type.
2882 DataArrayIdType *MEDCouplingUMesh::giveCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2885 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
2887 checkConnectivityFullyDefined();
2888 mcIdType nbCells=getNumberOfCells();
2889 int mdim=getMeshDimension();
2890 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
2891 if(mdim!=ToIdType(cm.getDimension()))
2892 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::giveCellsWithType : Mismatch between mesh dimension and dimension of the cell !");
2893 const mcIdType *ptI=_nodal_connec_index->getConstPointer();
2894 const mcIdType *pt=_nodal_connec->getConstPointer();
2895 for(mcIdType i=0;i<nbCells;i++)
2897 if((INTERP_KERNEL::NormalizedCellType)pt[ptI[i]]==type)
2898 ret->pushBackSilent(i);
2904 * Returns nb of cells having the geometric type \a type. No throw if no cells in \a this has the geometric type \a type.
2906 mcIdType MEDCouplingUMesh::getNumberOfCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2908 const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
2909 mcIdType nbOfCells(getNumberOfCells()),ret(0);
2910 for(mcIdType i=0;i<nbOfCells;i++)
2911 if((INTERP_KERNEL::NormalizedCellType) pt[ptI[i]]==type)
2917 * Returns the nodal connectivity of a given cell.
2918 * The separator of faces within polyhedron connectivity (-1) is not returned, thus
2919 * all returned node ids can be used in getCoordinatesOfNode().
2920 * \param [in] cellId - an id of the cell of interest.
2921 * \param [in,out] conn - a vector where the node ids are appended. It is not
2922 * cleared before the appending.
2923 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2925 void MEDCouplingUMesh::getNodeIdsOfCell(mcIdType cellId, std::vector<mcIdType>& conn) const
2927 const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
2928 for(const mcIdType *w=pt+ptI[cellId]+1;w!=pt+ptI[cellId+1];w++)
2933 std::string MEDCouplingUMesh::simpleRepr() const
2935 static const char msg0[]="No coordinates specified !";
2936 std::ostringstream ret;
2937 ret << "Unstructured mesh with name : \"" << getName() << "\"\n";
2938 ret << "Description of mesh : \"" << getDescription() << "\"\n";
2940 double tt=getTime(tmpp1,tmpp2);
2941 ret << "Time attached to the mesh [unit] : " << tt << " [" << getTimeUnit() << "]\n";
2942 ret << "Iteration : " << tmpp1 << " Order : " << tmpp2 << "\n";
2944 { ret << "Mesh dimension : " << _mesh_dim << "\nSpace dimension : "; }
2946 { ret << " Mesh dimension has not been set or is invalid !"; }
2949 const int spaceDim=getSpaceDimension();
2950 ret << spaceDim << "\nInfo attached on space dimension : ";
2951 for(int i=0;i<spaceDim;i++)
2952 ret << "\"" << _coords->getInfoOnComponent(i) << "\" ";
2956 ret << msg0 << "\n";
2957 ret << "Number of nodes : ";
2959 ret << getNumberOfNodes() << "\n";
2961 ret << msg0 << "\n";
2962 ret << "Number of cells : ";
2963 if(_nodal_connec!=0 && _nodal_connec_index!=0)
2964 ret << getNumberOfCells() << "\n";
2966 ret << "No connectivity specified !" << "\n";
2967 ret << "Cell types present : ";
2968 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
2970 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter);
2971 ret << cm.getRepr() << " ";
2977 std::string MEDCouplingUMesh::advancedRepr() const
2979 std::ostringstream ret;
2980 ret << simpleRepr();
2981 ret << "\nCoordinates array : \n___________________\n\n";
2983 _coords->reprWithoutNameStream(ret);
2985 ret << "No array set !\n";
2986 ret << "\n\nConnectivity arrays : \n_____________________\n\n";
2987 reprConnectivityOfThisLL(ret);
2992 * This method returns a C++ code that is a dump of \a this.
2993 * This method will throw if this is not fully defined.
2995 std::string MEDCouplingUMesh::cppRepr() const
2997 static const char coordsName[]="coords";
2998 static const char connName[]="conn";
2999 static const char connIName[]="connI";
3000 checkFullyDefined();
3001 std::ostringstream ret; ret << "// coordinates" << std::endl;
3002 _coords->reprCppStream(coordsName,ret); ret << std::endl << "// connectivity" << std::endl;
3003 _nodal_connec->reprCppStream(connName,ret); ret << std::endl;
3004 _nodal_connec_index->reprCppStream(connIName,ret); ret << std::endl;
3005 ret << "MEDCouplingUMesh *mesh=MEDCouplingUMesh::New(\"" << getName() << "\"," << getMeshDimension() << ");" << std::endl;
3006 ret << "mesh->setCoords(" << coordsName << ");" << std::endl;
3007 ret << "mesh->setConnectivity(" << connName << "," << connIName << ",true);" << std::endl;
3008 ret << coordsName << "->decrRef(); " << connName << "->decrRef(); " << connIName << "->decrRef();" << std::endl;
3012 std::string MEDCouplingUMesh::reprConnectivityOfThis() const
3014 std::ostringstream ret;
3015 reprConnectivityOfThisLL(ret);
3020 * This method builds a newly allocated instance (with the same name than \a this) that the caller has the responsibility to deal with.
3021 * This method returns an instance with all arrays allocated (connectivity, connectivity index, coordinates)
3022 * but with length of these arrays set to 0. It allows to define an "empty" mesh (with nor cells nor nodes but compliant with
3025 * This method expects that \a this has a mesh dimension set and higher or equal to 0. If not an exception will be thrown.
3026 * 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
3027 * with number of tuples set to 0, if not the array is taken as this in the returned instance.
3029 MEDCouplingUMesh *MEDCouplingUMesh::buildSetInstanceFromThis(std::size_t spaceDim) const
3031 int mdim=getMeshDimension();
3033 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSetInstanceFromThis : invalid mesh dimension ! Should be >= 0 !");
3034 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
3035 MCAuto<DataArrayIdType> tmp1,tmp2;
3036 bool needToCpyCT=true;
3039 tmp1=DataArrayIdType::New(); tmp1->alloc(0,1);
3047 if(!_nodal_connec_index)
3049 tmp2=DataArrayIdType::New(); tmp2->alloc(1,1); tmp2->setIJ(0,0,0);
3054 tmp2=_nodal_connec_index;
3057 ret->setConnectivity(tmp1,tmp2,false);
3062 MCAuto<DataArrayDouble> coords=DataArrayDouble::New(); coords->alloc(0,spaceDim);
3063 ret->setCoords(coords);
3066 ret->setCoords(_coords);
3070 mcIdType MEDCouplingUMesh::getNumberOfNodesInCell(mcIdType cellId) const
3072 const mcIdType *ptI=_nodal_connec_index->getConstPointer();
3073 const mcIdType *pt=_nodal_connec->getConstPointer();
3074 if(pt[ptI[cellId]]!=INTERP_KERNEL::NORM_POLYHED)
3075 return ptI[cellId+1]-ptI[cellId]-1;
3077 return ToIdType(std::count_if(pt+ptI[cellId]+1,pt+ptI[cellId+1],std::bind(std::not_equal_to<mcIdType>(),std::placeholders::_1,-1)));
3081 * Returns types of cells of the specified part of \a this mesh.
3082 * This method avoids computing sub-mesh explicitly to get its types.
3083 * \param [in] begin - an array of cell ids of interest.
3084 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3085 * \return std::set<INTERP_KERNEL::NormalizedCellType> - a set of enumeration items
3086 * describing the cell types.
3087 * \throw If the coordinates array is not set.
3088 * \throw If the nodal connectivity of cells is not defined.
3089 * \sa getAllGeoTypes()
3091 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getTypesOfPart(const mcIdType *begin, const mcIdType *end) const
3093 checkFullyDefined();
3094 std::set<INTERP_KERNEL::NormalizedCellType> ret;
3095 const mcIdType *conn=_nodal_connec->getConstPointer();
3096 const mcIdType *connIndex=_nodal_connec_index->getConstPointer();
3097 for(const mcIdType *w=begin;w!=end;w++)
3098 ret.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]);
3103 * Defines the nodal connectivity using given connectivity arrays in \ref numbering-indirect format.
3104 * Optionally updates
3105 * a set of types of cells constituting \a this mesh.
3106 * This method is for advanced users having prepared their connectivity before. For
3107 * more info on using this method see \ref MEDCouplingUMeshAdvBuild.
3108 * \param [in] conn - the nodal connectivity array.
3109 * \param [in] connIndex - the nodal connectivity index array.
3110 * \param [in] isComputingTypes - if \c true, the set of types constituting \a this
3113 void MEDCouplingUMesh::setConnectivity(DataArrayIdType *conn, DataArrayIdType *connIndex, bool isComputingTypes)
3115 DataArrayIdType::SetArrayIn(conn,_nodal_connec);
3116 DataArrayIdType::SetArrayIn(connIndex,_nodal_connec_index);
3117 if(isComputingTypes)
3123 * Copy constructor. If 'deepCopy' is false \a this is a shallow copy of other.
3124 * If 'deeCpy' is true all arrays (coordinates and connectivities) are deeply copied.
3126 MEDCouplingUMesh::MEDCouplingUMesh(const MEDCouplingUMesh& other, bool deepCpy):MEDCouplingPointSet(other,deepCpy),_mesh_dim(other._mesh_dim),
3127 _nodal_connec(0),_nodal_connec_index(0),
3128 _types(other._types)
3130 if(other._nodal_connec)
3131 _nodal_connec=other._nodal_connec->performCopyOrIncrRef(deepCpy);
3132 if(other._nodal_connec_index)
3133 _nodal_connec_index=other._nodal_connec_index->performCopyOrIncrRef(deepCpy);
3136 MEDCouplingUMesh::~MEDCouplingUMesh()
3139 _nodal_connec->decrRef();
3140 if(_nodal_connec_index)
3141 _nodal_connec_index->decrRef();
3145 * Recomputes a set of cell types of \a this mesh. For more info see
3146 * \ref MEDCouplingUMeshNodalConnectivity.
3148 void MEDCouplingUMesh::computeTypes()
3150 ComputeAllTypesInternal(_types,_nodal_connec,_nodal_connec_index);
3155 * Returns a number of cells constituting \a this mesh.
3156 * \return mcIdType - the number of cells in \a this mesh.
3157 * \throw If the nodal connectivity of cells is not defined.
3159 mcIdType MEDCouplingUMesh::getNumberOfCells() const
3161 if(_nodal_connec_index)
3162 return _nodal_connec_index->getNumberOfTuples()-1;
3167 throw INTERP_KERNEL::Exception("Unable to get number of cells because no connectivity specified !");
3171 * Returns a dimension of \a this mesh, i.e. a dimension of cells constituting \a this
3172 * mesh. For more info see \ref meshes.
3173 * \return int - the dimension of \a this mesh.
3174 * \throw If the mesh dimension is not defined using setMeshDimension().
3176 int MEDCouplingUMesh::getMeshDimension() const
3179 throw INTERP_KERNEL::Exception("No mesh dimension specified !");
3184 * Returns a length of the nodal connectivity array.
3185 * This method is for test reason. Normally the integer returned is not useable by
3186 * user. For more info see \ref MEDCouplingUMeshNodalConnectivity.
3187 * \return mcIdType - the length of the nodal connectivity array.
3189 mcIdType MEDCouplingUMesh::getNodalConnectivityArrayLen() const
3191 return _nodal_connec->getNbOfElems();
3195 * First step of serialization process. Used by ParaMEDMEM and MEDCouplingCorba to transfert data between process.
3197 void MEDCouplingUMesh::getTinySerializationInformation(std::vector<double>& tinyInfoD, std::vector<mcIdType>& tinyInfo, std::vector<std::string>& littleStrings) const
3199 MEDCouplingPointSet::getTinySerializationInformation(tinyInfoD,tinyInfo,littleStrings);
3200 tinyInfo.push_back(ToIdType(getMeshDimension()));
3201 tinyInfo.push_back(getNumberOfCells());
3203 tinyInfo.push_back(getNodalConnectivityArrayLen());
3205 tinyInfo.push_back(-1);
3209 * First step of unserialization process.
3211 bool MEDCouplingUMesh::isEmptyMesh(const std::vector<mcIdType>& tinyInfo) const
3213 return tinyInfo[6]<=0;
3217 * Second step of serialization process.
3218 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3219 * \param a1 DataArrayDouble
3220 * \param a2 DataArrayDouble
3221 * \param littleStrings string vector
3223 void MEDCouplingUMesh::resizeForUnserialization(const std::vector<mcIdType>& tinyInfo, DataArrayIdType *a1, DataArrayDouble *a2, std::vector<std::string>& littleStrings) const
3225 MEDCouplingPointSet::resizeForUnserialization(tinyInfo,a1,a2,littleStrings);
3227 a1->alloc(tinyInfo[7]+tinyInfo[6]+1,1);
3231 * Third and final step of serialization process.
3233 void MEDCouplingUMesh::serialize(DataArrayIdType *&a1, DataArrayDouble *&a2) const
3235 MEDCouplingPointSet::serialize(a1,a2);
3236 if(getMeshDimension()>-1)
3238 a1=DataArrayIdType::New();
3239 a1->alloc(getNodalConnectivityArrayLen()+getNumberOfCells()+1,1);
3240 mcIdType *ptA1=a1->getPointer();
3241 const mcIdType *conn=getNodalConnectivity()->getConstPointer();
3242 const mcIdType *index=getNodalConnectivityIndex()->getConstPointer();
3243 ptA1=std::copy(index,index+getNumberOfCells()+1,ptA1);
3244 std::copy(conn,conn+getNodalConnectivityArrayLen(),ptA1);
3251 * Second and final unserialization process.
3252 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3254 void MEDCouplingUMesh::unserialization(const std::vector<double>& tinyInfoD, const std::vector<mcIdType>& tinyInfo, const DataArrayIdType *a1, DataArrayDouble *a2, const std::vector<std::string>& littleStrings)
3256 MEDCouplingPointSet::unserialization(tinyInfoD,tinyInfo,a1,a2,littleStrings);
3257 setMeshDimension(FromIdType<int>(tinyInfo[5]));
3261 const mcIdType *recvBuffer=a1->getConstPointer();
3262 MCAuto<DataArrayIdType> myConnecIndex=DataArrayIdType::New();
3263 myConnecIndex->alloc(tinyInfo[6]+1,1);
3264 std::copy(recvBuffer,recvBuffer+tinyInfo[6]+1,myConnecIndex->getPointer());
3265 MCAuto<DataArrayIdType> myConnec=DataArrayIdType::New();
3266 myConnec->alloc(tinyInfo[7],1);
3267 std::copy(recvBuffer+tinyInfo[6]+1,recvBuffer+tinyInfo[6]+1+tinyInfo[7],myConnec->getPointer());
3268 setConnectivity(myConnec, myConnecIndex);
3275 * Returns a new MEDCouplingFieldDouble containing volumes of cells constituting \a this
3277 * For 1D cells, the returned field contains lengths.<br>
3278 * For 2D cells, the returned field contains areas.<br>
3279 * For 3D cells, the returned field contains volumes.
3280 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3281 * orientation, i.e. the volume is always positive.
3282 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on cells
3283 * and one time . The caller is to delete this field using decrRef() as it is no
3286 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureField(bool isAbs) const
3288 std::string name="MeasureOfMesh_";
3290 mcIdType nbelem=getNumberOfCells();
3291 MCAuto<MEDCouplingFieldDouble> field=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3292 field->setName(name);
3293 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3294 array->alloc(nbelem,1);
3295 double *area_vol=array->getPointer();
3296 field->setArray(array) ; array=0;
3297 field->setMesh(const_cast<MEDCouplingUMesh *>(this));
3298 field->synchronizeTimeWithMesh();
3299 if(getMeshDimension()!=-1)
3302 INTERP_KERNEL::NormalizedCellType type;
3303 int dim_space=getSpaceDimension();
3304 const double *coords=getCoords()->getConstPointer();
3305 const mcIdType *connec=getNodalConnectivity()->getConstPointer();
3306 const mcIdType *connec_index=getNodalConnectivityIndex()->getConstPointer();
3307 for(mcIdType iel=0;iel<nbelem;iel++)
3309 ipt=connec_index[iel];
3310 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3311 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);
3314 std::transform(area_vol,area_vol+nbelem,area_vol,[](double c){return fabs(c);});
3318 area_vol[0]=std::numeric_limits<double>::max();
3320 return field.retn();
3324 * Returns a new DataArrayDouble containing volumes of specified cells of \a this
3326 * For 1D cells, the returned array contains lengths.<br>
3327 * For 2D cells, the returned array contains areas.<br>
3328 * For 3D cells, the returned array contains volumes.
3329 * This method avoids building explicitly a part of \a this mesh to perform the work.
3330 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3331 * orientation, i.e. the volume is always positive.
3332 * \param [in] begin - an array of cell ids of interest.
3333 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3334 * \return DataArrayDouble * - a new instance of DataArrayDouble. The caller is to
3335 * delete this array using decrRef() as it is no more needed.
3337 * \if ENABLE_EXAMPLES
3338 * \ref cpp_mcumesh_getPartMeasureField "Here is a C++ example".<br>
3339 * \ref py_mcumesh_getPartMeasureField "Here is a Python example".
3341 * \sa getMeasureField()
3343 DataArrayDouble *MEDCouplingUMesh::getPartMeasureField(bool isAbs, const mcIdType *begin, const mcIdType *end) const
3345 std::string name="PartMeasureOfMesh_";
3347 std::size_t nbelem=std::distance(begin,end);
3348 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3349 array->setName(name);
3350 array->alloc(nbelem,1);
3351 double *area_vol=array->getPointer();
3352 if(getMeshDimension()!=-1)
3355 INTERP_KERNEL::NormalizedCellType type;
3356 int dim_space=getSpaceDimension();
3357 const double *coords=getCoords()->getConstPointer();
3358 const mcIdType *connec=getNodalConnectivity()->getConstPointer();
3359 const mcIdType *connec_index=getNodalConnectivityIndex()->getConstPointer();
3360 for(const mcIdType *iel=begin;iel!=end;iel++)
3362 ipt=connec_index[*iel];
3363 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3364 *area_vol++=INTERP_KERNEL::computeVolSurfOfCell2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,connec+ipt+1,connec_index[*iel+1]-ipt-1,coords,dim_space);
3367 std::transform(array->getPointer(),area_vol,array->getPointer(),[](double c){return fabs(c);});
3371 area_vol[0]=std::numeric_limits<double>::max();
3373 return array.retn();
3377 * Returns a new MEDCouplingFieldDouble containing volumes of cells of a dual mesh of
3378 * \a this one. The returned field contains the dual cell volume for each corresponding
3379 * node in \a this mesh. In other words, the field returns the getMeasureField() of
3380 * the dual mesh in P1 sens of \a this.<br>
3381 * For 1D cells, the returned field contains lengths.<br>
3382 * For 2D cells, the returned field contains areas.<br>
3383 * For 3D cells, the returned field contains volumes.
3384 * This method is useful to check "P1*" conservative interpolators.
3385 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3386 * orientation, i.e. the volume is always positive.
3387 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3388 * nodes and one time. The caller is to delete this array using decrRef() as
3389 * it is no more needed.
3391 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureFieldOnNode(bool isAbs) const
3393 MCAuto<MEDCouplingFieldDouble> tmp=getMeasureField(isAbs);
3394 std::string name="MeasureOnNodeOfMesh_";
3396 mcIdType nbNodes=getNumberOfNodes();
3397 MCAuto<DataArrayDouble> nnpc;
3399 MCAuto<DataArrayIdType> tmp2(computeNbOfNodesPerCell());
3400 nnpc=tmp2->convertToDblArr();
3402 std::for_each(nnpc->rwBegin(),nnpc->rwEnd(),[](double& v) { v=1./v; });
3403 const double *nnpcPtr(nnpc->begin());
3404 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_NODES);
3405 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3406 array->alloc(nbNodes,1);
3407 double *valsToFill=array->getPointer();
3408 std::fill(valsToFill,valsToFill+nbNodes,0.);
3409 const double *values=tmp->getArray()->getConstPointer();
3410 MCAuto<DataArrayIdType> da=DataArrayIdType::New();
3411 MCAuto<DataArrayIdType> daInd=DataArrayIdType::New();
3412 getReverseNodalConnectivity(da,daInd);
3413 const mcIdType *daPtr=da->getConstPointer();
3414 const mcIdType *daIPtr=daInd->getConstPointer();
3415 for(mcIdType i=0;i<nbNodes;i++)
3416 for(const mcIdType *cell=daPtr+daIPtr[i];cell!=daPtr+daIPtr[i+1];cell++)
3417 valsToFill[i]+=nnpcPtr[*cell]*values[*cell];
3419 ret->setArray(array);
3424 * Returns a new MEDCouplingFieldDouble holding normal vectors to cells of \a this
3425 * mesh. The returned normal vectors to each cell have a norm2 equal to 1.
3426 * The computed vectors have <em> this->getMeshDimension()+1 </em> components
3427 * and are normalized.
3428 * <br> \a this can be either
3429 * - a 2D mesh in 2D or 3D space or
3430 * - an 1D mesh in 2D space.
3432 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3433 * cells and one time. The caller is to delete this field using decrRef() as
3434 * it is no more needed.
3435 * \throw If the nodal connectivity of cells is not defined.
3436 * \throw If the coordinates array is not set.
3437 * \throw If the mesh dimension is not set.
3438 * \throw If the mesh and space dimension is not as specified above.
3440 MEDCouplingFieldDouble *MEDCouplingUMesh::buildOrthogonalField() const
3442 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3443 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3444 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3445 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3446 mcIdType nbOfCells=getNumberOfCells();
3447 int nbComp=getMeshDimension()+1;
3448 array->alloc(nbOfCells,nbComp);
3449 double *vals=array->getPointer();
3450 const mcIdType *connI=_nodal_connec_index->getConstPointer();
3451 const mcIdType *conn=_nodal_connec->getConstPointer();
3452 const double *coords=_coords->getConstPointer();
3453 if(getMeshDimension()==2)
3455 if(getSpaceDimension()==3)
3457 MCAuto<DataArrayDouble> loc=computeCellCenterOfMass();
3458 const double *locPtr=loc->getConstPointer();
3459 for(mcIdType i=0;i<nbOfCells;i++,vals+=3)
3461 mcIdType offset=connI[i];
3462 INTERP_KERNEL::crossprod<3>(locPtr+3*i,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3463 double n=INTERP_KERNEL::norm<3>(vals);
3464 std::transform(vals,vals+3,vals,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3469 MCAuto<MEDCouplingFieldDouble> isAbs=getMeasureField(false);
3470 const double *isAbsPtr=isAbs->getArray()->begin();
3471 for(mcIdType i=0;i<nbOfCells;i++,isAbsPtr++)
3472 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=*isAbsPtr>0.?1.:-1.; }
3475 else//meshdimension==1
3478 for(mcIdType i=0;i<nbOfCells;i++)
3480 mcIdType offset=connI[i];
3481 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3482 double n=INTERP_KERNEL::norm<2>(tmp);
3483 std::transform(tmp,tmp+2,tmp,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3488 ret->setArray(array);
3490 ret->synchronizeTimeWithSupport();
3495 * Returns a new MEDCouplingFieldDouble holding normal vectors to specified cells of
3496 * \a this mesh. The computed vectors have <em> this->getMeshDimension()+1 </em> components
3497 * and are normalized.
3498 * <br> \a this can be either
3499 * - a 2D mesh in 2D or 3D space or
3500 * - an 1D mesh in 2D space.
3502 * This method avoids building explicitly a part of \a this mesh to perform the work.
3503 * \param [in] begin - an array of cell ids of interest.
3504 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3505 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3506 * cells and one time. The caller is to delete this field using decrRef() as
3507 * it is no more needed.
3508 * \throw If the nodal connectivity of cells is not defined.
3509 * \throw If the coordinates array is not set.
3510 * \throw If the mesh dimension is not set.
3511 * \throw If the mesh and space dimension is not as specified above.
3512 * \sa buildOrthogonalField()
3514 * \if ENABLE_EXAMPLES
3515 * \ref cpp_mcumesh_buildPartOrthogonalField "Here is a C++ example".<br>
3516 * \ref py_mcumesh_buildPartOrthogonalField "Here is a Python example".
3519 MEDCouplingFieldDouble *MEDCouplingUMesh::buildPartOrthogonalField(const mcIdType *begin, const mcIdType *end) const
3521 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3522 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3523 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3524 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3525 std::size_t nbelems=std::distance(begin,end);
3526 int nbComp=getMeshDimension()+1;
3527 array->alloc(nbelems,nbComp);
3528 double *vals=array->getPointer();
3529 const mcIdType *connI=_nodal_connec_index->getConstPointer();
3530 const mcIdType *conn=_nodal_connec->getConstPointer();
3531 const double *coords=_coords->getConstPointer();
3532 if(getMeshDimension()==2)
3534 if(getSpaceDimension()==3)
3536 MCAuto<DataArrayDouble> loc=getPartBarycenterAndOwner(begin,end);
3537 const double *locPtr=loc->getConstPointer();
3538 for(const mcIdType *i=begin;i!=end;i++,vals+=3,locPtr+=3)
3540 mcIdType offset=connI[*i];
3541 INTERP_KERNEL::crossprod<3>(locPtr,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3542 double n=INTERP_KERNEL::norm<3>(vals);
3543 std::transform(vals,vals+3,vals,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3548 for(std::size_t i=0;i<nbelems;i++)
3549 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=1.; }
3552 else//meshdimension==1
3555 for(const mcIdType *i=begin;i!=end;i++)
3557 mcIdType offset=connI[*i];
3558 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3559 double n=INTERP_KERNEL::norm<2>(tmp);
3560 std::transform(tmp,tmp+2,tmp,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3565 ret->setArray(array);
3567 ret->synchronizeTimeWithSupport();
3572 * Returns a new MEDCouplingFieldDouble holding a direction vector for each SEG2 in \a
3573 * this 1D mesh. The computed vectors have <em> this->getSpaceDimension() </em> components
3574 * and are \b not normalized.
3575 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3576 * cells and one time. The caller is to delete this field using decrRef() as
3577 * it is no more needed.
3578 * \throw If the nodal connectivity of cells is not defined.
3579 * \throw If the coordinates array is not set.
3580 * \throw If \a this->getMeshDimension() != 1.
3581 * \throw If \a this mesh includes cells of type other than SEG2.
3583 MEDCouplingFieldDouble *MEDCouplingUMesh::buildDirectionVectorField() const
3585 if(getMeshDimension()!=1)
3586 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for buildDirectionVectorField !");
3587 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3588 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for buildDirectionVectorField !");
3589 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3590 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3591 mcIdType nbOfCells=getNumberOfCells();
3592 int spaceDim=getSpaceDimension();
3593 array->alloc(nbOfCells,spaceDim);
3594 double *pt=array->getPointer();
3595 const double *coo=getCoords()->getConstPointer();
3596 std::vector<mcIdType> conn;
3598 for(mcIdType i=0;i<nbOfCells;i++)
3601 getNodeIdsOfCell(i,conn);
3602 pt=std::transform(coo+conn[1]*spaceDim,coo+(conn[1]+1)*spaceDim,coo+conn[0]*spaceDim,pt,std::minus<double>());
3604 ret->setArray(array);
3606 ret->synchronizeTimeWithSupport();
3611 * Creates a 2D mesh by cutting \a this 3D mesh with a plane. In addition to the mesh,
3612 * returns a new DataArrayIdType, of length equal to the number of 2D cells in the result
3613 * mesh, holding, for each cell in the result mesh, an id of a 3D cell it comes
3614 * from. If a result face is shared by two 3D cells, then the face in included twice in
3616 * \param [in] origin - 3 components of a point defining location of the plane.
3617 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3618 * must be greater than 1e-6.
3619 * \param [in] eps - half-thickness of the plane.
3620 * \param [out] cellIds - a new instance of DataArrayIdType holding ids of 3D cells
3621 * producing correspondent 2D cells. The caller is to delete this array
3622 * using decrRef() as it is no more needed.
3623 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This mesh does
3624 * not share the node coordinates array with \a this mesh. The caller is to
3625 * delete this mesh using decrRef() as it is no more needed.
3626 * \throw If the coordinates array is not set.
3627 * \throw If the nodal connectivity of cells is not defined.
3628 * \throw If \a this->getMeshDimension() != 3 or \a this->getSpaceDimension() != 3.
3629 * \throw If magnitude of \a vec is less than 1e-6.
3630 * \throw If the plane does not intersect any 3D cell of \a this mesh.
3631 * \throw If \a this includes quadratic cells.
3633 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3D(const double *origin, const double *vec, double eps, DataArrayIdType *&cellIds) const
3635 checkFullyDefined();
3636 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3637 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3638 MCAuto<DataArrayIdType> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3639 if(candidates->empty())
3640 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane considering bounding boxes !");
3641 std::vector<mcIdType> nodes;
3642 DataArrayIdType *cellIds1D=0;
3643 MCAuto<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3644 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3645 MCAuto<DataArrayIdType> desc1=DataArrayIdType::New(),desc2=DataArrayIdType::New();
3646 MCAuto<DataArrayIdType> descIndx1=DataArrayIdType::New(),descIndx2=DataArrayIdType::New();
3647 MCAuto<DataArrayIdType> revDesc1=DataArrayIdType::New(),revDesc2=DataArrayIdType::New();
3648 MCAuto<DataArrayIdType> revDescIndx1=DataArrayIdType::New(),revDescIndx2=DataArrayIdType::New();
3649 MCAuto<MEDCouplingUMesh> mDesc2=subMesh->buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2);//meshDim==2 spaceDim==3
3650 revDesc2=0; revDescIndx2=0;
3651 MCAuto<MEDCouplingUMesh> mDesc1=mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3652 revDesc1=0; revDescIndx1=0;
3653 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3654 MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3656 std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3657 for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3659 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3660 std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(mDesc2->getNumberOfCells());
3661 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->getConstPointer(),mDesc2->getNodalConnectivityIndex()->getConstPointer(),
3662 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3663 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3664 MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New()),cellIds2(DataArrayIdType::New());
3665 connI->pushBackSilent(0); conn->alloc(0,1); cellIds2->alloc(0,1);
3666 subMesh->assemblyForSplitFrom3DSurf(cut3DSurf,desc2->getConstPointer(),descIndx2->getConstPointer(),conn,connI,cellIds2);
3667 if(cellIds2->empty())
3668 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3669 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3D",2);
3670 ret->setCoords(mDesc1->getCoords());
3671 ret->setConnectivity(conn,connI,true);
3672 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3677 * Creates an 1D mesh by cutting \a this 2D mesh in 3D space with a plane. In
3678 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
3679 from. If a result segment is shared by two 2D cells, then the segment in included twice in
3681 * \param [in] origin - 3 components of a point defining location of the plane.
3682 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3683 * must be greater than 1e-6.
3684 * \param [in] eps - half-thickness of the plane.
3685 * \param [out] cellIds - a new instance of DataArrayIdType holding ids of faces
3686 * producing correspondent segments. The caller is to delete this array
3687 * using decrRef() as it is no more needed.
3688 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This is an 1D
3689 * mesh in 3D space. This mesh does not share the node coordinates array with
3690 * \a this mesh. The caller is to delete this mesh using decrRef() as it is
3692 * \throw If the coordinates array is not set.
3693 * \throw If the nodal connectivity of cells is not defined.
3694 * \throw If \a this->getMeshDimension() != 2 or \a this->getSpaceDimension() != 3.
3695 * \throw If magnitude of \a vec is less than 1e-6.
3696 * \throw If the plane does not intersect any 2D cell of \a this mesh.
3697 * \throw If \a this includes quadratic cells.
3699 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3DSurf(const double *origin, const double *vec, double eps, DataArrayIdType *&cellIds) const
3701 checkFullyDefined();
3702 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
3703 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf works on umeshes with meshdim equal to 2 and spaceDim equal to 3 !");
3704 MCAuto<DataArrayIdType> candidates(getCellIdsCrossingPlane(origin,vec,eps));
3705 if(candidates->empty())
3706 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3D surf cells in this intercepts the specified plane considering bounding boxes !");
3707 std::vector<mcIdType> nodes;
3708 DataArrayIdType *cellIds1D(0);
3709 MCAuto<MEDCouplingUMesh> subMesh(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3710 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3711 MCAuto<DataArrayIdType> desc1(DataArrayIdType::New()),descIndx1(DataArrayIdType::New()),revDesc1(DataArrayIdType::New()),revDescIndx1(DataArrayIdType::New());
3712 MCAuto<MEDCouplingUMesh> mDesc1(subMesh->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3713 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3714 MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3716 std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3717 for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3719 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3720 mcIdType ncellsSub=subMesh->getNumberOfCells();
3721 std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(ncellsSub);
3722 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,subMesh->getNodalConnectivity()->getConstPointer(),subMesh->getNodalConnectivityIndex()->getConstPointer(),
3723 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3724 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3725 MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New()),cellIds2(DataArrayIdType::New()); connI->pushBackSilent(0);
3727 const mcIdType *nodal=subMesh->getNodalConnectivity()->getConstPointer();
3728 const mcIdType *nodalI=subMesh->getNodalConnectivityIndex()->getConstPointer();
3729 for(mcIdType i=0;i<ncellsSub;i++)
3731 if(cut3DSurf[i].first!=-1 && cut3DSurf[i].second!=-1)
3733 if(cut3DSurf[i].first!=-2)
3735 conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_SEG2)); conn->pushBackSilent(cut3DSurf[i].first); conn->pushBackSilent(cut3DSurf[i].second);
3736 connI->pushBackSilent(conn->getNumberOfTuples());
3737 cellIds2->pushBackSilent(i);
3741 mcIdType cellId3DSurf=cut3DSurf[i].second;
3742 mcIdType offset=nodalI[cellId3DSurf]+1;
3743 mcIdType nbOfEdges=nodalI[cellId3DSurf+1]-offset;
3744 for(mcIdType j=0;j<nbOfEdges;j++)
3746 conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_SEG2)); conn->pushBackSilent(nodal[offset+j]); conn->pushBackSilent(nodal[offset+(j+1)%nbOfEdges]);
3747 connI->pushBackSilent(conn->getNumberOfTuples());
3748 cellIds2->pushBackSilent(cellId3DSurf);
3753 if(cellIds2->empty())
3754 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3DSurf cells in this intercepts the specified plane !");
3755 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3DSurf",1);
3756 ret->setCoords(mDesc1->getCoords());
3757 ret->setConnectivity(conn,connI,true);
3758 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3762 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::clipSingle3DCellByPlane(const double origin[3], const double vec[3], double eps) const
3764 checkFullyDefined();
3765 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3766 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3767 if(getNumberOfCells()!=1)
3768 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works only on mesh containing exactly one cell !");
3770 std::vector<mcIdType> nodes;
3771 findNodesOnPlane(origin,vec,eps,nodes);
3772 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());
3773 MCAuto<MEDCouplingUMesh> mDesc2(buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2));//meshDim==2 spaceDim==3
3774 revDesc2=0; revDescIndx2=0;
3775 MCAuto<MEDCouplingUMesh> mDesc1(mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3776 revDesc1=0; revDescIndx1=0;
3777 DataArrayIdType *cellIds1D(0);
3778 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3779 MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3780 std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3781 for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3785 mcIdType oldNbNodes(mDesc1->getNumberOfNodes());
3786 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3787 sameNbNodes=(mDesc1->getNumberOfNodes()==oldNbNodes);
3789 std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(mDesc2->getNumberOfCells());
3790 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->begin(),mDesc2->getNodalConnectivityIndex()->begin(),
3791 mDesc1->getNodalConnectivity()->begin(),mDesc1->getNodalConnectivityIndex()->begin(),
3792 desc1->begin(),descIndx1->begin(),cut3DSurf);
3793 MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New());
3794 connI->pushBackSilent(0); conn->alloc(0,1);
3796 MCAuto<DataArrayIdType> cellIds2(DataArrayIdType::New()); cellIds2->alloc(0,1);
3797 assemblyForSplitFrom3DSurf(cut3DSurf,desc2->begin(),descIndx2->begin(),conn,connI,cellIds2);
3798 if(cellIds2->empty())
3799 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3801 std::vector<std::vector<mcIdType> > res;
3802 buildSubCellsFromCut(cut3DSurf,desc2->begin(),descIndx2->begin(),mDesc1->getCoords()->begin(),eps,res);
3803 std::size_t sz(res.size());
3804 if(ToIdType(res.size())==mDesc1->getNumberOfCells() && sameNbNodes)
3805 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane : cell is not clipped !");
3806 for(std::size_t i=0;i<sz;i++)
3808 conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYGON));
3809 conn->insertAtTheEnd(res[i].begin(),res[i].end());
3810 connI->pushBackSilent(conn->getNumberOfTuples());
3812 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
3813 ret->setCoords(mDesc1->getCoords());
3814 ret->setConnectivity(conn,connI,true);
3815 mcIdType nbCellsRet(ret->getNumberOfCells());
3817 MCAuto<DataArrayDouble> vec2(DataArrayDouble::New()); vec2->alloc(1,3); std::copy(vec,vec+3,vec2->getPointer());
3818 MCAuto<MEDCouplingFieldDouble> ortho(ret->buildOrthogonalField());
3819 MCAuto<DataArrayDouble> ortho2(ortho->getArray()->selectByTupleIdSafeSlice(0,1,1));
3820 MCAuto<DataArrayDouble> dott(DataArrayDouble::Dot(ortho2,vec2));
3821 MCAuto<DataArrayDouble> ccm(ret->computeCellCenterOfMass());
3822 MCAuto<DataArrayDouble> occm;
3824 MCAuto<DataArrayDouble> pt(DataArrayDouble::New()); pt->alloc(1,3); std::copy(origin,origin+3,pt->getPointer());
3825 occm=DataArrayDouble::Substract(ccm,pt);
3827 vec2=DataArrayDouble::New(); vec2->alloc(nbCellsRet,3);
3828 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);
3829 MCAuto<DataArrayDouble> dott2(DataArrayDouble::Dot(occm,vec2));
3831 const mcIdType *cPtr(ret->getNodalConnectivity()->begin()),*ciPtr(ret->getNodalConnectivityIndex()->begin());
3832 MCAuto<MEDCouplingUMesh> ret2(MEDCouplingUMesh::New("Clip3D",3));
3833 ret2->setCoords(mDesc1->getCoords());
3834 MCAuto<DataArrayIdType> conn2(DataArrayIdType::New()),conn2I(DataArrayIdType::New());
3835 conn2I->pushBackSilent(0); conn2->alloc(0,1);
3836 std::vector<mcIdType> cell0(1,ToIdType(INTERP_KERNEL::NORM_POLYHED));
3837 std::vector<mcIdType> cell1(1,ToIdType(INTERP_KERNEL::NORM_POLYHED));
3838 if(dott->getIJ(0,0)>0)
3840 cell0.insert(cell0.end(),cPtr+1,cPtr+ciPtr[1]);
3841 std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell1,cell1.end()));
3845 cell1.insert(cell1.end(),cPtr+1,cPtr+ciPtr[1]);
3846 std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell0,cell0.end()));
3848 for(mcIdType i=1;i<nbCellsRet;i++)
3850 if(dott2->getIJ(i,0)<0)
3852 if(ciPtr[i+1]-ciPtr[i]>=4)
3854 cell0.push_back(-1);
3855 cell0.insert(cell0.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
3860 if(ciPtr[i+1]-ciPtr[i]>=4)
3862 cell1.push_back(-1);
3863 cell1.insert(cell1.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
3867 conn2->insertAtTheEnd(cell0.begin(),cell0.end());
3868 conn2I->pushBackSilent(conn2->getNumberOfTuples());
3869 conn2->insertAtTheEnd(cell1.begin(),cell1.end());
3870 conn2I->pushBackSilent(conn2->getNumberOfTuples());
3871 ret2->setConnectivity(conn2,conn2I,true);
3872 ret2->checkConsistencyLight();
3873 ret2->orientCorrectlyPolyhedrons();
3878 * Finds cells whose bounding boxes intersect a given plane.
3879 * \param [in] origin - 3 components of a point defining location of the plane.
3880 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3881 * must be greater than 1e-6.
3882 * \param [in] eps - half-thickness of the plane.
3883 * \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of the found
3884 * cells. The caller is to delete this array using decrRef() as it is no more
3886 * \throw If the coordinates array is not set.
3887 * \throw If the nodal connectivity of cells is not defined.
3888 * \throw If \a this->getSpaceDimension() != 3.
3889 * \throw If magnitude of \a vec is less than 1e-6.
3890 * \sa buildSlice3D()
3892 DataArrayIdType *MEDCouplingUMesh::getCellIdsCrossingPlane(const double *origin, const double *vec, double eps) const
3894 checkFullyDefined();
3895 if(getSpaceDimension()!=3)
3896 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with spaceDim equal to 3 !");
3897 double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
3899 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellIdsCrossingPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
3901 vec2[0]=vec[1]; vec2[1]=-vec[0]; vec2[2]=0.;//vec2 is the result of cross product of vec with (0,0,1)
3902 double angle=acos(vec[2]/normm);
3903 MCAuto<DataArrayIdType> cellIds;
3907 MCAuto<DataArrayDouble> coo=_coords->deepCopy();
3908 double normm2(sqrt(vec2[0]*vec2[0]+vec2[1]*vec2[1]+vec2[2]*vec2[2]));
3909 if(normm2/normm>1e-6)
3910 DataArrayDouble::Rotate3DAlg(origin,vec2,angle,coo->getNumberOfTuples(),coo->getPointer(),coo->getPointer());
3911 MCAuto<MEDCouplingUMesh> mw=clone(false);//false -> shallow copy
3913 mw->getBoundingBox(bbox);
3914 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3915 cellIds=mw->getCellsInBoundingBox(bbox,eps);
3919 getBoundingBox(bbox);
3920 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3921 cellIds=getCellsInBoundingBox(bbox,eps);
3923 return cellIds.retn();
3927 * This method checks that \a this is a contiguous mesh. The user is expected to call this method on a mesh with meshdim==1.
3928 * If not an exception will thrown. If this is an empty mesh with no cell an exception will be thrown too.
3929 * No consideration of coordinate is done by this method.
3930 * 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)
3931 * If not false is returned. In case that false is returned a call to MEDCoupling::MEDCouplingUMesh::mergeNodes could be useful.
3933 bool MEDCouplingUMesh::isContiguous1D() const
3935 if(getMeshDimension()!=1)
3936 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense only for 1D mesh !");
3937 mcIdType nbCells=getNumberOfCells();
3939 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense for non empty mesh !");
3940 const mcIdType *connI(_nodal_connec_index->begin()),*conn(_nodal_connec->begin());
3941 mcIdType ref=conn[connI[0]+2];
3942 for(mcIdType i=1;i<nbCells;i++)
3944 if(conn[connI[i]+1]!=ref)
3946 ref=conn[connI[i]+2];
3952 * This method is only callable on mesh with meshdim == 1 containing only SEG2 and spaceDim==3.
3953 * This method projects this on the 3D line defined by (pt,v). This methods first checks that all SEG2 are along v vector.
3954 * \param pt reference point of the line
3955 * \param v normalized director vector of the line
3956 * \param eps max precision before throwing an exception
3957 * \param res output of size this->getNumberOfCells
3959 void MEDCouplingUMesh::project1D(const double *pt, const double *v, double eps, double *res) const
3961 if(getMeshDimension()!=1)
3962 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for project1D !");
3963 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3964 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for project1D !");
3965 if(getSpaceDimension()!=3)
3966 throw INTERP_KERNEL::Exception("Expected a umesh with spaceDim==3 for project1D !");
3967 MCAuto<MEDCouplingFieldDouble> f=buildDirectionVectorField();
3968 const double *fPtr=f->getArray()->getConstPointer();
3970 for(mcIdType i=0;i<getNumberOfCells();i++)
3972 const double *tmp1=fPtr+3*i;
3973 tmp[0]=tmp1[1]*v[2]-tmp1[2]*v[1];
3974 tmp[1]=tmp1[2]*v[0]-tmp1[0]*v[2];
3975 tmp[2]=tmp1[0]*v[1]-tmp1[1]*v[0];
3976 double n1=INTERP_KERNEL::norm<3>(tmp);
3977 n1/=INTERP_KERNEL::norm<3>(tmp1);
3979 throw INTERP_KERNEL::Exception("UMesh::Projection 1D failed !");
3981 const double *coo=getCoords()->getConstPointer();
3982 for(mcIdType i=0;i<getNumberOfNodes();i++)
3984 std::transform(coo+i*3,coo+i*3+3,pt,tmp,std::minus<double>());
3985 std::transform(tmp,tmp+3,v,tmp,std::multiplies<double>());
3986 res[i]=std::accumulate(tmp,tmp+3,0.);
3991 * 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.
3992 * \a this is expected to be a mesh so that its space dimension is equal to its
3993 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
3994 * 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).
3996 * 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
3997 * 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).
3998 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4000 * So this method is more accurate (so, more costly) than simply searching for the closest point in \a this.
4001 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4003 * \param [in] ptBg the start pointer (included) of the coordinates of the point
4004 * \param [in] ptEnd the end pointer (not included) of the coordinates of the point
4005 * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4006 * \return the positive value of the distance.
4007 * \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
4009 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoints
4011 double MEDCouplingUMesh::distanceToPoint(const double *ptBg, const double *ptEnd, mcIdType& cellId) const
4013 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4014 if(meshDim!=spaceDim-1)
4015 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint works only for spaceDim=meshDim+1 !");
4016 if(meshDim!=2 && meshDim!=1)
4017 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint : only mesh dimension 2 and 1 are implemented !");
4018 checkFullyDefined();
4019 if(ToIdType(std::distance(ptBg,ptEnd))!=spaceDim)
4020 { 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()); }
4021 DataArrayIdType *ret1=0;
4022 MCAuto<DataArrayDouble> pts=DataArrayDouble::New(); pts->useArray(ptBg,false,DeallocType::C_DEALLOC,1,spaceDim);
4023 MCAuto<DataArrayDouble> ret0=distanceToPoints(pts,ret1);
4024 MCAuto<DataArrayIdType> ret1Safe(ret1);
4025 cellId=*ret1Safe->begin();
4026 return *ret0->begin();
4030 * This method computes the distance from each point of points serie \a pts (stored in a DataArrayDouble in which each tuple represents a point)
4031 * to \a this and the first \a cellId in \a this corresponding to the returned distance.
4032 * 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
4033 * 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).
4034 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4036 * \a this is expected to be a mesh so that its space dimension is equal to its
4037 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4038 * 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).
4040 * So this method is more accurate (so, more costly) than simply searching for each point in \a pts the closest point in \a this.
4041 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4043 * \param [in] pts the list of points in which each tuple represents a point
4044 * \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.
4045 * \return a newly allocated object to be dealed by the caller that tells for each point in \a pts the distance to \a this.
4046 * \throw if number of components of \a pts is not equal to the space dimension.
4047 * \throw if mesh dimension of \a this is not equal to space dimension - 1.
4048 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoint
4050 DataArrayDouble *MEDCouplingUMesh::distanceToPoints(const DataArrayDouble *pts, DataArrayIdType *& cellIds) const
4053 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : input points pointer is NULL !");
4054 pts->checkAllocated();
4055 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4056 if(meshDim!=spaceDim-1)
4057 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints works only for spaceDim=meshDim+1 !");
4058 if(meshDim!=2 && meshDim!=1)
4059 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only mesh dimension 2 and 1 are implemented !");
4060 if(ToIdType(pts->getNumberOfComponents())!=spaceDim)
4062 std::ostringstream oss; oss << "MEDCouplingUMesh::distanceToPoints : input pts DataArrayDouble has " << pts->getNumberOfComponents() << " components whereas it should be equal to " << spaceDim << " (mesh spaceDimension) !";
4063 throw INTERP_KERNEL::Exception(oss.str());
4065 checkFullyDefined();
4066 mcIdType nbCells=getNumberOfCells();
4068 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : no cells in this !");
4069 mcIdType nbOfPts=pts->getNumberOfTuples();
4070 MCAuto<DataArrayDouble> ret0=DataArrayDouble::New(); ret0->alloc(nbOfPts,1);
4071 MCAuto<DataArrayIdType> ret1=DataArrayIdType::New(); ret1->alloc(nbOfPts,1);
4072 const mcIdType *nc=_nodal_connec->begin(),*ncI=_nodal_connec_index->begin(); const double *coords=_coords->begin();
4073 double *ret0Ptr=ret0->getPointer(); mcIdType *ret1Ptr=ret1->getPointer(); const double *ptsPtr=pts->begin();
4074 MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree());
4075 const double *bbox(bboxArr->begin());
4080 BBTreeDst<3> myTree(bbox,0,0,nbCells);
4081 for(mcIdType i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=3)
4083 double x=std::numeric_limits<double>::max();
4084 std::vector<mcIdType> elems;
4085 myTree.getMinDistanceOfMax(ptsPtr,x);
4086 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4087 DistanceToPoint3DSurfAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4093 BBTreeDst<2> myTree(bbox,0,0,nbCells);
4094 for(mcIdType i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=2)
4096 double x=std::numeric_limits<double>::max();
4097 std::vector<mcIdType> elems;
4098 myTree.getMinDistanceOfMax(ptsPtr,x);
4099 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4100 DistanceToPoint2DCurveAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4105 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only spacedim 2 and 3 supported !");
4107 cellIds=ret1.retn();
4116 * Finds cells in contact with a ball (i.e. a point with precision).
4117 * 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.
4118 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4120 * \warning This method is suitable if the caller intends to evaluate only one
4121 * point, for more points getCellsContainingPoints() is recommended as it is
4123 * \param [in] pos - array of coordinates of the ball central point.
4124 * \param [in] eps - ball radius.
4125 * \return mcIdType - a smallest id of cells being in contact with the ball, -1 in case
4126 * if there are no such cells.
4127 * \throw If the coordinates array is not set.
4128 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4130 mcIdType MEDCouplingUMesh::getCellContainingPoint(const double *pos, double eps) const
4132 std::vector<mcIdType> elts;
4133 getCellsContainingPoint(pos,eps,elts);
4136 return elts.front();
4140 * Finds cells in contact with a ball (i.e. a point with precision).
4141 * 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.
4142 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4143 * \warning This method is suitable if the caller intends to evaluate only one
4144 * point, for more points getCellsContainingPoints() is recommended as it is
4146 * \param [in] pos - array of coordinates of the ball central point.
4147 * \param [in] eps - ball radius.
4148 * \param [out] elts - vector returning ids of the found cells. It is cleared
4149 * before inserting ids.
4150 * \throw If the coordinates array is not set.
4151 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4153 * \if ENABLE_EXAMPLES
4154 * \ref cpp_mcumesh_getCellsContainingPoint "Here is a C++ example".<br>
4155 * \ref py_mcumesh_getCellsContainingPoint "Here is a Python example".
4158 void MEDCouplingUMesh::getCellsContainingPoint(const double *pos, double eps, std::vector<mcIdType>& elts) const
4160 MCAuto<DataArrayIdType> eltsUg,eltsIndexUg;
4161 getCellsContainingPoints(pos,1,eps,eltsUg,eltsIndexUg);
4162 elts.clear(); elts.insert(elts.end(),eltsUg->begin(),eltsUg->end());
4165 void MEDCouplingUMesh::getCellsContainingPointsZeAlg(const double *pos, mcIdType nbOfPoints, double eps,
4166 MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex,
4167 std::function<bool(INTERP_KERNEL::NormalizedCellType,mcIdType)> sensibilityTo2DQuadraticLinearCellsFunc) const
4169 int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
4174 const double *coords=_coords->getConstPointer();
4175 getCellsContainingPointsAlg<3>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4178 throw INTERP_KERNEL::Exception("For spaceDim==3 only meshDim==3 implemented for getelementscontainingpoints !");
4180 else if(spaceDim==2)
4184 const double *coords=_coords->getConstPointer();
4185 getCellsContainingPointsAlg<2>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4188 throw INTERP_KERNEL::Exception("For spaceDim==2 only meshDim==2 implemented for getelementscontainingpoints !");
4190 else if(spaceDim==1)
4194 const double *coords=_coords->getConstPointer();
4195 getCellsContainingPointsAlg<1>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4198 throw INTERP_KERNEL::Exception("For spaceDim==1 only meshDim==1 implemented for getelementscontainingpoints !");
4201 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPoints : not managed for mdim not in [1,2,3] !");
4205 * Finds cells in contact with several balls (i.e. points with precision).
4206 * This method is an extension of getCellContainingPoint() and
4207 * getCellsContainingPoint() for the case of multiple points.
4208 * 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.
4209 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4210 * \param [in] pos - an array of coordinates of points in full interlace mode :
4211 * X0,Y0,Z0,X1,Y1,Z1,... Size of the array must be \a
4212 * this->getSpaceDimension() * \a nbOfPoints
4213 * \param [in] nbOfPoints - number of points to locate within \a this mesh.
4214 * \param [in] eps - radius of balls (i.e. the precision).
4215 * \param [out] elts - vector returning ids of found cells.
4216 * \param [out] eltsIndex - an array, of length \a nbOfPoints + 1,
4217 * dividing cell ids in \a elts into groups each referring to one
4218 * point. Its every element (except the last one) is an index pointing to the
4219 * first id of a group of cells. For example cells in contact with the *i*-th
4220 * point are described by following range of indices:
4221 * [ \a eltsIndex[ *i* ], \a eltsIndex[ *i*+1 ] ) and the cell ids are
4222 * \a elts[ \a eltsIndex[ *i* ]], \a elts[ \a eltsIndex[ *i* ] + 1 ], ...
4223 * Number of cells in contact with the *i*-th point is
4224 * \a eltsIndex[ *i*+1 ] - \a eltsIndex[ *i* ].
4225 * \throw If the coordinates array is not set.
4226 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4228 * \if ENABLE_EXAMPLES
4229 * \ref cpp_mcumesh_getCellsContainingPoints "Here is a C++ example".<br>
4230 * \ref py_mcumesh_getCellsContainingPoints "Here is a Python example".
4233 void MEDCouplingUMesh::getCellsContainingPoints(const double *pos, mcIdType nbOfPoints, double eps,
4234 MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex) const
4236 auto yesImSensibleTo2DQuadraticLinearCellsFunc([](INTERP_KERNEL::NormalizedCellType ct, int mdim) { return INTERP_KERNEL::CellModel::GetCellModel(ct).isQuadratic() && mdim == 2; } );
4237 this->getCellsContainingPointsZeAlg(pos,nbOfPoints,eps,elts,eltsIndex,yesImSensibleTo2DQuadraticLinearCellsFunc);
4241 * Behaves like MEDCouplingMesh::getCellsContainingPoints for cells in \a this that are linear.
4242 * For quadratic cells in \a this, this method behaves by just considering linear part of cells.
4243 * This method is here only for backward compatibility (interpolation GaussPoints to GaussPoints).
4245 * \sa MEDCouplingUMesh::getCellsContainingPoints, MEDCouplingRemapper::prepareNotInterpKernelOnlyGaussGauss
4247 void MEDCouplingUMesh::getCellsContainingPointsLinearPartOnlyOnNonDynType(const double *pos, mcIdType nbOfPoints, double eps, MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex) const
4249 auto noImNotSensibleTo2DQuadraticLinearCellsFunc([](INTERP_KERNEL::NormalizedCellType,mcIdType) { return false; } );
4250 this->getCellsContainingPointsZeAlg(pos,nbOfPoints,eps,elts,eltsIndex,noImNotSensibleTo2DQuadraticLinearCellsFunc);
4254 * Finds butterfly cells in \a this mesh. A 2D cell is considered to be butterfly if at
4255 * least two its edges intersect each other anywhere except their extremities. An
4256 * INTERP_KERNEL::NORM_NORI3 cell can \b not be butterfly.
4257 * \param [in,out] cells - a vector returning ids of the found cells. It is not
4258 * cleared before filling in.
4259 * \param [in] eps - precision.
4260 * \throw If \a this->getMeshDimension() != 2.
4261 * \throw If \a this->getSpaceDimension() != 2 && \a this->getSpaceDimension() != 3.
4263 void MEDCouplingUMesh::checkButterflyCells(std::vector<mcIdType>& cells, double eps) const
4265 const char msg[]="Butterfly detection work only for 2D cells with spaceDim==2 or 3!";
4266 if(getMeshDimension()!=2)
4267 throw INTERP_KERNEL::Exception(msg);
4268 int spaceDim=getSpaceDimension();
4269 if(spaceDim!=2 && spaceDim!=3)
4270 throw INTERP_KERNEL::Exception(msg);
4271 const mcIdType *conn=_nodal_connec->getConstPointer();
4272 const mcIdType *connI=_nodal_connec_index->getConstPointer();
4273 mcIdType nbOfCells=getNumberOfCells();
4274 std::vector<double> cell2DinS2;
4275 for(mcIdType i=0;i<nbOfCells;i++)
4277 mcIdType offset=connI[i];
4278 mcIdType nbOfNodesForCell=connI[i+1]-offset-1;
4279 if(nbOfNodesForCell<=3)
4281 bool isQuad=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[offset]).isQuadratic();
4282 project2DCellOnXY(conn+offset+1,conn+connI[i+1],cell2DinS2);
4283 if(isButterfly2DCell(cell2DinS2,isQuad,eps))
4290 * This method is typically requested to unbutterfly 2D linear cells in \b this.
4292 * 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.
4293 * 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.
4295 * For each 2D linear cell in \b this, this method builds the convex envelop (or the convex hull) of the current cell.
4296 * This convex envelop is computed using Jarvis march algorithm.
4297 * The coordinates and the number of cells of \b this remain unchanged on invocation of this method.
4298 * 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)
4299 * 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.
4301 * \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.
4302 * \sa MEDCouplingUMesh::colinearize2D
4304 DataArrayIdType *MEDCouplingUMesh::convexEnvelop2D()
4306 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
4307 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convexEnvelop2D works only for meshDim=2 and spaceDim=2 !");
4308 checkFullyDefined();
4309 const double *coords=getCoords()->getConstPointer();
4310 mcIdType nbOfCells=getNumberOfCells();
4311 MCAuto<DataArrayIdType> nodalConnecIndexOut=DataArrayIdType::New();
4312 nodalConnecIndexOut->alloc(nbOfCells+1,1);
4313 MCAuto<DataArrayIdType> nodalConnecOut(DataArrayIdType::New());
4314 mcIdType *workIndexOut=nodalConnecIndexOut->getPointer();
4316 const mcIdType *nodalConnecIn=_nodal_connec->getConstPointer();
4317 const mcIdType *nodalConnecIndexIn=_nodal_connec_index->getConstPointer();
4318 std::set<INTERP_KERNEL::NormalizedCellType> types;
4319 MCAuto<DataArrayIdType> isChanged(DataArrayIdType::New());
4320 isChanged->alloc(0,1);
4321 for(mcIdType i=0;i<nbOfCells;i++,workIndexOut++)
4323 mcIdType pos=nodalConnecOut->getNumberOfTuples();
4324 if(BuildConvexEnvelopOf2DCellJarvis(coords,nodalConnecIn+nodalConnecIndexIn[i],nodalConnecIn+nodalConnecIndexIn[i+1],nodalConnecOut))
4325 isChanged->pushBackSilent(i);
4326 types.insert((INTERP_KERNEL::NormalizedCellType)nodalConnecOut->getIJ(pos,0));
4327 workIndexOut[1]=nodalConnecOut->getNumberOfTuples();
4329 if(isChanged->empty())
4331 setConnectivity(nodalConnecOut,nodalConnecIndexOut,false);
4333 return isChanged.retn();
4337 * This method is \b NOT const because it can modify \a this.
4338 * \a this is expected to be an unstructured mesh with meshDim==2 and spaceDim==3. If not an exception will be thrown.
4339 * \param mesh1D is an unstructured mesh with MeshDim==1 and spaceDim==3. If not an exception will be thrown.
4340 * \param policy specifies the type of extrusion chosen:
4341 * - \b 0 for translation only (most simple): the cells of the 1D mesh represent the vectors along which the 2D mesh
4342 * will be repeated to build each level
4343 * - \b 1 for translation and rotation: the translation is done as above. For each level, an arc of circle is fitted on
4344 * 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
4345 * 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
4347 * \return an unstructured mesh with meshDim==3 and spaceDim==3. The returned mesh has the same coords than \a this.
4349 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMesh(const MEDCouplingUMesh *mesh1D, int policy)
4351 checkFullyDefined();
4352 mesh1D->checkFullyDefined();
4353 if(!mesh1D->isContiguous1D())
4354 throw INTERP_KERNEL::Exception("buildExtrudedMesh : 1D mesh passed in parameter is not contiguous !");
4355 if(getSpaceDimension()!=mesh1D->getSpaceDimension())
4356 throw INTERP_KERNEL::Exception("Invalid call to buildExtrudedMesh this and mesh1D must have same space dimension !");
4357 if((getMeshDimension()!=2 || getSpaceDimension()!=3) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
4358 throw INTERP_KERNEL::Exception("Invalid 'this' for buildExtrudedMesh method : must be (meshDim==2 and spaceDim==3) or (meshDim==1 and spaceDim==2) !");
4359 if(mesh1D->getMeshDimension()!=1)
4360 throw INTERP_KERNEL::Exception("Invalid 'mesh1D' for buildExtrudedMesh method : must be meshDim==1 !");
4362 if(isPresenceOfQuadratic())
4364 if(mesh1D->isFullyQuadratic())
4367 throw INTERP_KERNEL::Exception("Invalid 2D mesh and 1D mesh because 2D mesh has quadratic cells and 1D is not fully quadratic !");
4369 mcIdType oldNbOfNodes(getNumberOfNodes());
4370 MCAuto<DataArrayDouble> newCoords;
4375 newCoords=fillExtCoordsUsingTranslation(mesh1D,isQuad);
4380 newCoords=fillExtCoordsUsingTranslAndAutoRotation(mesh1D,isQuad);
4384 throw INTERP_KERNEL::Exception("Not implemented extrusion policy : must be in (0) !");
4386 setCoords(newCoords);
4387 MCAuto<MEDCouplingUMesh> ret(buildExtrudedMeshFromThisLowLev(oldNbOfNodes,isQuad));
4394 * Checks if \a this mesh is constituted by only quadratic cells.
4395 * \return bool - \c true if there are only quadratic cells in \a this mesh.
4396 * \throw If the coordinates array is not set.
4397 * \throw If the nodal connectivity of cells is not defined.
4399 bool MEDCouplingUMesh::isFullyQuadratic() const
4401 checkFullyDefined();
4403 mcIdType nbOfCells=getNumberOfCells();
4404 for(mcIdType i=0;i<nbOfCells && ret;i++)
4406 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4407 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4408 ret=cm.isQuadratic();
4414 * Checks if \a this mesh includes any quadratic cell.
4415 * \return bool - \c true if there is at least one quadratic cells in \a this mesh.
4416 * \throw If the coordinates array is not set.
4417 * \throw If the nodal connectivity of cells is not defined.
4419 bool MEDCouplingUMesh::isPresenceOfQuadratic() const
4421 checkFullyDefined();
4423 mcIdType nbOfCells=getNumberOfCells();
4424 for(mcIdType i=0;i<nbOfCells && !ret;i++)
4426 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4427 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4428 ret=cm.isQuadratic();
4434 * Converts all quadratic cells to linear ones. If there are no quadratic cells in \a
4435 * this mesh, it remains unchanged.
4436 * \throw If the coordinates array is not set.
4437 * \throw If the nodal connectivity of cells is not defined.
4439 void MEDCouplingUMesh::convertQuadraticCellsToLinear()
4441 checkFullyDefined();
4442 mcIdType nbOfCells=getNumberOfCells();
4444 const mcIdType *iciptr=_nodal_connec_index->begin();
4445 for(mcIdType i=0;i<nbOfCells;i++)
4447 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4448 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4449 if(cm.isQuadratic())
4451 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4452 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4453 if(!cml.isDynamic())
4454 delta+=cm.getNumberOfNodes()-cml.getNumberOfNodes();
4456 delta+=(iciptr[i+1]-iciptr[i]-1)/2;
4461 MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()),newConnI(DataArrayIdType::New());
4462 const mcIdType *icptr(_nodal_connec->begin());
4463 newConn->alloc(getNodalConnectivityArrayLen()-delta,1);
4464 newConnI->alloc(nbOfCells+1,1);
4465 mcIdType *ocptr(newConn->getPointer()),*ociptr(newConnI->getPointer());
4468 for(mcIdType i=0;i<nbOfCells;i++,ociptr++)
4470 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)icptr[iciptr[i]];
4471 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4472 if(!cm.isQuadratic())
4474 _types.insert(type);
4475 ocptr=std::copy(icptr+iciptr[i],icptr+iciptr[i+1],ocptr);
4476 ociptr[1]=ociptr[0]+iciptr[i+1]-iciptr[i];
4480 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4481 _types.insert(typel);
4482 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4483 mcIdType newNbOfNodes=cml.getNumberOfNodes();
4485 newNbOfNodes=(iciptr[i+1]-iciptr[i]-1)/2;
4486 *ocptr++=ToIdType(typel);
4487 ocptr=std::copy(icptr+iciptr[i]+1,icptr+iciptr[i]+newNbOfNodes+1,ocptr);
4488 ociptr[1]=ociptr[0]+newNbOfNodes+1;
4491 setConnectivity(newConn,newConnI,false);
4495 * This method converts all linear cell in \a this to quadratic one.
4496 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, here it is needed to specify the target
4497 * 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)
4498 * 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.
4499 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, the coordinates in \a this can be become bigger. All created nodes will be put at the
4500 * end of the existing coordinates.
4502 * \param [in] conversionType specifies the type of conversion expected. Only 0 (default) and 1 are supported presently. 0 those that creates the 'most' simple
4503 * corresponding quadratic cells. 1 is those creating the 'most' complex.
4504 * \return a newly created DataArrayIdType instance that the caller should deal with containing cell ids of converted cells.
4506 * \throw if \a this is not fully defined. It throws too if \a conversionType is not in [0,1].
4508 * \sa MEDCouplingUMesh::convertQuadraticCellsToLinear
4510 DataArrayIdType *MEDCouplingUMesh::convertLinearCellsToQuadratic(int conversionType)
4512 DataArrayIdType *conn=0,*connI=0;
4513 DataArrayDouble *coords=0;
4514 std::set<INTERP_KERNEL::NormalizedCellType> types;
4515 checkFullyDefined();
4516 MCAuto<DataArrayIdType> ret,connSafe,connISafe;
4517 MCAuto<DataArrayDouble> coordsSafe;
4518 int meshDim=getMeshDimension();
4519 switch(conversionType)
4525 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);
4526 connSafe=conn; connISafe=connI; coordsSafe=coords;
4529 ret=convertLinearCellsToQuadratic2D0(conn,connI,coords,types);
4530 connSafe=conn; connISafe=connI; coordsSafe=coords;
4533 ret=convertLinearCellsToQuadratic3D0(conn,connI,coords,types);
4534 connSafe=conn; connISafe=connI; coordsSafe=coords;
4537 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 0 mesh dimensions available are [1,2,3] !");
4545 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);//it is not a bug. In 1D policy 0 and 1 are equals
4546 connSafe=conn; connISafe=connI; coordsSafe=coords;
4549 ret=convertLinearCellsToQuadratic2D1(conn,connI,coords,types);
4550 connSafe=conn; connISafe=connI; coordsSafe=coords;
4553 ret=convertLinearCellsToQuadratic3D1(conn,connI,coords,types);
4554 connSafe=conn; connISafe=connI; coordsSafe=coords;
4557 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 1 mesh dimensions available are [1,2,3] !");
4562 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion type available are 0 (default, the simplest) and 1 (the most complex) !");
4564 setConnectivity(connSafe,connISafe,false);
4566 setCoords(coordsSafe);
4571 * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
4572 * so that the number of cells remains the same. Quadratic faces are converted to
4573 * polygons. This method works only for 2D meshes in
4574 * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
4575 * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
4576 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
4577 * \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
4578 * a polylinized edge constituting the input polygon.
4579 * \throw If the coordinates array is not set.
4580 * \throw If the nodal connectivity of cells is not defined.
4581 * \throw If \a this->getMeshDimension() != 2.
4582 * \throw If \a this->getSpaceDimension() != 2.
4584 void MEDCouplingUMesh::tessellate2D(double eps)
4586 int meshDim(getMeshDimension()),spaceDim(getSpaceDimension());
4588 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : works only with space dimension equal to 2 !");
4592 return tessellate2DCurveInternal(eps);
4594 return tessellate2DInternal(eps);
4596 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : mesh dimension must be in [1,2] !");
4602 * This method only works if \a this has spaceDimension equal to 2 and meshDimension also equal to 2.
4603 * This method allows to modify connectivity of cells in \a this that shares some edges in \a edgeIdsToBeSplit.
4604 * The nodes to be added in those 2D cells are defined by the pair of \a nodeIdsToAdd and \a nodeIdsIndexToAdd.
4605 * Length of \a nodeIdsIndexToAdd is expected to equal to length of \a edgeIdsToBeSplit + 1.
4606 * The node ids in \a nodeIdsToAdd should be valid. Those nodes have to be sorted exactly following exactly the direction of the edge.
4607 * This method can be seen as the opposite method of colinearize2D.
4608 * 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
4609 * to avoid to modify the numbering of existing nodes.
4611 * \param [in] nodeIdsToAdd - the list of node ids to be added (\a nodeIdsIndexToAdd array allows to walk on this array)
4612 * \param [in] nodeIdsIndexToAdd - the entry point of \a nodeIdsToAdd to point to the corresponding nodes to be added.
4613 * \param [in] mesh1Desc - 1st output of buildDescendingConnectivity2 on \a this.
4614 * \param [in] desc - 2nd output of buildDescendingConnectivity2 on \a this.
4615 * \param [in] descI - 3rd output of buildDescendingConnectivity2 on \a this.
4616 * \param [in] revDesc - 4th output of buildDescendingConnectivity2 on \a this.
4617 * \param [in] revDescI - 5th output of buildDescendingConnectivity2 on \a this.
4619 * \sa buildDescendingConnectivity2
4621 void MEDCouplingUMesh::splitSomeEdgesOf2DMesh(const DataArrayIdType *nodeIdsToAdd, const DataArrayIdType *nodeIdsIndexToAdd, const DataArrayIdType *edgeIdsToBeSplit,
4622 const MEDCouplingUMesh *mesh1Desc, const DataArrayIdType *desc, const DataArrayIdType *descI, const DataArrayIdType *revDesc, const DataArrayIdType *revDescI)
4624 if(!nodeIdsToAdd || !nodeIdsIndexToAdd || !edgeIdsToBeSplit || !mesh1Desc || !desc || !descI || !revDesc || !revDescI)
4625 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : input pointers must be not NULL !");
4626 nodeIdsToAdd->checkAllocated(); nodeIdsIndexToAdd->checkAllocated(); edgeIdsToBeSplit->checkAllocated(); desc->checkAllocated(); descI->checkAllocated(); revDesc->checkAllocated(); revDescI->checkAllocated();
4627 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
4628 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : this must have spacedim=meshdim=2 !");
4629 if(mesh1Desc->getSpaceDimension()!=2 || mesh1Desc->getMeshDimension()!=1)
4630 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : mesh1Desc must be the explosion of this with spaceDim=2 and meshDim = 1 !");
4631 //DataArrayIdType *out0(0),*outi0(0);
4632 //MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
4633 //MCAuto<DataArrayIdType> out0s(out0),outi0s(outi0);
4634 //out0s=out0s->buildUnique(); out0s->sort(true);
4640 * Divides every cell of \a this mesh into simplices (triangles in 2D and tetrahedra in 3D).
4641 * In addition, returns an array mapping new cells to old ones. <br>
4642 * This method typically increases the number of cells in \a this mesh
4643 * but the number of nodes remains \b unchanged.
4644 * That's why the 3D splitting policies
4645 * INTERP_KERNEL::GENERAL_24 and INTERP_KERNEL::GENERAL_48 are not available here.
4646 * \param [in] policy - specifies a pattern used for splitting.
4647 * The semantic of \a policy is:
4648 * - 0 - to split QUAD4 by cutting it along 0-2 diagonal (for 2D mesh only).
4649 * - 1 - to split QUAD4 by cutting it along 1-3 diagonal (for 2D mesh only).
4650 * - INTERP_KERNEL::PLANAR_FACE_5 - to split HEXA8 into 5 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4651 * - INTERP_KERNEL::PLANAR_FACE_6 - to split HEXA8 into 6 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4654 * \return DataArrayIdType * - a new instance of DataArrayIdType holding, for each new cell,
4655 * an id of old cell producing it. The caller is to delete this array using
4656 * decrRef() as it is no more needed.
4658 * \throw If \a policy is 0 or 1 and \a this->getMeshDimension() != 2.
4659 * \throw If \a policy is INTERP_KERNEL::PLANAR_FACE_5 or INTERP_KERNEL::PLANAR_FACE_6
4660 * and \a this->getMeshDimension() != 3.
4661 * \throw If \a policy is not one of the four discussed above.
4662 * \throw If the nodal connectivity of cells is not defined.
4663 * \sa MEDCouplingUMesh::tetrahedrize, MEDCoupling1SGTUMesh::sortHexa8EachOther
4665 DataArrayIdType *MEDCouplingUMesh::simplexize(int policy)
4670 return simplexizePol0();
4672 return simplexizePol1();
4673 case INTERP_KERNEL::PLANAR_FACE_5:
4674 return simplexizePlanarFace5();
4675 case INTERP_KERNEL::PLANAR_FACE_6:
4676 return simplexizePlanarFace6();
4678 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)");
4683 * Checks if \a this mesh is constituted by simplex cells only. Simplex cells are:
4684 * - 1D: INTERP_KERNEL::NORM_SEG2
4685 * - 2D: INTERP_KERNEL::NORM_TRI3
4686 * - 3D: INTERP_KERNEL::NORM_TETRA4.
4688 * This method is useful for users that need to use P1 field services as
4689 * MEDCouplingFieldDouble::getValueOn(), MEDCouplingField::buildMeasureField() etc.
4690 * All these methods need mesh support containing only simplex cells.
4691 * \return bool - \c true if there are only simplex cells in \a this mesh.
4692 * \throw If the coordinates array is not set.
4693 * \throw If the nodal connectivity of cells is not defined.
4694 * \throw If \a this->getMeshDimension() < 1.
4696 bool MEDCouplingUMesh::areOnlySimplexCells() const
4698 checkFullyDefined();
4699 int mdim=getMeshDimension();
4700 if(mdim<1 || mdim>3)
4701 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::areOnlySimplexCells : only available with meshes having a meshdim 1, 2 or 3 !");
4702 mcIdType nbCells=getNumberOfCells();
4703 const mcIdType *conn=_nodal_connec->begin();
4704 const mcIdType *connI=_nodal_connec_index->begin();
4705 for(mcIdType i=0;i<nbCells;i++)
4707 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4717 * Converts degenerated 2D or 3D linear cells of \a this mesh into cells of simpler
4718 * type. For example an INTERP_KERNEL::NORM_QUAD4 cell having only three unique nodes in
4719 * its connectivity is transformed into an INTERP_KERNEL::NORM_TRI3 cell.
4720 * Quadratic cells in 2D are also handled. In those cells edges where start=end=midpoint are removed.
4721 * This method does \b not perform geometrical checks and checks only nodal connectivity of cells,
4722 * so it can be useful to call mergeNodes() before calling this method.
4723 * \throw If \a this->getMeshDimension() <= 1.
4724 * \throw If the coordinates array is not set.
4725 * \throw If the nodal connectivity of cells is not defined.
4727 void MEDCouplingUMesh::convertDegeneratedCells()
4729 checkFullyDefined();
4730 if(getMeshDimension()<=1)
4731 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4732 mcIdType nbOfCells=getNumberOfCells();
4735 mcIdType initMeshLgth=getNodalConnectivityArrayLen();
4736 mcIdType *conn=_nodal_connec->getPointer();
4737 mcIdType *index=_nodal_connec_index->getPointer();
4738 mcIdType posOfCurCell=0;
4740 mcIdType lgthOfCurCell;
4741 for(mcIdType i=0;i<nbOfCells;i++)
4743 lgthOfCurCell=index[i+1]-posOfCurCell;
4744 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4746 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
4747 conn+newPos+1,newLgth);
4748 conn[newPos]=newType;
4750 posOfCurCell=index[i+1];
4753 if(newPos!=initMeshLgth)
4754 _nodal_connec->reAlloc(newPos);
4759 * Same as MEDCouplingUMesh::convertDegeneratedCells() plus deletion of the flat cells.
4760 * A cell is flat in the following cases:
4761 * - for a linear cell, all points in the connectivity are equal
4762 * - for a quadratic cell, either the above, or a quadratic polygon with two (linear) points and two
4763 * identical quadratic points
4764 * \return a new instance of DataArrayIdType holding ids of removed cells. The caller is to delete
4765 * this array using decrRef() as it is no more needed.
4767 DataArrayIdType *MEDCouplingUMesh::convertDegeneratedCellsAndRemoveFlatOnes()
4769 checkFullyDefined();
4770 if(getMeshDimension()<=1)
4771 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4772 mcIdType nbOfCells=getNumberOfCells();
4773 MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(0,1);
4776 mcIdType initMeshLgth=getNodalConnectivityArrayLen();
4777 mcIdType *conn=_nodal_connec->getPointer();
4778 mcIdType *index=_nodal_connec_index->getPointer();
4779 mcIdType posOfCurCell=0;
4781 mcIdType lgthOfCurCell, nbDelCells(0);
4782 for(mcIdType i=0;i<nbOfCells;i++)
4784 lgthOfCurCell=index[i+1]-posOfCurCell;
4785 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4787 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
4788 conn+newPos+1,newLgth);
4789 // Shall we delete the cell if it is completely degenerated:
4790 bool delCell=INTERP_KERNEL::CellSimplify::isFlatCell(conn, newPos, newLgth, newType);
4794 ret->pushBackSilent(i);
4796 else //if the cell is to be deleted, simply stay at the same place
4798 conn[newPos]=newType;
4801 posOfCurCell=index[i+1];
4802 index[i+1-nbDelCells]=newPos;
4804 if(newPos!=initMeshLgth)
4805 _nodal_connec->reAlloc(newPos);
4806 const mcIdType nCellDel=ret->getNumberOfTuples();
4808 _nodal_connec_index->reAlloc(nbOfCells-nCellDel+1);
4814 * This method remove null 1D cells from \a this. A 1D cell is considered null if start node is equal to end node.
4815 * Only connectivity is considered here.
4817 bool MEDCouplingUMesh::removeDegenerated1DCells()
4819 checkConnectivityFullyDefined();
4820 if(getMeshDimension()!=1)
4821 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::removeDegenerated1DCells works on umeshes with meshdim equals to 1 !");
4822 std::size_t nbCells(getNumberOfCells()),newSize(0),newSize2(0);
4823 const mcIdType *conn(getNodalConnectivity()->begin()),*conni(getNodalConnectivityIndex()->begin());
4825 for(std::size_t i=0;i<nbCells;i++)
4827 INTERP_KERNEL::NormalizedCellType ct((INTERP_KERNEL::NormalizedCellType)conn[conni[i]]);
4828 if(ct==INTERP_KERNEL::NORM_SEG2 || ct==INTERP_KERNEL::NORM_SEG3)
4830 if(conn[conni[i]+1]!=conn[conni[i]+2])
4833 newSize2+=conni[i+1]-conni[i];
4838 std::ostringstream oss; oss << "MEDCouplingUMesh::removeDegenerated1DCells : cell #" << i << " in this is not of type SEG2/SEG3 !";
4839 throw INTERP_KERNEL::Exception(oss.str());
4843 if(newSize==nbCells)//no cells has been removed -> do nothing
4845 MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()),newConnI(DataArrayIdType::New()); newConnI->alloc(newSize+1,1); newConn->alloc(newSize2,1);
4846 mcIdType *newConnPtr(newConn->getPointer()),*newConnIPtr(newConnI->getPointer()); newConnIPtr[0]=0;
4847 for(std::size_t i=0;i<nbCells;i++)
4849 if(conn[conni[i]+1]!=conn[conni[i]+2])
4851 newConnIPtr[1]=newConnIPtr[0]+conni[i+1]-conni[i];
4852 newConnPtr=std::copy(conn+conni[i],conn+conni[i+1],newConnPtr);
4856 setConnectivity(newConn,newConnI,true);
4861 * Finds incorrectly oriented cells of this 2D mesh in 3D space.
4862 * A cell is considered to be oriented correctly if an angle between its
4863 * normal vector and a given vector is less than \c PI / \c 2.
4864 * \param [in] vec - 3 components of the vector specifying the correct orientation of
4866 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
4868 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
4869 * is not cleared before filling in.
4870 * \throw If \a this->getMeshDimension() != 2.
4871 * \throw If \a this->getSpaceDimension() != 3.
4873 * \if ENABLE_EXAMPLES
4874 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
4875 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
4878 void MEDCouplingUMesh::are2DCellsNotCorrectlyOriented(const double *vec, bool polyOnly, std::vector<mcIdType>& cells) const
4880 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
4881 throw INTERP_KERNEL::Exception("Invalid mesh to apply are2DCellsNotCorrectlyOriented on it : must be meshDim==2 and spaceDim==3 !");
4882 mcIdType nbOfCells=getNumberOfCells();
4883 const mcIdType *conn=_nodal_connec->begin();
4884 const mcIdType *connI=_nodal_connec_index->begin();
4885 const double *coordsPtr=_coords->begin();
4886 for(mcIdType i=0;i<nbOfCells;i++)
4888 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4889 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
4891 bool isQuadratic=INTERP_KERNEL::CellModel::GetCellModel(type).isQuadratic();
4892 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4899 * Reverse connectivity of 2D cells whose orientation is not correct. A cell is
4900 * considered to be oriented correctly if an angle between its normal vector and a
4901 * given vector is less than \c PI / \c 2.
4902 * \param [in] vec - 3 components of the vector specifying the correct orientation of
4904 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
4906 * \throw If \a this->getMeshDimension() != 2.
4907 * \throw If \a this->getSpaceDimension() != 3.
4909 * \if ENABLE_EXAMPLES
4910 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
4911 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
4914 * \sa changeOrientationOfCells
4916 void MEDCouplingUMesh::orientCorrectly2DCells(const double *vec, bool polyOnly)
4918 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
4919 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectly2DCells on it : must be meshDim==2 and spaceDim==3 !");
4920 mcIdType nbOfCells=getNumberOfCells();
4921 mcIdType *conn(_nodal_connec->getPointer());
4922 const mcIdType *connI(_nodal_connec_index->begin());
4923 const double *coordsPtr(_coords->begin());
4924 bool isModified(false);
4925 for(mcIdType i=0;i<nbOfCells;i++)
4927 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4928 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
4930 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
4931 bool isQuadratic(cm.isQuadratic());
4932 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4935 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
4940 _nodal_connec->declareAsNew();
4945 * This method change the orientation of cells in \a this without any consideration of coordinates. Only connectivity is impacted.
4947 * \sa orientCorrectly2DCells
4949 void MEDCouplingUMesh::changeOrientationOfCells()
4951 int mdim(getMeshDimension());
4952 if(mdim!=2 && mdim!=1)
4953 throw INTERP_KERNEL::Exception("Invalid mesh to apply changeOrientationOfCells on it : must be meshDim==2 or meshDim==1 !");
4954 mcIdType nbOfCells=getNumberOfCells();
4955 mcIdType *conn(_nodal_connec->getPointer());
4956 const mcIdType *connI(_nodal_connec_index->begin());
4959 for(mcIdType i=0;i<nbOfCells;i++)
4961 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4962 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
4963 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
4968 for(mcIdType i=0;i<nbOfCells;i++)
4970 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4971 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
4972 cm.changeOrientationOf1D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
4978 * Finds incorrectly oriented polyhedral cells, i.e. polyhedrons having correctly
4979 * oriented facets. The normal vector of the facet should point out of the cell.
4980 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
4981 * is not cleared before filling in.
4982 * \throw If \a this->getMeshDimension() != 3.
4983 * \throw If \a this->getSpaceDimension() != 3.
4984 * \throw If the coordinates array is not set.
4985 * \throw If the nodal connectivity of cells is not defined.
4987 * \if ENABLE_EXAMPLES
4988 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
4989 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
4992 void MEDCouplingUMesh::arePolyhedronsNotCorrectlyOriented(std::vector<mcIdType>& cells) const
4994 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
4995 throw INTERP_KERNEL::Exception("Invalid mesh to apply arePolyhedronsNotCorrectlyOriented on it : must be meshDim==3 and spaceDim==3 !");
4996 mcIdType nbOfCells=getNumberOfCells();
4997 const mcIdType *conn=_nodal_connec->begin();
4998 const mcIdType *connI=_nodal_connec_index->begin();
4999 const double *coordsPtr=_coords->begin();
5000 for(mcIdType i=0;i<nbOfCells;i++)
5002 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5003 if(type==INTERP_KERNEL::NORM_POLYHED)
5005 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5012 * Tries to fix connectivity of polyhedra, so that normal vector of all facets to point
5014 * \throw If \a this->getMeshDimension() != 3.
5015 * \throw If \a this->getSpaceDimension() != 3.
5016 * \throw If the coordinates array is not set.
5017 * \throw If the nodal connectivity of cells is not defined.
5018 * \throw If the reparation fails.
5020 * \if ENABLE_EXAMPLES
5021 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
5022 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
5024 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
5026 void MEDCouplingUMesh::orientCorrectlyPolyhedrons()
5028 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
5029 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectlyPolyhedrons on it : must be meshDim==3 and spaceDim==3 !");
5030 mcIdType nbOfCells=getNumberOfCells();
5031 mcIdType *conn=_nodal_connec->getPointer();
5032 const mcIdType *connI=_nodal_connec_index->begin();
5033 const double *coordsPtr=_coords->begin();
5034 for(mcIdType i=0;i<nbOfCells;i++)
5036 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5037 if(type==INTERP_KERNEL::NORM_POLYHED)
5041 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5042 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
5044 catch(INTERP_KERNEL::Exception& e)
5046 std::ostringstream oss; oss << "Something wrong in polyhedron #" << i << " : " << e.what();
5047 throw INTERP_KERNEL::Exception(oss.str());
5055 * This method invert orientation of all cells in \a this.
5056 * After calling this method the absolute value of measure of cells in \a this are the same than before calling.
5057 * This method only operates on the connectivity so coordinates are not touched at all.
5059 void MEDCouplingUMesh::invertOrientationOfAllCells()
5061 checkConnectivityFullyDefined();
5062 std::set<INTERP_KERNEL::NormalizedCellType> gts(getAllGeoTypes());
5063 mcIdType *conn(_nodal_connec->getPointer());
5064 const mcIdType *conni(_nodal_connec_index->begin());
5065 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator gt=gts.begin();gt!=gts.end();gt++)
5067 INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::OrientationInverter> oi(INTERP_KERNEL::OrientationInverter::BuildInstanceFrom(*gt));
5068 MCAuto<DataArrayIdType> cwt(giveCellsWithType(*gt));
5069 for(const mcIdType *it=cwt->begin();it!=cwt->end();it++)
5070 oi->operate(conn+conni[*it]+1,conn+conni[*it+1]);
5076 * Finds and fixes incorrectly oriented linear extruded volumes (INTERP_KERNEL::NORM_HEXA8,
5077 * INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXGP12 etc) to respect the MED convention
5078 * according to which the first facet of the cell should be oriented to have the normal vector
5079 * pointing out of cell.
5080 * \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of fixed
5081 * cells. The caller is to delete this array using decrRef() as it is no more
5083 * \throw If \a this->getMeshDimension() != 3.
5084 * \throw If \a this->getSpaceDimension() != 3.
5085 * \throw If the coordinates array is not set.
5086 * \throw If the nodal connectivity of cells is not defined.
5088 * \if ENABLE_EXAMPLES
5089 * \ref cpp_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a C++ example".<br>
5090 * \ref py_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a Python example".
5092 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
5094 DataArrayIdType *MEDCouplingUMesh::findAndCorrectBadOriented3DExtrudedCells()
5096 const char msg[]="check3DCellsWellOriented detection works only for 3D cells !";
5097 if(getMeshDimension()!=3)
5098 throw INTERP_KERNEL::Exception(msg);
5099 int spaceDim=getSpaceDimension();
5101 throw INTERP_KERNEL::Exception(msg);
5103 mcIdType nbOfCells=getNumberOfCells();
5104 mcIdType *conn=_nodal_connec->getPointer();
5105 const mcIdType *connI=_nodal_connec_index->begin();
5106 const double *coo=getCoords()->begin();
5107 MCAuto<DataArrayIdType> cells(DataArrayIdType::New()); cells->alloc(0,1);
5108 for(mcIdType i=0;i<nbOfCells;i++)
5110 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5111 if(cm.isExtruded() && !cm.isDynamic() && !cm.isQuadratic())
5113 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coo))
5115 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
5116 cells->pushBackSilent(i);
5120 return cells.retn();
5124 * This method is a faster method to correct orientation of all 3D cells in \a this.
5125 * 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.
5126 * This method makes the hypothesis that \a this a coherent that is to say MEDCouplingUMesh::checkConsistency should throw no exception.
5128 * \return a newly allocated mcIdType array with one components containing cell ids renumbered to fit the convention of MED (MED file and MEDCoupling)
5129 * \sa MEDCouplingUMesh::orientCorrectlyPolyhedrons,
5131 DataArrayIdType *MEDCouplingUMesh::findAndCorrectBadOriented3DCells()
5133 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
5134 throw INTERP_KERNEL::Exception("Invalid mesh to apply findAndCorrectBadOriented3DCells on it : must be meshDim==3 and spaceDim==3 !");
5135 mcIdType nbOfCells=getNumberOfCells();
5136 mcIdType *conn=_nodal_connec->getPointer();
5137 const mcIdType *connI=_nodal_connec_index->begin();
5138 const double *coordsPtr=_coords->begin();
5139 MCAuto<DataArrayIdType> ret=DataArrayIdType::New(); ret->alloc(0,1);
5140 for(mcIdType i=0;i<nbOfCells;i++)
5142 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5145 case INTERP_KERNEL::NORM_TETRA4:
5147 if(!IsTetra4WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5149 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+3));
5150 ret->pushBackSilent(i);
5154 case INTERP_KERNEL::NORM_PYRA5:
5156 if(!IsPyra5WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5158 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+4));
5159 ret->pushBackSilent(i);
5163 case INTERP_KERNEL::NORM_PENTA6:
5164 case INTERP_KERNEL::NORM_HEXA8:
5165 case INTERP_KERNEL::NORM_HEXGP12:
5167 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5169 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
5170 ret->pushBackSilent(i);
5174 case INTERP_KERNEL::NORM_POLYHED:
5176 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5178 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
5179 ret->pushBackSilent(i);
5184 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 !");
5192 * This method has a sense for meshes with spaceDim==3 and meshDim==2.
5193 * If it is not the case an exception will be thrown.
5194 * This method is fast because the first cell of \a this is used to compute the plane.
5195 * \param vec output of size at least 3 used to store the normal vector (with norm equal to Area ) of searched plane.
5196 * \param pos output of size at least 3 used to store a point owned of searched plane.
5198 void MEDCouplingUMesh::getFastAveragePlaneOfThis(double *vec, double *pos) const
5200 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
5201 throw INTERP_KERNEL::Exception("Invalid mesh to apply getFastAveragePlaneOfThis on it : must be meshDim==2 and spaceDim==3 !");
5202 const mcIdType *conn=_nodal_connec->begin();
5203 const mcIdType *connI=_nodal_connec_index->begin();
5204 const double *coordsPtr=_coords->begin();
5205 INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(conn+1,connI[1]-connI[0]-1,coordsPtr,vec);
5206 std::copy(coordsPtr+3*conn[1],coordsPtr+3*conn[1]+3,pos);
5210 * Creates a new MEDCouplingFieldDouble holding Edge Ratio values of all
5211 * cells. Currently cells of the following types are treated:
5212 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5213 * For a cell of other type an exception is thrown.
5214 * Space dimension of a 2D mesh can be either 2 or 3.
5215 * The Edge Ratio of a cell \f$t\f$ is:
5216 * \f$\frac{|t|_\infty}{|t|_0}\f$,
5217 * where \f$|t|_\infty\f$ and \f$|t|_0\f$ respectively denote the greatest and
5218 * the smallest edge lengths of \f$t\f$.
5219 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5220 * cells and one time, lying on \a this mesh. The caller is to delete this
5221 * field using decrRef() as it is no more needed.
5222 * \throw If the coordinates array is not set.
5223 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5224 * \throw If the connectivity data array has more than one component.
5225 * \throw If the connectivity data array has a named component.
5226 * \throw If the connectivity index data array has more than one component.
5227 * \throw If the connectivity index data array has a named component.
5228 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
5229 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5230 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5232 MEDCouplingFieldDouble *MEDCouplingUMesh::getEdgeRatioField() const
5234 checkConsistencyLight();
5235 int spaceDim=getSpaceDimension();
5236 int meshDim=getMeshDimension();
5237 if(spaceDim!=2 && spaceDim!=3)
5238 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : SpaceDimension must be equal to 2 or 3 !");
5239 if(meshDim!=2 && meshDim!=3)
5240 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : MeshDimension must be equal to 2 or 3 !");
5241 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5243 mcIdType nbOfCells=getNumberOfCells();
5244 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5245 arr->alloc(nbOfCells,1);
5246 double *pt=arr->getPointer();
5247 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5248 const mcIdType *conn=_nodal_connec->begin();
5249 const mcIdType *connI=_nodal_connec_index->begin();
5250 const double *coo=_coords->begin();
5252 for(mcIdType i=0;i<nbOfCells;i++,pt++)
5254 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5257 case INTERP_KERNEL::NORM_TRI3:
5259 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5260 *pt=INTERP_KERNEL::triEdgeRatio(tmp);
5263 case INTERP_KERNEL::NORM_QUAD4:
5265 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5266 *pt=INTERP_KERNEL::quadEdgeRatio(tmp);
5269 case INTERP_KERNEL::NORM_TETRA4:
5271 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5272 *pt=INTERP_KERNEL::tetraEdgeRatio(tmp);
5276 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5278 conn+=connI[i+1]-connI[i];
5280 ret->setName("EdgeRatio");
5281 ret->synchronizeTimeWithSupport();
5286 * Creates a new MEDCouplingFieldDouble holding Aspect Ratio values of all
5287 * cells. Currently cells of the following types are treated:
5288 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5289 * For a cell of other type an exception is thrown.
5290 * Space dimension of a 2D mesh can be either 2 or 3.
5291 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5292 * cells and one time, lying on \a this mesh. The caller is to delete this
5293 * field using decrRef() as it is no more needed.
5294 * \throw If the coordinates array is not set.
5295 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5296 * \throw If the connectivity data array has more than one component.
5297 * \throw If the connectivity data array has a named component.
5298 * \throw If the connectivity index data array has more than one component.
5299 * \throw If the connectivity index data array has a named component.
5300 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
5301 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5302 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5304 MEDCouplingFieldDouble *MEDCouplingUMesh::getAspectRatioField() const
5306 checkConsistencyLight();
5307 int spaceDim=getSpaceDimension();
5308 int meshDim=getMeshDimension();
5309 if(spaceDim!=2 && spaceDim!=3)
5310 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : SpaceDimension must be equal to 2 or 3 !");
5311 if(meshDim!=2 && meshDim!=3)
5312 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : MeshDimension must be equal to 2 or 3 !");
5313 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5315 mcIdType nbOfCells=getNumberOfCells();
5316 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5317 arr->alloc(nbOfCells,1);
5318 double *pt=arr->getPointer();
5319 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5320 const mcIdType *conn=_nodal_connec->begin();
5321 const mcIdType *connI=_nodal_connec_index->begin();
5322 const double *coo=_coords->begin();
5324 for(mcIdType i=0;i<nbOfCells;i++,pt++)
5326 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5329 case INTERP_KERNEL::NORM_TRI3:
5331 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5332 *pt=INTERP_KERNEL::triAspectRatio(tmp);
5335 case INTERP_KERNEL::NORM_QUAD4:
5337 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5338 *pt=INTERP_KERNEL::quadAspectRatio(tmp);
5341 case INTERP_KERNEL::NORM_TETRA4:
5343 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5344 *pt=INTERP_KERNEL::tetraAspectRatio(tmp);
5348 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5350 conn+=connI[i+1]-connI[i];
5352 ret->setName("AspectRatio");
5353 ret->synchronizeTimeWithSupport();
5358 * Creates a new MEDCouplingFieldDouble holding Warping factor values of all
5359 * cells of \a this 2D mesh in 3D space. It is a measure of the "planarity" of 2D cell
5360 * in 3D space. Currently only cells of the following types are
5361 * treated: INTERP_KERNEL::NORM_QUAD4.
5362 * For a cell of other type an exception is thrown.
5363 * The warp field is computed as follows: let (a,b,c,d) be the points of the quad.
5365 * \f$t=\vec{da}\times\vec{ab}\f$,
5366 * \f$u=\vec{ab}\times\vec{bc}\f$
5367 * \f$v=\vec{bc}\times\vec{cd}\f$
5368 * \f$w=\vec{cd}\times\vec{da}\f$, the warp is defined as \f$W^3\f$ with
5370 * W=min(\frac{t}{|t|}\cdot\frac{v}{|v|}, \frac{u}{|u|}\cdot\frac{w}{|w|})
5372 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5373 * cells and one time, lying on \a this mesh. The caller is to delete this
5374 * field using decrRef() as it is no more needed.
5375 * \throw If the coordinates array is not set.
5376 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5377 * \throw If the connectivity data array has more than one component.
5378 * \throw If the connectivity data array has a named component.
5379 * \throw If the connectivity index data array has more than one component.
5380 * \throw If the connectivity index data array has a named component.
5381 * \throw If \a this->getMeshDimension() != 2.
5382 * \throw If \a this->getSpaceDimension() != 3.
5383 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5385 MEDCouplingFieldDouble *MEDCouplingUMesh::getWarpField() const
5387 checkConsistencyLight();
5388 int spaceDim=getSpaceDimension();
5389 int meshDim=getMeshDimension();
5391 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : SpaceDimension must be equal to 3 !");
5393 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : MeshDimension must be equal to 2 !");
5394 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5396 mcIdType nbOfCells=getNumberOfCells();
5397 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5398 arr->alloc(nbOfCells,1);
5399 double *pt=arr->getPointer();
5400 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5401 const mcIdType *conn=_nodal_connec->begin();
5402 const mcIdType *connI=_nodal_connec_index->begin();
5403 const double *coo=_coords->begin();
5405 for(mcIdType i=0;i<nbOfCells;i++,pt++)
5407 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5410 case INTERP_KERNEL::NORM_QUAD4:
5412 FillInCompact3DMode(3,4,conn+1,coo,tmp);
5413 *pt=INTERP_KERNEL::quadWarp(tmp);
5417 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : A cell with not manged type (NORM_QUAD4) has been detected !");
5419 conn+=connI[i+1]-connI[i];
5421 ret->setName("Warp");
5422 ret->synchronizeTimeWithSupport();
5428 * Creates a new MEDCouplingFieldDouble holding Skew factor values of all
5429 * cells of \a this 2D mesh in 3D space. Currently cells of the following types are
5430 * treated: INTERP_KERNEL::NORM_QUAD4.
5431 * The skew is computed as follow for a quad with points (a,b,c,d): let
5432 * \f$u=\vec{ab}+\vec{dc}\f$ and \f$v=\vec{ac}+\vec{bd}\f$
5433 * then the skew is computed as:
5435 * s=\frac{u}{|u|}\cdot\frac{v}{|v|}
5438 * For a cell of other type an exception is thrown.
5439 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5440 * cells and one time, lying on \a this mesh. The caller is to delete this
5441 * field using decrRef() as it is no more needed.
5442 * \throw If the coordinates array is not set.
5443 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5444 * \throw If the connectivity data array has more than one component.
5445 * \throw If the connectivity data array has a named component.
5446 * \throw If the connectivity index data array has more than one component.
5447 * \throw If the connectivity index data array has a named component.
5448 * \throw If \a this->getMeshDimension() != 2.
5449 * \throw If \a this->getSpaceDimension() != 3.
5450 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5452 MEDCouplingFieldDouble *MEDCouplingUMesh::getSkewField() const
5454 checkConsistencyLight();
5455 int spaceDim=getSpaceDimension();
5456 int meshDim=getMeshDimension();
5458 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : SpaceDimension must be equal to 3 !");
5460 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : MeshDimension must be equal to 2 !");
5461 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5463 mcIdType nbOfCells=getNumberOfCells();
5464 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5465 arr->alloc(nbOfCells,1);
5466 double *pt=arr->getPointer();
5467 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5468 const mcIdType *conn=_nodal_connec->begin();
5469 const mcIdType *connI=_nodal_connec_index->begin();
5470 const double *coo=_coords->begin();
5472 for(mcIdType i=0;i<nbOfCells;i++,pt++)
5474 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5477 case INTERP_KERNEL::NORM_QUAD4:
5479 FillInCompact3DMode(3,4,conn+1,coo,tmp);
5480 *pt=INTERP_KERNEL::quadSkew(tmp);
5484 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : A cell with not manged type (NORM_QUAD4) has been detected !");
5486 conn+=connI[i+1]-connI[i];
5488 ret->setName("Skew");
5489 ret->synchronizeTimeWithSupport();
5494 * 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.
5496 * \return a new instance of field containing the result. The returned instance has to be deallocated by the caller.
5498 * \sa getSkewField, getWarpField, getAspectRatioField, getEdgeRatioField
5500 MEDCouplingFieldDouble *MEDCouplingUMesh::computeDiameterField() const
5502 checkConsistencyLight();
5503 MCAuto<MEDCouplingFieldDouble> ret(MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME));
5505 std::set<INTERP_KERNEL::NormalizedCellType> types;
5506 ComputeAllTypesInternal(types,_nodal_connec,_nodal_connec_index);
5507 int spaceDim(getSpaceDimension());
5508 mcIdType nbCells(getNumberOfCells());
5509 MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
5510 arr->alloc(nbCells,1);
5511 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++)
5513 INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::DiameterCalculator> dc(INTERP_KERNEL::CellModel::GetCellModel(*it).buildInstanceOfDiameterCalulator(spaceDim));
5514 MCAuto<DataArrayIdType> cellIds(giveCellsWithType(*it));
5515 dc->computeForListOfCellIdsUMeshFrmt(cellIds->begin(),cellIds->end(),_nodal_connec_index->begin(),_nodal_connec->begin(),getCoords()->begin(),arr->getPointer());
5518 ret->setName("Diameter");
5523 * This method aggregate the bbox of each cell and put it into bbox parameter (xmin,xmax,ymin,ymax,zmin,zmax).
5525 * \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)
5526 * For all other cases this input parameter is ignored.
5527 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5529 * \throw If \a this is not fully set (coordinates and connectivity).
5530 * \throw If a cell in \a this has no valid nodeId.
5531 * \sa MEDCouplingUMesh::getBoundingBoxForBBTreeFast, MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5533 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree(double arcDetEps) const
5535 int mDim(getMeshDimension()),sDim(getSpaceDimension());
5536 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.
5537 return getBoundingBoxForBBTreeFast();
5538 if((mDim==2 && sDim==2) || (mDim==1 && sDim==2))
5540 bool presenceOfQuadratic(false);
5541 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=_types.begin();it!=_types.end();it++)
5543 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(*it));
5544 if(cm.isQuadratic())
5545 presenceOfQuadratic=true;
5547 if(!presenceOfQuadratic)
5548 return getBoundingBoxForBBTreeFast();
5549 if(mDim==2 && sDim==2)
5550 return getBoundingBoxForBBTree2DQuadratic(arcDetEps);
5552 return getBoundingBoxForBBTree1DQuadratic(arcDetEps);
5554 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) !");
5558 * This method aggregate the bbox of each cell only considering the nodes constituting each cell and put it into bbox parameter.
5559 * So meshes having quadratic cells the computed bounding boxes can be invalid !
5561 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5563 * \throw If \a this is not fully set (coordinates and connectivity).
5564 * \throw If a cell in \a this has no valid nodeId.
5566 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTreeFast() const
5568 checkFullyDefined();
5569 int spaceDim(getSpaceDimension());
5570 mcIdType nbOfCells(getNumberOfCells()), nbOfNodes(getNumberOfNodes());
5571 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5572 double *bbox(ret->getPointer());
5573 for(mcIdType i=0;i<nbOfCells*spaceDim;i++)
5575 bbox[2*i]=std::numeric_limits<double>::max();
5576 bbox[2*i+1]=-std::numeric_limits<double>::max();
5578 const double *coordsPtr(_coords->begin());
5579 const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5580 for(mcIdType i=0;i<nbOfCells;i++)
5582 mcIdType offset=connI[i]+1;
5583 mcIdType nbOfNodesForCell(connI[i+1]-offset),kk(0);
5584 for(mcIdType j=0;j<nbOfNodesForCell;j++)
5586 mcIdType nodeId=conn[offset+j];
5587 if(nodeId>=0 && nodeId<nbOfNodes)
5589 for(int k=0;k<spaceDim;k++)
5591 bbox[2*spaceDim*i+2*k]=std::min(bbox[2*spaceDim*i+2*k],coordsPtr[spaceDim*nodeId+k]);
5592 bbox[2*spaceDim*i+2*k+1]=std::max(bbox[2*spaceDim*i+2*k+1],coordsPtr[spaceDim*nodeId+k]);
5599 std::ostringstream oss; oss << "MEDCouplingUMesh::getBoundingBoxForBBTree : cell #" << i << " contains no valid nodeId !";
5600 throw INTERP_KERNEL::Exception(oss.str());
5607 * This method aggregates the bbox of each 2D cell in \a this considering the whole shape. This method is particularly
5608 * useful for 2D meshes having quadratic cells
5609 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5610 * the two extremities of the arc of circle).
5612 * \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)
5613 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5614 * \throw If \a this is not fully defined.
5615 * \throw If \a this is not a mesh with meshDimension equal to 2.
5616 * \throw If \a this is not a mesh with spaceDimension equal to 2.
5617 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic
5619 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic(double arcDetEps) const
5621 checkFullyDefined();
5622 INTERP_KERNEL::QuadraticPlanarPrecision arcPrec(arcDetEps);
5624 int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
5625 mcIdType nbOfCells=getNumberOfCells();
5626 if(spaceDim!=2 || mDim!=2)
5627 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!");
5628 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5629 double *bbox(ret->getPointer());
5630 const double *coords(_coords->begin());
5631 const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5632 for(mcIdType i=0;i<nbOfCells;i++,bbox+=4,connI++)
5634 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5635 mcIdType sz(connI[1]-connI[0]-1);
5636 std::vector<INTERP_KERNEL::Node *> nodes(sz);
5637 INTERP_KERNEL::QuadraticPolygon *pol(0);
5638 for(mcIdType j=0;j<sz;j++)
5640 mcIdType nodeId(conn[*connI+1+j]);
5641 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5643 if(!cm.isQuadratic())
5644 pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
5646 pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
5647 INTERP_KERNEL::Bounds b; b.prepareForAggregation(); pol->fillBounds(b); delete pol;
5648 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax();
5654 * This method aggregates the bbox of each 1D cell in \a this considering the whole shape. This method is particularly
5655 * useful for 2D meshes having quadratic cells
5656 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5657 * the two extremities of the arc of circle).
5659 * \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)
5660 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5661 * \throw If \a this is not fully defined.
5662 * \throw If \a this is not a mesh with meshDimension equal to 1.
5663 * \throw If \a this is not a mesh with spaceDimension equal to 2.
5664 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5666 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic(double arcDetEps) const
5668 checkFullyDefined();
5669 int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
5670 mcIdType nbOfCells=getNumberOfCells();
5671 if(spaceDim!=2 || mDim!=1)
5672 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!");
5673 INTERP_KERNEL::QuadraticPlanarPrecision arcPrec(arcDetEps);
5674 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5675 double *bbox(ret->getPointer());
5676 const double *coords(_coords->begin());
5677 const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5678 for(mcIdType i=0;i<nbOfCells;i++,bbox+=4,connI++)
5680 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5681 mcIdType sz(connI[1]-connI[0]-1);
5682 std::vector<INTERP_KERNEL::Node *> nodes(sz);
5683 INTERP_KERNEL::Edge *edge(0);
5684 for(mcIdType j=0;j<sz;j++)
5686 mcIdType nodeId(conn[*connI+1+j]);
5687 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5689 if(!cm.isQuadratic())
5690 edge=INTERP_KERNEL::QuadraticPolygon::BuildLinearEdge(nodes);
5692 edge=INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(nodes);
5693 const INTERP_KERNEL::Bounds& b(edge->getBounds());
5694 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax(); edge->decrRef();
5701 namespace MEDCouplingImpl
5706 ConnReader(const mcIdType *c, mcIdType val):_conn(c),_val(val) { }
5707 bool operator() (const mcIdType& pos) { return _conn[pos]!=_val; }
5709 const mcIdType *_conn;
5716 ConnReader2(const mcIdType *c, mcIdType val):_conn(c),_val(val) { }
5717 bool operator() (const mcIdType& pos) { return _conn[pos]==_val; }
5719 const mcIdType *_conn;
5727 * This method expects that \a this is sorted by types. If not an exception will be thrown.
5728 * This method returns in the same format as code (see MEDCouplingUMesh::checkTypeConsistencyAndContig or MEDCouplingUMesh::splitProfilePerType) how
5729 * \a this is composed in cell types.
5730 * The returned array is of size 3*n where n is the number of different types present in \a this.
5731 * For every k in [0,n] ret[3*k+2]==-1 because it has no sense here.
5732 * This parameter is kept only for compatibility with other method listed above.
5734 std::vector<mcIdType> MEDCouplingUMesh::getDistributionOfTypes() const
5736 checkConnectivityFullyDefined();
5737 const mcIdType *conn=_nodal_connec->begin();
5738 const mcIdType *connI=_nodal_connec_index->begin();
5739 const mcIdType *work=connI;
5740 mcIdType nbOfCells=getNumberOfCells();
5741 std::size_t n=getAllGeoTypes().size();
5742 std::vector<mcIdType> ret(3*n,-1); //ret[3*k+2]==-1 because it has no sense here
5743 std::set<INTERP_KERNEL::NormalizedCellType> types;
5744 for(std::size_t i=0;work!=connI+nbOfCells;i++)
5746 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn[*work];
5747 if(types.find(typ)!=types.end())
5749 std::ostringstream oss; oss << "MEDCouplingUMesh::getDistributionOfTypes : Type " << INTERP_KERNEL::CellModel::GetCellModel(typ).getRepr();
5750 oss << " is not contiguous !";
5751 throw INTERP_KERNEL::Exception(oss.str());
5755 const mcIdType *work2=std::find_if(work+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,typ));
5756 ret[3*i+1]=ToIdType(std::distance(work,work2));
5763 * This method is used to check that this has contiguous cell type in same order than described in \a code.
5764 * only for types cell, type node is not managed.
5765 * Format of \a code is the following. \a code should be of size 3*n and non empty. If not an exception is thrown.
5766 * foreach k in [0,n) on 3*k pos represent the geometric type and 3*k+1 number of elements of type 3*k.
5767 * 3*k+2 refers if different from -1 the pos in 'idsPerType' to get the corresponding array.
5768 * If 2 or more same geometric type is in \a code and exception is thrown too.
5770 * This method firstly checks
5771 * If it exists k so that 3*k geometric type is not in geometric types of this an exception will be thrown.
5772 * If it exists k so that 3*k geometric type exists but the number of consecutive cell types does not match,
5773 * an exception is thrown too.
5775 * If all geometric types in \a code are exactly those in \a this null pointer is returned.
5776 * If it exists a geometric type in \a this \b not in \a code \b no exception is thrown
5777 * and a DataArrayIdType instance is returned that the user has the responsibility to deallocate.
5779 DataArrayIdType *MEDCouplingUMesh::checkTypeConsistencyAndContig(const std::vector<mcIdType>& code, const std::vector<const DataArrayIdType *>& idsPerType) const
5782 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code is empty, should not !");
5783 std::size_t sz=code.size();
5786 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code size is NOT %3 !");
5787 std::vector<INTERP_KERNEL::NormalizedCellType> types;
5789 bool isNoPflUsed=true;
5790 for(std::size_t i=0;i<n;i++)
5791 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)code[3*i])==types.end())
5793 types.push_back((INTERP_KERNEL::NormalizedCellType)code[3*i]);
5795 if(_types.find((INTERP_KERNEL::NormalizedCellType)code[3*i])==_types.end())
5796 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : expected geo types not in this !");
5797 isNoPflUsed=isNoPflUsed && (code[3*i+2]==-1);
5800 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code contains duplication of types in unstructured mesh !");
5803 if(!checkConsecutiveCellTypesAndOrder(&types[0],&types[0]+types.size()))
5804 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : non contiguous type !");
5805 if(types.size()==_types.size())
5808 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
5810 mcIdType *retPtr=ret->getPointer();
5811 const mcIdType *connI=_nodal_connec_index->begin();
5812 const mcIdType *conn=_nodal_connec->begin();
5813 mcIdType nbOfCells=getNumberOfCells();
5814 const mcIdType *i=connI;
5816 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++,kk++)
5818 i=std::find_if(i,connI+nbOfCells,MEDCouplingImpl::ConnReader2(conn,ToIdType((*it))));
5819 mcIdType offset=ToIdType(std::distance(connI,i));
5820 const mcIdType *j=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType((*it))));
5821 mcIdType nbOfCellsOfCurType=ToIdType(std::distance(i,j));
5822 if(code[3*kk+2]==-1)
5823 for(mcIdType k=0;k<nbOfCellsOfCurType;k++)
5827 mcIdType idInIdsPerType=code[3*kk+2];
5828 if(idInIdsPerType>=0 && idInIdsPerType<ToIdType(idsPerType.size()))
5830 const DataArrayIdType *zePfl=idsPerType[idInIdsPerType];
5833 zePfl->checkAllocated();
5834 if(zePfl->getNumberOfComponents()==1)
5836 for(const mcIdType *k=zePfl->begin();k!=zePfl->end();k++,retPtr++)
5838 if(*k>=0 && *k<nbOfCellsOfCurType)
5839 *retPtr=(*k)+offset;
5842 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : the section " << kk << " points to the profile #" << idInIdsPerType;
5843 oss << ", and this profile contains a value " << *k << " should be in [0," << nbOfCellsOfCurType << ") !";
5844 throw INTERP_KERNEL::Exception(oss.str());
5849 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of a profile with nb of compo != 1 !");
5852 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of null profile !");
5856 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : at section " << kk << " of code it points to the array #" << idInIdsPerType;
5857 oss << " should be in [0," << idsPerType.size() << ") !";
5858 throw INTERP_KERNEL::Exception(oss.str());
5867 * This method makes the hypothesis that \a this is sorted by type. If not an exception will be thrown.
5868 * 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.
5869 * 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.
5870 * This method has 1 input \a profile and 3 outputs \a code \a idsInPflPerType and \a idsPerType.
5872 * \param [in] profile list of IDs constituing the profile
5873 * \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.
5874 * \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,
5875 * \a idsInPflPerType[i] stores the tuple ids in \a profile that correspond to the geometric type code[3*i+0]
5876 * \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.
5877 * This vector can be empty in case of all geometric type cells are fully covered in ascending in the given input \a profile.
5878 * \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
5880 void MEDCouplingUMesh::splitProfilePerType(const DataArrayIdType *profile, std::vector<mcIdType>& code, std::vector<DataArrayIdType *>& idsInPflPerType, std::vector<DataArrayIdType *>& idsPerType, bool smartPflKiller) const
5883 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile is NULL !");
5884 if(profile->getNumberOfComponents()!=1)
5885 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile should have exactly one component !");
5886 checkConnectivityFullyDefined();
5887 const mcIdType *conn=_nodal_connec->begin();
5888 const mcIdType *connI=_nodal_connec_index->begin();
5889 mcIdType nbOfCells=getNumberOfCells();
5890 std::vector<INTERP_KERNEL::NormalizedCellType> types;
5891 std::vector<mcIdType> typeRangeVals(1);
5892 for(const mcIdType *i=connI;i!=connI+nbOfCells;)
5894 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5895 if(std::find(types.begin(),types.end(),curType)!=types.end())
5897 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : current mesh is not sorted by type !");
5899 types.push_back(curType);
5900 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
5901 typeRangeVals.push_back(ToIdType(std::distance(connI,i)));
5904 DataArrayIdType *castArr=0,*rankInsideCast=0,*castsPresent=0;
5905 profile->splitByValueRange(&typeRangeVals[0],&typeRangeVals[0]+typeRangeVals.size(),castArr,rankInsideCast,castsPresent);
5906 MCAuto<DataArrayIdType> tmp0=castArr;
5907 MCAuto<DataArrayIdType> tmp1=rankInsideCast;
5908 MCAuto<DataArrayIdType> tmp2=castsPresent;
5910 mcIdType nbOfCastsFinal=castsPresent->getNumberOfTuples();
5911 code.resize(3*nbOfCastsFinal);
5912 std::vector< MCAuto<DataArrayIdType> > idsInPflPerType2;
5913 std::vector< MCAuto<DataArrayIdType> > idsPerType2;
5914 for(mcIdType i=0;i<nbOfCastsFinal;i++)
5916 mcIdType castId=castsPresent->getIJ(i,0);
5917 MCAuto<DataArrayIdType> tmp3=castArr->findIdsEqual(castId);
5918 idsInPflPerType2.push_back(tmp3);
5919 code[3*i]=ToIdType(types[castId]);
5920 code[3*i+1]=tmp3->getNumberOfTuples();
5921 MCAuto<DataArrayIdType> tmp4=rankInsideCast->selectByTupleId(tmp3->begin(),tmp3->begin()+tmp3->getNumberOfTuples());
5922 if(!smartPflKiller || !tmp4->isIota(typeRangeVals[castId+1]-typeRangeVals[castId]))
5924 tmp4->copyStringInfoFrom(*profile);
5925 idsPerType2.push_back(tmp4);
5926 code[3*i+2]=ToIdType(idsPerType2.size())-1;
5933 std::size_t sz2=idsInPflPerType2.size();
5934 idsInPflPerType.resize(sz2);
5935 for(std::size_t i=0;i<sz2;i++)
5937 DataArrayIdType *locDa=idsInPflPerType2[i];
5939 idsInPflPerType[i]=locDa;
5941 std::size_t sz=idsPerType2.size();
5942 idsPerType.resize(sz);
5943 for(std::size_t i=0;i<sz;i++)
5945 DataArrayIdType *locDa=idsPerType2[i];
5947 idsPerType[i]=locDa;
5952 * This method is here too emulate the MEDMEM behaviour on BDC (buildDescendingConnectivity). Hoping this method becomes deprecated very soon.
5953 * This method make the assumption that \a this and 'nM1LevMesh' mesh lyies on same coords (same pointer) as MED and MEDMEM does.
5954 * The following equality should be verified 'nM1LevMesh->getMeshDimension()==this->getMeshDimension()-1'
5955 * 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.
5957 MEDCouplingUMesh *MEDCouplingUMesh::emulateMEDMEMBDC(const MEDCouplingUMesh *nM1LevMesh, DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *&revDesc, DataArrayIdType *&revDescIndx, DataArrayIdType *& nM1LevMeshIds, DataArrayIdType *&meshnM1Old2New) const
5959 checkFullyDefined();
5960 nM1LevMesh->checkFullyDefined();
5961 if(getMeshDimension()-1!=nM1LevMesh->getMeshDimension())
5962 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : The mesh passed as first argument should have a meshDim equal to this->getMeshDimension()-1 !" );
5963 if(_coords!=nM1LevMesh->getCoords())
5964 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : 'this' and mesh in first argument should share the same coords : Use tryToShareSameCoords method !");
5965 MCAuto<DataArrayIdType> tmp0=DataArrayIdType::New();
5966 MCAuto<DataArrayIdType> tmp1=DataArrayIdType::New();
5967 MCAuto<MEDCouplingUMesh> ret1=buildDescendingConnectivity(desc,descIndx,tmp0,tmp1);
5968 MCAuto<DataArrayIdType> ret0=ret1->sortCellsInMEDFileFrmt();
5969 desc->transformWithIndArr(ret0->begin(),ret0->begin()+ret0->getNbOfElems());
5970 MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
5971 tmp->setConnectivity(tmp0,tmp1);
5972 tmp->renumberCells(ret0->begin(),false);
5973 revDesc=tmp->getNodalConnectivity();
5974 revDescIndx=tmp->getNodalConnectivityIndex();
5975 DataArrayIdType *ret=0;
5976 if(!ret1->areCellsIncludedIn(nM1LevMesh,2,ret))
5979 ret->getMaxValue(tmp2);
5981 std::ostringstream oss; oss << "MEDCouplingUMesh::emulateMEDMEMBDC : input N-1 mesh present a cell not in descending mesh ... Id of cell is " << tmp2 << " !";
5982 throw INTERP_KERNEL::Exception(oss.str());
5987 revDescIndx->incrRef();
5990 meshnM1Old2New=ret0;
5995 * Permutes the nodal connectivity arrays so that the cells are sorted by type, which is
5996 * necessary for writing the mesh to MED file. Additionally returns a permutation array
5997 * in "Old to New" mode.
5998 * \return DataArrayIdType * - a new instance of DataArrayIdType. The caller is to delete
5999 * this array using decrRef() as it is no more needed.
6000 * \throw If the nodal connectivity of cells is not defined.
6002 DataArrayIdType *MEDCouplingUMesh::sortCellsInMEDFileFrmt()
6004 checkConnectivityFullyDefined();
6005 MCAuto<DataArrayIdType> ret=getRenumArrForMEDFileFrmt();
6006 renumberCells(ret->begin(),false);
6011 * This methods checks that cells are sorted by their types.
6012 * This method makes asumption (no check) that connectivity is correctly set before calling.
6014 bool MEDCouplingUMesh::checkConsecutiveCellTypes() const
6016 checkFullyDefined();
6017 const mcIdType *conn=_nodal_connec->begin();
6018 const mcIdType *connI=_nodal_connec_index->begin();
6019 mcIdType nbOfCells=getNumberOfCells();
6020 std::set<INTERP_KERNEL::NormalizedCellType> types;
6021 for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6023 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6024 if(types.find(curType)!=types.end())
6026 types.insert(curType);
6027 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6033 * This method is a specialization of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method that is called here.
6034 * The geometric type order is specified by MED file.
6036 * \sa MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder
6038 bool MEDCouplingUMesh::checkConsecutiveCellTypesForMEDFileFrmt() const
6040 return checkConsecutiveCellTypesAndOrder(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
6044 * This method performs the same job as checkConsecutiveCellTypes except that the order of types sequence is analyzed to check
6045 * that the order is specified in array defined by [ \a orderBg , \a orderEnd ).
6046 * If there is some geo types in \a this \b NOT in [ \a orderBg, \a orderEnd ) it is OK (return true) if contiguous.
6047 * If there is some geo types in [ \a orderBg, \a orderEnd ) \b NOT in \a this it is OK too (return true) if contiguous.
6049 bool MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
6051 checkFullyDefined();
6052 const mcIdType *conn=_nodal_connec->begin();
6053 const mcIdType *connI=_nodal_connec_index->begin();
6054 mcIdType nbOfCells=getNumberOfCells();
6057 mcIdType lastPos=-1;
6058 std::set<INTERP_KERNEL::NormalizedCellType> sg;
6059 for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6061 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6062 const INTERP_KERNEL::NormalizedCellType *isTypeExists=std::find(orderBg,orderEnd,curType);
6063 if(isTypeExists!=orderEnd)
6065 mcIdType pos=ToIdType(std::distance(orderBg,isTypeExists));
6069 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6073 if(sg.find(curType)==sg.end())
6075 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6086 * This method returns 2 newly allocated DataArrayIdType instances. The first is an array of size 'this->getNumberOfCells()' with one component,
6087 * 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
6088 * 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'.
6090 DataArrayIdType *MEDCouplingUMesh::getLevArrPerCellTypes(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd, DataArrayIdType *&nbPerType) const
6092 checkConnectivityFullyDefined();
6093 mcIdType nbOfCells=getNumberOfCells();
6094 const mcIdType *conn=_nodal_connec->begin();
6095 const mcIdType *connI=_nodal_connec_index->begin();
6096 MCAuto<DataArrayIdType> tmpa=DataArrayIdType::New();
6097 MCAuto<DataArrayIdType> tmpb=DataArrayIdType::New();
6098 tmpa->alloc(nbOfCells,1);
6099 tmpb->alloc(std::distance(orderBg,orderEnd),1);
6100 tmpb->fillWithZero();
6101 mcIdType *tmp=tmpa->getPointer();
6102 mcIdType *tmp2=tmpb->getPointer();
6103 for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6105 const INTERP_KERNEL::NormalizedCellType *where=std::find(orderBg,orderEnd,(INTERP_KERNEL::NormalizedCellType)conn[*i]);
6108 mcIdType pos=ToIdType(std::distance(orderBg,where));
6110 tmp[std::distance(connI,i)]=pos;
6114 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*i]);
6115 std::ostringstream oss; oss << "MEDCouplingUMesh::getLevArrPerCellTypes : Cell #" << std::distance(connI,i);
6116 oss << " has a type " << cm.getRepr() << " not in input array of type !";
6117 throw INTERP_KERNEL::Exception(oss.str());
6120 nbPerType=tmpb.retn();
6125 * This method behaves exactly as MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec but the order is those defined in MED file spec.
6127 * \return a new object containing the old to new correspondence.
6129 * \sa MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec, MEDCouplingUMesh::sortCellsInMEDFileFrmt.
6131 DataArrayIdType *MEDCouplingUMesh::getRenumArrForMEDFileFrmt() const
6133 return getRenumArrForConsecutiveCellTypesSpec(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
6137 * 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.
6138 * This method returns an array of size getNumberOfCells() that gives a renumber array old2New that can be used as input of MEDCouplingMesh::renumberCells.
6139 * The mesh after this call to MEDCouplingMesh::renumberCells will pass the test of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder with the same inputs.
6140 * The returned array minimizes the permutations that is to say the order of cells inside same geometric type remains the same.
6142 DataArrayIdType *MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
6144 DataArrayIdType *nbPerType=0;
6145 MCAuto<DataArrayIdType> tmpa=getLevArrPerCellTypes(orderBg,orderEnd,nbPerType);
6146 nbPerType->decrRef();
6147 return tmpa->buildPermArrPerLevel();
6151 * This method reorganize the cells of \a this so that the cells with same geometric types are put together.
6152 * The number of cells remains unchanged after the call of this method.
6153 * This method tries to minimizes the number of needed permutations. So, this method behaves not exactly as
6154 * MEDCouplingUMesh::sortCellsInMEDFileFrmt.
6156 * \return the array giving the correspondence old to new.
6158 DataArrayIdType *MEDCouplingUMesh::rearrange2ConsecutiveCellTypes()
6160 checkFullyDefined();
6162 const mcIdType *conn=_nodal_connec->begin();
6163 const mcIdType *connI=_nodal_connec_index->begin();
6164 mcIdType nbOfCells=getNumberOfCells();
6165 std::vector<INTERP_KERNEL::NormalizedCellType> types;
6166 for(const mcIdType *i=connI;i!=connI+nbOfCells && (types.size()!=_types.size());)
6167 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)conn[*i])==types.end())
6169 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6170 types.push_back(curType);
6171 for(i++;i!=connI+nbOfCells && (INTERP_KERNEL::NormalizedCellType)conn[*i]==curType;i++);
6173 DataArrayIdType *ret=DataArrayIdType::New();
6174 ret->alloc(nbOfCells,1);
6175 mcIdType *retPtr=ret->getPointer();
6176 std::fill(retPtr,retPtr+nbOfCells,-1);
6177 mcIdType newCellId=0;
6178 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
6180 for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6181 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
6182 retPtr[std::distance(connI,i)]=newCellId++;
6184 renumberCells(retPtr,false);
6189 * This method splits \a this into as mush as untructured meshes that consecutive set of same type cells.
6190 * So this method has typically a sense if MEDCouplingUMesh::checkConsecutiveCellTypes has a sense.
6191 * This method makes asumption that connectivity is correctly set before calling.
6193 std::vector<MEDCouplingUMesh *> MEDCouplingUMesh::splitByType() const
6195 checkConnectivityFullyDefined();
6196 const mcIdType *conn=_nodal_connec->begin();
6197 const mcIdType *connI=_nodal_connec_index->begin();
6198 mcIdType nbOfCells=getNumberOfCells();
6199 std::vector<MEDCouplingUMesh *> ret;
6200 for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6202 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6203 mcIdType beginCellId=ToIdType(std::distance(connI,i));
6204 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6205 mcIdType endCellId=ToIdType(std::distance(connI,i));
6206 mcIdType sz=endCellId-beginCellId;
6207 mcIdType *cells=new mcIdType[sz];
6208 for(mcIdType j=0;j<sz;j++)
6209 cells[j]=beginCellId+j;
6210 MEDCouplingUMesh *m=(MEDCouplingUMesh *)buildPartOfMySelf(cells,cells+sz,true);
6218 * This method performs the opposite operation than those in MEDCoupling1SGTUMesh::buildUnstructured.
6219 * If \a this is a single geometric type unstructured mesh, it will be converted into a more compact data structure,
6220 * MEDCoupling1GTUMesh instance. The returned instance will aggregate the same DataArrayDouble instance of coordinates than \a this.
6222 * \return a newly allocated instance, that the caller must manage.
6223 * \throw If \a this contains more than one geometric type.
6224 * \throw If the nodal connectivity of \a this is not fully defined.
6225 * \throw If the internal data is not coherent.
6227 MEDCoupling1GTUMesh *MEDCouplingUMesh::convertIntoSingleGeoTypeMesh() const
6229 checkConnectivityFullyDefined();
6230 if(_types.size()!=1)
6231 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6232 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6233 MCAuto<MEDCoupling1GTUMesh> ret=MEDCoupling1GTUMesh::New(getName(),typ);
6234 ret->setCoords(getCoords());
6235 MEDCoupling1SGTUMesh *retC=dynamic_cast<MEDCoupling1SGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6238 MCAuto<DataArrayIdType> c=convertNodalConnectivityToStaticGeoTypeMesh();
6239 retC->setNodalConnectivity(c);
6243 MEDCoupling1DGTUMesh *retD=dynamic_cast<MEDCoupling1DGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6245 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : Internal error !");
6246 DataArrayIdType *c=0,*ci=0;
6247 convertNodalConnectivityToDynamicGeoTypeMesh(c,ci);
6248 MCAuto<DataArrayIdType> cs(c),cis(ci);
6249 retD->setNodalConnectivity(cs,cis);
6254 DataArrayIdType *MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh() const
6256 checkConnectivityFullyDefined();
6257 if(_types.size()!=1)
6258 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6259 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6260 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6263 std::ostringstream oss; oss << "MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : this contains a single geo type (" << cm.getRepr() << ") but ";
6264 oss << "this type is dynamic ! Only static geometric type is possible for that type ! call convertNodalConnectivityToDynamicGeoTypeMesh instead !";
6265 throw INTERP_KERNEL::Exception(oss.str());
6267 mcIdType nbCells=getNumberOfCells();
6268 mcIdType typi=ToIdType(typ);
6269 mcIdType nbNodesPerCell=ToIdType(cm.getNumberOfNodes());
6270 MCAuto<DataArrayIdType> connOut=DataArrayIdType::New(); connOut->alloc(nbCells*nbNodesPerCell,1);
6271 mcIdType *outPtr=connOut->getPointer();
6272 const mcIdType *conn=_nodal_connec->begin();
6273 const mcIdType *connI=_nodal_connec_index->begin();
6275 for(mcIdType i=0;i<nbCells;i++,connI++)
6277 if(conn[connI[0]]==typi && connI[1]-connI[0]==nbNodesPerCell)
6278 outPtr=std::copy(conn+connI[0]+1,conn+connI[1],outPtr);
6281 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 << ") !";
6282 throw INTERP_KERNEL::Exception(oss.str());
6285 return connOut.retn();
6289 * Convert the nodal connectivity of the mesh so that all the cells are of dynamic types (polygon or quadratic
6290 * polygon). This returns the corresponding new nodal connectivity in \ref numbering-indirect format.
6291 * \param nodalConn nodal connectivity
6292 * \param nodalConnIndex nodal connectivity indices
6294 void MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh(DataArrayIdType *&nodalConn, DataArrayIdType *&nodalConnIndex) const
6296 static const char msg0[]="MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : nodal connectivity in this are invalid ! Call checkConsistency !";
6297 checkConnectivityFullyDefined();
6298 if(_types.size()!=1)
6299 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6300 mcIdType nbCells=getNumberOfCells(),
6301 lgth=_nodal_connec->getNumberOfTuples();
6303 throw INTERP_KERNEL::Exception(msg0);
6304 MCAuto<DataArrayIdType> c(DataArrayIdType::New()),ci(DataArrayIdType::New());
6305 c->alloc(lgth-nbCells,1); ci->alloc(nbCells+1,1);
6306 mcIdType *cp(c->getPointer()),*cip(ci->getPointer());
6307 const mcIdType *incp(_nodal_connec->begin()),*incip(_nodal_connec_index->begin());
6309 for(mcIdType i=0;i<nbCells;i++,cip++,incip++)
6311 mcIdType strt(incip[0]+1),stop(incip[1]);//+1 to skip geo type
6312 mcIdType delta(stop-strt);
6315 if((strt>=0 && strt<lgth) && (stop>=0 && stop<=lgth))
6316 cp=std::copy(incp+strt,incp+stop,cp);
6318 throw INTERP_KERNEL::Exception(msg0);
6321 throw INTERP_KERNEL::Exception(msg0);
6322 cip[1]=cip[0]+delta;
6324 nodalConn=c.retn(); nodalConnIndex=ci.retn();
6328 * This method takes in input a vector of MEDCouplingUMesh instances lying on the same coordinates with same mesh dimensions.
6329 * Each mesh in \b ms must be sorted by type with the same order (typically using MEDCouplingUMesh::sortCellsInMEDFileFrmt).
6330 * This method is particularly useful for MED file interaction. It allows to aggregate several meshes and keeping the type sorting
6331 * and the track of the permutation by chunk of same geotype cells to retrieve it. The traditional formats old2new and new2old
6332 * are not used here to avoid the build of big permutation array.
6334 * \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
6335 * those specified in MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6336 * \param [out] szOfCellGrpOfSameType is a newly allocated DataArrayIdType instance whose number of tuples is equal to the number of chunks of same geotype
6337 * in all meshes in \b ms. The accumulation of all values of this array is equal to the number of cells of returned mesh.
6338 * \param [out] idInMsOfCellGrpOfSameType is a newly allocated DataArrayIdType instance having the same size than \b szOfCellGrpOfSameType. This
6339 * output array gives for each chunck of same type the corresponding mesh id in \b ms.
6340 * \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
6341 * is sorted by type following the geo cell types order of MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6343 MEDCouplingUMesh *MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& ms,
6344 DataArrayIdType *&szOfCellGrpOfSameType,
6345 DataArrayIdType *&idInMsOfCellGrpOfSameType)
6347 std::vector<const MEDCouplingUMesh *> ms2;
6348 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms.begin();it!=ms.end();it++)
6351 (*it)->checkConnectivityFullyDefined();
6355 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : input vector is empty !");
6356 const DataArrayDouble *refCoo=ms2[0]->getCoords();
6357 int meshDim=ms2[0]->getMeshDimension();
6358 std::vector<const MEDCouplingUMesh *> m1ssm;
6359 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmAuto;
6361 std::vector<const MEDCouplingUMesh *> m1ssmSingle;
6362 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmSingleAuto;
6363 mcIdType fake=0,rk=0;
6364 MCAuto<DataArrayIdType> ret1(DataArrayIdType::New()),ret2(DataArrayIdType::New());
6365 ret1->alloc(0,1); ret2->alloc(0,1);
6366 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms2.begin();it!=ms2.end();it++,rk++)
6368 if(meshDim!=(*it)->getMeshDimension())
6369 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshdims mismatch !");
6370 if(refCoo!=(*it)->getCoords())
6371 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshes are not shared by a single coordinates coords !");
6372 std::vector<MEDCouplingUMesh *> sp=(*it)->splitByType();
6373 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<const MEDCouplingUMesh *> >(m1ssm));
6374 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<MCAuto<MEDCouplingUMesh> > >(m1ssmAuto));
6375 for(std::vector<MEDCouplingUMesh *>::const_iterator it2=sp.begin();it2!=sp.end();it2++)
6377 MEDCouplingUMesh *singleCell=static_cast<MEDCouplingUMesh *>((*it2)->buildPartOfMySelf(&fake,&fake+1,true));
6378 m1ssmSingleAuto.push_back(singleCell);
6379 m1ssmSingle.push_back(singleCell);
6380 ret1->pushBackSilent((*it2)->getNumberOfCells()); ret2->pushBackSilent(rk);
6383 MCAuto<MEDCouplingUMesh> m1ssmSingle2=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmSingle);
6384 MCAuto<DataArrayIdType> renum=m1ssmSingle2->sortCellsInMEDFileFrmt();
6385 std::vector<const MEDCouplingUMesh *> m1ssmfinal(m1ssm.size());
6386 for(mcIdType i=0;i<ToIdType(m1ssm.size());i++)
6387 m1ssmfinal[renum->getIJ(i,0)]=m1ssm[i];
6388 MCAuto<MEDCouplingUMesh> ret0=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmfinal);
6389 szOfCellGrpOfSameType=ret1->renumber(renum->begin());
6390 idInMsOfCellGrpOfSameType=ret2->renumber(renum->begin());
6395 * This method returns a newly created DataArrayIdType instance.
6396 * This method retrieves cell ids in [ \a begin, \a end ) that have the type \a type.
6398 DataArrayIdType *MEDCouplingUMesh::keepCellIdsByType(INTERP_KERNEL::NormalizedCellType type, const mcIdType *begin, const mcIdType *end) const
6400 checkFullyDefined();
6401 const mcIdType *conn=_nodal_connec->begin();
6402 const mcIdType *connIndex=_nodal_connec_index->begin();
6403 MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(0,1);
6404 for(const mcIdType *w=begin;w!=end;w++)
6405 if((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]==type)
6406 ret->pushBackSilent(*w);
6411 * This method makes the assumption that da->getNumberOfTuples()<this->getNumberOfCells(). This method makes the assumption that ids contained in 'da'
6412 * are in [0:getNumberOfCells())
6414 DataArrayIdType *MEDCouplingUMesh::convertCellArrayPerGeoType(const DataArrayIdType *da) const
6416 checkFullyDefined();
6417 const mcIdType *conn=_nodal_connec->begin();
6418 const mcIdType *connI=_nodal_connec_index->begin();
6419 mcIdType nbOfCells=getNumberOfCells();
6420 std::set<INTERP_KERNEL::NormalizedCellType> types(getAllGeoTypes());
6421 mcIdType *tmp=new mcIdType[nbOfCells];
6422 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
6425 for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6426 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
6427 tmp[std::distance(connI,i)]=j++;
6429 DataArrayIdType *ret=DataArrayIdType::New();
6430 ret->alloc(da->getNumberOfTuples(),da->getNumberOfComponents());
6431 ret->copyStringInfoFrom(*da);
6432 mcIdType *retPtr=ret->getPointer();
6433 const mcIdType *daPtr=da->begin();
6434 mcIdType nbOfElems=da->getNbOfElems();
6435 for(mcIdType k=0;k<nbOfElems;k++)
6436 retPtr[k]=tmp[daPtr[k]];
6442 * This method reduced number of cells of this by keeping cells whose type is different from 'type' and if type=='type'
6443 * This method \b works \b for mesh sorted by type.
6444 * cells whose ids is in 'idsPerGeoType' array.
6445 * This method conserves coords and name of mesh.
6447 MEDCouplingUMesh *MEDCouplingUMesh::keepSpecifiedCells(INTERP_KERNEL::NormalizedCellType type, const mcIdType *idsPerGeoTypeBg, const mcIdType *idsPerGeoTypeEnd) const
6449 std::vector<mcIdType> code=getDistributionOfTypes();
6450 std::size_t nOfTypesInThis=code.size()/3;
6451 mcIdType sz=0,szOfType=0;
6452 for(std::size_t i=0;i<nOfTypesInThis;i++)
6457 szOfType=code[3*i+1];
6459 for(const mcIdType *work=idsPerGeoTypeBg;work!=idsPerGeoTypeEnd;work++)
6460 if(*work<0 || *work>=szOfType)
6462 std::ostringstream oss; oss << "MEDCouplingUMesh::keepSpecifiedCells : Request on type " << type << " at place #" << std::distance(idsPerGeoTypeBg,work) << " value " << *work;
6463 oss << ". It should be in [0," << szOfType << ") !";
6464 throw INTERP_KERNEL::Exception(oss.str());
6466 MCAuto<DataArrayIdType> idsTokeep=DataArrayIdType::New(); idsTokeep->alloc(sz+std::distance(idsPerGeoTypeBg,idsPerGeoTypeEnd),1);
6467 mcIdType *idsPtr=idsTokeep->getPointer();
6469 for(std::size_t i=0;i<nOfTypesInThis;i++)
6472 for(mcIdType j=0;j<code[3*i+1];j++)
6475 idsPtr=std::transform(idsPerGeoTypeBg,idsPerGeoTypeEnd,idsPtr,std::bind(std::plus<mcIdType>(),std::placeholders::_1,offset));
6476 offset+=code[3*i+1];
6478 MCAuto<MEDCouplingUMesh> ret=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(idsTokeep->begin(),idsTokeep->end(),true));
6479 ret->copyTinyInfoFrom(this);
6484 * This method returns a vector of size 'this->getNumberOfCells()'.
6485 * This method retrieves for each cell in \a this if it is linear (false) or quadratic(true).
6487 std::vector<bool> MEDCouplingUMesh::getQuadraticStatus() const
6489 mcIdType ncell=getNumberOfCells();
6490 std::vector<bool> ret(ncell);
6491 const mcIdType *cI=getNodalConnectivityIndex()->begin();
6492 const mcIdType *c=getNodalConnectivity()->begin();
6493 for(mcIdType i=0;i<ncell;i++)
6495 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[i]];
6496 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6497 ret[i]=cm.isQuadratic();
6503 * Returns a newly created mesh (with ref count ==1) that contains merge of \a this and \a other.
6505 MEDCouplingMesh *MEDCouplingUMesh::mergeMyselfWith(const MEDCouplingMesh *other) const
6507 if(other->getType()!=UNSTRUCTURED)
6508 throw INTERP_KERNEL::Exception("Merge of umesh only available with umesh each other !");
6509 const MEDCouplingUMesh *otherC=static_cast<const MEDCouplingUMesh *>(other);
6510 return MergeUMeshes(this,otherC);
6514 * Returns a new DataArrayDouble holding barycenters of all cells. The barycenter is
6515 * computed by averaging coordinates of cell nodes, so this method is not a right
6516 * choice for degenerated meshes (not well oriented, cells with measure close to zero).
6517 * Beware also that for quadratic meshes, degenerated arc of circles are turned into linear edges for the computation.
6518 * This happens with a default detection precision of eps=1.0e-14. If you need control over this use computeCellCenterOfMassWithPrecision().
6519 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
6520 * this->getNumberOfCells() tuples per \a this->getSpaceDimension()
6521 * components. The caller is to delete this array using decrRef() as it is
6523 * \throw If the coordinates array is not set.
6524 * \throw If the nodal connectivity of cells is not defined.
6525 * \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
6526 * \sa MEDCouplingUMesh::computeCellCenterOfMassWithPrecision
6528 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMass() const
6530 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6531 int spaceDim=getSpaceDimension();
6532 mcIdType nbOfCells=getNumberOfCells();
6533 ret->alloc(nbOfCells,spaceDim);
6534 ret->copyStringInfoFrom(*getCoords());
6535 double *ptToFill=ret->getPointer();
6536 const mcIdType *nodal=_nodal_connec->begin();
6537 const mcIdType *nodalI=_nodal_connec_index->begin();
6538 const double *coor=_coords->begin();
6539 for(mcIdType i=0;i<nbOfCells;i++)
6541 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6542 INTERP_KERNEL::computeBarycenter2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[i]+1,nodalI[i+1]-nodalI[i]-1,coor,spaceDim,ptToFill);
6550 * See computeCellCenterOfMass().
6551 * \param eps a precision for the detection of degenerated arc of circles.
6552 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
6553 * this->getNumberOfCells() tuples per \a this->getSpaceDimension()
6554 * components. The caller is to delete this array using decrRef() as it is
6556 * \throw If the coordinates array is not set.
6557 * \throw If the nodal connectivity of cells is not defined.
6558 * \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
6559 * \sa MEDCouplingUMesh::computeCellCenterOfMassWithPrecision
6561 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMassWithPrecision(double eps) const
6563 INTERP_KERNEL::QuadraticPlanarPrecision prec(eps);
6564 MCAuto<DataArrayDouble> ret = computeCellCenterOfMass();
6570 * This method computes for each cell in \a this, the location of the iso barycenter of nodes constituting
6571 * the cell. Contrary to badly named MEDCouplingUMesh::computeCellCenterOfMass method that returns the center of inertia of the
6573 * \return a newly allocated DataArrayDouble instance that the caller has to deal with. The returned
6574 * DataArrayDouble instance will have \c this->getNumberOfCells() tuples and \c this->getSpaceDimension() components.
6576 * \sa MEDCouplingUMesh::computeCellCenterOfMass
6577 * \throw If \a this is not fully defined (coordinates and connectivity)
6578 * \throw If there is presence in nodal connectivity in \a this of node ids not in [0, \c this->getNumberOfNodes() )
6580 DataArrayDouble *MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell() const
6582 checkFullyDefined();
6583 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6584 int spaceDim=getSpaceDimension();
6585 mcIdType nbOfCells=getNumberOfCells();
6586 mcIdType nbOfNodes=getNumberOfNodes();
6587 ret->alloc(nbOfCells,spaceDim);
6588 double *ptToFill=ret->getPointer();
6589 const mcIdType *nodal=_nodal_connec->begin();
6590 const mcIdType *nodalI=_nodal_connec_index->begin();
6591 const double *coor=_coords->begin();
6592 for(mcIdType i=0;i<nbOfCells;i++,ptToFill+=spaceDim)
6594 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6595 std::fill(ptToFill,ptToFill+spaceDim,0.);
6596 if(type!=INTERP_KERNEL::NORM_POLYHED)
6598 for(const mcIdType *conn=nodal+nodalI[i]+1;conn!=nodal+nodalI[i+1];conn++)
6600 if(*conn>=0 && *conn<nbOfNodes)
6601 std::transform(coor+spaceDim*conn[0],coor+spaceDim*(conn[0]+1),ptToFill,ptToFill,std::plus<double>());
6604 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of nodeId #" << *conn << " should be in [0," << nbOfNodes << ") !";
6605 throw INTERP_KERNEL::Exception(oss.str());
6608 mcIdType nbOfNodesInCell=nodalI[i+1]-nodalI[i]-1;
6609 if(nbOfNodesInCell>0)
6610 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind(std::multiplies<double>(),std::placeholders::_1,1./(double)nbOfNodesInCell));
6613 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of cell with no nodes !";
6614 throw INTERP_KERNEL::Exception(oss.str());
6619 std::set<mcIdType> s(nodal+nodalI[i]+1,nodal+nodalI[i+1]);
6621 for(std::set<mcIdType>::const_iterator it=s.begin();it!=s.end();it++)
6623 if(*it>=0 && *it<nbOfNodes)
6624 std::transform(coor+spaceDim*(*it),coor+spaceDim*((*it)+1),ptToFill,ptToFill,std::plus<double>());
6627 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell polyhedron cell #" << i << " presence of nodeId #" << *it << " should be in [0," << nbOfNodes << ") !";
6628 throw INTERP_KERNEL::Exception(oss.str());
6632 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind(std::multiplies<double>(),std::placeholders::_1,1./(double)s.size()));
6635 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on polyhedron cell #" << i << " there are no nodes !";
6636 throw INTERP_KERNEL::Exception(oss.str());
6644 * Returns a new DataArrayDouble holding barycenters of specified cells. The
6645 * barycenter is computed by averaging coordinates of cell nodes. The cells to treat
6646 * are specified via an array of cell ids.
6647 * \warning Validity of the specified cell ids is not checked!
6648 * Valid range is [ 0, \a this->getNumberOfCells() ).
6649 * \param [in] begin - an array of cell ids of interest.
6650 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
6651 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size ( \a
6652 * end - \a begin ) tuples per \a this->getSpaceDimension() components. The
6653 * caller is to delete this array using decrRef() as it is no more needed.
6654 * \throw If the coordinates array is not set.
6655 * \throw If the nodal connectivity of cells is not defined.
6657 * \if ENABLE_EXAMPLES
6658 * \ref cpp_mcumesh_getPartBarycenterAndOwner "Here is a C++ example".<br>
6659 * \ref py_mcumesh_getPartBarycenterAndOwner "Here is a Python example".
6662 DataArrayDouble *MEDCouplingUMesh::getPartBarycenterAndOwner(const mcIdType *begin, const mcIdType *end) const
6664 DataArrayDouble *ret=DataArrayDouble::New();
6665 int spaceDim=getSpaceDimension();
6666 std::size_t nbOfTuple=std::distance(begin,end);
6667 ret->alloc(nbOfTuple,spaceDim);
6668 double *ptToFill=ret->getPointer();
6669 double *tmp=new double[spaceDim];
6670 const mcIdType *nodal=_nodal_connec->begin();
6671 const mcIdType *nodalI=_nodal_connec_index->begin();
6672 const double *coor=_coords->begin();
6673 for(const mcIdType *w=begin;w!=end;w++)
6675 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[*w]];
6676 INTERP_KERNEL::computeBarycenter2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[*w]+1,nodalI[*w+1]-nodalI[*w]-1,coor,spaceDim,ptToFill);
6684 * 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".
6685 * So the returned instance will have 4 components and \c this->getNumberOfCells() tuples.
6686 * So this method expects that \a this has a spaceDimension equal to 3 and meshDimension equal to 2.
6687 * The computation of the plane equation is done using each time the 3 first nodes of 2D cells.
6688 * This method is useful to detect 2D cells in 3D space that are not coplanar.
6690 * \return DataArrayDouble * - a new instance of DataArrayDouble having 4 components and a number of tuples equal to number of cells in \a this.
6691 * \throw If spaceDim!=3 or meshDim!=2.
6692 * \throw If connectivity of \a this is invalid.
6693 * \throw If connectivity of a cell in \a this points to an invalid node.
6695 DataArrayDouble *MEDCouplingUMesh::computePlaneEquationOf3DFaces() const
6697 MCAuto<DataArrayDouble> ret(DataArrayDouble::New());
6698 mcIdType nbOfCells=getNumberOfCells();
6699 mcIdType nbOfNodes(getNumberOfNodes());
6700 if(getSpaceDimension()!=3 || getMeshDimension()!=2)
6701 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computePlaneEquationOf3DFaces : This method must be applied on a mesh having meshDimension equal 2 and a spaceDimension equal to 3 !");
6702 ret->alloc(nbOfCells,4);
6703 double *retPtr(ret->getPointer());
6704 const mcIdType *nodal(_nodal_connec->begin()),*nodalI(_nodal_connec_index->begin());
6705 const double *coor(_coords->begin());
6706 for(mcIdType i=0;i<nbOfCells;i++,nodalI++,retPtr+=4)
6708 double matrix[16]={0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,0},matrix2[16];
6709 if(nodalI[1]-nodalI[0]>=4)
6711 double aa[3]={coor[nodal[nodalI[0]+1+1]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6712 coor[nodal[nodalI[0]+1+1]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6713 coor[nodal[nodalI[0]+1+1]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]}
6714 ,bb[3]={coor[nodal[nodalI[0]+1+2]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6715 coor[nodal[nodalI[0]+1+2]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6716 coor[nodal[nodalI[0]+1+2]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]};
6717 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]};
6718 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]));
6719 for(int j=0;j<3;j++)
6721 mcIdType nodeId(nodal[nodalI[0]+1+j]);
6722 if(nodeId>=0 && nodeId<nbOfNodes)
6723 std::copy(coor+nodeId*3,coor+(nodeId+1)*3,matrix+4*j);
6726 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! This cell points to an invalid nodeId : " << nodeId << " !";
6727 throw INTERP_KERNEL::Exception(oss.str());
6730 if(sqrt(cc[0]*cc[0]+cc[1]*cc[1]+cc[2]*cc[2])>(1e-3*aa_norm*bb_norm))
6732 INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6733 retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6737 if(nodalI[1]-nodalI[0]==4)
6739 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : cell" << i << " : Presence of The 3 colinear points !";
6740 throw INTERP_KERNEL::Exception(oss.str());
6743 double dd[3]={0.,0.,0.};
6744 for(mcIdType offset=nodalI[0]+1;offset<nodalI[1];offset++)
6745 std::transform(coor+3*nodal[offset],coor+3*(nodal[offset]+1),dd,dd,std::plus<double>());
6746 mcIdType nbOfNodesInCell(nodalI[1]-nodalI[0]-1);
6747 std::transform(dd,dd+3,dd,std::bind(std::multiplies<double>(),std::placeholders::_1,1./(double)nbOfNodesInCell));
6748 std::copy(dd,dd+3,matrix+4*2);
6749 INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6750 retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6755 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! Must be constitued by more than 3 nodes !";
6756 throw INTERP_KERNEL::Exception(oss.str());
6763 * This method expects as input a DataArrayDouble non nul instance 'da' that should be allocated. If not an exception is thrown.
6766 MEDCouplingUMesh *MEDCouplingUMesh::Build0DMeshFromCoords(DataArrayDouble *da)
6769 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build0DMeshFromCoords : instance of DataArrayDouble must be not null !");
6770 da->checkAllocated();
6771 std::string name(da->getName());
6772 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New(name,0));
6774 ret->setName("Mesh");
6776 mcIdType nbOfTuples(da->getNumberOfTuples());
6777 MCAuto<DataArrayIdType> c(DataArrayIdType::New()),cI(DataArrayIdType::New());
6778 c->alloc(2*nbOfTuples,1);
6779 cI->alloc(nbOfTuples+1,1);
6780 mcIdType *cp(c->getPointer()),*cip(cI->getPointer());
6782 for(mcIdType i=0;i<nbOfTuples;i++)
6784 *cp++=INTERP_KERNEL::NORM_POINT1;
6788 ret->setConnectivity(c,cI,true);
6792 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::Build1DMeshFromCoords(DataArrayDouble *da)
6795 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build01MeshFromCoords : instance of DataArrayDouble must be not null !");
6796 da->checkAllocated();
6797 std::string name(da->getName());
6798 MCAuto<MEDCouplingUMesh> ret;
6800 MCAuto<MEDCouplingCMesh> tmp(MEDCouplingCMesh::New());
6801 MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
6802 arr->alloc(da->getNumberOfTuples());
6803 tmp->setCoordsAt(0,arr);
6804 ret=tmp->buildUnstructured();
6808 ret->setName("Mesh");
6815 * Creates a new MEDCouplingUMesh by concatenating two given meshes of the same dimension.
6816 * Cells and nodes of
6817 * the first mesh precede cells and nodes of the second mesh within the result mesh.
6818 * \param [in] mesh1 - the first mesh.
6819 * \param [in] mesh2 - the second mesh.
6820 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6821 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6822 * is no more needed.
6823 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
6824 * \throw If the coordinates array is not set in none of the meshes.
6825 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
6826 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
6828 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
6830 std::vector<const MEDCouplingUMesh *> tmp(2);
6831 tmp[0]=const_cast<MEDCouplingUMesh *>(mesh1); tmp[1]=const_cast<MEDCouplingUMesh *>(mesh2);
6832 return MergeUMeshes(tmp);
6836 * Creates a new MEDCouplingUMesh by concatenating all given meshes of the same dimension.
6837 * Cells and nodes of
6838 * the *i*-th mesh precede cells and nodes of the (*i*+1)-th mesh within the result mesh.
6839 * \param [in] a - a vector of meshes (MEDCouplingUMesh) to concatenate.
6840 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6841 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6842 * is no more needed.
6843 * \throw If \a a.size() == 0.
6844 * \throw If \a a[ *i* ] == NULL.
6845 * \throw If the coordinates array is not set in none of the meshes.
6846 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
6847 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
6849 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const std::vector<const MEDCouplingUMesh *>& a)
6851 std::size_t sz=a.size();
6853 return MergeUMeshesLL(a);
6854 for(std::size_t ii=0;ii<sz;ii++)
6857 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshes : item #" << ii << " in input array of size "<< sz << " is empty !";
6858 throw INTERP_KERNEL::Exception(oss.str());
6860 std::vector< MCAuto<MEDCouplingUMesh> > bb(sz);
6861 std::vector< const MEDCouplingUMesh * > aa(sz);
6863 for(std::size_t i=0;i<sz && spaceDim==-3;i++)
6865 const MEDCouplingUMesh *cur=a[i];
6866 const DataArrayDouble *coo=cur->getCoords();
6868 spaceDim=int(coo->getNumberOfComponents());
6871 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : no spaceDim specified ! unable to perform merge !");
6872 for(std::size_t i=0;i<sz;i++)
6874 bb[i]=a[i]->buildSetInstanceFromThis(spaceDim);
6877 return MergeUMeshesLL(aa);
6881 * Creates a new MEDCouplingUMesh by concatenating cells of two given meshes of same
6882 * dimension and sharing the node coordinates array.
6883 * All cells of the first mesh precede all cells of the second mesh
6884 * within the result mesh.
6885 * \param [in] mesh1 - the first mesh.
6886 * \param [in] mesh2 - the second mesh.
6887 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6888 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6889 * is no more needed.
6890 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
6891 * \throw If the meshes do not share the node coordinates array.
6892 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
6893 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
6895 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
6897 std::vector<const MEDCouplingUMesh *> tmp(2);
6898 tmp[0]=mesh1; tmp[1]=mesh2;
6899 return MergeUMeshesOnSameCoords(tmp);
6903 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
6904 * dimension and sharing the node coordinates array.
6905 * All cells of the *i*-th mesh precede all cells of the
6906 * (*i*+1)-th mesh within the result mesh.
6907 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
6908 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6909 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6910 * is no more needed.
6911 * \throw If \a a.size() == 0.
6912 * \throw If \a a[ *i* ] == NULL.
6913 * \throw If the meshes do not share the node coordinates array.
6914 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
6915 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
6917 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes)
6920 throw INTERP_KERNEL::Exception("meshes input parameter is expected to be non empty.");
6921 for(std::size_t ii=0;ii<meshes.size();ii++)
6924 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshesOnSameCoords : item #" << ii << " in input array of size "<< meshes.size() << " is empty !";
6925 throw INTERP_KERNEL::Exception(oss.str());
6927 const DataArrayDouble *coords=meshes.front()->getCoords();
6928 int meshDim=meshes.front()->getMeshDimension();
6929 std::vector<const MEDCouplingUMesh *>::const_iterator iter=meshes.begin();
6930 mcIdType meshLgth=0;
6931 mcIdType meshIndexLgth=0;
6932 for(;iter!=meshes.end();iter++)
6934 if(coords!=(*iter)->getCoords())
6935 throw INTERP_KERNEL::Exception("meshes does not share the same coords ! Try using tryToShareSameCoords method !");
6936 if(meshDim!=(*iter)->getMeshDimension())
6937 throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, FuseUMeshesOnSameCoords impossible !");
6938 meshLgth+=(*iter)->getNodalConnectivityArrayLen();
6939 meshIndexLgth+=(*iter)->getNumberOfCells();
6941 MCAuto<DataArrayIdType> nodal=DataArrayIdType::New();
6942 nodal->alloc(meshLgth,1);
6943 mcIdType *nodalPtr=nodal->getPointer();
6944 MCAuto<DataArrayIdType> nodalIndex=DataArrayIdType::New();
6945 nodalIndex->alloc(meshIndexLgth+1,1);
6946 mcIdType *nodalIndexPtr=nodalIndex->getPointer();
6948 for(iter=meshes.begin();iter!=meshes.end();iter++)
6950 const mcIdType *nod=(*iter)->getNodalConnectivity()->begin();
6951 const mcIdType *index=(*iter)->getNodalConnectivityIndex()->begin();
6952 mcIdType nbOfCells=(*iter)->getNumberOfCells();
6953 mcIdType meshLgth2=(*iter)->getNodalConnectivityArrayLen();
6954 nodalPtr=std::copy(nod,nod+meshLgth2,nodalPtr);
6955 if(iter!=meshes.begin())
6956 nodalIndexPtr=std::transform(index+1,index+nbOfCells+1,nodalIndexPtr,std::bind(std::plus<mcIdType>(),std::placeholders::_1,offset));
6958 nodalIndexPtr=std::copy(index,index+nbOfCells+1,nodalIndexPtr);
6961 MEDCouplingUMesh *ret=MEDCouplingUMesh::New();
6962 ret->setName("merge");
6963 ret->setMeshDimension(meshDim);
6964 ret->setConnectivity(nodal,nodalIndex,true);
6965 ret->setCoords(coords);
6970 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
6971 * dimension and sharing the node coordinates array. Cells of the *i*-th mesh precede
6972 * cells of the (*i*+1)-th mesh within the result mesh. Duplicates of cells are
6973 * removed from \a this mesh and arrays mapping between new and old cell ids in "Old to
6974 * New" mode are returned for each input mesh.
6975 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
6976 * \param [in] compType - specifies a cell comparison technique. For meaning of its
6977 * valid values [0,1,2], see zipConnectivityTraducer().
6978 * \param [in,out] corr - an array of DataArrayIdType, of the same size as \a
6979 * meshes. The *i*-th array describes cell ids mapping for \a meshes[ *i* ]
6980 * mesh. The caller is to delete each of the arrays using decrRef() as it is
6982 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6983 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6984 * is no more needed.
6985 * \throw If \a meshes.size() == 0.
6986 * \throw If \a meshes[ *i* ] == NULL.
6987 * \throw If the meshes do not share the node coordinates array.
6988 * \throw If \a meshes[ *i* ]->getMeshDimension() < 0.
6989 * \throw If the \a meshes are of different dimension (getMeshDimension()).
6990 * \throw If the nodal connectivity of cells of any of \a meshes is not defined.
6991 * \throw If the nodal connectivity any of \a meshes includes an invalid id.
6993 MEDCouplingUMesh *MEDCouplingUMesh::FuseUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes, int compType, std::vector<DataArrayIdType *>& corr)
6995 //All checks are delegated to MergeUMeshesOnSameCoords
6996 MCAuto<MEDCouplingUMesh> ret=MergeUMeshesOnSameCoords(meshes);
6997 MCAuto<DataArrayIdType> o2n=ret->zipConnectivityTraducer(compType);
6998 corr.resize(meshes.size());
6999 std::size_t nbOfMeshes=meshes.size();
7001 const mcIdType *o2nPtr=o2n->begin();
7002 for(std::size_t i=0;i<nbOfMeshes;i++)
7004 DataArrayIdType *tmp=DataArrayIdType::New();
7005 mcIdType curNbOfCells=meshes[i]->getNumberOfCells();
7006 tmp->alloc(curNbOfCells,1);
7007 std::copy(o2nPtr+offset,o2nPtr+offset+curNbOfCells,tmp->getPointer());
7008 offset+=curNbOfCells;
7009 tmp->setName(meshes[i]->getName());
7016 * Makes all given meshes share the nodal connectivity array. The common connectivity
7017 * array is created by concatenating the connectivity arrays of all given meshes. All
7018 * the given meshes must be of the same space dimension but dimension of cells **can
7019 * differ**. This method is particularly useful in MEDLoader context to build a \ref
7020 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
7021 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
7022 * \param [in,out] meshes - a vector of meshes to update.
7023 * \throw If any of \a meshes is NULL.
7024 * \throw If the coordinates array is not set in any of \a meshes.
7025 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
7026 * \throw If \a meshes are of different space dimension.
7028 void MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords(const std::vector<MEDCouplingUMesh *>& meshes)
7030 std::size_t sz=meshes.size();
7033 std::vector< const DataArrayDouble * > coords(meshes.size());
7034 std::vector< const DataArrayDouble * >::iterator it2=coords.begin();
7035 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++,it2++)
7039 (*it)->checkConnectivityFullyDefined();
7040 const DataArrayDouble *coo=(*it)->getCoords();
7045 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
7046 oss << " has no coordinate array defined !";
7047 throw INTERP_KERNEL::Exception(oss.str());
7052 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
7053 oss << " is null !";
7054 throw INTERP_KERNEL::Exception(oss.str());
7057 MCAuto<DataArrayDouble> res=DataArrayDouble::Aggregate(coords);
7058 std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();
7059 mcIdType offset=(*it)->getNumberOfNodes();
7060 (*it++)->setCoords(res);
7061 for(;it!=meshes.end();it++)
7063 mcIdType oldNumberOfNodes=(*it)->getNumberOfNodes();
7064 (*it)->setCoords(res);
7065 (*it)->shiftNodeNumbersInConn(offset);
7066 offset+=oldNumberOfNodes;
7071 * Merges nodes coincident with a given precision within all given meshes that share
7072 * the nodal connectivity array. The given meshes **can be of different** mesh
7073 * dimension. This method is particularly useful in MEDLoader context to build a \ref
7074 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
7075 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
7076 * \param [in,out] meshes - a vector of meshes to update.
7077 * \param [in] eps - the precision used to detect coincident nodes (infinite norm).
7078 * \throw If any of \a meshes is NULL.
7079 * \throw If the \a meshes do not share the same node coordinates array.
7080 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
7082 void MEDCouplingUMesh::MergeNodesOnUMeshesSharingSameCoords(const std::vector<MEDCouplingUMesh *>& meshes, double eps)
7086 std::set<const DataArrayDouble *> s;
7087 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
7090 s.insert((*it)->getCoords());
7093 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 !";
7094 throw INTERP_KERNEL::Exception(oss.str());
7099 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 !";
7100 throw INTERP_KERNEL::Exception(oss.str());
7102 const DataArrayDouble *coo=*(s.begin());
7106 DataArrayIdType *comm,*commI;
7107 coo->findCommonTuples(eps,-1,comm,commI);
7108 MCAuto<DataArrayIdType> tmp1(comm),tmp2(commI);
7109 mcIdType oldNbOfNodes=coo->getNumberOfTuples();
7110 mcIdType newNbOfNodes;
7111 MCAuto<DataArrayIdType> o2n=DataArrayIdType::ConvertIndexArrayToO2N(oldNbOfNodes,comm->begin(),commI->begin(),commI->end(),newNbOfNodes);
7112 if(oldNbOfNodes==newNbOfNodes)
7114 MCAuto<DataArrayDouble> newCoords=coo->renumberAndReduce(o2n->begin(),newNbOfNodes);
7115 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
7117 (*it)->renumberNodesInConn(o2n->begin());
7118 (*it)->setCoords(newCoords);
7124 * This static operates only for coords in 3D. The polygon is specified by its connectivity nodes in [ \a begin , \a end ).
7126 bool MEDCouplingUMesh::IsPolygonWellOriented(bool isQuadratic, const double *vec, const mcIdType *begin, const mcIdType *end, const double *coords)
7129 double v[3]={0.,0.,0.};
7130 std::size_t sz=std::distance(begin,end);
7134 // Algorithm: sum in v the cross products of (e1, e2) where e_i it the vector between (0,0,0) and point i
7135 // and e2 is linear point directly following e1 in the connectivity. All points are used.
7136 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];
7137 v[1]+=coords[3*begin[i]+2]*coords[3*begin[(i+1)%sz]]-coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+2];
7138 v[2]+=coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+1]-coords[3*begin[i]+1]*coords[3*begin[(i+1)%sz]];
7142 // Same algorithm as above but also using intermediate quadratic points.
7143 // (taking only linear points might lead to issues if the linearized version of the
7144 // polygon is not convex or self-intersecting ... see testCellOrientation4)
7145 std::size_t hsz = sz/2;
7146 for(std::size_t j=0;j<sz;j++)
7148 if (j%2) // current point i is quadratic, next point i+1 is standard
7151 ip1 = ((j-1)/2 + 1)%hsz; // ip1 means "i+1", i.e. next point
7153 else // current point i is standard, next point i+1 is quadratic
7158 v[0]+=coords[3*begin[i]+1]*coords[3*begin[ip1]+2]-coords[3*begin[i]+2]*coords[3*begin[ip1]+1];
7159 v[1]+=coords[3*begin[i]+2]*coords[3*begin[ip1]]-coords[3*begin[i]]*coords[3*begin[ip1]+2];
7160 v[2]+=coords[3*begin[i]]*coords[3*begin[ip1]+1]-coords[3*begin[i]+1]*coords[3*begin[ip1]];
7163 double ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
7168 * The polyhedron is specified by its connectivity nodes in [ \a begin , \a end ).
7170 bool MEDCouplingUMesh::IsPolyhedronWellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7172 std::vector<std::pair<mcIdType,mcIdType> > edges;
7173 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
7174 const mcIdType *bgFace=begin;
7175 for(std::size_t i=0;i<nbOfFaces;i++)
7177 const mcIdType *endFace=std::find(bgFace+1,end,-1);
7178 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
7179 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7181 std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7182 if(std::find(edges.begin(),edges.end(),p1)!=edges.end())
7184 edges.push_back(p1);
7188 return INTERP_KERNEL::calculateVolumeForPolyh2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,ToIdType(std::distance(begin,end)),coords)>-EPS_FOR_POLYH_ORIENTATION;
7192 * The 3D extruded static cell (PENTA6,HEXA8,HEXAGP12...) its connectivity nodes in [ \a begin , \a end ).
7194 bool MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7196 double vec0[3],vec1[3];
7197 std::size_t sz=std::distance(begin,end);
7199 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented : the length of nodal connectivity of extruded cell is not even !");
7200 mcIdType nbOfNodes=ToIdType(sz/2);
7201 INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,nbOfNodes,coords,vec0);
7202 const double *pt0=coords+3*begin[0];
7203 const double *pt1=coords+3*begin[nbOfNodes];
7204 vec1[0]=pt1[0]-pt0[0]; vec1[1]=pt1[1]-pt0[1]; vec1[2]=pt1[2]-pt0[2];
7205 return (vec0[0]*vec1[0]+vec0[1]*vec1[1]+vec0[2]*vec1[2])<0.;
7208 void MEDCouplingUMesh::CorrectExtrudedStaticCell(mcIdType *begin, mcIdType *end)
7210 std::size_t sz=std::distance(begin,end);
7211 INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz];
7212 std::size_t nbOfNodes(sz/2);
7213 std::copy(begin,end,(mcIdType *)tmp);
7214 for(std::size_t j=1;j<nbOfNodes;j++)
7216 begin[j]=tmp[nbOfNodes-j];
7217 begin[j+nbOfNodes]=tmp[nbOfNodes+nbOfNodes-j];
7221 bool MEDCouplingUMesh::IsTetra4WellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7223 std::size_t sz=std::distance(begin,end);
7225 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsTetra4WellOriented : Tetra4 cell with not 4 nodes ! Call checkConsistency !");
7226 double vec0[3],vec1[3];
7227 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[1],*pt2=coords+3*begin[2],*pt3=coords+3*begin[3];
7228 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];
7229 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;
7232 bool MEDCouplingUMesh::IsPyra5WellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7234 std::size_t sz=std::distance(begin,end);
7236 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsPyra5WellOriented : Pyra5 cell with not 5 nodes ! Call checkConsistency !");
7238 INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,4,coords,vec0);
7239 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[4];
7240 return (vec0[0]*(pt1[0]-pt0[0])+vec0[1]*(pt1[1]-pt0[1])+vec0[2]*(pt1[2]-pt0[2]))<0.;
7244 * 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 )
7245 * 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
7248 * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not.
7249 * \param [in] coords the coordinates with nb of components exactly equal to 3
7250 * \param [in] index begin of the nodal connectivity (geometric type included) of a single polyhedron cell
7251 * \param [out] res the result is put at the end of the vector without any alteration of the data.
7253 void MEDCouplingUMesh::SimplifyPolyhedronCell(double eps, const DataArrayDouble *coords, mcIdType index, DataArrayIdType *res, MEDCouplingUMesh *faces,
7254 DataArrayIdType *E_Fi, DataArrayIdType *E_F, DataArrayIdType *F_Ei, DataArrayIdType *F_E)
7256 mcIdType nbFaces = E_Fi->getIJ(index + 1, 0) - E_Fi->getIJ(index, 0);
7257 MCAuto<DataArrayDouble> v=DataArrayDouble::New(); v->alloc(nbFaces,3);
7258 double *vPtr=v->getPointer();
7259 MCAuto<DataArrayDouble> p=DataArrayDouble::New(); p->alloc(nbFaces,2);
7260 double *pPtr=p->getPointer();
7261 mcIdType *e_fi = E_Fi->getPointer(), *e_f = E_F->getPointer(), *f_ei = F_Ei->getPointer(), *f_e = F_E->getPointer();
7262 const mcIdType *f_idx = faces->getNodalConnectivityIndex()->getPointer(), *f_cnn = faces->getNodalConnectivity()->getPointer();
7263 for(mcIdType i=0;i<nbFaces;i++,vPtr+=3,pPtr++)
7265 mcIdType face = e_f[e_fi[index] + i];
7266 ComputeVecAndPtOfFace(eps, coords->begin(), f_cnn + f_idx[face] + 1, f_cnn + f_idx[face + 1], vPtr, pPtr);
7267 // to differentiate faces going to different cells:
7269 for (mcIdType j = f_ei[face]; j < f_ei[face + 1]; j++)
7270 *pPtr += FromIdType<double>(f_e[j]);
7272 pPtr=p->getPointer(); vPtr=v->getPointer();
7273 DataArrayIdType *comm1=0,*commI1=0;
7274 v->findCommonTuples(eps,-1,comm1,commI1);
7275 for (mcIdType i = 0; i < nbFaces; i++)
7276 if (comm1->findIdFirstEqual(i) < 0)
7278 comm1->pushBackSilent(i);
7279 commI1->pushBackSilent(comm1->getNumberOfTuples());
7281 MCAuto<DataArrayIdType> comm1Auto(comm1),commI1Auto(commI1);
7282 const mcIdType *comm1Ptr=comm1->begin();
7283 const mcIdType *commI1Ptr=commI1->begin();
7284 mcIdType nbOfGrps1=commI1Auto->getNumberOfTuples()-1;
7285 res->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYHED));
7287 for(mcIdType i=0;i<nbOfGrps1;i++)
7289 mcIdType vecId=comm1Ptr[commI1Ptr[i]];
7290 MCAuto<DataArrayDouble> tmpgrp2=p->selectByTupleId(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7291 DataArrayIdType *comm2=0,*commI2=0;
7292 tmpgrp2->findCommonTuples(eps,-1,comm2,commI2);
7293 for (mcIdType j = 0; j < commI1Ptr[i+1] - commI1Ptr[i]; j++)
7294 if (comm2->findIdFirstEqual(j) < 0)
7296 comm2->pushBackSilent(j);
7297 commI2->pushBackSilent(comm2->getNumberOfTuples());
7299 MCAuto<DataArrayIdType> comm2Auto(comm2),commI2Auto(commI2);
7300 const mcIdType *comm2Ptr=comm2->begin();
7301 const mcIdType *commI2Ptr=commI2->begin();
7302 mcIdType nbOfGrps2=commI2Auto->getNumberOfTuples()-1;
7303 for(mcIdType j=0;j<nbOfGrps2;j++)
7305 if(commI2Ptr[j+1] == commI2Ptr[j] + 1)
7307 mcIdType face = e_f[e_fi[index] + comm1Ptr[commI1Ptr[i] + comm2Ptr[commI2Ptr[j]]]]; //hmmm
7308 res->insertAtTheEnd(f_cnn + f_idx[face] + 1, f_cnn + f_idx[face + 1]);
7309 res->pushBackSilent(-1);
7313 mcIdType pointId=comm1Ptr[commI1Ptr[i]+comm2Ptr[commI2Ptr[j]]];
7314 MCAuto<DataArrayIdType> ids2=comm2->selectByTupleIdSafeSlice(commI2Ptr[j],commI2Ptr[j+1],1);
7315 ids2->transformWithIndArr(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7316 ids2->transformWithIndArr(e_f + e_fi[index], e_f + e_fi[index + 1]);
7317 MCAuto<MEDCouplingUMesh> mm3=static_cast<MEDCouplingUMesh *>(faces->buildPartOfMySelf(ids2->begin(),ids2->end(),true));
7318 MCAuto<DataArrayIdType> idsNodeTmp=mm3->zipCoordsTraducer();
7319 MCAuto<DataArrayIdType> idsNode=idsNodeTmp->invertArrayO2N2N2O(mm3->getNumberOfNodes());
7320 const mcIdType *idsNodePtr=idsNode->begin();
7321 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];
7322 double vec[3]; vec[0]=vPtr[3*vecId+1]; vec[1]=-vPtr[3*vecId]; vec[2]=0.;
7323 double norm=vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2];
7324 if(std::abs(norm)>eps)
7326 double angle=INTERP_KERNEL::EdgeArcCircle::SafeAsin(norm);
7327 mm3->rotate(center,vec,angle);
7329 mm3->changeSpaceDimension(2);
7330 MCAuto<MEDCouplingUMesh> mm4=mm3->buildSpreadZonesWithPoly();
7331 const mcIdType *conn4=mm4->getNodalConnectivity()->begin();
7332 const mcIdType *connI4=mm4->getNodalConnectivityIndex()->begin();
7333 mcIdType nbOfCells=mm4->getNumberOfCells();
7334 for(mcIdType k=0;k<nbOfCells;k++)
7337 for(const mcIdType *work=conn4+connI4[k]+1;work!=conn4+connI4[k+1];work++,l++)
7338 res->pushBackSilent(idsNodePtr[*work]);
7339 res->pushBackSilent(-1);
7344 res->popBackSilent();
7348 * 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
7349 * through origin. The plane is defined by its nodal connectivity [ \b begin, \b end ).
7351 * \param [in] eps below that value the dot product of 2 vectors is considered as colinears
7352 * \param [in] coords coordinates expected to have 3 components.
7353 * \param [in] begin start of the nodal connectivity of the face.
7354 * \param [in] end end of the nodal connectivity (excluded) of the face.
7355 * \param [out] v the normalized vector of size 3
7356 * \param [out] p the pos of plane
7358 void MEDCouplingUMesh::ComputeVecAndPtOfFace(double eps, const double *coords, const mcIdType *begin, const mcIdType *end, double *v, double *p)
7360 std::size_t nbPoints=std::distance(begin,end);
7362 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeVecAndPtOfFace : < of 3 points in face ! not able to find a plane on that face !");
7363 double vec[3]={0.,0.,0.};
7365 bool refFound=false;
7366 for(;j<nbPoints-1 && !refFound;j++)
7368 vec[0]=coords[3*begin[j+1]]-coords[3*begin[j]];
7369 vec[1]=coords[3*begin[j+1]+1]-coords[3*begin[j]+1];
7370 vec[2]=coords[3*begin[j+1]+2]-coords[3*begin[j]+2];
7371 double norm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
7375 vec[0]/=norm; vec[1]/=norm; vec[2]/=norm;
7378 for(std::size_t i=j;i<nbPoints-1;i++)
7381 curVec[0]=coords[3*begin[i+1]]-coords[3*begin[i]];
7382 curVec[1]=coords[3*begin[i+1]+1]-coords[3*begin[i]+1];
7383 curVec[2]=coords[3*begin[i+1]+2]-coords[3*begin[i]+2];
7384 double norm=sqrt(curVec[0]*curVec[0]+curVec[1]*curVec[1]+curVec[2]*curVec[2]);
7387 curVec[0]/=norm; curVec[1]/=norm; curVec[2]/=norm;
7388 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];
7389 norm=sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
7392 v[0]/=norm; v[1]/=norm; v[2]/=norm;
7393 *p=v[0]*coords[3*begin[i]]+v[1]*coords[3*begin[i]+1]+v[2]*coords[3*begin[i]+2];
7397 throw INTERP_KERNEL::Exception("Not able to find a normal vector of that 3D face !");
7401 * This method tries to obtain a well oriented polyhedron.
7402 * If the algorithm fails, an exception will be thrown.
7404 void MEDCouplingUMesh::TryToCorrectPolyhedronOrientation(mcIdType *begin, mcIdType *end, const double *coords)
7406 std::list< std::pair<mcIdType,mcIdType> > edgesOK,edgesFinished;
7407 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
7408 std::vector<bool> isPerm(nbOfFaces,false);//field on faces False: I don't know, True : oriented
7410 mcIdType *bgFace=begin,*endFace=std::find(begin+1,end,-1);
7411 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
7412 for(std::size_t l=0;l<nbOfEdgesInFace;l++) { std::pair<mcIdType,mcIdType> p1(bgFace[l],bgFace[(l+1)%nbOfEdgesInFace]); edgesOK.push_back(p1); }
7414 while(std::find(isPerm.begin(),isPerm.end(),false)!=isPerm.end())
7417 std::size_t smthChanged=0;
7418 for(std::size_t i=0;i<nbOfFaces;i++)
7420 endFace=std::find(bgFace+1,end,-1);
7421 nbOfEdgesInFace=std::distance(bgFace,endFace);
7425 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7427 std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7428 std::pair<mcIdType,mcIdType> p2(p1.second,p1.first);
7429 bool b1=std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end();
7430 bool b2=std::find(edgesOK.begin(),edgesOK.end(),p2)!=edgesOK.end();
7431 if(b1 || b2) { b=b2; isPerm[i]=true; smthChanged++; break; }
7436 std::reverse(bgFace+1,endFace);
7437 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7439 std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7440 std::pair<mcIdType,mcIdType> p2(p1.second,p1.first);
7441 if(std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end())
7442 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7443 if(std::find(edgesFinished.begin(),edgesFinished.end(),p1)!=edgesFinished.end() || std::find(edgesFinished.begin(),edgesFinished.end(),p2)!=edgesFinished.end())
7444 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7445 std::list< std::pair<mcIdType,mcIdType> >::iterator it=std::find(edgesOK.begin(),edgesOK.end(),p2);
7446 if(it!=edgesOK.end())
7449 edgesFinished.push_back(p1);
7452 edgesOK.push_back(p1);
7459 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired !"); }
7461 if(!edgesOK.empty())
7462 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired : Some edges are shared only once !"); }
7463 if(INTERP_KERNEL::calculateVolumeForPolyh2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,ToIdType(std::distance(begin,end)),coords)<-EPS_FOR_POLYH_ORIENTATION)
7464 {//not lucky ! The first face was not correctly oriented : reorient all faces...
7466 for(std::size_t i=0;i<nbOfFaces;i++)
7468 endFace=std::find(bgFace+1,end,-1);
7469 std::reverse(bgFace+1,endFace);
7477 * This method makes the assumption spacedimension == meshdimension == 2.
7478 * This method works only for linear cells.
7480 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYGON in pos#0)
7482 DataArrayIdType *MEDCouplingUMesh::buildUnionOf2DMesh() const
7484 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
7485 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : meshdimension, spacedimension must be equal to 2 !");
7486 MCAuto<MEDCouplingUMesh> skin(computeSkin());
7487 mcIdType oldNbOfNodes(skin->getNumberOfNodes());
7488 MCAuto<DataArrayIdType> o2n(skin->zipCoordsTraducer());
7489 mcIdType nbOfNodesExpected(skin->getNumberOfNodes());
7490 MCAuto<DataArrayIdType> n2o(o2n->invertArrayO2N2N2O(oldNbOfNodes));
7491 mcIdType nbCells=skin->getNumberOfCells();
7492 if(nbCells==nbOfNodesExpected)
7493 return buildUnionOf2DMeshLinear(skin,n2o);
7494 else if(2*nbCells==nbOfNodesExpected)
7495 return buildUnionOf2DMeshQuadratic(skin,n2o);
7497 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : the mesh 2D in input appears to be not in a single part of a 2D mesh !");
7501 * This method makes the assumption spacedimension == meshdimension == 3.
7502 * This method works only for linear cells.
7504 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYHED in pos#0)
7506 DataArrayIdType *MEDCouplingUMesh::buildUnionOf3DMesh() const
7508 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
7509 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf3DMesh : meshdimension, spacedimension must be equal to 2 !");
7510 MCAuto<MEDCouplingUMesh> m=computeSkin();
7511 const mcIdType *conn=m->getNodalConnectivity()->begin();
7512 const mcIdType *connI=m->getNodalConnectivityIndex()->begin();
7513 mcIdType nbOfCells=m->getNumberOfCells();
7514 MCAuto<DataArrayIdType> ret=DataArrayIdType::New(); ret->alloc(m->getNodalConnectivity()->getNumberOfTuples(),1);
7515 mcIdType *work=ret->getPointer(); *work++=INTERP_KERNEL::NORM_POLYHED;
7518 work=std::copy(conn+connI[0]+1,conn+connI[1],work);
7519 for(mcIdType i=1;i<nbOfCells;i++)
7522 work=std::copy(conn+connI[i]+1,conn+connI[i+1],work);
7528 * \brief Creates a graph of cell neighbors
7529 * \return MEDCouplingSkyLineArray * - an sky line array the user should delete.
7530 * In the sky line array, graph arcs are stored in terms of (index,value) notation.
7532 * - index: 0 3 5 6 6
7533 * - value: 1 2 3 2 3 3
7534 * means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7535 * Arcs are not doubled but reflexive (1,1) arcs are present for each cell
7537 MEDCouplingSkyLineArray* MEDCouplingUMesh::generateGraph() const
7539 checkConnectivityFullyDefined();
7541 int meshDim = this->getMeshDimension();
7542 MEDCoupling::DataArrayIdType* indexr=MEDCoupling::DataArrayIdType::New();
7543 MEDCoupling::DataArrayIdType* revConn=MEDCoupling::DataArrayIdType::New();
7544 this->getReverseNodalConnectivity(revConn,indexr);
7545 const mcIdType* indexr_ptr=indexr->begin();
7546 const mcIdType* revConn_ptr=revConn->begin();
7548 const MEDCoupling::DataArrayIdType* index;
7549 const MEDCoupling::DataArrayIdType* conn;
7550 conn=this->getNodalConnectivity(); // it includes a type as the 1st element!!!
7551 index=this->getNodalConnectivityIndex();
7552 mcIdType nbCells=this->getNumberOfCells();
7553 const mcIdType* index_ptr=index->begin();
7554 const mcIdType* conn_ptr=conn->begin();
7556 //creating graph arcs (cell to cell relations)
7557 //arcs are stored in terms of (index,value) notation
7560 // means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7561 // in present version arcs are not doubled but reflexive (1,1) arcs are present for each cell
7563 //warning here one node have less than or equal effective number of cell with it
7564 //but cell could have more than effective nodes
7565 //because other equals nodes in other domain (with other global inode)
7566 std::vector <mcIdType> cell2cell_index(nbCells+1,0);
7567 std::vector <mcIdType> cell2cell;
7568 cell2cell.reserve(3*nbCells);
7570 for (mcIdType icell=0; icell<nbCells;icell++)
7572 std::map<mcIdType,mcIdType > counter;
7573 for (mcIdType iconn=index_ptr[icell]+1; iconn<index_ptr[icell+1];iconn++)
7575 mcIdType inode=conn_ptr[iconn];
7576 for (mcIdType iconnr=indexr_ptr[inode]; iconnr<indexr_ptr[inode+1];iconnr++)
7578 mcIdType icell2=revConn_ptr[iconnr];
7579 std::map<mcIdType,mcIdType>::iterator iter=counter.find(icell2);
7580 if (iter!=counter.end()) (iter->second)++;
7581 else counter.insert(std::make_pair(icell2,1));
7584 for (std::map<mcIdType,mcIdType>::const_iterator iter=counter.begin();
7585 iter!=counter.end(); iter++)
7586 if (iter->second >= meshDim)
7588 cell2cell_index[icell+1]++;
7589 cell2cell.push_back(iter->first);
7594 cell2cell_index[0]=0;
7595 for (mcIdType icell=0; icell<nbCells;icell++)
7596 cell2cell_index[icell+1]=cell2cell_index[icell]+cell2cell_index[icell+1];
7598 //filling up index and value to create skylinearray structure
7599 MEDCouplingSkyLineArray * array(MEDCouplingSkyLineArray::New(cell2cell_index,cell2cell));
7604 void MEDCouplingUMesh::writeVTKLL(std::ostream& ofs, const std::string& cellData, const std::string& pointData, DataArrayByte *byteData) const
7606 mcIdType nbOfCells=getNumberOfCells();
7608 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::writeVTK : the unstructured mesh has no cells !");
7609 ofs << " <" << getVTKDataSetType() << ">\n";
7610 ofs << " <Piece NumberOfPoints=\"" << getNumberOfNodes() << "\" NumberOfCells=\"" << nbOfCells << "\">\n";
7611 ofs << " <PointData>\n" << pointData << std::endl;
7612 ofs << " </PointData>\n";
7613 ofs << " <CellData>\n" << cellData << std::endl;
7614 ofs << " </CellData>\n";
7615 ofs << " <Points>\n";
7616 if(getSpaceDimension()==3)
7617 _coords->writeVTK(ofs,8,"Points",byteData);
7620 MCAuto<DataArrayDouble> coo=_coords->changeNbOfComponents(3,0.);
7621 coo->writeVTK(ofs,8,"Points",byteData);
7623 ofs << " </Points>\n";
7624 ofs << " <Cells>\n";
7625 const mcIdType *cPtr=_nodal_connec->begin();
7626 const mcIdType *cIPtr=_nodal_connec_index->begin();
7627 MCAuto<DataArrayIdType> faceoffsets=DataArrayIdType::New(); faceoffsets->alloc(nbOfCells,1);
7628 MCAuto<DataArrayIdType> types=DataArrayIdType::New(); types->alloc(nbOfCells,1);
7629 MCAuto<DataArrayIdType> offsets=DataArrayIdType::New(); offsets->alloc(nbOfCells,1);
7630 MCAuto<DataArrayIdType> connectivity=DataArrayIdType::New(); connectivity->alloc(_nodal_connec->getNumberOfTuples()-nbOfCells,1);
7631 mcIdType *w1=faceoffsets->getPointer(),*w2=types->getPointer(),*w3=offsets->getPointer(),*w4=connectivity->getPointer();
7632 mcIdType szFaceOffsets=0,szConn=0;
7633 for(mcIdType i=0;i<nbOfCells;i++,w1++,w2++,w3++)
7636 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]!=INTERP_KERNEL::NORM_POLYHED)
7639 *w3=szConn+cIPtr[i+1]-cIPtr[i]-1; szConn+=cIPtr[i+1]-cIPtr[i]-1;
7640 w4=std::copy(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],w4);
7644 mcIdType deltaFaceOffset=cIPtr[i+1]-cIPtr[i]+1;
7645 *w1=szFaceOffsets+deltaFaceOffset; szFaceOffsets+=deltaFaceOffset;
7646 std::set<mcIdType> c(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1]); c.erase(-1);
7647 *w3=szConn+ToIdType(c.size()); szConn+=ToIdType(c.size());
7648 w4=std::copy(c.begin(),c.end(),w4);
7651 std::unique_ptr<mcIdType[]> medcoupling2vtkTypeTraducer_mcIdType(new mcIdType[MEDCOUPLING2VTKTYPETRADUCER_LGTH]);
7652 for(auto ii = 0; ii<MEDCOUPLING2VTKTYPETRADUCER_LGTH ; ++ii)
7653 medcoupling2vtkTypeTraducer_mcIdType[ii] = MEDCOUPLING2VTKTYPETRADUCER[ii]!=MEDCOUPLING2VTKTYPETRADUCER_NONE?MEDCOUPLING2VTKTYPETRADUCER[ii] : -1;
7654 types->transformWithIndArr(medcoupling2vtkTypeTraducer_mcIdType.get(),medcoupling2vtkTypeTraducer_mcIdType.get()+MEDCOUPLING2VTKTYPETRADUCER_LGTH);
7655 types->writeVTK(ofs,8,"UInt8","types",byteData);
7656 std::string vtkTypeName = Traits<mcIdType>::VTKReprStr;
7657 offsets->writeVTK(ofs,8,vtkTypeName,"offsets",byteData);
7658 if(szFaceOffsets!=0)
7659 {//presence of Polyhedra
7660 connectivity->reAlloc(szConn);
7661 faceoffsets->writeVTK(ofs,8,vtkTypeName,"faceoffsets",byteData);
7662 MCAuto<DataArrayIdType> faces=DataArrayIdType::New(); faces->alloc(szFaceOffsets,1);
7663 w1=faces->getPointer();
7664 for(mcIdType i=0;i<nbOfCells;i++)
7665 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]==INTERP_KERNEL::NORM_POLYHED)
7667 mcIdType nbFaces=ToIdType(std::count(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],-1))+1;
7669 const mcIdType *w6=cPtr+cIPtr[i]+1,*w5=0;
7670 for(mcIdType j=0;j<nbFaces;j++)
7672 w5=std::find(w6,cPtr+cIPtr[i+1],-1);
7673 *w1++=ToIdType(std::distance(w6,w5));
7674 w1=std::copy(w6,w5,w1);
7678 faces->writeVTK(ofs,8,vtkTypeName,"faces",byteData);
7680 connectivity->writeVTK(ofs,8,vtkTypeName,"connectivity",byteData);
7681 ofs << " </Cells>\n";
7682 ofs << " </Piece>\n";
7683 ofs << " </" << getVTKDataSetType() << ">\n";
7686 void MEDCouplingUMesh::reprQuickOverview(std::ostream& stream) const
7688 stream << "MEDCouplingUMesh C++ instance at " << this << ". Name : \"" << getName() << "\".";
7690 { stream << " Not set !"; return ; }
7691 stream << " Mesh dimension : " << _mesh_dim << ".";
7695 { stream << " No coordinates set !"; return ; }
7696 if(!_coords->isAllocated())
7697 { stream << " Coordinates set but not allocated !"; return ; }
7698 stream << " Space dimension : " << _coords->getNumberOfComponents() << "." << std::endl;
7699 stream << "Number of nodes : " << _coords->getNumberOfTuples() << ".";
7700 if(!_nodal_connec_index)
7701 { stream << std::endl << "Nodal connectivity NOT set !"; return ; }
7702 if(!_nodal_connec_index->isAllocated())
7703 { stream << std::endl << "Nodal connectivity set but not allocated !"; return ; }
7704 mcIdType lgth=_nodal_connec_index->getNumberOfTuples();
7705 std::size_t cpt=_nodal_connec_index->getNumberOfComponents();
7706 if(cpt!=1 || lgth<1)
7708 stream << std::endl << "Number of cells : " << lgth-1 << ".";
7711 std::string MEDCouplingUMesh::getVTKDataSetType() const
7713 return std::string("UnstructuredGrid");
7716 std::string MEDCouplingUMesh::getVTKFileExtension() const
7718 return std::string("vtu");
7724 * Provides a renumbering of the cells of this (which has to be a piecewise connected 1D line), so that
7725 * the segments of the line are indexed in consecutive order (i.e. cells \a i and \a i+1 are neighbors).
7726 * This doesn't modify the mesh. This method only works using nodal connectivity consideration. Coordinates of nodes are ignored here.
7727 * The caller is to deal with the resulting DataArrayIdType.
7728 * \throw If the coordinate array is not set.
7729 * \throw If the nodal connectivity of the cells is not defined.
7730 * \throw If m1 is not a mesh of dimension 2, or m1 is not a mesh of dimension 1
7731 * \throw If m2 is not a (piecewise) line (i.e. if a point has more than 2 adjacent segments)
7733 * \sa DataArrayIdType::sortEachPairToMakeALinkedList
7735 DataArrayIdType *MEDCouplingUMesh::orderConsecutiveCells1D() const
7737 checkFullyDefined();
7738 if(getMeshDimension()!=1)
7739 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D works on unstructured mesh with meshdim = 1 !");
7741 // Check that this is a line (and not a more complex 1D mesh) - each point is used at most by 2 segments:
7742 MCAuto<DataArrayIdType> _d(DataArrayIdType::New()),_dI(DataArrayIdType::New());
7743 MCAuto<DataArrayIdType> _rD(DataArrayIdType::New()),_rDI(DataArrayIdType::New());
7744 MCAuto<MEDCouplingUMesh> m_points(buildDescendingConnectivity(_d, _dI, _rD, _rDI));
7745 const mcIdType *d(_d->begin()), *dI(_dI->begin());
7746 const mcIdType *rD(_rD->begin()), *rDI(_rDI->begin());
7747 MCAuto<DataArrayIdType> _dsi(_rDI->deltaShiftIndex());
7748 const mcIdType * dsi(_dsi->begin());
7749 MCAuto<DataArrayIdType> dsii = _dsi->findIdsNotInRange(0,3);
7751 if (dsii->getNumberOfTuples())
7752 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D only work with a mesh being a (piecewise) connected line!");
7754 mcIdType nc=getNumberOfCells();
7755 MCAuto<DataArrayIdType> result(DataArrayIdType::New());
7756 result->alloc(nc,1);
7758 // set of edges not used so far
7759 std::set<mcIdType> edgeSet;
7760 for (mcIdType i=0; i<nc; edgeSet.insert(i), i++);
7762 mcIdType startSeg=0;
7764 // while we have points with only one neighbor segments
7767 std::list<mcIdType> linePiece;
7768 // fills a list of consecutive segment linked to startSeg. This can go forward or backward.
7769 for (int direction=0;direction<2;direction++) // direction=0 --> forward, direction=1 --> backward
7771 // Fill the list forward (resp. backward) from the start segment:
7772 mcIdType activeSeg = startSeg;
7773 mcIdType prevPointId = -20;
7775 while (!edgeSet.empty())
7777 if (!(direction == 1 && prevPointId==-20)) // prevent adding twice startSeg
7780 linePiece.push_back(activeSeg);
7782 linePiece.push_front(activeSeg);
7783 edgeSet.erase(activeSeg);
7786 mcIdType ptId1 = d[dI[activeSeg]], ptId2 = d[dI[activeSeg]+1];
7787 ptId = direction ? (ptId1 == prevPointId ? ptId2 : ptId1) : (ptId2 == prevPointId ? ptId1 : ptId2);
7788 if (dsi[ptId] == 1) // hitting the end of the line
7791 mcIdType seg1 = rD[rDI[ptId]], seg2 = rD[rDI[ptId]+1];
7792 activeSeg = (seg1 == activeSeg) ? seg2 : seg1;
7795 // Done, save final piece into DA:
7796 std::copy(linePiece.begin(), linePiece.end(), result->getPointer()+newIdx);
7797 newIdx += ToIdType(linePiece.size());
7799 // identify next valid start segment (one which is not consumed)
7800 if(!edgeSet.empty())
7801 startSeg = *(edgeSet.begin());
7803 while (!edgeSet.empty());
7804 return result.retn();
7808 * This method split some of edges of 2D cells in \a this. The edges to be split are specified in \a subNodesInSeg
7809 * and in \a subNodesInSegI using \ref numbering-indirect storage mode.
7810 * To do the work this method can optionally needs information about middle of subedges for quadratic cases if
7811 * a minimal creation of new nodes is wanted.
7812 * So this method try to reduce at most the number of new nodes. The only case that can lead this method to add
7813 * nodes if a SEG3 is split without information of middle.
7814 * \b WARNING : is returned value is different from 0 a call to MEDCouplingUMesh::mergeNodes is necessary to
7815 * avoid to have a non conform mesh.
7817 * \return mcIdType - the number of new nodes created (in most of cases 0).
7819 * \throw If \a this is not coherent.
7820 * \throw If \a this has not spaceDim equal to 2.
7821 * \throw If \a this has not meshDim equal to 2.
7822 * \throw If some subcells needed to be split are orphan.
7823 * \sa MEDCouplingUMesh::conformize2D
7825 mcIdType MEDCouplingUMesh::split2DCells(const DataArrayIdType *desc, const DataArrayIdType *descI, const DataArrayIdType *subNodesInSeg, const DataArrayIdType *subNodesInSegI, const DataArrayIdType *midOpt, const DataArrayIdType *midOptI)
7827 if(!desc || !descI || !subNodesInSeg || !subNodesInSegI)
7828 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : the 4 first arrays must be not null !");
7829 desc->checkAllocated(); descI->checkAllocated(); subNodesInSeg->checkAllocated(); subNodesInSegI->checkAllocated();
7830 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
7831 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : This method only works for meshes with spaceDim=2 and meshDim=2 !");
7832 if(midOpt==0 && midOptI==0)
7834 split2DCellsLinear(desc,descI,subNodesInSeg,subNodesInSegI);
7837 else if(midOpt!=0 && midOptI!=0)
7838 return split2DCellsQuadratic(desc,descI,subNodesInSeg,subNodesInSegI,midOpt,midOptI);
7840 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : middle parameters must be set to null for all or not null for all.");
7844 * 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
7845 * 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
7846 * the geometric cell type set to INTERP_KERNEL::NORM_POLYGON.
7847 * 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
7848 * 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.
7850 * \return false if the input connectivity represents already the convex hull, true if the input cell needs to be reordered.
7852 bool MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis(const double *coords, const mcIdType *nodalConnBg, const mcIdType *nodalConnEnd, DataArrayIdType *nodalConnecOut)
7854 std::size_t sz=std::distance(nodalConnBg,nodalConnEnd);
7857 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)*nodalConnBg);
7858 if(cm.getDimension()==2)
7860 const mcIdType *node=nodalConnBg+1;
7861 mcIdType startNode=*node++;
7862 double refX=coords[2*startNode];
7863 for(;node!=nodalConnEnd;node++)
7865 if(coords[2*(*node)]<refX)
7868 refX=coords[2*startNode];
7871 std::vector<mcIdType> tmpOut; tmpOut.reserve(sz); tmpOut.push_back(startNode);
7875 double angle0=-M_PI/2;
7877 mcIdType nextNode=-1;
7878 mcIdType prevNode=-1;
7880 double angleNext=0.;
7881 while(nextNode!=startNode)
7885 for(node=nodalConnBg+1;node!=nodalConnEnd;node++)
7887 if(*node!=tmpOut.back() && *node!=prevNode)
7889 tmp2[0]=coords[2*(*node)]-coords[2*tmpOut.back()]; tmp2[1]=coords[2*(*node)+1]-coords[2*tmpOut.back()+1];
7890 double angleM=INTERP_KERNEL::EdgeArcCircle::GetAbsoluteAngle(tmp2,tmp1);
7895 res=angle0-angleM+2.*M_PI;
7904 if(nextNode!=startNode)
7906 angle0=angleNext-M_PI;
7909 prevNode=tmpOut.back();
7910 tmpOut.push_back(nextNode);
7913 std::vector<mcIdType> tmp3(2*(sz-1));
7914 std::vector<mcIdType>::iterator it=std::copy(nodalConnBg+1,nodalConnEnd,tmp3.begin());
7915 std::copy(nodalConnBg+1,nodalConnEnd,it);
7916 if(std::search(tmp3.begin(),tmp3.end(),tmpOut.begin(),tmpOut.end())!=tmp3.end())
7918 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
7921 if(std::search(tmp3.rbegin(),tmp3.rend(),tmpOut.begin(),tmpOut.end())!=tmp3.rend())
7923 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
7928 nodalConnecOut->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYGON));
7929 nodalConnecOut->insertAtTheEnd(tmpOut.begin(),tmpOut.end());
7934 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
7937 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
7941 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
7942 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
7943 * 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]].
7944 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
7945 * A negative value in \b arrIn means that it is ignored.
7946 * 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.
7948 * \param [in] arrIn arr origin array from which the extraction will be done.
7949 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7950 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
7951 * \sa MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed, MEDCouplingUMesh::partitionBySpreadZone
7953 DataArrayIdType *MEDCouplingUMesh::ComputeSpreadZoneGradually(const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn)
7955 mcIdType seed=0,nbOfDepthPeelingPerformed=0;
7956 return ComputeSpreadZoneGraduallyFromSeed(&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfDepthPeelingPerformed);
7960 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
7961 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
7962 * 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]].
7963 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
7964 * A negative value in \b arrIn means that it is ignored.
7965 * 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.
7966 * \param [in] seedBg the begin pointer (included) of an array containing the seed of the search zone
7967 * \param [in] seedEnd the end pointer (not included) of an array containing the seed of the search zone
7968 * \param [in] arrIn arr origin array from which the extraction will be done.
7969 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7970 * \param [in] nbOfDepthPeeling the max number of peels requested in search. By default -1, that is to say, no limit.
7971 * \param [out] nbOfDepthPeelingPerformed the number of peels effectively performed. May be different from \a nbOfDepthPeeling
7972 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
7973 * \sa MEDCouplingUMesh::partitionBySpreadZone
7975 DataArrayIdType *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(const mcIdType *seedBg, const mcIdType *seedEnd, const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn, mcIdType nbOfDepthPeeling, mcIdType& nbOfDepthPeelingPerformed)
7977 nbOfDepthPeelingPerformed=0;
7979 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed : arrIndxIn input pointer is NULL !");
7980 mcIdType nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
7983 DataArrayIdType *ret=DataArrayIdType::New(); ret->alloc(0,1);
7987 std::vector<bool> fetched(nbOfTuples,false);
7988 return ComputeSpreadZoneGraduallyFromSeedAlg(fetched,seedBg,seedEnd,arrIn,arrIndxIn,nbOfDepthPeeling,nbOfDepthPeelingPerformed);
7994 * \b this is expected to be a mesh fully defined whose spaceDim==meshDim.
7995 * It returns a new allocated mesh having the same mesh dimension and lying on same coordinates.
7996 * The returned mesh contains as poly cells as number of contiguous zone (regarding connectivity).
7997 * A spread contiguous zone is built using poly cells (polyhedra in 3D, polygons in 2D and polyline in 1D).
7998 * The sum of measure field of returned mesh is equal to the sum of measure field of this.
8000 * \return a newly allocated mesh lying on the same coords than \b this with same meshdimension than \b this.
8002 MEDCouplingUMesh *MEDCouplingUMesh::buildSpreadZonesWithPoly() const
8004 checkFullyDefined();
8005 int mdim=getMeshDimension();
8006 int spaceDim=getSpaceDimension();
8008 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension and spacedimension do not match !");
8009 std::vector<DataArrayIdType *> partition=partitionBySpreadZone();
8010 std::vector< MCAuto<DataArrayIdType> > partitionAuto; partitionAuto.reserve(partition.size());
8011 std::copy(partition.begin(),partition.end(),std::back_insert_iterator<std::vector< MCAuto<DataArrayIdType> > >(partitionAuto));
8012 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
8013 ret->setCoords(getCoords());
8014 ret->allocateCells(ToIdType(partition.size()));
8016 for(std::vector<DataArrayIdType *>::const_iterator it=partition.begin();it!=partition.end();it++)
8018 MCAuto<MEDCouplingUMesh> tmp=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf((*it)->begin(),(*it)->end(),true));
8019 MCAuto<DataArrayIdType> cell;
8023 cell=tmp->buildUnionOf2DMesh();
8026 cell=tmp->buildUnionOf3DMesh();
8029 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension supported are [2,3] ! Not implemented yet for others !");
8032 ret->insertNextCell((INTERP_KERNEL::NormalizedCellType)cell->getIJSafe(0,0),cell->getNumberOfTuples()-1,cell->begin()+1);
8035 ret->finishInsertingCells();
8040 * This method partitions \b this into contiguous zone.
8041 * This method only needs a well defined connectivity. Coordinates are not considered here.
8042 * This method returns a vector of \b newly allocated arrays that the caller has to deal with.
8044 std::vector<DataArrayIdType *> MEDCouplingUMesh::partitionBySpreadZone() const
8046 DataArrayIdType *neigh=0,*neighI=0;
8047 computeNeighborsOfCells(neigh,neighI);
8048 MCAuto<DataArrayIdType> neighAuto(neigh),neighIAuto(neighI);
8049 return PartitionBySpreadZone(neighAuto,neighIAuto);
8052 std::vector<DataArrayIdType *> MEDCouplingUMesh::PartitionBySpreadZone(const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn)
8054 if(!arrIn || !arrIndxIn)
8055 throw INTERP_KERNEL::Exception("PartitionBySpreadZone : null input pointers !");
8056 arrIn->checkAllocated(); arrIndxIn->checkAllocated();
8057 mcIdType nbOfTuples(arrIndxIn->getNumberOfTuples());
8058 if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1 || nbOfTuples<1)
8059 throw INTERP_KERNEL::Exception("PartitionBySpreadZone : invalid arrays in input !");
8060 mcIdType nbOfCellsCur(nbOfTuples-1);
8061 std::vector<DataArrayIdType *> ret;
8064 std::vector<bool> fetchedCells(nbOfCellsCur,false);
8065 std::vector< MCAuto<DataArrayIdType> > ret2;
8067 while(seed<nbOfCellsCur)
8069 mcIdType nbOfPeelPerformed=0;
8070 ret2.push_back(ComputeSpreadZoneGraduallyFromSeedAlg(fetchedCells,&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfPeelPerformed));
8071 seed=ToIdType(std::distance(fetchedCells.begin(),std::find(fetchedCells.begin()+seed,fetchedCells.end(),false)));
8073 for(std::vector< MCAuto<DataArrayIdType> >::iterator it=ret2.begin();it!=ret2.end();it++)
8074 ret.push_back((*it).retn());
8079 * This method returns given a distribution of cell type (returned for example by MEDCouplingUMesh::getDistributionOfTypes method and customized after) a
8080 * newly allocated DataArrayIdType instance with 2 components ready to be interpreted as input of DataArrayIdType::findRangeIdForEachTuple method.
8082 * \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.
8083 * \return a newly allocated DataArrayIdType to be managed by the caller.
8084 * \throw In case of \a code has not the right format (typically of size 3*n)
8086 DataArrayIdType *MEDCouplingUMesh::ComputeRangesFromTypeDistribution(const std::vector<mcIdType>& code)
8088 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
8089 std::size_t nb=code.size()/3;
8090 if(code.size()%3!=0)
8091 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeRangesFromTypeDistribution : invalid input code !");
8093 mcIdType *retPtr=ret->getPointer();
8094 for(std::size_t i=0;i<nb;i++,retPtr+=2)
8096 retPtr[0]=code[3*i+2];
8097 retPtr[1]=code[3*i+2]+code[3*i+1];
8103 * This method expects that \a this a 3D mesh (spaceDim=3 and meshDim=3) with all coordinates and connectivities set.
8104 * All cells in \a this are expected to be linear 3D cells.
8105 * This method will split **all** 3D cells in \a this into INTERP_KERNEL::NORM_TETRA4 cells and put them in the returned mesh.
8106 * It leads to an increase to number of cells.
8107 * This method contrary to MEDCouplingUMesh::simplexize can append coordinates in \a this to perform its work.
8108 * The \a nbOfAdditionalPoints returned value informs about it. If > 0, the coordinates array in returned mesh will have \a nbOfAdditionalPoints
8109 * more tuples (nodes) than in \a this. Anyway, all the nodes in \a this (with the same order) will be in the returned mesh.
8111 * \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.
8112 * For all other cells, the splitting policy will be ignored. See INTERP_KERNEL::SplittingPolicy for the images.
8113 * \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.
8114 * \param [out] n2oCells - A new instance of DataArrayIdType holding, for each new cell,
8115 * an id of old cell producing it. The caller is to delete this array using
8116 * decrRef() as it is no more needed.
8117 * \return MEDCoupling1SGTUMesh * - the mesh containing only INTERP_KERNEL::NORM_TETRA4 cells.
8119 * \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
8120 * the policy PLANAR_FACE_6 should be used on a mesh sorted with MEDCoupling1SGTUMesh::sortHexa8EachOther.
8122 * \throw If \a this is not a 3D mesh (spaceDim==3 and meshDim==3).
8123 * \throw If \a this is not fully constituted with linear 3D cells.
8124 * \sa MEDCouplingUMesh::simplexize, MEDCoupling1SGTUMesh::sortHexa8EachOther
8126 MEDCoupling1SGTUMesh *MEDCouplingUMesh::tetrahedrize(int policy, DataArrayIdType *& n2oCells, mcIdType& nbOfAdditionalPoints) const
8128 INTERP_KERNEL::SplittingPolicy pol((INTERP_KERNEL::SplittingPolicy)policy);
8129 checkConnectivityFullyDefined();
8130 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
8131 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tetrahedrize : only available for mesh with meshdim == 3 and spacedim == 3 !");
8132 mcIdType nbOfCells=getNumberOfCells();
8133 mcIdType nbNodes(getNumberOfNodes());
8134 MCAuto<MEDCoupling1SGTUMesh> ret0(MEDCoupling1SGTUMesh::New(getName(),INTERP_KERNEL::NORM_TETRA4));
8135 MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(nbOfCells,1);
8136 mcIdType *retPt(ret->getPointer());
8137 MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()); newConn->alloc(0,1);
8138 MCAuto<DataArrayDouble> addPts(DataArrayDouble::New()); addPts->alloc(0,1);
8139 const mcIdType *oldc(_nodal_connec->begin());
8140 const mcIdType *oldci(_nodal_connec_index->begin());
8141 const double *coords(_coords->begin());
8142 for(mcIdType i=0;i<nbOfCells;i++,oldci++,retPt++)
8144 std::vector<mcIdType> a; std::vector<double> b;
8145 INTERP_KERNEL::SplitIntoTetras(pol,(INTERP_KERNEL::NormalizedCellType)oldc[oldci[0]],oldc+oldci[0]+1,oldc+oldci[1],coords,a,b);
8146 std::size_t nbOfTet(a.size()/4); *retPt=ToIdType(nbOfTet);
8147 const mcIdType *aa(&a[0]);
8150 for(std::vector<mcIdType>::iterator it=a.begin();it!=a.end();it++)
8152 *it=(-(*(it))-1+nbNodes);
8153 addPts->insertAtTheEnd(b.begin(),b.end());
8154 nbNodes+=ToIdType(b.size()/3);
8156 for(std::size_t j=0;j<nbOfTet;j++,aa+=4)
8157 newConn->insertAtTheEnd(aa,aa+4);
8159 if(!addPts->empty())
8161 addPts->rearrange(3);
8162 nbOfAdditionalPoints=addPts->getNumberOfTuples();
8163 addPts=DataArrayDouble::Aggregate(getCoords(),addPts);
8164 ret0->setCoords(addPts);
8168 nbOfAdditionalPoints=0;
8169 ret0->setCoords(getCoords());
8171 ret0->setNodalConnectivity(newConn);
8173 ret->computeOffsetsFull();
8174 n2oCells=ret->buildExplicitArrOfSliceOnScaledArr(0,nbOfCells,1);
8178 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),
8179 _own_cell(true),_cell_id(-1),_nb_cell(0)
8184 _nb_cell=mesh->getNumberOfCells();
8188 MEDCouplingUMeshCellIterator::~MEDCouplingUMeshCellIterator()
8196 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh, MEDCouplingUMeshCell *itc, mcIdType bg, mcIdType end):_mesh(mesh),_cell(itc),
8197 _own_cell(false),_cell_id(bg-1),
8204 MEDCouplingUMeshCell *MEDCouplingUMeshCellIterator::nextt()
8207 if(_cell_id<_nb_cell)
8216 MEDCouplingUMeshCellByTypeEntry::MEDCouplingUMeshCellByTypeEntry(MEDCouplingUMesh *mesh):_mesh(mesh)
8222 MEDCouplingUMeshCellByTypeIterator *MEDCouplingUMeshCellByTypeEntry::iterator()
8224 return new MEDCouplingUMeshCellByTypeIterator(_mesh);
8227 MEDCouplingUMeshCellByTypeEntry::~MEDCouplingUMeshCellByTypeEntry()
8233 MEDCouplingUMeshCellEntry::MEDCouplingUMeshCellEntry(MEDCouplingUMesh *mesh, INTERP_KERNEL::NormalizedCellType type, MEDCouplingUMeshCell *itc, mcIdType bg, mcIdType end):_mesh(mesh),_type(type),
8241 MEDCouplingUMeshCellEntry::~MEDCouplingUMeshCellEntry()
8247 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCellEntry::getType() const
8252 mcIdType MEDCouplingUMeshCellEntry::getNumberOfElems() const
8257 MEDCouplingUMeshCellIterator *MEDCouplingUMeshCellEntry::iterator()
8259 return new MEDCouplingUMeshCellIterator(_mesh,_itc,_bg,_end);
8262 MEDCouplingUMeshCellByTypeIterator::MEDCouplingUMeshCellByTypeIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),_cell_id(0),_nb_cell(0)
8267 _nb_cell=mesh->getNumberOfCells();
8271 MEDCouplingUMeshCellByTypeIterator::~MEDCouplingUMeshCellByTypeIterator()
8278 MEDCouplingUMeshCellEntry *MEDCouplingUMeshCellByTypeIterator::nextt()
8280 const mcIdType *c=_mesh->getNodalConnectivity()->begin();
8281 const mcIdType *ci=_mesh->getNodalConnectivityIndex()->begin();
8282 if(_cell_id<_nb_cell)
8284 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[_cell_id]];
8285 mcIdType nbOfElems=ToIdType(std::distance(ci+_cell_id,std::find_if(ci+_cell_id,ci+_nb_cell,MEDCouplingImpl::ConnReader(c,type))));
8286 mcIdType startId=_cell_id;
8287 _cell_id+=nbOfElems;
8288 return new MEDCouplingUMeshCellEntry(_mesh,type,_cell,startId,_cell_id);
8294 MEDCouplingUMeshCell::MEDCouplingUMeshCell(MEDCouplingUMesh *mesh):_conn(0),_conn_indx(0),_conn_lgth(NOTICABLE_FIRST_VAL)
8298 _conn=mesh->getNodalConnectivity()->getPointer();
8299 _conn_indx=mesh->getNodalConnectivityIndex()->getPointer();
8303 void MEDCouplingUMeshCell::next()
8305 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8310 _conn_lgth=_conn_indx[1]-_conn_indx[0];
8313 std::string MEDCouplingUMeshCell::repr() const
8315 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8317 std::ostringstream oss; oss << "Cell Type " << INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)_conn[0]).getRepr();
8319 std::copy(_conn+1,_conn+_conn_lgth,std::ostream_iterator<mcIdType>(oss," "));
8323 return std::string("MEDCouplingUMeshCell::repr : Invalid pos");
8326 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCell::getType() const
8328 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8329 return (INTERP_KERNEL::NormalizedCellType)_conn[0];
8331 return INTERP_KERNEL::NORM_ERROR;
8334 const mcIdType *MEDCouplingUMeshCell::getAllConn(mcIdType& lgth) const
8337 if(_conn_lgth!=NOTICABLE_FIRST_VAL)