1 // Copyright (C) 2007-2020 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 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.
214 * \param [in] eps - a not used parameter.
215 * \throw If the mesh dimension is not set.
216 * \throw If the coordinates array is not set (if mesh dimension != -1 ).
217 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
218 * \throw If the connectivity data array has more than one component.
219 * \throw If the connectivity data array has a named component.
220 * \throw If the connectivity index data array has more than one component.
221 * \throw If the connectivity index data array has a named component.
222 * \throw If number of nodes defining an element does not correspond to the type of element.
223 * \throw If the nodal connectivity includes an invalid node id.
225 void MEDCouplingUMesh::checkConsistency(double eps) const
227 checkConsistencyLight();
230 int meshDim=getMeshDimension();
231 mcIdType nbOfNodes=getNumberOfNodes();
232 mcIdType nbOfCells=getNumberOfCells();
233 const mcIdType *ptr=_nodal_connec->getConstPointer();
234 const mcIdType *ptrI=_nodal_connec_index->getConstPointer();
235 for(mcIdType i=0;i<nbOfCells;i++)
237 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)ptr[ptrI[i]]);
238 if(ToIdType(cm.getDimension())!=meshDim)
240 std::ostringstream oss;
241 oss << "MEDCouplingUMesh::checkConsistency : cell << #" << i<< " with type Type " << cm.getRepr() << " in 'this' whereas meshdim == " << meshDim << " !";
242 throw INTERP_KERNEL::Exception(oss.str());
244 mcIdType nbOfNodesInCell=ptrI[i+1]-ptrI[i]-1;
246 if(nbOfNodesInCell!=ToIdType(cm.getNumberOfNodes()))
248 std::ostringstream oss;
249 oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with static Type '" << cm.getRepr() << "' has " << cm.getNumberOfNodes();
250 oss << " nodes whereas in connectivity there is " << nbOfNodesInCell << " nodes ! Looks very bad !";
251 throw INTERP_KERNEL::Exception(oss.str());
253 if(cm.isQuadratic() && cm.isDynamic() && meshDim == 2)
254 if (nbOfNodesInCell % 2 || nbOfNodesInCell < 4)
256 std::ostringstream oss;
257 oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with quadratic type '" << cm.getRepr() << "' has " << nbOfNodesInCell;
258 oss << " nodes. This should be even, and greater or equal than 4!! Looks very bad!";
259 throw INTERP_KERNEL::Exception(oss.str());
261 for(const mcIdType *w=ptr+ptrI[i]+1;w!=ptr+ptrI[i+1];w++)
266 if(nodeId>=nbOfNodes)
268 std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " whereas there are only " << nbOfNodes << " nodes in the mesh !";
269 throw INTERP_KERNEL::Exception(oss.str());
274 std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " in connectivity ! sounds bad !";
275 throw INTERP_KERNEL::Exception(oss.str());
279 if((INTERP_KERNEL::NormalizedCellType)(ptr[ptrI[i]])!=INTERP_KERNEL::NORM_POLYHED)
281 std::ostringstream oss; oss << "Cell #" << i << " is built with node #-1 in connectivity ! sounds bad !";
282 throw INTERP_KERNEL::Exception(oss.str());
290 * Sets dimension of \a this mesh. The mesh dimension in general depends on types of
291 * elements contained in the mesh. For more info on the mesh dimension see
292 * \ref MEDCouplingUMeshPage.
293 * \param [in] meshDim - a new mesh dimension.
294 * \throw If \a meshDim is invalid. A valid range is <em> -1 <= meshDim <= 3</em>.
296 void MEDCouplingUMesh::setMeshDimension(int meshDim)
298 if(meshDim<-1 || meshDim>3)
299 throw INTERP_KERNEL::Exception("Invalid meshDim specified ! Must be greater or equal to -1 and lower or equal to 3 !");
305 * Allocates memory to store an estimation of the given number of cells.
306 * The closer the estimation to the number of cells effectively inserted, the less need the library requires
307 * to reallocate memory. If the number of cells to be inserted is not known simply assign 0 to this parameter.
308 * If a nodal connectivity previously existed before the call of this method, it will be reset.
310 * \param [in] nbOfCells - estimation of the number of cell \a this mesh will contain.
312 * \if ENABLE_EXAMPLES
313 * \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
314 * \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
317 void MEDCouplingUMesh::allocateCells(mcIdType nbOfCells)
320 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::allocateCells : the input number of cells should be >= 0 !");
321 if(_nodal_connec_index)
323 _nodal_connec_index->decrRef();
327 _nodal_connec->decrRef();
329 _nodal_connec_index=DataArrayIdType::New();
330 _nodal_connec_index->reserve(nbOfCells+1);
331 _nodal_connec_index->pushBackSilent(0);
332 _nodal_connec=DataArrayIdType::New();
333 _nodal_connec->reserve(2*nbOfCells);
339 * Appends a cell to the connectivity array. For deeper understanding what is
340 * happening see \ref MEDCouplingUMeshNodalConnectivity.
341 * \param [in] type - type of cell to add.
342 * \param [in] size - number of nodes constituting this cell.
343 * \param [in] nodalConnOfCell - the connectivity of the cell to add.
345 * \if ENABLE_EXAMPLES
346 * \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
347 * \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
350 void MEDCouplingUMesh::insertNextCell(INTERP_KERNEL::NormalizedCellType type, mcIdType size, const mcIdType *nodalConnOfCell)
352 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
353 if(_nodal_connec_index==0)
354 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::insertNextCell : nodal connectivity not set ! invoke allocateCells before calling insertNextCell !");
355 if(ToIdType(cm.getDimension())==_mesh_dim)
358 if(size!=ToIdType(cm.getNumberOfNodes()))
360 std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : Trying to push a " << cm.getRepr() << " cell with a size of " << size;
361 oss << " ! Expecting " << cm.getNumberOfNodes() << " !";
362 throw INTERP_KERNEL::Exception(oss.str());
364 mcIdType idx=_nodal_connec_index->back();
365 mcIdType val=idx+size+1;
366 _nodal_connec_index->pushBackSilent(val);
367 _nodal_connec->writeOnPlace(idx,type,nodalConnOfCell,size);
372 std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : cell type " << cm.getRepr() << " has a dimension " << cm.getDimension();
373 oss << " whereas Mesh Dimension of current UMesh instance is set to " << _mesh_dim << " ! Please invoke \"setMeshDimension\" method before or invoke ";
374 oss << "\"MEDCouplingUMesh::New\" static method with 2 parameters name and meshDimension !";
375 throw INTERP_KERNEL::Exception(oss.str());
380 * Compacts data arrays to release unused memory. This method is to be called after
381 * finishing cell insertion using \a this->insertNextCell().
383 * \if ENABLE_EXAMPLES
384 * \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
385 * \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
388 void MEDCouplingUMesh::finishInsertingCells()
390 _nodal_connec->pack();
391 _nodal_connec_index->pack();
392 _nodal_connec->declareAsNew();
393 _nodal_connec_index->declareAsNew();
398 * Entry point for iteration over cells of this. Warning the returned cell iterator should be deallocated.
399 * Useful for python users.
401 MEDCouplingUMeshCellIterator *MEDCouplingUMesh::cellIterator()
403 return new MEDCouplingUMeshCellIterator(this);
407 * Entry point for iteration over cells groups geo types per geotypes. Warning the returned cell iterator should be deallocated.
408 * If \a this is not so that the cells are grouped by geo types, this method will throw an exception.
409 * In this case MEDCouplingUMesh::sortCellsInMEDFileFrmt or MEDCouplingUMesh::rearrange2ConsecutiveCellTypes methods for example can be called before invoking this method.
410 * Useful for python users.
412 MEDCouplingUMeshCellByTypeEntry *MEDCouplingUMesh::cellsByType()
414 if(!checkConsecutiveCellTypes())
415 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::cellsByType : this mesh is not sorted by type !");
416 return new MEDCouplingUMeshCellByTypeEntry(this);
420 * Returns a set of all cell types available in \a this mesh.
421 * \return std::set<INTERP_KERNEL::NormalizedCellType> - the set of cell types.
422 * \warning this method does not throw any exception even if \a this is not defined.
423 * \sa MEDCouplingUMesh::getAllGeoTypesSorted
425 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypes() const
431 * This method returns the sorted list of geometric types in \a this.
432 * 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
433 * having the same geometric type. So a same geometric type can appear more than once if the cells are not sorted per geometric type.
435 * \throw if connectivity in \a this is not correctly defined.
437 * \sa MEDCouplingMesh::getAllGeoTypes
439 std::vector<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypesSorted() const
441 std::vector<INTERP_KERNEL::NormalizedCellType> ret;
442 checkConnectivityFullyDefined();
443 mcIdType nbOfCells=getNumberOfCells();
446 if(getNodalConnectivityArrayLen()<1)
447 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAllGeoTypesSorted : the connectivity in this seems invalid !");
448 const mcIdType *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin());
449 ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci++]);
450 for(mcIdType i=1;i<nbOfCells;i++,ci++)
451 if(ret.back()!=((INTERP_KERNEL::NormalizedCellType)c[*ci]))
452 ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci]);
457 * This method is a method that compares \a this and \a other.
458 * This method compares \b all attributes, even names and component names.
460 bool MEDCouplingUMesh::isEqualIfNotWhy(const MEDCouplingMesh *other, double prec, std::string& reason) const
463 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isEqualIfNotWhy : input other pointer is null !");
464 std::ostringstream oss; oss.precision(15);
465 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
468 reason="mesh given in input is not castable in MEDCouplingUMesh !";
471 if(!MEDCouplingPointSet::isEqualIfNotWhy(other,prec,reason))
473 if(_mesh_dim!=otherC->_mesh_dim)
475 oss << "umesh dimension mismatch : this mesh dimension=" << _mesh_dim << " other mesh dimension=" << otherC->_mesh_dim;
479 if(_types!=otherC->_types)
481 oss << "umesh geometric type mismatch :\nThis geometric types are :";
482 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
483 { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
484 oss << "\nOther geometric types are :";
485 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=otherC->_types.begin();iter!=otherC->_types.end();iter++)
486 { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
490 if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
491 if(_nodal_connec==0 || otherC->_nodal_connec==0)
493 reason="Only one UMesh between the two this and other has its nodal connectivity DataArrayInt defined !";
496 if(_nodal_connec!=otherC->_nodal_connec)
497 if(!_nodal_connec->isEqualIfNotWhy(*otherC->_nodal_connec,reason))
499 reason.insert(0,"Nodal connectivity DataArrayInt differ : ");
502 if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
503 if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
505 reason="Only one UMesh between the two this and other has its nodal connectivity index DataArrayInt defined !";
508 if(_nodal_connec_index!=otherC->_nodal_connec_index)
509 if(!_nodal_connec_index->isEqualIfNotWhy(*otherC->_nodal_connec_index,reason))
511 reason.insert(0,"Nodal connectivity index DataArrayInt differ : ");
518 * Checks if data arrays of this mesh (node coordinates, nodal
519 * connectivity of cells, etc) of two meshes are same. Textual data like name etc. are
521 * \param [in] other - the mesh to compare with.
522 * \param [in] prec - precision value used to compare node coordinates.
523 * \return bool - \a true if the two meshes are same.
525 bool MEDCouplingUMesh::isEqualWithoutConsideringStr(const MEDCouplingMesh *other, double prec) const
527 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
530 if(!MEDCouplingPointSet::isEqualWithoutConsideringStr(other,prec))
532 if(_mesh_dim!=otherC->_mesh_dim)
534 if(_types!=otherC->_types)
536 if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
537 if(_nodal_connec==0 || otherC->_nodal_connec==0)
539 if(_nodal_connec!=otherC->_nodal_connec)
540 if(!_nodal_connec->isEqualWithoutConsideringStr(*otherC->_nodal_connec))
542 if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
543 if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
545 if(_nodal_connec_index!=otherC->_nodal_connec_index)
546 if(!_nodal_connec_index->isEqualWithoutConsideringStr(*otherC->_nodal_connec_index))
552 * Checks if \a this and \a other meshes are geometrically equivalent with high
553 * probability, else an exception is thrown. The meshes are considered equivalent if
554 * (1) meshes contain the same number of nodes and the same number of elements of the
555 * same types (2) three cells of the two meshes (first, last and middle) are based
556 * on coincident nodes (with a specified precision).
557 * \param [in] other - the mesh to compare with.
558 * \param [in] prec - the precision used to compare nodes of the two meshes.
559 * \throw If the two meshes do not match.
561 void MEDCouplingUMesh::checkFastEquivalWith(const MEDCouplingMesh *other, double prec) const
563 MEDCouplingPointSet::checkFastEquivalWith(other,prec);
564 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
566 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkFastEquivalWith : Two meshes are not not unstructured !");
570 * Returns the reverse nodal connectivity. The reverse nodal connectivity enumerates
571 * cells each node belongs to.
572 * \warning For speed reasons, this method does not check if node ids in the nodal
573 * connectivity correspond to the size of node coordinates array.
574 * \param [in,out] revNodal - an array holding ids of cells sharing each node.
575 * \param [in,out] revNodalIndx - an array, of length \a this->getNumberOfNodes() + 1,
576 * dividing cell ids in \a revNodal into groups each referring to one
577 * node. Its every element (except the last one) is an index pointing to the
578 * first id of a group of cells. For example cells sharing the node #1 are
579 * described by following range of indices:
580 * [ \a revNodalIndx[1], \a revNodalIndx[2] ) and the cell ids are
581 * \a revNodal[ \a revNodalIndx[1] ], \a revNodal[ \a revNodalIndx[1] + 1], ...
582 * Number of cells sharing the *i*-th node is
583 * \a revNodalIndx[ *i*+1 ] - \a revNodalIndx[ *i* ].
584 * \throw If the coordinates array is not set.
585 * \throw If the nodal connectivity of cells is not defined.
587 * \if ENABLE_EXAMPLES
588 * \ref cpp_mcumesh_getReverseNodalConnectivity "Here is a C++ example".<br>
589 * \ref py_mcumesh_getReverseNodalConnectivity "Here is a Python example".
592 void MEDCouplingUMesh::getReverseNodalConnectivity(DataArrayIdType *revNodal, DataArrayIdType *revNodalIndx) const
595 mcIdType nbOfNodes(getNumberOfNodes());
596 mcIdType *revNodalIndxPtr=(mcIdType *)malloc((nbOfNodes+1)*sizeof(mcIdType));
597 revNodalIndx->useArray(revNodalIndxPtr,true,DeallocType::C_DEALLOC,nbOfNodes+1,1);
598 std::fill(revNodalIndxPtr,revNodalIndxPtr+nbOfNodes+1,0);
599 const mcIdType *conn(_nodal_connec->begin()),*connIndex(_nodal_connec_index->begin());
600 mcIdType nbOfCells(getNumberOfCells()),nbOfEltsInRevNodal(0);
601 for(mcIdType eltId=0;eltId<nbOfCells;eltId++)
603 const mcIdType *strtNdlConnOfCurCell(conn+connIndex[eltId]+1),*endNdlConnOfCurCell(conn+connIndex[eltId+1]);
604 for(const mcIdType *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
605 if(*iter>=0)//for polyhedrons
607 nbOfEltsInRevNodal++;
608 revNodalIndxPtr[(*iter)+1]++;
611 std::transform(revNodalIndxPtr+1,revNodalIndxPtr+nbOfNodes+1,revNodalIndxPtr,revNodalIndxPtr+1,std::plus<mcIdType>());
612 mcIdType *revNodalPtr=(mcIdType *)malloc(nbOfEltsInRevNodal*sizeof(mcIdType));
613 revNodal->useArray(revNodalPtr,true,DeallocType::C_DEALLOC,nbOfEltsInRevNodal,1);
614 std::fill(revNodalPtr,revNodalPtr+nbOfEltsInRevNodal,-1);
615 for(mcIdType eltId=0;eltId<nbOfCells;eltId++)
617 const mcIdType *strtNdlConnOfCurCell=conn+connIndex[eltId]+1;
618 const mcIdType *endNdlConnOfCurCell=conn+connIndex[eltId+1];
619 for(const mcIdType *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
620 if(*iter>=0)//for polyhedrons
621 *std::find_if(revNodalPtr+revNodalIndxPtr[*iter],revNodalPtr+revNodalIndxPtr[*iter+1],std::bind(std::equal_to<mcIdType>(),std::placeholders::_1,-1))=eltId;
626 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
627 * this->getMeshDimension(), that bound cells of \a this mesh. In addition arrays
628 * describing correspondence between cells of \a this and the result meshes are
629 * returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending connectivity,
630 * i.e. enumerate cells of the result mesh bounding each cell of \a this mesh. The
631 * arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
632 * i.e. enumerate cells of \a this mesh bounded by each cell of the result mesh.
633 * \warning For speed reasons, this method does not check if node ids in the nodal
634 * connectivity correspond to the size of node coordinates array.
635 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
636 * to write this mesh to the MED file, its cells must be sorted using
637 * sortCellsInMEDFileFrmt().
638 * \param [in,out] desc - the array containing cell ids of the result mesh bounding
639 * each cell of \a this mesh.
640 * \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
641 * dividing cell ids in \a desc into groups each referring to one
642 * cell of \a this mesh. Its every element (except the last one) is an index
643 * pointing to the first id of a group of cells. For example cells of the
644 * result mesh bounding the cell #1 of \a this mesh are described by following
646 * [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
647 * \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
648 * Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
649 * \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
650 * \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
651 * by each cell of the result mesh.
652 * \param [in,out] revDescIndx - the array, of length one more than number of cells
653 * in the result mesh,
654 * dividing cell ids in \a revDesc into groups each referring to one
655 * cell of the result mesh the same way as \a descIndx divides \a desc.
656 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is to
657 * delete this mesh using decrRef() as it is no more needed.
658 * \throw If the coordinates array is not set.
659 * \throw If the nodal connectivity of cells is node defined.
660 * \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
661 * revDescIndx == NULL.
663 * \if ENABLE_EXAMPLES
664 * \ref cpp_mcumesh_buildDescendingConnectivity "Here is a C++ example".<br>
665 * \ref py_mcumesh_buildDescendingConnectivity "Here is a Python example".
667 * \sa buildDescendingConnectivity2()
669 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
671 return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
675 * \a this has to have a mesh dimension equal to 3. If it is not the case an INTERP_KERNEL::Exception will be thrown.
676 * This behaves exactly as MEDCouplingUMesh::buildDescendingConnectivity does except that this method compute directly the transition from mesh dimension 3 to sub edges (dimension 1)
677 * in one shot. That is to say that this method is equivalent to 2 successive calls to MEDCouplingUMesh::buildDescendingConnectivity.
678 * This method returns 4 arrays and a mesh as MEDCouplingUMesh::buildDescendingConnectivity does.
679 * \sa MEDCouplingUMesh::buildDescendingConnectivity
681 MEDCouplingUMesh *MEDCouplingUMesh::explode3DMeshTo1D(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
684 if(getMeshDimension()!=3)
685 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explode3DMeshTo1D : This has to have a mesh dimension to 3 !");
686 return buildDescendingConnectivityGen<MinusTwoSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
690 * 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.
691 * This method works for both meshes with mesh dimension equal to 2 or 3. Dynamical cells are not supported (polygons, polyhedrons...)
693 * \sa explode3DMeshTo1D, buildDescendingConnectiviy
695 MEDCouplingUMesh *MEDCouplingUMesh::explodeMeshIntoMicroEdges(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
698 switch(getMeshDimension())
701 return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
703 return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
705 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explodeMeshIntoMicroEdges : Only 2D and 3D supported !");
710 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
711 * this->getMeshDimension(), that bound cells of \a this mesh. In
712 * addition arrays describing correspondence between cells of \a this and the result
713 * meshes are returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending
714 * connectivity, i.e. enumerate cells of the result mesh bounding each cell of \a this
715 * mesh. This method differs from buildDescendingConnectivity() in that apart
716 * from cell ids, \a desc returns mutual orientation of cells in \a this and the
717 * result meshes. So a positive id means that order of nodes in corresponding cells
718 * of two meshes is same, and a negative id means a reverse order of nodes. Since a
719 * cell with id #0 can't be negative, the array \a desc returns ids in FORTRAN mode,
720 * i.e. cell ids are one-based.
721 * Arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
722 * i.e. enumerate cells of \a this mesh bounded by each cell of the result mesh.
723 * \warning For speed reasons, this method does not check if node ids in the nodal
724 * connectivity correspond to the size of node coordinates array.
725 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
726 * to write this mesh to the MED file, its cells must be sorted using
727 * sortCellsInMEDFileFrmt().
728 * \param [in,out] desc - the array containing cell ids of the result mesh bounding
729 * each cell of \a this mesh.
730 * \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
731 * dividing cell ids in \a desc into groups each referring to one
732 * cell of \a this mesh. Its every element (except the last one) is an index
733 * pointing to the first id of a group of cells. For example cells of the
734 * result mesh bounding the cell #1 of \a this mesh are described by following
736 * [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
737 * \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
738 * Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
739 * \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
740 * \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
741 * by each cell of the result mesh.
742 * \param [in,out] revDescIndx - the array, of length one more than number of cells
743 * in the result mesh,
744 * dividing cell ids in \a revDesc into groups each referring to one
745 * cell of the result mesh the same way as \a descIndx divides \a desc.
746 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This result mesh
747 * shares the node coordinates array with \a this mesh. The caller is to
748 * delete this mesh using decrRef() as it is no more needed.
749 * \throw If the coordinates array is not set.
750 * \throw If the nodal connectivity of cells is node defined.
751 * \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
752 * revDescIndx == NULL.
754 * \if ENABLE_EXAMPLES
755 * \ref cpp_mcumesh_buildDescendingConnectivity2 "Here is a C++ example".<br>
756 * \ref py_mcumesh_buildDescendingConnectivity2 "Here is a Python example".
758 * \sa buildDescendingConnectivity()
760 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity2(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
762 return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingOrientationSensitiveNbrer);
766 * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
767 * For speed reasons no check of this will be done. This method calls
768 * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
769 * This method lists cell by cell in \b this which are its neighbors. To compute the result
770 * only connectivities are considered.
771 * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
772 * The format of return is hence \ref numbering-indirect.
774 * \param [out] neighbors is an array storing all the neighbors of all cells in \b this. This array is newly
775 * allocated and should be dealt by the caller. \b neighborsIndx 2nd output
776 * parameter allows to select the right part in this array (\ref numbering-indirect). The number of tuples
777 * is equal to the last values in \b neighborsIndx.
778 * \param [out] neighborsIndx is an array of size this->getNumberOfCells()+1 newly allocated and should be
779 * dealt by the caller. This arrays allow to use the first output parameter \b neighbors (\ref numbering-indirect).
781 void MEDCouplingUMesh::computeNeighborsOfCells(DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIndx) const
783 MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
784 MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
785 MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
786 MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
787 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
789 ComputeNeighborsOfCellsAdv(desc,descIndx,revDesc,revDescIndx,neighbors,neighborsIndx);
792 void MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne(const DataArrayIdType *nodeNeigh, const DataArrayIdType *nodeNeighI, MCAuto<DataArrayIdType>& cellNeigh, MCAuto<DataArrayIdType>& cellNeighIndex) const
794 if(!nodeNeigh || !nodeNeighI)
795 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : null pointer !");
796 checkConsistencyLight();
797 nodeNeigh->checkAllocated(); nodeNeighI->checkAllocated();
798 nodeNeigh->checkNbOfComps(1,"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : node neigh");
799 nodeNeighI->checkNbOfComps(1,"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : node neigh index");
800 nodeNeighI->checkNbOfTuples(1+getNumberOfNodes(),"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : invalid length");
801 mcIdType nbCells=getNumberOfCells();
802 const mcIdType *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin()),*ne(nodeNeigh->begin()),*nei(nodeNeighI->begin());
803 cellNeigh=DataArrayIdType::New(); cellNeigh->alloc(0,1); cellNeighIndex=DataArrayIdType::New(); cellNeighIndex->alloc(1,1); cellNeighIndex->setIJ(0,0,0);
804 for(mcIdType i=0;i<nbCells;i++)
806 std::set<mcIdType> s;
807 for(const mcIdType *it=c+ci[i]+1;it!=c+ci[i+1];it++)
809 s.insert(ne+nei[*it],ne+nei[*it+1]);
811 cellNeigh->insertAtTheEnd(s.begin(),s.end());
812 cellNeighIndex->pushBackSilent(cellNeigh->getNumberOfTuples());
817 * This method is called by MEDCouplingUMesh::computeNeighborsOfCells. This methods performs the algorithm
818 * of MEDCouplingUMesh::computeNeighborsOfCells.
819 * This method is useful for users that want to reduce along a criterion the set of neighbours cell. This is
820 * typically the case to extract a set a neighbours,
821 * excluding a set of meshdim-1 cells in input descending connectivity.
822 * Typically \b desc, \b descIndx, \b revDesc and \b revDescIndx (\ref numbering-indirect) input params are
823 * the result of MEDCouplingUMesh::buildDescendingConnectivity.
824 * This method lists cell by cell in \b this which are its neighbors. To compute the result only connectivities
826 * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
828 * \param [in] desc descending connectivity array.
829 * \param [in] descIndx descending connectivity index array used to walk through \b desc (\ref numbering-indirect).
830 * \param [in] revDesc reverse descending connectivity array.
831 * \param [in] revDescIndx reverse descending connectivity index array used to walk through \b revDesc (\ref numbering-indirect).
832 * \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
833 * parameter allows to select the right part in this array. The number of tuples is equal to the last values in \b neighborsIndx.
834 * \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.
836 void MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(const DataArrayIdType *desc, const DataArrayIdType *descIndx, const DataArrayIdType *revDesc, const DataArrayIdType *revDescIndx,
837 DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIndx)
839 if(!desc || !descIndx || !revDesc || !revDescIndx)
840 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeNeighborsOfCellsAdv some input array is empty !");
841 const mcIdType *descPtr=desc->begin();
842 const mcIdType *descIPtr=descIndx->begin();
843 const mcIdType *revDescPtr=revDesc->begin();
844 const mcIdType *revDescIPtr=revDescIndx->begin();
846 mcIdType nbCells=descIndx->getNumberOfTuples()-1;
847 MCAuto<DataArrayIdType> out0=DataArrayIdType::New();
848 MCAuto<DataArrayIdType> out1=DataArrayIdType::New(); out1->alloc(nbCells+1,1);
849 mcIdType *out1Ptr=out1->getPointer();
851 out0->reserve(desc->getNumberOfTuples());
852 for(mcIdType i=0;i<nbCells;i++,descIPtr++,out1Ptr++)
854 for(const mcIdType *w1=descPtr+descIPtr[0];w1!=descPtr+descIPtr[1];w1++)
856 std::set<mcIdType> s(revDescPtr+revDescIPtr[*w1],revDescPtr+revDescIPtr[(*w1)+1]);
858 out0->insertAtTheEnd(s.begin(),s.end());
860 *out1Ptr=out0->getNumberOfTuples();
862 neighbors=out0.retn();
863 neighborsIndx=out1.retn();
867 * Explodes \a this into edges whatever its dimension.
869 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::explodeIntoEdges(MCAuto<DataArrayIdType>& desc, MCAuto<DataArrayIdType>& descIndex, MCAuto<DataArrayIdType>& revDesc, MCAuto<DataArrayIdType>& revDescIndx) const
872 int mdim(getMeshDimension());
873 desc=DataArrayIdType::New(); descIndex=DataArrayIdType::New(); revDesc=DataArrayIdType::New(); revDescIndx=DataArrayIdType::New();
874 MCAuto<MEDCouplingUMesh> mesh1D;
879 mesh1D=explode3DMeshTo1D(desc,descIndex,revDesc,revDescIndx);
884 mesh1D=buildDescendingConnectivity(desc,descIndex,revDesc,revDescIndx);
889 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2] !");
896 * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
897 * For speed reasons no check of this will be done. This method calls
898 * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
899 * This method lists node by node in \b this which are its neighbors. To compute the result
900 * only connectivities are considered.
901 * The neighbor nodes of node having id 'nodeId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
903 * \param [out] neighbors is an array storing all the neighbors of all nodes in \b this. This array
904 * is newly allocated and should be dealt by the caller. \b neighborsIndx 2nd output
905 * parameter allows to select the right part in this array (\ref numbering-indirect).
906 * The number of tuples is equal to the last values in \b neighborsIndx.
907 * \param [out] neighborsIdx is an array of size this->getNumberOfCells()+1 newly allocated and should
908 * be dealt by the caller. This arrays allow to use the first output parameter \b neighbors.
910 * \sa MEDCouplingUMesh::computeEnlargedNeighborsOfNodes
912 void MEDCouplingUMesh::computeNeighborsOfNodes(DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIdx) const
915 mcIdType mdim(getMeshDimension()),nbNodes(getNumberOfNodes());
916 MCAuto<DataArrayIdType> desc(DataArrayIdType::New()),descIndx(DataArrayIdType::New()),revDesc(DataArrayIdType::New()),revDescIndx(DataArrayIdType::New());
917 MCConstAuto<MEDCouplingUMesh> mesh1D;
922 mesh1D=explode3DMeshTo1D(desc,descIndx,revDesc,revDescIndx);
927 mesh1D=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
932 mesh1D.takeRef(this);
937 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2,1] !");
940 desc=DataArrayIdType::New(); descIndx=DataArrayIdType::New(); revDesc=0; revDescIndx=0;
941 mesh1D->getReverseNodalConnectivity(desc,descIndx);
942 MCAuto<DataArrayIdType> ret0(DataArrayIdType::New());
943 ret0->alloc(desc->getNumberOfTuples(),1);
944 mcIdType *r0Pt(ret0->getPointer());
945 const mcIdType *c1DPtr(mesh1D->getNodalConnectivity()->begin()),*rn(desc->begin()),*rni(descIndx->begin());
946 for(mcIdType i=0;i<nbNodes;i++,rni++)
948 for(const mcIdType *oneDCellIt=rn+rni[0];oneDCellIt!=rn+rni[1];oneDCellIt++)
949 *r0Pt++=c1DPtr[3*(*oneDCellIt)+1]==i?c1DPtr[3*(*oneDCellIt)+2]:c1DPtr[3*(*oneDCellIt)+1];
951 neighbors=ret0.retn();
952 neighborsIdx=descIndx.retn();
956 * 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.
957 * 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.
958 * This method is useful to find ghost cells of a part of a mesh with a code based on fields on nodes.
960 * \sa MEDCouplingUMesh::computeNeighborsOfNodes
962 void MEDCouplingUMesh::computeEnlargedNeighborsOfNodes(MCAuto<DataArrayIdType> &neighbors, MCAuto<DataArrayIdType>& neighborsIdx) const
965 mcIdType nbOfNodes(getNumberOfNodes());
966 const mcIdType *conn(_nodal_connec->begin()),*connIndex(_nodal_connec_index->begin());
967 mcIdType nbOfCells=getNumberOfCells();
968 std::vector< std::set<mcIdType> > st0(nbOfNodes);
969 for(mcIdType eltId=0;eltId<nbOfCells;eltId++)
971 const mcIdType *strtNdlConnOfCurCell(conn+connIndex[eltId]+1),*endNdlConnOfCurCell(conn+connIndex[eltId+1]);
972 std::set<mcIdType> s(strtNdlConnOfCurCell,endNdlConnOfCurCell); s.erase(-1); //for polyhedrons
973 for(std::set<mcIdType>::const_iterator iter2=s.begin();iter2!=s.end();iter2++)
974 st0[*iter2].insert(s.begin(),s.end());
976 neighborsIdx=DataArrayIdType::New(); neighborsIdx->alloc(nbOfNodes+1,1); neighborsIdx->setIJ(0,0,0);
978 mcIdType *neighIdx(neighborsIdx->getPointer());
979 for(std::vector< std::set<mcIdType> >::const_iterator it=st0.begin();it!=st0.end();it++,neighIdx++)
982 neighIdx[1]=neighIdx[0];
984 neighIdx[1]=neighIdx[0]+ToIdType((*it).size())-1;
987 neighbors=DataArrayIdType::New(); neighbors->alloc(neighborsIdx->back(),1);
989 const mcIdType *neighIdx(neighborsIdx->begin());
990 mcIdType *neigh(neighbors->getPointer()),nodeId(0);
991 for(std::vector< std::set<mcIdType> >::const_iterator it=st0.begin();it!=st0.end();it++,neighIdx++,nodeId++)
993 std::set<mcIdType> s(*it); s.erase(nodeId);
994 std::copy(s.begin(),s.end(),neigh+*neighIdx);
1000 * Converts specified cells to either polygons (if \a this is a 2D mesh) or
1001 * polyhedrons (if \a this is a 3D mesh). The cells to convert are specified by an
1002 * array of cell ids. Pay attention that after conversion all algorithms work slower
1003 * with \a this mesh than before conversion. <br> If an exception is thrown during the
1004 * conversion due presence of invalid ids in the array of cells to convert, as a
1005 * result \a this mesh contains some already converted elements. In this case the 2D
1006 * mesh remains valid but 3D mesh becomes \b inconsistent!
1007 * \warning This method can significantly modify the order of geometric types in \a this,
1008 * hence, to write this mesh to the MED file, its cells must be sorted using
1009 * sortCellsInMEDFileFrmt().
1010 * \param [in] cellIdsToConvertBg - the array holding ids of cells to convert.
1011 * \param [in] cellIdsToConvertEnd - a pointer to the last-plus-one-th element of \a
1012 * cellIdsToConvertBg.
1013 * \throw If the coordinates array is not set.
1014 * \throw If the nodal connectivity of cells is node defined.
1015 * \throw If dimension of \a this mesh is not either 2 or 3.
1017 * \if ENABLE_EXAMPLES
1018 * \ref cpp_mcumesh_convertToPolyTypes "Here is a C++ example".<br>
1019 * \ref py_mcumesh_convertToPolyTypes "Here is a Python example".
1022 void MEDCouplingUMesh::convertToPolyTypes(const mcIdType *cellIdsToConvertBg, const mcIdType *cellIdsToConvertEnd)
1024 checkFullyDefined();
1025 int dim=getMeshDimension();
1027 throw INTERP_KERNEL::Exception("Invalid mesh dimension : must be 2 or 3 !");
1028 mcIdType nbOfCells=getNumberOfCells();
1031 const mcIdType *connIndex=_nodal_connec_index->begin();
1032 mcIdType *conn=_nodal_connec->getPointer();
1033 for(const mcIdType *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1035 if(*iter>=0 && *iter<nbOfCells)
1037 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*iter]]);
1038 if(!cm.isQuadratic())
1039 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_POLYGON;
1041 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_QPOLYG;
1045 std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1046 oss << " in range [0," << nbOfCells << ") !";
1047 throw INTERP_KERNEL::Exception(oss.str());
1053 mcIdType *connIndex(_nodal_connec_index->getPointer());
1054 const mcIdType *connOld(_nodal_connec->getConstPointer());
1055 MCAuto<DataArrayIdType> connNew(DataArrayIdType::New()),connNewI(DataArrayIdType::New()); connNew->alloc(0,1); connNewI->alloc(1,1); connNewI->setIJ(0,0,0);
1056 std::vector<bool> toBeDone(nbOfCells,false);
1057 for(const mcIdType *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1059 if(*iter>=0 && *iter<nbOfCells)
1060 toBeDone[*iter]=true;
1063 std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1064 oss << " in range [0," << nbOfCells << ") !";
1065 throw INTERP_KERNEL::Exception(oss.str());
1068 for(mcIdType cellId=0;cellId<nbOfCells;cellId++)
1070 mcIdType pos(connIndex[cellId]),posP1(connIndex[cellId+1]);
1071 mcIdType lgthOld(posP1-pos-1);
1072 if(toBeDone[cellId])
1074 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connOld[pos]);
1075 unsigned nbOfFaces(cm.getNumberOfSons2(connOld+pos+1,lgthOld));
1076 mcIdType *tmp(new mcIdType[nbOfFaces*lgthOld+1]);
1077 mcIdType *work=tmp; *work++=INTERP_KERNEL::NORM_POLYHED;
1078 for(unsigned j=0;j<nbOfFaces;j++)
1080 INTERP_KERNEL::NormalizedCellType type;
1081 unsigned offset=cm.fillSonCellNodalConnectivity2(j,connOld+pos+1,lgthOld,work,type);
1085 std::size_t newLgth(std::distance(tmp,work)-1);//-1 for last -1
1086 connNew->pushBackValsSilent(tmp,tmp+newLgth);
1087 connNewI->pushBackSilent(connNewI->back()+ToIdType(newLgth));
1092 connNew->pushBackValsSilent(connOld+pos,connOld+posP1);
1093 connNewI->pushBackSilent(connNewI->back()+posP1-pos);
1096 setConnectivity(connNew,connNewI,false);//false because computeTypes called just behind.
1102 * Converts all cells to either polygons (if \a this is a 2D mesh) or
1103 * polyhedrons (if \a this is a 3D mesh).
1104 * \warning As this method is purely for user-friendliness and no optimization is
1105 * done to avoid construction of a useless vector, this method can be costly
1107 * \throw If the coordinates array is not set.
1108 * \throw If the nodal connectivity of cells is node defined.
1109 * \throw If dimension of \a this mesh is not either 2 or 3.
1111 void MEDCouplingUMesh::convertAllToPoly()
1113 mcIdType nbOfCells=getNumberOfCells();
1114 std::vector<mcIdType> cellIds(nbOfCells);
1115 for(mcIdType i=0;i<nbOfCells;i++)
1117 convertToPolyTypes(&cellIds[0],&cellIds[0]+ToIdType(cellIds.size()));
1121 * Fixes nodal connectivity of invalid cells of type NORM_POLYHED. This method
1122 * expects that all NORM_POLYHED cells have connectivity similar to that of prismatic
1123 * volumes like NORM_HEXA8, NORM_PENTA6 etc., i.e. the first half of nodes describes a
1124 * base facet of the volume and the second half of nodes describes an opposite facet
1125 * having the same number of nodes as the base one. This method converts such
1126 * connectivity to a valid polyhedral format where connectivity of each facet is
1127 * explicitly described and connectivity of facets are separated by -1. If \a this mesh
1128 * contains a NORM_POLYHED cell with a valid connectivity, or an invalid connectivity is
1129 * not as expected, an exception is thrown and the mesh remains unchanged. Care of
1130 * a correct orientation of the first facet of a polyhedron, else orientation of a
1131 * corrected cell is reverse.<br>
1132 * This method is useful to build an extruded unstructured mesh with polyhedrons as
1133 * it releases the user from boring description of polyhedra connectivity in the valid
1135 * \throw If \a this->getMeshDimension() != 3.
1136 * \throw If \a this->getSpaceDimension() != 3.
1137 * \throw If the nodal connectivity of cells is not defined.
1138 * \throw If the coordinates array is not set.
1139 * \throw If \a this mesh contains polyhedrons with the valid connectivity.
1140 * \throw If \a this mesh contains polyhedrons with odd number of nodes.
1142 * \if ENABLE_EXAMPLES
1143 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
1144 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
1147 void MEDCouplingUMesh::convertExtrudedPolyhedra()
1149 checkFullyDefined();
1150 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1151 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertExtrudedPolyhedra works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
1152 mcIdType nbOfCells=getNumberOfCells();
1153 MCAuto<DataArrayIdType> newCi=DataArrayIdType::New();
1154 newCi->alloc(nbOfCells+1,1);
1155 mcIdType *newci=newCi->getPointer();
1156 const mcIdType *ci=_nodal_connec_index->getConstPointer();
1157 const mcIdType *c=_nodal_connec->getConstPointer();
1159 for(mcIdType i=0;i<nbOfCells;i++)
1161 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1162 if(type==INTERP_KERNEL::NORM_POLYHED)
1164 if(std::count(c+ci[i]+1,c+ci[i+1],-1)!=0)
1166 std::ostringstream oss; oss << "MEDCouplingUMesh::convertExtrudedPolyhedra : cell # " << i << " is a polhedron BUT it has NOT exactly 1 face !";
1167 throw INTERP_KERNEL::Exception(oss.str());
1169 std::size_t n2=std::distance(c+ci[i]+1,c+ci[i+1]);
1172 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 !";
1173 throw INTERP_KERNEL::Exception(oss.str());
1175 mcIdType n1=ToIdType(n2/2);
1176 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)
1179 newci[i+1]=(ci[i+1]-ci[i])+newci[i];
1181 MCAuto<DataArrayIdType> newC=DataArrayIdType::New();
1182 newC->alloc(newci[nbOfCells],1);
1183 mcIdType *newc=newC->getPointer();
1184 for(mcIdType i=0;i<nbOfCells;i++)
1186 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1187 if(type==INTERP_KERNEL::NORM_POLYHED)
1189 std::size_t n1=std::distance(c+ci[i]+1,c+ci[i+1])/2;
1190 newc=std::copy(c+ci[i],c+ci[i]+n1+1,newc);
1192 for(std::size_t j=0;j<n1;j++)
1194 newc[j]=c[ci[i]+1+n1+(n1-j)%n1];
1196 newc[n1+5*j+1]=c[ci[i]+1+j];
1197 newc[n1+5*j+2]=c[ci[i]+1+j+n1];
1198 newc[n1+5*j+3]=c[ci[i]+1+(j+1)%n1+n1];
1199 newc[n1+5*j+4]=c[ci[i]+1+(j+1)%n1];
1204 newc=std::copy(c+ci[i],c+ci[i+1],newc);
1206 _nodal_connec_index->decrRef(); _nodal_connec_index=newCi.retn();
1207 _nodal_connec->decrRef(); _nodal_connec=newC.retn();
1212 * Converts all polygons (if \a this is a 2D mesh) or polyhedrons (if \a this is a 3D
1213 * mesh) to cells of classical types. This method is opposite to convertToPolyTypes().
1214 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
1215 * to write this mesh to the MED file, its cells must be sorted using
1216 * sortCellsInMEDFileFrmt().
1217 * \warning Cells (and most notably polyhedrons) must be correctly oriented for this to work
1218 * properly. See orientCorrectlyPolyhedrons() and arePolyhedronsNotCorrectlyOriented().
1219 * \return \c true if at least one cell has been converted, \c false else. In the
1220 * last case the nodal connectivity remains unchanged.
1221 * \throw If the coordinates array is not set.
1222 * \throw If the nodal connectivity of cells is not defined.
1223 * \throw If \a this->getMeshDimension() < 0.
1225 bool MEDCouplingUMesh::unPolyze()
1227 checkFullyDefined();
1228 int mdim=getMeshDimension();
1230 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::unPolyze works on umeshes with meshdim equals to 0, 1 2 or 3 !");
1233 mcIdType nbOfCells=getNumberOfCells();
1236 mcIdType initMeshLgth=getNodalConnectivityArrayLen();
1237 mcIdType *conn=_nodal_connec->getPointer();
1238 mcIdType *index=_nodal_connec_index->getPointer();
1239 mcIdType posOfCurCell=0;
1241 mcIdType lgthOfCurCell;
1243 for(mcIdType i=0;i<nbOfCells;i++)
1245 lgthOfCurCell=index[i+1]-posOfCurCell;
1246 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
1247 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
1248 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::NORM_ERROR;
1252 switch(cm.getDimension())
1256 INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[lgthOfCurCell-1];
1257 std::copy(conn+posOfCurCell+1,conn+posOfCurCell+lgthOfCurCell,(mcIdType *)tmp);
1258 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly2D(cm.isQuadratic(),tmp,lgthOfCurCell-1,conn+newPos+1,newLgth);
1263 mcIdType nbOfFaces,lgthOfPolyhConn;
1264 INTERP_KERNEL::AutoPtr<mcIdType> zipFullReprOfPolyh=INTERP_KERNEL::CellSimplify::getFullPolyh3DCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,nbOfFaces,lgthOfPolyhConn);
1265 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly3D(zipFullReprOfPolyh,nbOfFaces,lgthOfPolyhConn,conn+newPos+1,newLgth);
1268 /* case 1: // Not supported yet
1270 newType=(lgthOfCurCell==3)?INTERP_KERNEL::NORM_SEG2:INTERP_KERNEL::NORM_POLYL;
1275 ret=ret || (newType!=type);
1276 conn[newPos]=newType;
1278 posOfCurCell=index[i+1];
1283 std::copy(conn+posOfCurCell,conn+posOfCurCell+lgthOfCurCell,conn+newPos);
1284 newPos+=lgthOfCurCell;
1285 posOfCurCell+=lgthOfCurCell;
1289 if(newPos!=initMeshLgth)
1290 _nodal_connec->reAlloc(newPos);
1297 * This method expects that spaceDimension is equal to 3 and meshDimension equal to 3.
1298 * This method performs operation only on polyhedrons in \b this. If no polyhedrons exists in \b this, \b this remains unchanged.
1299 * This method allows to merge if any coplanar 3DSurf cells that may appear in some polyhedrons cells.
1301 * \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
1304 void MEDCouplingUMesh::simplifyPolyhedra(double eps)
1306 checkFullyDefined();
1307 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1308 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplifyPolyhedra : works on meshdimension 3 and spaceDimension 3 !");
1309 MCAuto<DataArrayDouble> coords=getCoords()->deepCopy();
1310 coords->recenterForMaxPrecision(eps);
1312 mcIdType nbOfCells=getNumberOfCells();
1313 const mcIdType *conn=_nodal_connec->getConstPointer();
1314 const mcIdType *index=_nodal_connec_index->getConstPointer();
1315 MCAuto<DataArrayIdType> connINew=DataArrayIdType::New();
1316 connINew->alloc(nbOfCells+1,1);
1317 mcIdType *connINewPtr=connINew->getPointer(); *connINewPtr++=0;
1318 MCAuto<DataArrayIdType> connNew=DataArrayIdType::New(); connNew->alloc(0,1);
1319 MCAuto<DataArrayIdType> E_Fi(DataArrayIdType::New()), E_F(DataArrayIdType::New()), F_Ei(DataArrayIdType::New()), F_E(DataArrayIdType::New());
1320 MCAuto<MEDCouplingUMesh> m_faces(buildDescendingConnectivity(E_F, E_Fi, F_E, F_Ei));
1322 for(mcIdType i=0;i<nbOfCells;i++,connINewPtr++)
1324 if(conn[index[i]]==ToIdType(INTERP_KERNEL::NORM_POLYHED))
1326 SimplifyPolyhedronCell(eps,coords, i,connNew, m_faces, E_Fi, E_F, F_Ei, F_E);
1330 connNew->insertAtTheEnd(conn+index[i],conn+index[i+1]);
1331 *connINewPtr=connNew->getNumberOfTuples();
1334 setConnectivity(connNew,connINew,false);
1338 * This method returns all node ids used in the connectivity of \b this. The data array returned has to be dealt by the caller.
1339 * The returned node ids are sorted ascendingly. This method is close to MEDCouplingUMesh::getNodeIdsInUse except
1340 * the format of the returned DataArrayIdType instance.
1342 * \return a newly allocated DataArrayIdType sorted ascendingly of fetched node ids.
1343 * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1345 DataArrayIdType *MEDCouplingUMesh::computeFetchedNodeIds() const
1347 checkConnectivityFullyDefined();
1348 const mcIdType *maxEltPt(std::max_element(_nodal_connec->begin(),_nodal_connec->end()));
1349 mcIdType maxElt(maxEltPt==_nodal_connec->end()?0:std::abs(*maxEltPt)+1);
1350 std::vector<bool> retS(maxElt,false);
1351 computeNodeIdsAlg(retS);
1352 return DataArrayIdType::BuildListOfSwitchedOn(retS);
1356 * \param [in,out] nodeIdsInUse an array of size typically equal to nbOfNodes.
1357 * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1359 void MEDCouplingUMesh::computeNodeIdsAlg(std::vector<bool>& nodeIdsInUse) const
1361 mcIdType nbOfNodes=ToIdType(nodeIdsInUse.size()),
1362 nbOfCells=getNumberOfCells();
1363 const mcIdType *connIndex(_nodal_connec_index->getConstPointer()),*conn(_nodal_connec->getConstPointer());
1364 for(mcIdType i=0;i<nbOfCells;i++)
1365 for(mcIdType j=connIndex[i]+1;j<connIndex[i+1];j++)
1368 if(conn[j]<nbOfNodes)
1369 nodeIdsInUse[conn[j]]=true;
1372 std::ostringstream oss; oss << "MEDCouplingUMesh::computeNodeIdsAlg : In cell #" << i << " presence of node id " << conn[j] << " not in [0," << nbOfNodes << ") !";
1373 throw INTERP_KERNEL::Exception(oss.str());
1380 struct MEDCouplingAccVisit
1382 MEDCouplingAccVisit():_new_nb_of_nodes(0) { }
1383 mcIdType operator()(mcIdType val) { if(val!=-1) return _new_nb_of_nodes++; else return -1; }
1384 mcIdType _new_nb_of_nodes;
1390 * Finds nodes not used in any cell and returns an array giving a new id to every node
1391 * by excluding the unused nodes, for which the array holds -1. The result array is
1392 * a mapping in "Old to New" mode.
1393 * \param [out] nbrOfNodesInUse - number of node ids present in the nodal connectivity.
1394 * \return DataArrayIdType * - a new instance of DataArrayIdType. Its length is \a
1395 * this->getNumberOfNodes(). It holds for each node of \a this mesh either -1
1396 * if the node is unused or a new id else. The caller is to delete this
1397 * array using decrRef() as it is no more needed.
1398 * \throw If the coordinates array is not set.
1399 * \throw If the nodal connectivity of cells is not defined.
1400 * \throw If the nodal connectivity includes an invalid id.
1402 * \if ENABLE_EXAMPLES
1403 * \ref cpp_mcumesh_getNodeIdsInUse "Here is a C++ example".<br>
1404 * \ref py_mcumesh_getNodeIdsInUse "Here is a Python example".
1406 * \sa computeFetchedNodeIds, computeNodeIdsAlg()
1408 DataArrayIdType *MEDCouplingUMesh::getNodeIdsInUse(mcIdType& nbrOfNodesInUse) const
1411 mcIdType nbOfNodes(getNumberOfNodes());
1412 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1413 ret->alloc(nbOfNodes,1);
1414 mcIdType *traducer=ret->getPointer();
1415 std::fill(traducer,traducer+nbOfNodes,-1);
1416 mcIdType nbOfCells=getNumberOfCells();
1417 const mcIdType *connIndex=_nodal_connec_index->getConstPointer();
1418 const mcIdType *conn=_nodal_connec->getConstPointer();
1419 for(mcIdType i=0;i<nbOfCells;i++)
1420 for(mcIdType j=connIndex[i]+1;j<connIndex[i+1];j++)
1423 if(conn[j]<nbOfNodes)
1424 traducer[conn[j]]=1;
1427 std::ostringstream oss; oss << "MEDCouplingUMesh::getNodeIdsInUse : In cell #" << i << " presence of node id " << conn[j] << " not in [0," << nbOfNodes << ") !";
1428 throw INTERP_KERNEL::Exception(oss.str());
1431 nbrOfNodesInUse=ToIdType(std::count(traducer,traducer+nbOfNodes,1));
1432 std::transform(traducer,traducer+nbOfNodes,traducer,MEDCouplingAccVisit());
1437 * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1438 * For each cell in \b this the number of nodes constituting cell is computed.
1439 * For each polyhedron cell, the sum of the number of nodes of each face constituting polyhedron cell is returned.
1440 * So for pohyhedrons some nodes can be counted several times in the returned result.
1442 * \return a newly allocated array
1443 * \sa MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell
1445 DataArrayIdType *MEDCouplingUMesh::computeNbOfNodesPerCell() const
1447 checkConnectivityFullyDefined();
1448 mcIdType nbOfCells=getNumberOfCells();
1449 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1450 ret->alloc(nbOfCells,1);
1451 mcIdType *retPtr=ret->getPointer();
1452 const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1453 const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1454 for(mcIdType i=0;i<nbOfCells;i++,retPtr++)
1456 if(conn[connI[i]]!=ToIdType(INTERP_KERNEL::NORM_POLYHED))
1457 *retPtr=connI[i+1]-connI[i]-1;
1459 *retPtr=connI[i+1]-connI[i]-1-ToIdType(std::count(conn+connI[i]+1,conn+connI[i+1],-1));
1465 * This method computes effective number of nodes per cell. That is to say nodes appearing several times in nodal connectivity of a cell,
1466 * will be counted only once here whereas it will be counted several times in MEDCouplingUMesh::computeNbOfNodesPerCell method.
1468 * \return DataArrayIdType * - new object to be deallocated by the caller.
1469 * \sa MEDCouplingUMesh::computeNbOfNodesPerCell
1471 DataArrayIdType *MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell() const
1473 checkConnectivityFullyDefined();
1474 mcIdType nbOfCells=getNumberOfCells();
1475 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1476 ret->alloc(nbOfCells,1);
1477 mcIdType *retPtr=ret->getPointer();
1478 const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1479 const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1480 for(mcIdType i=0;i<nbOfCells;i++,retPtr++)
1482 std::set<mcIdType> s(conn+connI[i]+1,conn+connI[i+1]);
1483 if(conn[connI[i]]!=ToIdType(INTERP_KERNEL::NORM_POLYHED))
1484 *retPtr=ToIdType(s.size());
1488 *retPtr=ToIdType(s.size());
1495 * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1496 * For each cell in \b this the number of faces constituting (entity of dimension this->getMeshDimension()-1) cell is computed.
1498 * \return a newly allocated array
1500 DataArrayIdType *MEDCouplingUMesh::computeNbOfFacesPerCell() const
1502 checkConnectivityFullyDefined();
1503 mcIdType nbOfCells=getNumberOfCells();
1504 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1505 ret->alloc(nbOfCells,1);
1506 mcIdType *retPtr=ret->getPointer();
1507 const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1508 const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1509 for(mcIdType i=0;i<nbOfCells;i++,retPtr++,connI++)
1511 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]);
1512 *retPtr=cm.getNumberOfSons2(conn+connI[0]+1,connI[1]-connI[0]-1);
1518 * Removes unused nodes (the node coordinates array is shorten) and returns an array
1519 * mapping between new and old node ids in "Old to New" mode. -1 values in the returned
1520 * array mean that the corresponding old node is no more used.
1521 * \return DataArrayIdType * - a new instance of DataArrayIdType of length \a
1522 * this->getNumberOfNodes() before call of this method. The caller is to
1523 * delete this array using decrRef() as it is no more needed.
1524 * \throw If the coordinates array is not set.
1525 * \throw If the nodal connectivity of cells is not defined.
1526 * \throw If the nodal connectivity includes an invalid id.
1527 * \sa areAllNodesFetched
1529 * \if ENABLE_EXAMPLES
1530 * \ref cpp_mcumesh_zipCoordsTraducer "Here is a C++ example".<br>
1531 * \ref py_mcumesh_zipCoordsTraducer "Here is a Python example".
1534 DataArrayIdType *MEDCouplingUMesh::zipCoordsTraducer()
1536 return MEDCouplingPointSet::zipCoordsTraducer();
1540 * This method stands if 'cell1' and 'cell2' are equals regarding 'compType' policy.
1541 * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1543 int MEDCouplingUMesh::AreCellsEqual(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2, int compType)
1548 return AreCellsEqualPolicy0(conn,connI,cell1,cell2);
1550 return AreCellsEqualPolicy1(conn,connI,cell1,cell2);
1552 return AreCellsEqualPolicy2(conn,connI,cell1,cell2);
1554 return AreCellsEqualPolicy2NoType(conn,connI,cell1,cell2);
1556 return AreCellsEqualPolicy7(conn,connI,cell1,cell2);
1558 throw INTERP_KERNEL::Exception("Unknown comparison asked ! Must be in 0,1,2,3 or 7.");
1562 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 0.
1564 int MEDCouplingUMesh::AreCellsEqualPolicy0(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1566 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1567 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;
1572 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 1.
1574 int MEDCouplingUMesh::AreCellsEqualPolicy1(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1576 mcIdType sz=connI[cell1+1]-connI[cell1];
1577 if(sz==connI[cell2+1]-connI[cell2])
1579 if(conn[connI[cell1]]==conn[connI[cell2]])
1581 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1582 unsigned dim=cm.getDimension();
1587 mcIdType sz1=2*(sz-1);
1588 INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz1];
1589 mcIdType *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(mcIdType *)tmp);
1590 std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1591 work=std::search((mcIdType *)tmp,(mcIdType *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1592 return work!=tmp+sz1?1:0;
1595 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;//case of SEG2 and SEG3
1598 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy1 : not implemented yet for meshdim == 3 !");
1605 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 2.
1607 int MEDCouplingUMesh::AreCellsEqualPolicy2(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1609 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1611 if(conn[connI[cell1]]==conn[connI[cell2]])
1613 std::set<mcIdType> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1614 std::set<mcIdType> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1622 * This method is less restrictive than AreCellsEqualPolicy2. Here the geometric type is absolutely not taken into account !
1624 int MEDCouplingUMesh::AreCellsEqualPolicy2NoType(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1626 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1628 std::set<mcIdType> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1629 std::set<mcIdType> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1636 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 7.
1638 int MEDCouplingUMesh::AreCellsEqualPolicy7(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1640 mcIdType sz=connI[cell1+1]-connI[cell1];
1641 if(sz==connI[cell2+1]-connI[cell2])
1643 if(conn[connI[cell1]]==conn[connI[cell2]])
1645 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1646 unsigned dim=cm.getDimension();
1651 mcIdType sz1=2*(sz-1);
1652 INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz1];
1653 mcIdType *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(mcIdType *)tmp);
1654 std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1655 work=std::search((mcIdType *)tmp,(mcIdType *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1660 std::reverse_iterator<mcIdType *> it1((mcIdType *)tmp+sz1);
1661 std::reverse_iterator<mcIdType *> it2((mcIdType *)tmp);
1662 if(std::search(it1,it2,conn+connI[cell2]+1,conn+connI[cell2+1])!=it2)
1669 {//case of SEG2 and SEG3
1670 if(std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1))
1672 if(!cm.isQuadratic())
1674 std::reverse_iterator<const mcIdType *> it1(conn+connI[cell1+1]);
1675 std::reverse_iterator<const mcIdType *> it2(conn+connI[cell1]+1);
1676 if(std::equal(it1,it2,conn+connI[cell2]+1))
1682 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])
1689 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy7 : not implemented yet for meshdim == 3 !");
1697 * This method find cells that are equal (regarding \a compType) in \a this. The comparison is specified by \a compType (see zipConnectivityTraducer).
1698 * This method keeps the coordinates of \a this. The comparison starts at rank \a startCellId cell id (included).
1699 * 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.
1700 * If \a startCellId is greater than 0 algorithm starts at cell #startCellId but for each cell all candidates are considered.
1701 * This method is time consuming.
1703 * \param [in] compType input specifying the technique used to compare cells each other.
1704 * - 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.
1705 * - 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)
1706 * and their type equal. For 1D mesh the policy 1 is equivalent to 0.
1707 * - 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
1708 * can be used for users not sensitive to orientation of cell
1709 * \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.
1710 * \param [out] commonCellsArr common cells ids (\ref numbering-indirect)
1711 * \param [out] commonCellsIArr common cells ids (\ref numbering-indirect)
1714 void MEDCouplingUMesh::findCommonCells(int compType, mcIdType startCellId, DataArrayIdType *& commonCellsArr, DataArrayIdType *& commonCellsIArr) const
1716 MCAuto<DataArrayIdType> revNodal=DataArrayIdType::New(),revNodalI=DataArrayIdType::New();
1717 getReverseNodalConnectivity(revNodal,revNodalI);
1718 FindCommonCellsAlg(compType,startCellId,_nodal_connec,_nodal_connec_index,revNodal,revNodalI,commonCellsArr,commonCellsIArr);
1721 void MEDCouplingUMesh::FindCommonCellsAlg(int compType, mcIdType startCellId, const DataArrayIdType *nodal, const DataArrayIdType *nodalI, const DataArrayIdType *revNodal, const DataArrayIdType *revNodalI,
1722 DataArrayIdType *& commonCellsArr, DataArrayIdType *& commonCellsIArr)
1724 MCAuto<DataArrayIdType> commonCells=DataArrayIdType::New(),commonCellsI=DataArrayIdType::New(); commonCells->alloc(0,1);
1725 mcIdType nbOfCells=nodalI->getNumberOfTuples()-1;
1726 commonCellsI->reserve(1); commonCellsI->pushBackSilent(0);
1727 const mcIdType *revNodalPtr=revNodal->getConstPointer(),*revNodalIPtr=revNodalI->getConstPointer();
1728 const mcIdType *connPtr=nodal->getConstPointer(),*connIPtr=nodalI->getConstPointer();
1729 std::vector<bool> isFetched(nbOfCells,false);
1732 for(mcIdType i=startCellId;i<nbOfCells;i++)
1736 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));
1737 std::vector<mcIdType> v,v2;
1738 if(connOfNode!=connPtr+connIPtr[i+1])
1740 const mcIdType *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1741 v2.insert(v2.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1]);
1744 for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1748 const mcIdType *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1749 std::vector<mcIdType>::iterator it=std::set_intersection(v.begin(),v.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1750 v2.resize(std::distance(v2.begin(),it));
1754 if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1756 mcIdType pos=commonCellsI->back();
1757 commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1758 for(const mcIdType *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1759 isFetched[*it]=true;
1767 for(mcIdType i=startCellId;i<nbOfCells;i++)
1771 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));
1772 // v2 contains the result of successive intersections using rev nodal on on each node of cell #i
1773 std::vector<mcIdType> v,v2;
1774 if(connOfNode!=connPtr+connIPtr[i+1])
1776 v2.insert(v2.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1]);
1779 for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1783 std::vector<mcIdType>::iterator it=std::set_intersection(v.begin(),v.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1784 v2.resize(std::distance(v2.begin(),it));
1786 // v2 contains now candidates. Problem candidates are sorted using id rank.
1791 auto it(std::find(v2.begin(),v2.end(),i));
1792 std::swap(*v2.begin(),*it);
1794 if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1796 mcIdType newPos(commonCells->getNumberOfTuples());
1797 mcIdType pos(commonCellsI->back());
1798 std::sort(commonCells->getPointerSilent()+pos,commonCells->getPointerSilent()+newPos);
1799 commonCellsI->pushBackSilent(newPos);
1800 for(const mcIdType *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1801 isFetched[*it]=true;
1807 commonCellsArr=commonCells.retn();
1808 commonCellsIArr=commonCellsI.retn();
1812 * Checks if \a this mesh includes all cells of an \a other mesh, and returns an array
1813 * giving for each cell of the \a other an id of a cell in \a this mesh. A value larger
1814 * than \a this->getNumberOfCells() in the returned array means that there is no
1815 * corresponding cell in \a this mesh.
1816 * It is expected that \a this and \a other meshes share the same node coordinates
1817 * array, if it is not so an exception is thrown.
1818 * \param [in] other - the mesh to compare with.
1819 * \param [in] compType - specifies a cell comparison technique. For meaning of its
1820 * valid values [0,1,2], see zipConnectivityTraducer().
1821 * \param [out] arr - a new instance of DataArrayIdType returning correspondence
1822 * between cells of the two meshes. It contains \a other->getNumberOfCells()
1823 * values. The caller is to delete this array using
1824 * decrRef() as it is no more needed.
1825 * \return bool - \c true if all cells of \a other mesh are present in the \a this
1828 * \if ENABLE_EXAMPLES
1829 * \ref cpp_mcumesh_areCellsIncludedIn "Here is a C++ example".<br>
1830 * \ref py_mcumesh_areCellsIncludedIn "Here is a Python example".
1832 * \sa checkDeepEquivalOnSameNodesWith()
1833 * \sa checkGeoEquivalWith()
1835 bool MEDCouplingUMesh::areCellsIncludedIn(const MEDCouplingUMesh *other, int compType, DataArrayIdType *& arr) const
1837 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1838 mcIdType nbOfCells=getNumberOfCells();
1839 static const int possibleCompType[]={0,1,2};
1840 if(std::find(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),compType)==possibleCompType+sizeof(possibleCompType)/sizeof(int))
1842 std::ostringstream oss; oss << "MEDCouplingUMesh::areCellsIncludedIn : only following policies are possible : ";
1843 std::copy(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),std::ostream_iterator<int>(oss," "));
1845 throw INTERP_KERNEL::Exception(oss.str());
1848 if(other->getNumberOfCells()==0)
1850 MCAuto<DataArrayIdType> dftRet(DataArrayIdType::New()); dftRet->alloc(0,1); arr=dftRet.retn(); arr->setName(other->getName());
1853 DataArrayIdType *commonCells(nullptr),*commonCellsI(nullptr);
1854 mesh->findCommonCells(compType,nbOfCells,commonCells,commonCellsI);
1855 MCAuto<DataArrayIdType> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1856 mcIdType newNbOfCells=-1;
1857 MCAuto<DataArrayIdType> o2n = DataArrayIdType::ConvertIndexArrayToO2N(ToIdType(mesh->getNumberOfCells()),commonCells->begin(),commonCellsI->begin(),commonCellsI->end(),newNbOfCells);
1858 MCAuto<DataArrayIdType> p0(o2n->selectByTupleIdSafeSlice(0,nbOfCells,1));
1859 mcIdType maxPart(p0->getMaxValueInArray());
1860 bool ret(maxPart==newNbOfCells-1);
1861 MCAuto<DataArrayIdType> p1(p0->invertArrayO2N2N2O(newNbOfCells));
1862 // fill p1 array in case of presence of cells in other not in this
1863 mcIdType *pt(p1->getPointer());
1864 for(mcIdType i = maxPart ; i < newNbOfCells-1 ; ++i )
1867 MCAuto<DataArrayIdType> p2(o2n->subArray(nbOfCells));
1868 p2->transformWithIndArr(p1->begin(),p1->end()); p2->setName(other->getName());
1874 * This method makes the assumption that \a this and \a other share the same coords. If not an exception will be thrown !
1875 * This method tries to determine if \b other is fully included in \b this.
1876 * The main difference is that this method is not expected to throw exception.
1877 * This method has two outputs :
1879 * \param other other mesh
1880 * \param arr is an output parameter that returns a \b newly created instance. This array is of size 'other->getNumberOfCells()'.
1881 * \return If \a other is fully included in 'this 'true is returned. If not false is returned.
1883 bool MEDCouplingUMesh::areCellsIncludedInPolicy7(const MEDCouplingUMesh *other, DataArrayIdType *& arr) const
1885 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1886 DataArrayIdType *commonCells=0,*commonCellsI=0;
1887 mcIdType thisNbCells=getNumberOfCells();
1888 mesh->findCommonCells(7,thisNbCells,commonCells,commonCellsI);
1889 MCAuto<DataArrayIdType> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1890 const mcIdType *commonCellsPtr=commonCells->getConstPointer(),*commonCellsIPtr=commonCellsI->getConstPointer();
1891 mcIdType otherNbCells=other->getNumberOfCells();
1892 MCAuto<DataArrayIdType> arr2=DataArrayIdType::New();
1893 arr2->alloc(otherNbCells,1);
1894 arr2->fillWithZero();
1895 mcIdType *arr2Ptr=arr2->getPointer();
1896 mcIdType nbOfCommon=commonCellsI->getNumberOfTuples()-1;
1897 for(mcIdType i=0;i<nbOfCommon;i++)
1899 mcIdType start=commonCellsPtr[commonCellsIPtr[i]];
1900 if(start<thisNbCells)
1902 for(mcIdType j=commonCellsIPtr[i]+1;j!=commonCellsIPtr[i+1];j++)
1904 mcIdType sig=commonCellsPtr[j]>0?1:-1;
1905 mcIdType val=std::abs(commonCellsPtr[j])-1;
1906 if(val>=thisNbCells)
1907 arr2Ptr[val-thisNbCells]=sig*(start+1);
1911 arr2->setName(other->getName());
1912 if(arr2->presenceOfValue(0))
1918 MEDCouplingUMesh *MEDCouplingUMesh::mergeMyselfWithOnSameCoords(const MEDCouplingPointSet *other) const
1921 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : input other is null !");
1922 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
1924 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : the input other mesh is not of type unstructured !");
1925 std::vector<const MEDCouplingUMesh *> ms(2);
1928 return MergeUMeshesOnSameCoords(ms);
1932 * Build a sub part of \b this lying or not on the same coordinates than \b this (regarding value of \b keepCoords).
1933 * By default coordinates are kept. This method is close to MEDCouplingUMesh::buildPartOfMySelf except that here input
1934 * cellIds is not given explicitly but by a range python like.
1936 * \param start starting ID
1937 * \param end end ID (excluded)
1938 * \param step step size
1939 * \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.
1940 * \return a newly allocated
1942 * \warning This method modifies can generate an unstructured mesh whose cells are not sorted by geometric type order.
1943 * In view of the MED file writing, a renumbering of cells of returned unstructured mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
1945 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfSlice(mcIdType start, mcIdType end, mcIdType step, bool keepCoords) const
1947 if(getMeshDimension()!=-1)
1948 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelfSlice(start,end,step,keepCoords));
1951 mcIdType newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfSlice for -1 dimension mesh ");
1953 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
1955 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
1957 return const_cast<MEDCouplingUMesh *>(this);
1962 * Creates a new MEDCouplingUMesh containing specified cells of \a this mesh.
1963 * The result mesh shares or not the node coordinates array with \a this mesh depending
1964 * on \a keepCoords parameter.
1965 * \warning Cells of the result mesh can be \b not sorted by geometric type, hence,
1966 * to write this mesh to the MED file, its cells must be sorted using
1967 * sortCellsInMEDFileFrmt().
1968 * \param [in] begin - an array of cell ids to include to the new mesh.
1969 * \param [in] end - a pointer to last-plus-one-th element of \a begin.
1970 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
1971 * array of \a this mesh, else "free" nodes are removed from the result mesh
1972 * by calling zipCoords().
1973 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
1974 * to delete this mesh using decrRef() as it is no more needed.
1975 * \throw If the coordinates array is not set.
1976 * \throw If the nodal connectivity of cells is not defined.
1977 * \throw If any cell id in the array \a begin is not valid.
1979 * \if ENABLE_EXAMPLES
1980 * \ref cpp_mcumesh_buildPartOfMySelf "Here is a C++ example".<br>
1981 * \ref py_mcumesh_buildPartOfMySelf "Here is a Python example".
1984 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelf(const mcIdType *begin, const mcIdType *end, bool keepCoords) const
1986 if(getMeshDimension()!=-1)
1987 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelf(begin,end,keepCoords));
1991 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
1993 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
1995 return const_cast<MEDCouplingUMesh *>(this);
2000 * This method operates only on nodal connectivity on \b this. Coordinates of \b this is completely ignored here.
2002 * 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.
2003 * Size of [ \b cellIdsBg, \b cellIdsEnd ) ) must be equal to the number of cells of otherOnSameCoordsThanThis.
2004 * The number of cells of \b this will remain the same with this method.
2006 * \param [in] cellIdsBg begin of cell ids (included) of cells in this to assign
2007 * \param [in] cellIdsEnd end of cell ids (excluded) of cells in this to assign
2008 * \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 ).
2009 * Coordinate pointer of \b this and those of \b otherOnSameCoordsThanThis must be the same
2011 void MEDCouplingUMesh::setPartOfMySelf(const mcIdType *cellIdsBg, const mcIdType *cellIdsEnd, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2013 checkConnectivityFullyDefined();
2014 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2015 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2016 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelf : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2017 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2019 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2020 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2021 throw INTERP_KERNEL::Exception(oss.str());
2023 mcIdType nbOfCellsToModify( ToIdType((std::distance(cellIdsBg,cellIdsEnd))));
2024 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2026 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2027 throw INTERP_KERNEL::Exception(oss.str());
2029 mcIdType nbOfCells(getNumberOfCells());
2030 bool easyAssign(true);
2031 const mcIdType *connI(_nodal_connec_index->begin());
2032 const mcIdType *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->begin();
2033 for(const mcIdType *it=cellIdsBg;it!=cellIdsEnd && easyAssign;it++,connIOther++)
2035 if(*it>=0 && *it<nbOfCells)
2037 easyAssign=(connIOther[1]-connIOther[0])==(connI[*it+1]-connI[*it]);
2041 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : On pos #" << std::distance(cellIdsBg,it) << " id is equal to " << *it << " which is not in [0," << nbOfCells << ") !";
2042 throw INTERP_KERNEL::Exception(oss.str());
2047 DataArrayIdType::SetPartOfIndexedArraysSameIdx(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2052 DataArrayIdType *arrOut=0,*arrIOut=0;
2053 DataArrayIdType::SetPartOfIndexedArrays(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2055 MCAuto<DataArrayIdType> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2056 setConnectivity(arrOut,arrIOut,true);
2060 void MEDCouplingUMesh::setPartOfMySelfSlice(mcIdType start, mcIdType end, mcIdType step, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2062 checkConnectivityFullyDefined();
2063 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2064 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2065 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelfSlice : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2066 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2068 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2069 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2070 throw INTERP_KERNEL::Exception(oss.str());
2072 mcIdType nbOfCellsToModify=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::setPartOfMySelfSlice : ");
2073 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2075 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2076 throw INTERP_KERNEL::Exception(oss.str());
2078 mcIdType nbOfCells=getNumberOfCells();
2079 bool easyAssign=true;
2080 const mcIdType *connI=_nodal_connec_index->getConstPointer();
2081 const mcIdType *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2083 for(mcIdType i=0;i<nbOfCellsToModify && easyAssign;i++,it+=step,connIOther++)
2085 if(it>=0 && it<nbOfCells)
2087 easyAssign=(connIOther[1]-connIOther[0])==(connI[it+1]-connI[it]);
2091 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : On pos #" << i << " id is equal to " << it << " which is not in [0," << nbOfCells << ") !";
2092 throw INTERP_KERNEL::Exception(oss.str());
2097 DataArrayIdType::SetPartOfIndexedArraysSameIdxSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2102 DataArrayIdType *arrOut=0,*arrIOut=0;
2103 DataArrayIdType::SetPartOfIndexedArraysSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2105 MCAuto<DataArrayIdType> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2106 setConnectivity(arrOut,arrIOut,true);
2112 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2113 * this->getMeshDimension(), that bound some cells of \a this mesh.
2114 * The cells of lower dimension to include to the result mesh are selected basing on
2115 * specified node ids and the value of \a fullyIn parameter. If \a fullyIn ==\c true, a
2116 * cell is copied if its all nodes are in the array \a begin of node ids. If \a fullyIn
2117 * ==\c false, a cell is copied if any its node is in the array of node ids. The
2118 * created mesh shares the node coordinates array with \a this mesh.
2119 * \param [in] begin - the array of node ids.
2120 * \param [in] end - a pointer to the (last+1)-th element of \a begin.
2121 * \param [in] fullyIn - if \c true, then cells whose all nodes are in the
2122 * array \a begin are added, else cells whose any node is in the
2123 * array \a begin are added.
2124 * \return MEDCouplingUMesh * - new instance of MEDCouplingUMesh. The caller is
2125 * to delete this mesh using decrRef() as it is no more needed.
2126 * \throw If the coordinates array is not set.
2127 * \throw If the nodal connectivity of cells is not defined.
2128 * \throw If any node id in \a begin is not valid.
2130 * \if ENABLE_EXAMPLES
2131 * \ref cpp_mcumesh_buildFacePartOfMySelfNode "Here is a C++ example".<br>
2132 * \ref py_mcumesh_buildFacePartOfMySelfNode "Here is a Python example".
2135 MEDCouplingUMesh *MEDCouplingUMesh::buildFacePartOfMySelfNode(const mcIdType *begin, const mcIdType *end, bool fullyIn) const
2137 MCAuto<DataArrayIdType> desc,descIndx,revDesc,revDescIndx;
2138 desc=DataArrayIdType::New(); descIndx=DataArrayIdType::New(); revDesc=DataArrayIdType::New(); revDescIndx=DataArrayIdType::New();
2139 MCAuto<MEDCouplingUMesh> subMesh=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2140 desc=0; descIndx=0; revDesc=0; revDescIndx=0;
2141 return static_cast<MEDCouplingUMesh*>(subMesh->buildPartOfMySelfNode(begin,end,fullyIn));
2145 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2146 * this->getMeshDimension(), which bound only one cell of \a this mesh.
2147 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2148 * array of \a this mesh, else "free" nodes are removed from the result mesh
2149 * by calling zipCoords().
2150 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2151 * to delete this mesh using decrRef() as it is no more needed.
2152 * \throw If the coordinates array is not set.
2153 * \throw If the nodal connectivity of cells is not defined.
2155 * \if ENABLE_EXAMPLES
2156 * \ref cpp_mcumesh_buildBoundaryMesh "Here is a C++ example".<br>
2157 * \ref py_mcumesh_buildBoundaryMesh "Here is a Python example".
2160 MEDCouplingUMesh *MEDCouplingUMesh::buildBoundaryMesh(bool keepCoords) const
2162 DataArrayIdType *desc=DataArrayIdType::New();
2163 DataArrayIdType *descIndx=DataArrayIdType::New();
2164 DataArrayIdType *revDesc=DataArrayIdType::New();
2165 DataArrayIdType *revDescIndx=DataArrayIdType::New();
2167 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2170 descIndx->decrRef();
2171 mcIdType nbOfCells=meshDM1->getNumberOfCells();
2172 const mcIdType *revDescIndxC=revDescIndx->getConstPointer();
2173 std::vector<mcIdType> boundaryCells;
2174 for(mcIdType i=0;i<nbOfCells;i++)
2175 if(revDescIndxC[i+1]-revDescIndxC[i]==1)
2176 boundaryCells.push_back(i);
2177 revDescIndx->decrRef();
2178 MEDCouplingUMesh *ret=meshDM1->buildPartOfMySelf(&boundaryCells[0],&boundaryCells[0]+boundaryCells.size(),keepCoords);
2183 * This method returns a newly created DataArrayIdType instance containing ids of cells located in boundary.
2184 * A cell is detected to be on boundary if it contains one or more than one face having only one father.
2185 * This method makes the assumption that \a this is fully defined (coords,connectivity). If not an exception will be thrown.
2187 DataArrayIdType *MEDCouplingUMesh::findCellIdsOnBoundary() const
2189 checkFullyDefined();
2190 MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
2191 MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
2192 MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
2193 MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
2195 buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx)->decrRef();
2196 desc=(DataArrayIdType*)0; descIndx=(DataArrayIdType*)0;
2198 MCAuto<DataArrayIdType> tmp=revDescIndx->deltaShiftIndex();
2199 MCAuto<DataArrayIdType> faceIds=tmp->findIdsEqual(1); tmp=(DataArrayIdType*)0;
2200 const mcIdType *revDescPtr=revDesc->getConstPointer();
2201 const mcIdType *revDescIndxPtr=revDescIndx->getConstPointer();
2202 mcIdType nbOfCells=getNumberOfCells();
2203 std::vector<bool> ret1(nbOfCells,false);
2205 for(const mcIdType *pt=faceIds->begin();pt!=faceIds->end();pt++)
2206 if(!ret1[revDescPtr[revDescIndxPtr[*pt]]])
2207 { ret1[revDescPtr[revDescIndxPtr[*pt]]]=true; sz++; }
2209 DataArrayIdType *ret2=DataArrayIdType::New();
2211 mcIdType *ret2Ptr=ret2->getPointer();
2213 for(std::vector<bool>::const_iterator it=ret1.begin();it!=ret1.end();it++,sz++)
2216 ret2->setName("BoundaryCells");
2221 * This method finds in \b this the cell ids that lie on mesh \b otherDimM1OnSameCoords.
2222 * \b this and \b otherDimM1OnSameCoords have to lie on the same coordinate array pointer. The coherency of that coords array with connectivity
2223 * of \b this and \b otherDimM1OnSameCoords is not important here because this method works only on connectivity.
2224 * this->getMeshDimension() - 1 must be equal to otherDimM1OnSameCoords.getMeshDimension()
2226 * s0 is the cell ids set in \b this lying on at least one node in the fetched nodes in \b otherDimM1OnSameCoords.
2227 * 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
2228 * equals a cell in \b otherDimM1OnSameCoords.
2230 * \throw if \b otherDimM1OnSameCoords is not part of constituent of \b this, or if coordinate pointer of \b this and \b otherDimM1OnSameCoords
2231 * are not same, or if this->getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension()
2233 * \param [in] otherDimM1OnSameCoords other mesh
2234 * \param [out] cellIdsRk0 a newly allocated array containing the cell ids of s0 (which are cell ids of \b this) in the above algorithm.
2235 * \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
2236 * cellIdsRk1->transformWithIndArr(cellIdsRk0->begin(),cellIdsRk0->end());
2238 void MEDCouplingUMesh::findCellIdsLyingOn(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayIdType *&cellIdsRk0, DataArrayIdType *&cellIdsRk1) const
2240 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2241 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : coordinates pointer are not the same ! Use tryToShareSameCoords method !");
2242 checkConnectivityFullyDefined();
2243 otherDimM1OnSameCoords.checkConnectivityFullyDefined();
2244 if(getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension())
2245 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : invalid mesh dimension of input mesh regarding meshdimesion of this !");
2246 MCAuto<DataArrayIdType> fetchedNodeIds1=otherDimM1OnSameCoords.computeFetchedNodeIds();
2247 MCAuto<DataArrayIdType> s0arr=getCellIdsLyingOnNodes(fetchedNodeIds1->begin(),fetchedNodeIds1->end(),false);
2248 MCAuto<MEDCouplingUMesh> thisPart=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(s0arr->begin(),s0arr->end(),true));
2249 MCAuto<DataArrayIdType> descThisPart=DataArrayIdType::New(),descIThisPart=DataArrayIdType::New(),revDescThisPart=DataArrayIdType::New(),revDescIThisPart=DataArrayIdType::New();
2250 MCAuto<MEDCouplingUMesh> thisPartConsti=thisPart->buildDescendingConnectivity(descThisPart,descIThisPart,revDescThisPart,revDescIThisPart);
2251 const mcIdType *revDescThisPartPtr=revDescThisPart->getConstPointer(),*revDescIThisPartPtr=revDescIThisPart->getConstPointer();
2252 DataArrayIdType *idsOtherInConsti=0;
2253 bool b=thisPartConsti->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsOtherInConsti);
2254 MCAuto<DataArrayIdType> idsOtherInConstiAuto(idsOtherInConsti);
2256 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : the given mdim-1 mesh in other is not a constituent of this !");
2257 std::set<mcIdType> s1;
2258 for(const mcIdType *idOther=idsOtherInConsti->begin();idOther!=idsOtherInConsti->end();idOther++)
2259 s1.insert(revDescThisPartPtr+revDescIThisPartPtr[*idOther],revDescThisPartPtr+revDescIThisPartPtr[*idOther+1]);
2260 MCAuto<DataArrayIdType> s1arr_renum1=DataArrayIdType::New(); s1arr_renum1->alloc(s1.size(),1); std::copy(s1.begin(),s1.end(),s1arr_renum1->getPointer());
2261 s1arr_renum1->sort();
2262 cellIdsRk0=s0arr.retn();
2263 //cellIdsRk1=s_renum1.retn();
2264 cellIdsRk1=s1arr_renum1.retn();
2268 * 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
2269 * returned. This subpart of meshdim-1 mesh is built using meshdim-1 cells in it shared only one cell in \b this.
2271 * \return a newly allocated mesh lying on the same coordinates than \b this. The caller has to deal with returned mesh.
2273 MEDCouplingUMesh *MEDCouplingUMesh::computeSkin() const
2275 MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
2276 MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
2277 MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
2278 MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
2280 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2281 revDesc=0; desc=0; descIndx=0;
2282 MCAuto<DataArrayIdType> revDescIndx2=revDescIndx->deltaShiftIndex();
2283 MCAuto<DataArrayIdType> part=revDescIndx2->findIdsEqual(1);
2284 return static_cast<MEDCouplingUMesh *>(meshDM1->buildPartOfMySelf(part->begin(),part->end(),true));
2288 * Finds nodes lying on the boundary of \a this mesh.
2289 * \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of found
2290 * nodes. The caller is to delete this array using decrRef() as it is no
2292 * \throw If the coordinates array is not set.
2293 * \throw If the nodal connectivity of cells is node defined.
2295 * \if ENABLE_EXAMPLES
2296 * \ref cpp_mcumesh_findBoundaryNodes "Here is a C++ example".<br>
2297 * \ref py_mcumesh_findBoundaryNodes "Here is a Python example".
2300 DataArrayIdType *MEDCouplingUMesh::findBoundaryNodes() const
2302 MCAuto<MEDCouplingUMesh> skin=computeSkin();
2303 return skin->computeFetchedNodeIds();
2306 MEDCouplingUMesh *MEDCouplingUMesh::buildUnstructured() const
2309 return const_cast<MEDCouplingUMesh *>(this);
2313 * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2314 * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2315 * 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.
2316 * 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.
2317 * 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.
2319 * \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
2320 * parameter is altered during the call.
2321 * \param [out] nodeIdsToDuplicate node ids needed to be duplicated following the algorithm explain above.
2322 * \param [out] cellIdsNeededToBeRenum cell ids in \b this in which the renumber of nodes should be performed.
2323 * \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.
2326 void MEDCouplingUMesh::findNodesToDuplicate(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayIdType *& nodeIdsToDuplicate,
2327 DataArrayIdType *& cellIdsNeededToBeRenum, DataArrayIdType *& cellIdsNotModified) const
2329 typedef MCAuto<DataArrayIdType> DAInt;
2330 typedef MCAuto<MEDCouplingUMesh> MCUMesh;
2332 checkFullyDefined();
2333 otherDimM1OnSameCoords.checkFullyDefined();
2334 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2335 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : meshes do not share the same coords array !");
2336 if(otherDimM1OnSameCoords.getMeshDimension()!=getMeshDimension()-1)
2337 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the mesh given in other parameter must have this->getMeshDimension()-1 !");
2339 // Checking star-shaped M1 group:
2340 DAInt dt0=DataArrayIdType::New(),dit0=DataArrayIdType::New(),rdt0=DataArrayIdType::New(),rdit0=DataArrayIdType::New();
2341 MCUMesh meshM2 = otherDimM1OnSameCoords.buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); // 2D: a mesh of points, 3D: a mesh of segs
2342 DAInt dsi = rdit0->deltaShiftIndex();
2343 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.
2344 if(idsTmp0->getNumberOfTuples())
2345 throw INTERP_KERNEL::Exception("MEDFileUMesh::buildInnerBoundaryAlongM1Group: group is too complex: some points (or edges) have more than two connected segments (or faces)!");
2346 dt0=0; dit0=0; rdt0=0; rdit0=0; idsTmp0=0;
2348 // Get extreme nodes from the group (they won't be duplicated except if they also lie on bound of M0 -- see below),
2349 // ie nodes belonging to the boundary "cells" (might be points) of M1
2350 DAInt xtremIdsM2 = dsi->findIdsEqual(1); dsi = 0;
2351 MCUMesh meshM2Part = static_cast<MEDCouplingUMesh *>(meshM2->buildPartOfMySelf(xtremIdsM2->begin(), xtremIdsM2->end(),true));
2352 DAInt xtrem = meshM2Part->computeFetchedNodeIds();
2353 // Remove from the list points on the boundary of the M0 mesh (those need duplication!)
2354 dt0=DataArrayIdType::New(),dit0=DataArrayIdType::New(),rdt0=DataArrayIdType::New(),rdit0=DataArrayIdType::New();
2355 MCUMesh m0desc = buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); dt0=0; dit0=0; rdt0=0;
2356 dsi = rdit0->deltaShiftIndex();
2357 DAInt boundSegs = dsi->findIdsEqual(1); dsi = 0; // boundary segs/faces of the M0 mesh
2358 MCUMesh m0descSkin = static_cast<MEDCouplingUMesh *>(m0desc->buildPartOfMySelf(boundSegs->begin(),boundSegs->end(), true));
2359 DAInt fNodes = m0descSkin->computeFetchedNodeIds();
2360 // 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)
2361 // 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
2362 // although they are technically on the skin of the cube.
2364 if (getMeshDimension() == 3)
2366 DAInt dnu1=DataArrayIdType::New(), dnu2=DataArrayIdType::New(), dnu3=DataArrayIdType::New(), dnu4=DataArrayIdType::New();
2367 MCUMesh m0descSkinDesc = m0descSkin->buildDescendingConnectivity(dnu1, dnu2, dnu3, dnu4); // all segments of the skin of the 3D (M0) mesh
2368 dnu1=0;dnu2=0;dnu3=0;dnu4=0;
2369 DataArrayIdType * corresp=0;
2370 meshM2->areCellsIncludedIn(m0descSkinDesc,2,corresp);
2371 DAInt validIds = corresp->findIdsInRange(0, meshM2->getNumberOfCells());
2373 if (validIds->getNumberOfTuples())
2375 // 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:
2376 MCUMesh m1IntersecSkin = static_cast<MEDCouplingUMesh *>(m0descSkinDesc->buildPartOfMySelf(validIds->begin(), validIds->end(), true));
2377 // Its boundary nodes should no be duplicated (this is for example the tip of the crack inside the cube described above)
2378 DAInt notDuplSkin = m1IntersecSkin->findBoundaryNodes();
2379 DAInt fNodes1 = fNodes->buildSubstraction(notDuplSkin);
2381 // Also, in this (segment) mesh, nodes connected to more than 3 segs should not be dup either (singular points - see testBuildInnerBoundary6())
2382 dt0=DataArrayIdType::New(),dit0=DataArrayIdType::New(),rdt0=DataArrayIdType::New(),rdit0=DataArrayIdType::New();
2383 MCUMesh meshM2Desc = meshM2->buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); dt0=0; dit0=0; rdt0=0; // a mesh made of node cells
2384 dsi = rdit0->deltaShiftIndex();
2385 DAInt singPoints = dsi->findIdsNotInRange(-1,4); // points connected to (strictly) more than 3 segments
2386 const mcIdType *cc = meshM2Desc->getNodalConnectivity()->begin(), *ccI = meshM2Desc->getNodalConnectivityIndex()->begin();
2387 mcIdType * singPointsP = singPoints->rwBegin();
2388 for (mcIdType j=0; j < singPoints->getNumberOfTuples(); j++) // replace ids in singPoints by real coordinate index (was index of cells in notDuplSkin)
2390 mcIdType nodeCellIdx = singPointsP[j];
2391 singPointsP[j] = cc[ccI[nodeCellIdx]+1]; // +1 to skip type
2393 DAInt fNodes2 = fNodes1->buildSubstraction(singPoints);
2394 notDup = xtrem->buildSubstraction(fNodes2);
2397 notDup = xtrem->buildSubstraction(fNodes);
2400 notDup = xtrem->buildSubstraction(fNodes);
2402 // Now compute cells around group (i.e. cells where we will do the propagation to identify the two sub-sets delimited by the group)
2403 DAInt m1Nodes = otherDimM1OnSameCoords.computeFetchedNodeIds();
2404 DAInt dupl = m1Nodes->buildSubstraction(notDup);
2405 DAInt cellsAroundGroup = getCellIdsLyingOnNodes(dupl->begin(), dupl->end(), false); // false= take cell in, even if not all nodes are in notDup
2408 MCUMesh m0Part2=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(cellsAroundGroup->begin(),cellsAroundGroup->end(),true));
2409 mcIdType nCells2 = m0Part2->getNumberOfCells();
2410 DAInt desc00=DataArrayIdType::New(),descI00=DataArrayIdType::New(),revDesc00=DataArrayIdType::New(),revDescI00=DataArrayIdType::New();
2411 MCUMesh m01=m0Part2->buildDescendingConnectivity(desc00,descI00,revDesc00,revDescI00);
2413 // Neighbor information of the mesh without considering the crack (serves to count how many connex pieces it is made of)
2414 DataArrayIdType *tmp00=0,*tmp11=0;
2415 MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00, tmp00, tmp11);
2416 DAInt neighInit00(tmp00);
2417 DAInt neighIInit00(tmp11);
2418 // Neighbor information of the mesh WITH the crack (some neighbors are removed):
2419 DataArrayIdType *idsTmp=0;
2420 m01->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsTmp);
2422 // In the neighbor information remove the connection between high dimension cells and its low level constituents which are part
2423 // of the frontier given in parameter (i.e. the cells of low dimension from the group delimiting the crack):
2424 DataArrayIdType::RemoveIdsFromIndexedArrays(ids->begin(),ids->end(),desc00,descI00);
2425 DataArrayIdType *tmp0=0,*tmp1=0;
2426 // Compute the neighbor of each cell in m0Part2, taking into account the broken link above. Two
2427 // cells on either side of the crack (defined by the mesh of low dimension) are not neighbor anymore.
2428 ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00,tmp0,tmp1);
2429 DAInt neigh00(tmp0);
2430 DAInt neighI00(tmp1);
2432 // For each initial connex part of the sub-mesh (or said differently for each independent crack):
2433 mcIdType seed = 0, nIter = 0;
2434 mcIdType nIterMax = nCells2+1; // Safety net for the loop
2435 DAInt hitCells = DataArrayIdType::New(); hitCells->alloc(nCells2);
2436 hitCells->fillWithValue(-1);
2437 DAInt cellsToModifyConn0_torenum = DataArrayIdType::New();
2438 cellsToModifyConn0_torenum->alloc(0,1);
2439 while (nIter < nIterMax)
2441 DAInt t = hitCells->findIdsEqual(-1);
2442 if (!t->getNumberOfTuples())
2444 // Connex zone without the crack (to compute the next seed really)
2446 DAInt connexCheck = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neighInit00,neighIInit00, -1, dnu);
2448 for (mcIdType * ptr = connexCheck->getPointer(); cnt < connexCheck->getNumberOfTuples(); ptr++, cnt++)
2449 hitCells->setIJ(*ptr,0,1);
2450 // Connex zone WITH the crack (to identify cells lying on either part of the crack)
2451 DAInt spreadZone = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neigh00,neighI00, -1, dnu);
2452 cellsToModifyConn0_torenum = DataArrayIdType::Aggregate(cellsToModifyConn0_torenum, spreadZone, 0);
2453 // Compute next seed, i.e. a cell in another connex part, which was not covered by the previous iterations
2454 DAInt comple = cellsToModifyConn0_torenum->buildComplement(nCells2);
2455 DAInt nonHitCells = hitCells->findIdsEqual(-1);
2456 DAInt intersec = nonHitCells->buildIntersection(comple);
2457 if (intersec->getNumberOfTuples())
2458 { seed = intersec->getIJ(0,0); }
2463 if (nIter >= nIterMax)
2464 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate(): internal error - too many iterations.");
2466 DAInt cellsToModifyConn1_torenum=cellsToModifyConn0_torenum->buildComplement(neighI00->getNumberOfTuples()-1);
2467 cellsToModifyConn0_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2468 cellsToModifyConn1_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2470 cellIdsNeededToBeRenum=cellsToModifyConn0_torenum.retn();
2471 cellIdsNotModified=cellsToModifyConn1_torenum.retn();
2472 nodeIdsToDuplicate=dupl.retn();
2476 * This method operates a modification of the connectivity and coords in \b this.
2477 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2478 * its ids will be modified to id this->getNumberOfNodes()+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2479 * 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
2480 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id this->getNumberOfNodes()+0, node id nodeIdsToDuplicateBg[1] will have id this->getNumberOfNodes()+1,
2481 * node id nodeIdsToDuplicateBg[2] will have id this->getNumberOfNodes()+2...
2483 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2485 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2486 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2488 void MEDCouplingUMesh::duplicateNodes(const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd)
2490 mcIdType nbOfNodes=getNumberOfNodes();
2491 duplicateNodesInCoords(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd);
2492 duplicateNodesInConn(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,nbOfNodes);
2496 * This method renumbers only nodal connectivity in \a this. The renumbering is only an offset applied. So this method is a specialization of
2497 * \a renumberNodesInConn. \b WARNING, this method does not check that the resulting node ids in the nodal connectivity is in a valid range !
2499 * \param [in] offset - specifies the offset to be applied on each element of connectivity.
2501 * \sa renumberNodesInConn
2503 void MEDCouplingUMesh::renumberNodesWithOffsetInConn(mcIdType offset)
2505 checkConnectivityFullyDefined();
2506 mcIdType *conn(getNodalConnectivity()->getPointer());
2507 const mcIdType *connIndex(getNodalConnectivityIndex()->getConstPointer());
2508 mcIdType nbOfCells=getNumberOfCells();
2509 for(mcIdType i=0;i<nbOfCells;i++)
2510 for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2512 mcIdType& node=conn[iconn];
2513 if(node>=0)//avoid polyhedron separator
2518 _nodal_connec->declareAsNew();
2523 * Same than renumberNodesInConn(const mcIdType *) except that here the format of old-to-new traducer is using map instead
2524 * 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
2527 void MEDCouplingUMesh::renumberNodesInConn(const INTERP_KERNEL::HashMap<mcIdType,mcIdType>& newNodeNumbersO2N)
2529 this->renumberNodesInConnT< INTERP_KERNEL::HashMap<mcIdType,mcIdType> >(newNodeNumbersO2N);
2533 * Same than renumberNodesInConn(const mcIdType *) except that here the format of old-to-new traducer is using map instead
2534 * 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
2537 void MEDCouplingUMesh::renumberNodesInConn(const std::map<mcIdType,mcIdType>& newNodeNumbersO2N)
2539 this->renumberNodesInConnT< std::map<mcIdType,mcIdType> >(newNodeNumbersO2N);
2543 * Changes ids of nodes within the nodal connectivity arrays according to a permutation
2544 * array in "Old to New" mode. The node coordinates array is \b not changed by this method.
2545 * This method is a generalization of shiftNodeNumbersInConn().
2546 * \warning This method performs no check of validity of new ids. **Use it with care !**
2547 * \param [in] newNodeNumbersO2N - a permutation array, of length \a
2548 * this->getNumberOfNodes(), in "Old to New" mode.
2549 * See \ref numbering for more info on renumbering modes.
2550 * \throw If the nodal connectivity of cells is not defined.
2552 * \if ENABLE_EXAMPLES
2553 * \ref cpp_mcumesh_renumberNodesInConn "Here is a C++ example".<br>
2554 * \ref py_mcumesh_renumberNodesInConn "Here is a Python example".
2557 void MEDCouplingUMesh::renumberNodesInConn(const mcIdType *newNodeNumbersO2N)
2559 checkConnectivityFullyDefined();
2560 mcIdType *conn=getNodalConnectivity()->getPointer();
2561 const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2562 mcIdType nbOfCells=getNumberOfCells();
2563 for(mcIdType i=0;i<nbOfCells;i++)
2564 for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2566 mcIdType& node=conn[iconn];
2567 if(node>=0)//avoid polyhedron separator
2569 node=newNodeNumbersO2N[node];
2572 _nodal_connec->declareAsNew();
2577 * This method renumbers nodes \b in \b connectivity \b only \b without \b any \b reference \b to \b coords.
2578 * This method performs no check on the fact that new coordinate ids are valid. \b Use \b it \b with \b care !
2579 * This method is an specialization of \ref MEDCoupling::MEDCouplingUMesh::renumberNodesInConn "renumberNodesInConn method".
2581 * \param [in] delta specifies the shift size applied to nodeId in nodal connectivity in \b this.
2583 void MEDCouplingUMesh::shiftNodeNumbersInConn(mcIdType delta)
2585 checkConnectivityFullyDefined();
2586 mcIdType *conn=getNodalConnectivity()->getPointer();
2587 const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2588 mcIdType nbOfCells=getNumberOfCells();
2589 for(mcIdType i=0;i<nbOfCells;i++)
2590 for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2592 mcIdType& node=conn[iconn];
2593 if(node>=0)//avoid polyhedron separator
2598 _nodal_connec->declareAsNew();
2603 * This method operates a modification of the connectivity in \b this.
2604 * 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.
2605 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2606 * its ids will be modified to id offset+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2607 * 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
2608 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id offset+0, node id nodeIdsToDuplicateBg[1] will have id offset+1,
2609 * node id nodeIdsToDuplicateBg[2] will have id offset+2...
2611 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2612 * As an another consequense after the call of this method \b this can be transiently non cohrent.
2614 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2615 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2616 * \param [in] offset the offset applied to all node ids in connectivity that are in [ \a nodeIdsToDuplicateBg, \a nodeIdsToDuplicateEnd ).
2618 void MEDCouplingUMesh::duplicateNodesInConn(const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd, mcIdType offset)
2620 checkConnectivityFullyDefined();
2621 std::map<mcIdType,mcIdType> m;
2622 mcIdType val=offset;
2623 for(const mcIdType *work=nodeIdsToDuplicateBg;work!=nodeIdsToDuplicateEnd;work++,val++)
2625 mcIdType *conn=getNodalConnectivity()->getPointer();
2626 const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2627 mcIdType nbOfCells=getNumberOfCells();
2628 for(mcIdType i=0;i<nbOfCells;i++)
2629 for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2631 mcIdType& node=conn[iconn];
2632 if(node>=0)//avoid polyhedron separator
2634 std::map<mcIdType,mcIdType>::iterator it=m.find(node);
2643 * This method renumbers cells of \a this using the array specified by [old2NewBg;old2NewBg+getNumberOfCells())
2645 * Contrary to MEDCouplingPointSet::renumberNodes, this method makes a permutation without any fuse of cell.
2646 * After the call of this method the number of cells remains the same as before.
2648 * If 'check' equals true the method will check that any elements in [ \a old2NewBg; \a old2NewEnd ) is unique ; if not
2649 * an INTERP_KERNEL::Exception will be thrown. When 'check' equals true [ \a old2NewBg ; \a old2NewEnd ) is not expected to
2650 * be strictly in [0;this->getNumberOfCells()).
2652 * If 'check' equals false the method will not check the content of [ \a old2NewBg ; \a old2NewEnd ).
2653 * To avoid any throw of SIGSEGV when 'check' equals false, the elements in [ \a old2NewBg ; \a old2NewEnd ) should be unique and
2654 * should be contained in[0;this->getNumberOfCells()).
2656 * \param [in] old2NewBg is expected to be a dynamically allocated pointer of size at least equal to this->getNumberOfCells()
2657 * \param check whether to check content of old2NewBg
2659 void MEDCouplingUMesh::renumberCells(const mcIdType *old2NewBg, bool check)
2661 checkConnectivityFullyDefined();
2662 mcIdType nbCells=getNumberOfCells();
2663 const mcIdType *array=old2NewBg;
2665 array=DataArrayIdType::CheckAndPreparePermutation(old2NewBg,old2NewBg+nbCells);
2667 const mcIdType *conn=_nodal_connec->getConstPointer();
2668 const mcIdType *connI=_nodal_connec_index->getConstPointer();
2669 MCAuto<DataArrayIdType> o2n=DataArrayIdType::New(); o2n->useArray(array,false,DeallocType::C_DEALLOC,nbCells,1);
2670 MCAuto<DataArrayIdType> n2o=o2n->invertArrayO2N2N2O(nbCells);
2671 const mcIdType *n2oPtr=n2o->begin();
2672 MCAuto<DataArrayIdType> newConn=DataArrayIdType::New();
2673 newConn->alloc(_nodal_connec->getNumberOfTuples(),_nodal_connec->getNumberOfComponents());
2674 newConn->copyStringInfoFrom(*_nodal_connec);
2675 MCAuto<DataArrayIdType> newConnI=DataArrayIdType::New();
2676 newConnI->alloc(_nodal_connec_index->getNumberOfTuples(),_nodal_connec_index->getNumberOfComponents());
2677 newConnI->copyStringInfoFrom(*_nodal_connec_index);
2679 mcIdType *newC=newConn->getPointer();
2680 mcIdType *newCI=newConnI->getPointer();
2683 for(mcIdType i=0;i<nbCells;i++)
2685 mcIdType pos=n2oPtr[i];
2686 mcIdType nbOfElts=connI[pos+1]-connI[pos];
2687 newC=std::copy(conn+connI[pos],conn+connI[pos+1],newC);
2692 setConnectivity(newConn,newConnI);
2694 free(const_cast<mcIdType *>(array));
2698 * Finds cells whose bounding boxes intersect a given bounding box.
2699 * \param [in] bbox - an array defining the bounding box via coordinates of its
2700 * extremum points in "no interlace" mode, i.e. xMin, xMax, yMin, yMax, zMin,
2702 * \param [in] eps - a factor used to increase size of the bounding box of cell
2703 * before comparing it with \a bbox. This factor is multiplied by the maximal
2704 * extent of the bounding box of cell to produce an addition to this bounding box.
2705 * \return DataArrayIdType * - a new instance of DataArrayIdType holding ids for found
2706 * cells. The caller is to delete this array using decrRef() as it is no more
2708 * \throw If the coordinates array is not set.
2709 * \throw If the nodal connectivity of cells is not defined.
2711 * \if ENABLE_EXAMPLES
2712 * \ref cpp_mcumesh_getCellsInBoundingBox "Here is a C++ example".<br>
2713 * \ref py_mcumesh_getCellsInBoundingBox "Here is a Python example".
2716 DataArrayIdType *MEDCouplingUMesh::getCellsInBoundingBox(const double *bbox, double eps) const
2718 MCAuto<DataArrayIdType> elems=DataArrayIdType::New(); elems->alloc(0,1);
2719 if(getMeshDimension()==-1)
2721 elems->pushBackSilent(0);
2722 return elems.retn();
2724 int dim=getSpaceDimension();
2725 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2726 const mcIdType* conn = getNodalConnectivity()->getConstPointer();
2727 const mcIdType* conn_index= getNodalConnectivityIndex()->getConstPointer();
2728 const double* coords = getCoords()->getConstPointer();
2729 mcIdType nbOfCells=getNumberOfCells();
2730 for ( mcIdType ielem=0; ielem<nbOfCells;ielem++ )
2732 for (int i=0; i<dim; i++)
2734 elem_bb[i*2]=std::numeric_limits<double>::max();
2735 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2738 for (mcIdType inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2740 mcIdType node= conn[inode];
2741 if(node>=0)//avoid polyhedron separator
2743 for (int idim=0; idim<dim; idim++)
2745 if ( coords[node*dim+idim] < elem_bb[idim*2] )
2747 elem_bb[idim*2] = coords[node*dim+idim] ;
2749 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2751 elem_bb[idim*2+1] = coords[node*dim+idim] ;
2756 if (intersectsBoundingBox(elem_bb, bbox, dim, eps))
2757 elems->pushBackSilent(ielem);
2759 return elems.retn();
2763 * Given a boundary box 'bbox' returns elements 'elems' contained in this 'bbox' or touching 'bbox' (within 'eps' distance).
2764 * Warning 'elems' is incremented during the call so if elems is not empty before call returned elements will be
2765 * added in 'elems' parameter.
2767 DataArrayIdType *MEDCouplingUMesh::getCellsInBoundingBox(const INTERP_KERNEL::DirectedBoundingBox& bbox, double eps)
2769 MCAuto<DataArrayIdType> elems=DataArrayIdType::New(); elems->alloc(0,1);
2770 if(getMeshDimension()==-1)
2772 elems->pushBackSilent(0);
2773 return elems.retn();
2775 int dim=getSpaceDimension();
2776 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2777 const mcIdType* conn = getNodalConnectivity()->getConstPointer();
2778 const mcIdType* conn_index= getNodalConnectivityIndex()->getConstPointer();
2779 const double* coords = getCoords()->getConstPointer();
2780 mcIdType nbOfCells=getNumberOfCells();
2781 for ( mcIdType ielem=0; ielem<nbOfCells;ielem++ )
2783 for (int i=0; i<dim; i++)
2785 elem_bb[i*2]=std::numeric_limits<double>::max();
2786 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2789 for (mcIdType inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2791 mcIdType node= conn[inode];
2792 if(node>=0)//avoid polyhedron separator
2794 for (int idim=0; idim<dim; idim++)
2796 if ( coords[node*dim+idim] < elem_bb[idim*2] )
2798 elem_bb[idim*2] = coords[node*dim+idim] ;
2800 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2802 elem_bb[idim*2+1] = coords[node*dim+idim] ;
2807 if(intersectsBoundingBox(bbox, elem_bb, dim, eps))
2808 elems->pushBackSilent(ielem);
2810 return elems.retn();
2814 * Returns a type of a cell by its id.
2815 * \param [in] cellId - the id of the cell of interest.
2816 * \return INTERP_KERNEL::NormalizedCellType - enumeration item describing the cell type.
2817 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2819 INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::getTypeOfCell(mcIdType cellId) const
2821 const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
2822 if(cellId<_nodal_connec_index->getNbOfElems()-1)
2823 return (INTERP_KERNEL::NormalizedCellType) pt[ptI[cellId]];
2826 std::ostringstream oss; oss << "MEDCouplingUMesh::getTypeOfCell : Requesting type of cell #" << cellId << " but it should be in [0," << _nodal_connec_index->getNbOfElems()-1 << ") !";
2827 throw INTERP_KERNEL::Exception(oss.str());
2832 * This method returns a newly allocated array containing cell ids (ascendingly sorted) whose geometric type are equal to type.
2833 * This method does not throw exception if geometric type \a type is not in \a this.
2834 * This method throws an INTERP_KERNEL::Exception if meshdimension of \b this is not equal to those of \b type.
2835 * The coordinates array is not considered here.
2837 * \param [in] type the geometric type
2838 * \return cell ids in this having geometric type \a type.
2840 DataArrayIdType *MEDCouplingUMesh::giveCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2843 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
2845 checkConnectivityFullyDefined();
2846 mcIdType nbCells=getNumberOfCells();
2847 int mdim=getMeshDimension();
2848 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
2849 if(mdim!=ToIdType(cm.getDimension()))
2850 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::giveCellsWithType : Mismatch between mesh dimension and dimension of the cell !");
2851 const mcIdType *ptI=_nodal_connec_index->getConstPointer();
2852 const mcIdType *pt=_nodal_connec->getConstPointer();
2853 for(mcIdType i=0;i<nbCells;i++)
2855 if((INTERP_KERNEL::NormalizedCellType)pt[ptI[i]]==type)
2856 ret->pushBackSilent(i);
2862 * Returns nb of cells having the geometric type \a type. No throw if no cells in \a this has the geometric type \a type.
2864 mcIdType MEDCouplingUMesh::getNumberOfCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2866 const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
2867 mcIdType nbOfCells(getNumberOfCells()),ret(0);
2868 for(mcIdType i=0;i<nbOfCells;i++)
2869 if((INTERP_KERNEL::NormalizedCellType) pt[ptI[i]]==type)
2875 * Returns the nodal connectivity of a given cell.
2876 * The separator of faces within polyhedron connectivity (-1) is not returned, thus
2877 * all returned node ids can be used in getCoordinatesOfNode().
2878 * \param [in] cellId - an id of the cell of interest.
2879 * \param [in,out] conn - a vector where the node ids are appended. It is not
2880 * cleared before the appending.
2881 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2883 void MEDCouplingUMesh::getNodeIdsOfCell(mcIdType cellId, std::vector<mcIdType>& conn) const
2885 const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
2886 for(const mcIdType *w=pt+ptI[cellId]+1;w!=pt+ptI[cellId+1];w++)
2891 std::string MEDCouplingUMesh::simpleRepr() const
2893 static const char msg0[]="No coordinates specified !";
2894 std::ostringstream ret;
2895 ret << "Unstructured mesh with name : \"" << getName() << "\"\n";
2896 ret << "Description of mesh : \"" << getDescription() << "\"\n";
2898 double tt=getTime(tmpp1,tmpp2);
2899 ret << "Time attached to the mesh [unit] : " << tt << " [" << getTimeUnit() << "]\n";
2900 ret << "Iteration : " << tmpp1 << " Order : " << tmpp2 << "\n";
2902 { ret << "Mesh dimension : " << _mesh_dim << "\nSpace dimension : "; }
2904 { ret << " Mesh dimension has not been set or is invalid !"; }
2907 const int spaceDim=getSpaceDimension();
2908 ret << spaceDim << "\nInfo attached on space dimension : ";
2909 for(int i=0;i<spaceDim;i++)
2910 ret << "\"" << _coords->getInfoOnComponent(i) << "\" ";
2914 ret << msg0 << "\n";
2915 ret << "Number of nodes : ";
2917 ret << getNumberOfNodes() << "\n";
2919 ret << msg0 << "\n";
2920 ret << "Number of cells : ";
2921 if(_nodal_connec!=0 && _nodal_connec_index!=0)
2922 ret << getNumberOfCells() << "\n";
2924 ret << "No connectivity specified !" << "\n";
2925 ret << "Cell types present : ";
2926 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
2928 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter);
2929 ret << cm.getRepr() << " ";
2935 std::string MEDCouplingUMesh::advancedRepr() const
2937 std::ostringstream ret;
2938 ret << simpleRepr();
2939 ret << "\nCoordinates array : \n___________________\n\n";
2941 _coords->reprWithoutNameStream(ret);
2943 ret << "No array set !\n";
2944 ret << "\n\nConnectivity arrays : \n_____________________\n\n";
2945 reprConnectivityOfThisLL(ret);
2950 * This method returns a C++ code that is a dump of \a this.
2951 * This method will throw if this is not fully defined.
2953 std::string MEDCouplingUMesh::cppRepr() const
2955 static const char coordsName[]="coords";
2956 static const char connName[]="conn";
2957 static const char connIName[]="connI";
2958 checkFullyDefined();
2959 std::ostringstream ret; ret << "// coordinates" << std::endl;
2960 _coords->reprCppStream(coordsName,ret); ret << std::endl << "// connectivity" << std::endl;
2961 _nodal_connec->reprCppStream(connName,ret); ret << std::endl;
2962 _nodal_connec_index->reprCppStream(connIName,ret); ret << std::endl;
2963 ret << "MEDCouplingUMesh *mesh=MEDCouplingUMesh::New(\"" << getName() << "\"," << getMeshDimension() << ");" << std::endl;
2964 ret << "mesh->setCoords(" << coordsName << ");" << std::endl;
2965 ret << "mesh->setConnectivity(" << connName << "," << connIName << ",true);" << std::endl;
2966 ret << coordsName << "->decrRef(); " << connName << "->decrRef(); " << connIName << "->decrRef();" << std::endl;
2970 std::string MEDCouplingUMesh::reprConnectivityOfThis() const
2972 std::ostringstream ret;
2973 reprConnectivityOfThisLL(ret);
2978 * This method builds a newly allocated instance (with the same name than \a this) that the caller has the responsibility to deal with.
2979 * This method returns an instance with all arrays allocated (connectivity, connectivity index, coordinates)
2980 * but with length of these arrays set to 0. It allows to define an "empty" mesh (with nor cells nor nodes but compliant with
2983 * This method expects that \a this has a mesh dimension set and higher or equal to 0. If not an exception will be thrown.
2984 * 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
2985 * with number of tuples set to 0, if not the array is taken as this in the returned instance.
2987 MEDCouplingUMesh *MEDCouplingUMesh::buildSetInstanceFromThis(std::size_t spaceDim) const
2989 int mdim=getMeshDimension();
2991 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSetInstanceFromThis : invalid mesh dimension ! Should be >= 0 !");
2992 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
2993 MCAuto<DataArrayIdType> tmp1,tmp2;
2994 bool needToCpyCT=true;
2997 tmp1=DataArrayIdType::New(); tmp1->alloc(0,1);
3005 if(!_nodal_connec_index)
3007 tmp2=DataArrayIdType::New(); tmp2->alloc(1,1); tmp2->setIJ(0,0,0);
3012 tmp2=_nodal_connec_index;
3015 ret->setConnectivity(tmp1,tmp2,false);
3020 MCAuto<DataArrayDouble> coords=DataArrayDouble::New(); coords->alloc(0,spaceDim);
3021 ret->setCoords(coords);
3024 ret->setCoords(_coords);
3028 mcIdType MEDCouplingUMesh::getNumberOfNodesInCell(mcIdType cellId) const
3030 const mcIdType *ptI=_nodal_connec_index->getConstPointer();
3031 const mcIdType *pt=_nodal_connec->getConstPointer();
3032 if(pt[ptI[cellId]]!=INTERP_KERNEL::NORM_POLYHED)
3033 return ptI[cellId+1]-ptI[cellId]-1;
3035 return ToIdType(std::count_if(pt+ptI[cellId]+1,pt+ptI[cellId+1],std::bind(std::not_equal_to<mcIdType>(),std::placeholders::_1,-1)));
3039 * Returns types of cells of the specified part of \a this mesh.
3040 * This method avoids computing sub-mesh explicitly to get its types.
3041 * \param [in] begin - an array of cell ids of interest.
3042 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3043 * \return std::set<INTERP_KERNEL::NormalizedCellType> - a set of enumeration items
3044 * describing the cell types.
3045 * \throw If the coordinates array is not set.
3046 * \throw If the nodal connectivity of cells is not defined.
3047 * \sa getAllGeoTypes()
3049 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getTypesOfPart(const mcIdType *begin, const mcIdType *end) const
3051 checkFullyDefined();
3052 std::set<INTERP_KERNEL::NormalizedCellType> ret;
3053 const mcIdType *conn=_nodal_connec->getConstPointer();
3054 const mcIdType *connIndex=_nodal_connec_index->getConstPointer();
3055 for(const mcIdType *w=begin;w!=end;w++)
3056 ret.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]);
3061 * Defines the nodal connectivity using given connectivity arrays in \ref numbering-indirect format.
3062 * Optionally updates
3063 * a set of types of cells constituting \a this mesh.
3064 * This method is for advanced users having prepared their connectivity before. For
3065 * more info on using this method see \ref MEDCouplingUMeshAdvBuild.
3066 * \param [in] conn - the nodal connectivity array.
3067 * \param [in] connIndex - the nodal connectivity index array.
3068 * \param [in] isComputingTypes - if \c true, the set of types constituting \a this
3071 void MEDCouplingUMesh::setConnectivity(DataArrayIdType *conn, DataArrayIdType *connIndex, bool isComputingTypes)
3073 DataArrayIdType::SetArrayIn(conn,_nodal_connec);
3074 DataArrayIdType::SetArrayIn(connIndex,_nodal_connec_index);
3075 if(isComputingTypes)
3081 * Copy constructor. If 'deepCopy' is false \a this is a shallow copy of other.
3082 * If 'deeCpy' is true all arrays (coordinates and connectivities) are deeply copied.
3084 MEDCouplingUMesh::MEDCouplingUMesh(const MEDCouplingUMesh& other, bool deepCpy):MEDCouplingPointSet(other,deepCpy),_mesh_dim(other._mesh_dim),
3085 _nodal_connec(0),_nodal_connec_index(0),
3086 _types(other._types)
3088 if(other._nodal_connec)
3089 _nodal_connec=other._nodal_connec->performCopyOrIncrRef(deepCpy);
3090 if(other._nodal_connec_index)
3091 _nodal_connec_index=other._nodal_connec_index->performCopyOrIncrRef(deepCpy);
3094 MEDCouplingUMesh::~MEDCouplingUMesh()
3097 _nodal_connec->decrRef();
3098 if(_nodal_connec_index)
3099 _nodal_connec_index->decrRef();
3103 * Recomputes a set of cell types of \a this mesh. For more info see
3104 * \ref MEDCouplingUMeshNodalConnectivity.
3106 void MEDCouplingUMesh::computeTypes()
3108 ComputeAllTypesInternal(_types,_nodal_connec,_nodal_connec_index);
3113 * Returns a number of cells constituting \a this mesh.
3114 * \return mcIdType - the number of cells in \a this mesh.
3115 * \throw If the nodal connectivity of cells is not defined.
3117 mcIdType MEDCouplingUMesh::getNumberOfCells() const
3119 if(_nodal_connec_index)
3120 return _nodal_connec_index->getNumberOfTuples()-1;
3125 throw INTERP_KERNEL::Exception("Unable to get number of cells because no connectivity specified !");
3129 * Returns a dimension of \a this mesh, i.e. a dimension of cells constituting \a this
3130 * mesh. For more info see \ref meshes.
3131 * \return int - the dimension of \a this mesh.
3132 * \throw If the mesh dimension is not defined using setMeshDimension().
3134 int MEDCouplingUMesh::getMeshDimension() const
3137 throw INTERP_KERNEL::Exception("No mesh dimension specified !");
3142 * Returns a length of the nodal connectivity array.
3143 * This method is for test reason. Normally the integer returned is not useable by
3144 * user. For more info see \ref MEDCouplingUMeshNodalConnectivity.
3145 * \return mcIdType - the length of the nodal connectivity array.
3147 mcIdType MEDCouplingUMesh::getNodalConnectivityArrayLen() const
3149 return _nodal_connec->getNbOfElems();
3153 * First step of serialization process. Used by ParaMEDMEM and MEDCouplingCorba to transfert data between process.
3155 void MEDCouplingUMesh::getTinySerializationInformation(std::vector<double>& tinyInfoD, std::vector<mcIdType>& tinyInfo, std::vector<std::string>& littleStrings) const
3157 MEDCouplingPointSet::getTinySerializationInformation(tinyInfoD,tinyInfo,littleStrings);
3158 tinyInfo.push_back(ToIdType(getMeshDimension()));
3159 tinyInfo.push_back(getNumberOfCells());
3161 tinyInfo.push_back(getNodalConnectivityArrayLen());
3163 tinyInfo.push_back(-1);
3167 * First step of unserialization process.
3169 bool MEDCouplingUMesh::isEmptyMesh(const std::vector<mcIdType>& tinyInfo) const
3171 return tinyInfo[6]<=0;
3175 * Second step of serialization process.
3176 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3177 * \param a1 DataArrayDouble
3178 * \param a2 DataArrayDouble
3179 * \param littleStrings string vector
3181 void MEDCouplingUMesh::resizeForUnserialization(const std::vector<mcIdType>& tinyInfo, DataArrayIdType *a1, DataArrayDouble *a2, std::vector<std::string>& littleStrings) const
3183 MEDCouplingPointSet::resizeForUnserialization(tinyInfo,a1,a2,littleStrings);
3185 a1->alloc(tinyInfo[7]+tinyInfo[6]+1,1);
3189 * Third and final step of serialization process.
3191 void MEDCouplingUMesh::serialize(DataArrayIdType *&a1, DataArrayDouble *&a2) const
3193 MEDCouplingPointSet::serialize(a1,a2);
3194 if(getMeshDimension()>-1)
3196 a1=DataArrayIdType::New();
3197 a1->alloc(getNodalConnectivityArrayLen()+getNumberOfCells()+1,1);
3198 mcIdType *ptA1=a1->getPointer();
3199 const mcIdType *conn=getNodalConnectivity()->getConstPointer();
3200 const mcIdType *index=getNodalConnectivityIndex()->getConstPointer();
3201 ptA1=std::copy(index,index+getNumberOfCells()+1,ptA1);
3202 std::copy(conn,conn+getNodalConnectivityArrayLen(),ptA1);
3209 * Second and final unserialization process.
3210 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3212 void MEDCouplingUMesh::unserialization(const std::vector<double>& tinyInfoD, const std::vector<mcIdType>& tinyInfo, const DataArrayIdType *a1, DataArrayDouble *a2, const std::vector<std::string>& littleStrings)
3214 MEDCouplingPointSet::unserialization(tinyInfoD,tinyInfo,a1,a2,littleStrings);
3215 setMeshDimension(FromIdType<int>(tinyInfo[5]));
3219 const mcIdType *recvBuffer=a1->getConstPointer();
3220 MCAuto<DataArrayIdType> myConnecIndex=DataArrayIdType::New();
3221 myConnecIndex->alloc(tinyInfo[6]+1,1);
3222 std::copy(recvBuffer,recvBuffer+tinyInfo[6]+1,myConnecIndex->getPointer());
3223 MCAuto<DataArrayIdType> myConnec=DataArrayIdType::New();
3224 myConnec->alloc(tinyInfo[7],1);
3225 std::copy(recvBuffer+tinyInfo[6]+1,recvBuffer+tinyInfo[6]+1+tinyInfo[7],myConnec->getPointer());
3226 setConnectivity(myConnec, myConnecIndex);
3233 * Returns a new MEDCouplingFieldDouble containing volumes of cells constituting \a this
3235 * For 1D cells, the returned field contains lengths.<br>
3236 * For 2D cells, the returned field contains areas.<br>
3237 * For 3D cells, the returned field contains volumes.
3238 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3239 * orientation, i.e. the volume is always positive.
3240 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on cells
3241 * and one time . The caller is to delete this field using decrRef() as it is no
3244 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureField(bool isAbs) const
3246 std::string name="MeasureOfMesh_";
3248 mcIdType nbelem=getNumberOfCells();
3249 MCAuto<MEDCouplingFieldDouble> field=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3250 field->setName(name);
3251 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3252 array->alloc(nbelem,1);
3253 double *area_vol=array->getPointer();
3254 field->setArray(array) ; array=0;
3255 field->setMesh(const_cast<MEDCouplingUMesh *>(this));
3256 field->synchronizeTimeWithMesh();
3257 if(getMeshDimension()!=-1)
3260 INTERP_KERNEL::NormalizedCellType type;
3261 int dim_space=getSpaceDimension();
3262 const double *coords=getCoords()->getConstPointer();
3263 const mcIdType *connec=getNodalConnectivity()->getConstPointer();
3264 const mcIdType *connec_index=getNodalConnectivityIndex()->getConstPointer();
3265 for(mcIdType iel=0;iel<nbelem;iel++)
3267 ipt=connec_index[iel];
3268 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3269 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);
3272 std::transform(area_vol,area_vol+nbelem,area_vol,[](double c){return fabs(c);});
3276 area_vol[0]=std::numeric_limits<double>::max();
3278 return field.retn();
3282 * Returns a new DataArrayDouble containing volumes of specified cells of \a this
3284 * For 1D cells, the returned array contains lengths.<br>
3285 * For 2D cells, the returned array contains areas.<br>
3286 * For 3D cells, the returned array contains volumes.
3287 * This method avoids building explicitly a part of \a this mesh to perform the work.
3288 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3289 * orientation, i.e. the volume is always positive.
3290 * \param [in] begin - an array of cell ids of interest.
3291 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3292 * \return DataArrayDouble * - a new instance of DataArrayDouble. The caller is to
3293 * delete this array using decrRef() as it is no more needed.
3295 * \if ENABLE_EXAMPLES
3296 * \ref cpp_mcumesh_getPartMeasureField "Here is a C++ example".<br>
3297 * \ref py_mcumesh_getPartMeasureField "Here is a Python example".
3299 * \sa getMeasureField()
3301 DataArrayDouble *MEDCouplingUMesh::getPartMeasureField(bool isAbs, const mcIdType *begin, const mcIdType *end) const
3303 std::string name="PartMeasureOfMesh_";
3305 std::size_t nbelem=std::distance(begin,end);
3306 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3307 array->setName(name);
3308 array->alloc(nbelem,1);
3309 double *area_vol=array->getPointer();
3310 if(getMeshDimension()!=-1)
3313 INTERP_KERNEL::NormalizedCellType type;
3314 int dim_space=getSpaceDimension();
3315 const double *coords=getCoords()->getConstPointer();
3316 const mcIdType *connec=getNodalConnectivity()->getConstPointer();
3317 const mcIdType *connec_index=getNodalConnectivityIndex()->getConstPointer();
3318 for(const mcIdType *iel=begin;iel!=end;iel++)
3320 ipt=connec_index[*iel];
3321 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3322 *area_vol++=INTERP_KERNEL::computeVolSurfOfCell2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,connec+ipt+1,connec_index[*iel+1]-ipt-1,coords,dim_space);
3325 std::transform(array->getPointer(),area_vol,array->getPointer(),[](double c){return fabs(c);});
3329 area_vol[0]=std::numeric_limits<double>::max();
3331 return array.retn();
3335 * Returns a new MEDCouplingFieldDouble containing volumes of cells of a dual mesh of
3336 * \a this one. The returned field contains the dual cell volume for each corresponding
3337 * node in \a this mesh. In other words, the field returns the getMeasureField() of
3338 * the dual mesh in P1 sens of \a this.<br>
3339 * For 1D cells, the returned field contains lengths.<br>
3340 * For 2D cells, the returned field contains areas.<br>
3341 * For 3D cells, the returned field contains volumes.
3342 * This method is useful to check "P1*" conservative interpolators.
3343 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3344 * orientation, i.e. the volume is always positive.
3345 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3346 * nodes and one time. The caller is to delete this array using decrRef() as
3347 * it is no more needed.
3349 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureFieldOnNode(bool isAbs) const
3351 MCAuto<MEDCouplingFieldDouble> tmp=getMeasureField(isAbs);
3352 std::string name="MeasureOnNodeOfMesh_";
3354 mcIdType nbNodes=getNumberOfNodes();
3355 MCAuto<DataArrayDouble> nnpc;
3357 MCAuto<DataArrayIdType> tmp2(computeNbOfNodesPerCell());
3358 nnpc=tmp2->convertToDblArr();
3360 std::for_each(nnpc->rwBegin(),nnpc->rwEnd(),[](double& v) { v=1./v; });
3361 const double *nnpcPtr(nnpc->begin());
3362 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_NODES);
3363 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3364 array->alloc(nbNodes,1);
3365 double *valsToFill=array->getPointer();
3366 std::fill(valsToFill,valsToFill+nbNodes,0.);
3367 const double *values=tmp->getArray()->getConstPointer();
3368 MCAuto<DataArrayIdType> da=DataArrayIdType::New();
3369 MCAuto<DataArrayIdType> daInd=DataArrayIdType::New();
3370 getReverseNodalConnectivity(da,daInd);
3371 const mcIdType *daPtr=da->getConstPointer();
3372 const mcIdType *daIPtr=daInd->getConstPointer();
3373 for(mcIdType i=0;i<nbNodes;i++)
3374 for(const mcIdType *cell=daPtr+daIPtr[i];cell!=daPtr+daIPtr[i+1];cell++)
3375 valsToFill[i]+=nnpcPtr[*cell]*values[*cell];
3377 ret->setArray(array);
3382 * Returns a new MEDCouplingFieldDouble holding normal vectors to cells of \a this
3383 * mesh. The returned normal vectors to each cell have a norm2 equal to 1.
3384 * The computed vectors have <em> this->getMeshDimension()+1 </em> components
3385 * and are normalized.
3386 * <br> \a this can be either
3387 * - a 2D mesh in 2D or 3D space or
3388 * - an 1D mesh in 2D space.
3390 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3391 * cells and one time. The caller is to delete this field using decrRef() as
3392 * it is no more needed.
3393 * \throw If the nodal connectivity of cells is not defined.
3394 * \throw If the coordinates array is not set.
3395 * \throw If the mesh dimension is not set.
3396 * \throw If the mesh and space dimension is not as specified above.
3398 MEDCouplingFieldDouble *MEDCouplingUMesh::buildOrthogonalField() const
3400 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3401 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3402 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3403 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3404 mcIdType nbOfCells=getNumberOfCells();
3405 int nbComp=getMeshDimension()+1;
3406 array->alloc(nbOfCells,nbComp);
3407 double *vals=array->getPointer();
3408 const mcIdType *connI=_nodal_connec_index->getConstPointer();
3409 const mcIdType *conn=_nodal_connec->getConstPointer();
3410 const double *coords=_coords->getConstPointer();
3411 if(getMeshDimension()==2)
3413 if(getSpaceDimension()==3)
3415 MCAuto<DataArrayDouble> loc=computeCellCenterOfMass();
3416 const double *locPtr=loc->getConstPointer();
3417 for(mcIdType i=0;i<nbOfCells;i++,vals+=3)
3419 mcIdType offset=connI[i];
3420 INTERP_KERNEL::crossprod<3>(locPtr+3*i,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3421 double n=INTERP_KERNEL::norm<3>(vals);
3422 std::transform(vals,vals+3,vals,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3427 MCAuto<MEDCouplingFieldDouble> isAbs=getMeasureField(false);
3428 const double *isAbsPtr=isAbs->getArray()->begin();
3429 for(mcIdType i=0;i<nbOfCells;i++,isAbsPtr++)
3430 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=*isAbsPtr>0.?1.:-1.; }
3433 else//meshdimension==1
3436 for(mcIdType i=0;i<nbOfCells;i++)
3438 mcIdType offset=connI[i];
3439 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3440 double n=INTERP_KERNEL::norm<2>(tmp);
3441 std::transform(tmp,tmp+2,tmp,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3446 ret->setArray(array);
3448 ret->synchronizeTimeWithSupport();
3453 * Returns a new MEDCouplingFieldDouble holding normal vectors to specified cells of
3454 * \a this mesh. The computed vectors have <em> this->getMeshDimension()+1 </em> components
3455 * and are normalized.
3456 * <br> \a this can be either
3457 * - a 2D mesh in 2D or 3D space or
3458 * - an 1D mesh in 2D space.
3460 * This method avoids building explicitly a part of \a this mesh to perform the work.
3461 * \param [in] begin - an array of cell ids of interest.
3462 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3463 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3464 * cells and one time. The caller is to delete this field using decrRef() as
3465 * it is no more needed.
3466 * \throw If the nodal connectivity of cells is not defined.
3467 * \throw If the coordinates array is not set.
3468 * \throw If the mesh dimension is not set.
3469 * \throw If the mesh and space dimension is not as specified above.
3470 * \sa buildOrthogonalField()
3472 * \if ENABLE_EXAMPLES
3473 * \ref cpp_mcumesh_buildPartOrthogonalField "Here is a C++ example".<br>
3474 * \ref py_mcumesh_buildPartOrthogonalField "Here is a Python example".
3477 MEDCouplingFieldDouble *MEDCouplingUMesh::buildPartOrthogonalField(const mcIdType *begin, const mcIdType *end) const
3479 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3480 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3481 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3482 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3483 std::size_t nbelems=std::distance(begin,end);
3484 int nbComp=getMeshDimension()+1;
3485 array->alloc(nbelems,nbComp);
3486 double *vals=array->getPointer();
3487 const mcIdType *connI=_nodal_connec_index->getConstPointer();
3488 const mcIdType *conn=_nodal_connec->getConstPointer();
3489 const double *coords=_coords->getConstPointer();
3490 if(getMeshDimension()==2)
3492 if(getSpaceDimension()==3)
3494 MCAuto<DataArrayDouble> loc=getPartBarycenterAndOwner(begin,end);
3495 const double *locPtr=loc->getConstPointer();
3496 for(const mcIdType *i=begin;i!=end;i++,vals+=3,locPtr+=3)
3498 mcIdType offset=connI[*i];
3499 INTERP_KERNEL::crossprod<3>(locPtr,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3500 double n=INTERP_KERNEL::norm<3>(vals);
3501 std::transform(vals,vals+3,vals,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3506 for(std::size_t i=0;i<nbelems;i++)
3507 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=1.; }
3510 else//meshdimension==1
3513 for(const mcIdType *i=begin;i!=end;i++)
3515 mcIdType offset=connI[*i];
3516 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3517 double n=INTERP_KERNEL::norm<2>(tmp);
3518 std::transform(tmp,tmp+2,tmp,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3523 ret->setArray(array);
3525 ret->synchronizeTimeWithSupport();
3530 * Returns a new MEDCouplingFieldDouble holding a direction vector for each SEG2 in \a
3531 * this 1D mesh. The computed vectors have <em> this->getSpaceDimension() </em> components
3532 * and are \b not normalized.
3533 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3534 * cells and one time. The caller is to delete this field using decrRef() as
3535 * it is no more needed.
3536 * \throw If the nodal connectivity of cells is not defined.
3537 * \throw If the coordinates array is not set.
3538 * \throw If \a this->getMeshDimension() != 1.
3539 * \throw If \a this mesh includes cells of type other than SEG2.
3541 MEDCouplingFieldDouble *MEDCouplingUMesh::buildDirectionVectorField() const
3543 if(getMeshDimension()!=1)
3544 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for buildDirectionVectorField !");
3545 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3546 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for buildDirectionVectorField !");
3547 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3548 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3549 mcIdType nbOfCells=getNumberOfCells();
3550 int spaceDim=getSpaceDimension();
3551 array->alloc(nbOfCells,spaceDim);
3552 double *pt=array->getPointer();
3553 const double *coo=getCoords()->getConstPointer();
3554 std::vector<mcIdType> conn;
3556 for(mcIdType i=0;i<nbOfCells;i++)
3559 getNodeIdsOfCell(i,conn);
3560 pt=std::transform(coo+conn[1]*spaceDim,coo+(conn[1]+1)*spaceDim,coo+conn[0]*spaceDim,pt,std::minus<double>());
3562 ret->setArray(array);
3564 ret->synchronizeTimeWithSupport();
3569 * Creates a 2D mesh by cutting \a this 3D mesh with a plane. In addition to the mesh,
3570 * returns a new DataArrayIdType, of length equal to the number of 2D cells in the result
3571 * mesh, holding, for each cell in the result mesh, an id of a 3D cell it comes
3572 * from. If a result face is shared by two 3D cells, then the face in included twice in
3574 * \param [in] origin - 3 components of a point defining location of the plane.
3575 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3576 * must be greater than 1e-6.
3577 * \param [in] eps - half-thickness of the plane.
3578 * \param [out] cellIds - a new instance of DataArrayIdType holding ids of 3D cells
3579 * producing correspondent 2D cells. The caller is to delete this array
3580 * using decrRef() as it is no more needed.
3581 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This mesh does
3582 * not share the node coordinates array with \a this mesh. The caller is to
3583 * delete this mesh using decrRef() as it is no more needed.
3584 * \throw If the coordinates array is not set.
3585 * \throw If the nodal connectivity of cells is not defined.
3586 * \throw If \a this->getMeshDimension() != 3 or \a this->getSpaceDimension() != 3.
3587 * \throw If magnitude of \a vec is less than 1e-6.
3588 * \throw If the plane does not intersect any 3D cell of \a this mesh.
3589 * \throw If \a this includes quadratic cells.
3591 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3D(const double *origin, const double *vec, double eps, DataArrayIdType *&cellIds) const
3593 checkFullyDefined();
3594 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3595 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3596 MCAuto<DataArrayIdType> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3597 if(candidates->empty())
3598 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane considering bounding boxes !");
3599 std::vector<mcIdType> nodes;
3600 DataArrayIdType *cellIds1D=0;
3601 MCAuto<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3602 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3603 MCAuto<DataArrayIdType> desc1=DataArrayIdType::New(),desc2=DataArrayIdType::New();
3604 MCAuto<DataArrayIdType> descIndx1=DataArrayIdType::New(),descIndx2=DataArrayIdType::New();
3605 MCAuto<DataArrayIdType> revDesc1=DataArrayIdType::New(),revDesc2=DataArrayIdType::New();
3606 MCAuto<DataArrayIdType> revDescIndx1=DataArrayIdType::New(),revDescIndx2=DataArrayIdType::New();
3607 MCAuto<MEDCouplingUMesh> mDesc2=subMesh->buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2);//meshDim==2 spaceDim==3
3608 revDesc2=0; revDescIndx2=0;
3609 MCAuto<MEDCouplingUMesh> mDesc1=mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3610 revDesc1=0; revDescIndx1=0;
3611 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3612 MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3614 std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3615 for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3617 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3618 std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(mDesc2->getNumberOfCells());
3619 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->getConstPointer(),mDesc2->getNodalConnectivityIndex()->getConstPointer(),
3620 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3621 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3622 MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New()),cellIds2(DataArrayIdType::New());
3623 connI->pushBackSilent(0); conn->alloc(0,1); cellIds2->alloc(0,1);
3624 subMesh->assemblyForSplitFrom3DSurf(cut3DSurf,desc2->getConstPointer(),descIndx2->getConstPointer(),conn,connI,cellIds2);
3625 if(cellIds2->empty())
3626 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3627 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3D",2);
3628 ret->setCoords(mDesc1->getCoords());
3629 ret->setConnectivity(conn,connI,true);
3630 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3635 * Creates an 1D mesh by cutting \a this 2D mesh in 3D space with a plane. In
3636 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
3637 from. If a result segment is shared by two 2D cells, then the segment in included twice in
3639 * \param [in] origin - 3 components of a point defining location of the plane.
3640 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3641 * must be greater than 1e-6.
3642 * \param [in] eps - half-thickness of the plane.
3643 * \param [out] cellIds - a new instance of DataArrayIdType holding ids of faces
3644 * producing correspondent segments. The caller is to delete this array
3645 * using decrRef() as it is no more needed.
3646 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This is an 1D
3647 * mesh in 3D space. This mesh does not share the node coordinates array with
3648 * \a this mesh. The caller is to delete this mesh using decrRef() as it is
3650 * \throw If the coordinates array is not set.
3651 * \throw If the nodal connectivity of cells is not defined.
3652 * \throw If \a this->getMeshDimension() != 2 or \a this->getSpaceDimension() != 3.
3653 * \throw If magnitude of \a vec is less than 1e-6.
3654 * \throw If the plane does not intersect any 2D cell of \a this mesh.
3655 * \throw If \a this includes quadratic cells.
3657 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3DSurf(const double *origin, const double *vec, double eps, DataArrayIdType *&cellIds) const
3659 checkFullyDefined();
3660 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
3661 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf works on umeshes with meshdim equal to 2 and spaceDim equal to 3 !");
3662 MCAuto<DataArrayIdType> candidates(getCellIdsCrossingPlane(origin,vec,eps));
3663 if(candidates->empty())
3664 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3D surf cells in this intercepts the specified plane considering bounding boxes !");
3665 std::vector<mcIdType> nodes;
3666 DataArrayIdType *cellIds1D(0);
3667 MCAuto<MEDCouplingUMesh> subMesh(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3668 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3669 MCAuto<DataArrayIdType> desc1(DataArrayIdType::New()),descIndx1(DataArrayIdType::New()),revDesc1(DataArrayIdType::New()),revDescIndx1(DataArrayIdType::New());
3670 MCAuto<MEDCouplingUMesh> mDesc1(subMesh->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3671 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3672 MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3674 std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3675 for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3677 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3678 mcIdType ncellsSub=subMesh->getNumberOfCells();
3679 std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(ncellsSub);
3680 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,subMesh->getNodalConnectivity()->getConstPointer(),subMesh->getNodalConnectivityIndex()->getConstPointer(),
3681 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3682 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3683 MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New()),cellIds2(DataArrayIdType::New()); connI->pushBackSilent(0);
3685 const mcIdType *nodal=subMesh->getNodalConnectivity()->getConstPointer();
3686 const mcIdType *nodalI=subMesh->getNodalConnectivityIndex()->getConstPointer();
3687 for(mcIdType i=0;i<ncellsSub;i++)
3689 if(cut3DSurf[i].first!=-1 && cut3DSurf[i].second!=-1)
3691 if(cut3DSurf[i].first!=-2)
3693 conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_SEG2)); conn->pushBackSilent(cut3DSurf[i].first); conn->pushBackSilent(cut3DSurf[i].second);
3694 connI->pushBackSilent(conn->getNumberOfTuples());
3695 cellIds2->pushBackSilent(i);
3699 mcIdType cellId3DSurf=cut3DSurf[i].second;
3700 mcIdType offset=nodalI[cellId3DSurf]+1;
3701 mcIdType nbOfEdges=nodalI[cellId3DSurf+1]-offset;
3702 for(mcIdType j=0;j<nbOfEdges;j++)
3704 conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_SEG2)); conn->pushBackSilent(nodal[offset+j]); conn->pushBackSilent(nodal[offset+(j+1)%nbOfEdges]);
3705 connI->pushBackSilent(conn->getNumberOfTuples());
3706 cellIds2->pushBackSilent(cellId3DSurf);
3711 if(cellIds2->empty())
3712 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3DSurf cells in this intercepts the specified plane !");
3713 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3DSurf",1);
3714 ret->setCoords(mDesc1->getCoords());
3715 ret->setConnectivity(conn,connI,true);
3716 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3720 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::clipSingle3DCellByPlane(const double origin[3], const double vec[3], double eps) const
3722 checkFullyDefined();
3723 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3724 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3725 if(getNumberOfCells()!=1)
3726 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works only on mesh containing exactly one cell !");
3728 std::vector<mcIdType> nodes;
3729 findNodesOnPlane(origin,vec,eps,nodes);
3730 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());
3731 MCAuto<MEDCouplingUMesh> mDesc2(buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2));//meshDim==2 spaceDim==3
3732 revDesc2=0; revDescIndx2=0;
3733 MCAuto<MEDCouplingUMesh> mDesc1(mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3734 revDesc1=0; revDescIndx1=0;
3735 DataArrayIdType *cellIds1D(0);
3736 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3737 MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3738 std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3739 for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3743 mcIdType oldNbNodes(mDesc1->getNumberOfNodes());
3744 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3745 sameNbNodes=(mDesc1->getNumberOfNodes()==oldNbNodes);
3747 std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(mDesc2->getNumberOfCells());
3748 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->begin(),mDesc2->getNodalConnectivityIndex()->begin(),
3749 mDesc1->getNodalConnectivity()->begin(),mDesc1->getNodalConnectivityIndex()->begin(),
3750 desc1->begin(),descIndx1->begin(),cut3DSurf);
3751 MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New());
3752 connI->pushBackSilent(0); conn->alloc(0,1);
3754 MCAuto<DataArrayIdType> cellIds2(DataArrayIdType::New()); cellIds2->alloc(0,1);
3755 assemblyForSplitFrom3DSurf(cut3DSurf,desc2->begin(),descIndx2->begin(),conn,connI,cellIds2);
3756 if(cellIds2->empty())
3757 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3759 std::vector<std::vector<mcIdType> > res;
3760 buildSubCellsFromCut(cut3DSurf,desc2->begin(),descIndx2->begin(),mDesc1->getCoords()->begin(),eps,res);
3761 std::size_t sz(res.size());
3762 if(ToIdType(res.size())==mDesc1->getNumberOfCells() && sameNbNodes)
3763 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane : cell is not clipped !");
3764 for(std::size_t i=0;i<sz;i++)
3766 conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYGON));
3767 conn->insertAtTheEnd(res[i].begin(),res[i].end());
3768 connI->pushBackSilent(conn->getNumberOfTuples());
3770 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
3771 ret->setCoords(mDesc1->getCoords());
3772 ret->setConnectivity(conn,connI,true);
3773 mcIdType nbCellsRet(ret->getNumberOfCells());
3775 MCAuto<DataArrayDouble> vec2(DataArrayDouble::New()); vec2->alloc(1,3); std::copy(vec,vec+3,vec2->getPointer());
3776 MCAuto<MEDCouplingFieldDouble> ortho(ret->buildOrthogonalField());
3777 MCAuto<DataArrayDouble> ortho2(ortho->getArray()->selectByTupleIdSafeSlice(0,1,1));
3778 MCAuto<DataArrayDouble> dott(DataArrayDouble::Dot(ortho2,vec2));
3779 MCAuto<DataArrayDouble> ccm(ret->computeCellCenterOfMass());
3780 MCAuto<DataArrayDouble> occm;
3782 MCAuto<DataArrayDouble> pt(DataArrayDouble::New()); pt->alloc(1,3); std::copy(origin,origin+3,pt->getPointer());
3783 occm=DataArrayDouble::Substract(ccm,pt);
3785 vec2=DataArrayDouble::New(); vec2->alloc(nbCellsRet,3);
3786 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);
3787 MCAuto<DataArrayDouble> dott2(DataArrayDouble::Dot(occm,vec2));
3789 const mcIdType *cPtr(ret->getNodalConnectivity()->begin()),*ciPtr(ret->getNodalConnectivityIndex()->begin());
3790 MCAuto<MEDCouplingUMesh> ret2(MEDCouplingUMesh::New("Clip3D",3));
3791 ret2->setCoords(mDesc1->getCoords());
3792 MCAuto<DataArrayIdType> conn2(DataArrayIdType::New()),conn2I(DataArrayIdType::New());
3793 conn2I->pushBackSilent(0); conn2->alloc(0,1);
3794 std::vector<mcIdType> cell0(1,ToIdType(INTERP_KERNEL::NORM_POLYHED));
3795 std::vector<mcIdType> cell1(1,ToIdType(INTERP_KERNEL::NORM_POLYHED));
3796 if(dott->getIJ(0,0)>0)
3798 cell0.insert(cell0.end(),cPtr+1,cPtr+ciPtr[1]);
3799 std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell1,cell1.end()));
3803 cell1.insert(cell1.end(),cPtr+1,cPtr+ciPtr[1]);
3804 std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell0,cell0.end()));
3806 for(mcIdType i=1;i<nbCellsRet;i++)
3808 if(dott2->getIJ(i,0)<0)
3810 if(ciPtr[i+1]-ciPtr[i]>=4)
3812 cell0.push_back(-1);
3813 cell0.insert(cell0.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
3818 if(ciPtr[i+1]-ciPtr[i]>=4)
3820 cell1.push_back(-1);
3821 cell1.insert(cell1.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
3825 conn2->insertAtTheEnd(cell0.begin(),cell0.end());
3826 conn2I->pushBackSilent(conn2->getNumberOfTuples());
3827 conn2->insertAtTheEnd(cell1.begin(),cell1.end());
3828 conn2I->pushBackSilent(conn2->getNumberOfTuples());
3829 ret2->setConnectivity(conn2,conn2I,true);
3830 ret2->checkConsistencyLight();
3831 ret2->orientCorrectlyPolyhedrons();
3836 * Finds cells whose bounding boxes intersect a given plane.
3837 * \param [in] origin - 3 components of a point defining location of the plane.
3838 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3839 * must be greater than 1e-6.
3840 * \param [in] eps - half-thickness of the plane.
3841 * \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of the found
3842 * cells. The caller is to delete this array using decrRef() as it is no more
3844 * \throw If the coordinates array is not set.
3845 * \throw If the nodal connectivity of cells is not defined.
3846 * \throw If \a this->getSpaceDimension() != 3.
3847 * \throw If magnitude of \a vec is less than 1e-6.
3848 * \sa buildSlice3D()
3850 DataArrayIdType *MEDCouplingUMesh::getCellIdsCrossingPlane(const double *origin, const double *vec, double eps) const
3852 checkFullyDefined();
3853 if(getSpaceDimension()!=3)
3854 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with spaceDim equal to 3 !");
3855 double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
3857 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellIdsCrossingPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
3859 vec2[0]=vec[1]; vec2[1]=-vec[0]; vec2[2]=0.;//vec2 is the result of cross product of vec with (0,0,1)
3860 double angle=acos(vec[2]/normm);
3861 MCAuto<DataArrayIdType> cellIds;
3865 MCAuto<DataArrayDouble> coo=_coords->deepCopy();
3866 double normm2(sqrt(vec2[0]*vec2[0]+vec2[1]*vec2[1]+vec2[2]*vec2[2]));
3867 if(normm2/normm>1e-6)
3868 DataArrayDouble::Rotate3DAlg(origin,vec2,angle,coo->getNumberOfTuples(),coo->getPointer(),coo->getPointer());
3869 MCAuto<MEDCouplingUMesh> mw=clone(false);//false -> shallow copy
3871 mw->getBoundingBox(bbox);
3872 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3873 cellIds=mw->getCellsInBoundingBox(bbox,eps);
3877 getBoundingBox(bbox);
3878 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3879 cellIds=getCellsInBoundingBox(bbox,eps);
3881 return cellIds.retn();
3885 * This method checks that \a this is a contiguous mesh. The user is expected to call this method on a mesh with meshdim==1.
3886 * If not an exception will thrown. If this is an empty mesh with no cell an exception will be thrown too.
3887 * No consideration of coordinate is done by this method.
3888 * 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)
3889 * If not false is returned. In case that false is returned a call to MEDCoupling::MEDCouplingUMesh::mergeNodes could be useful.
3891 bool MEDCouplingUMesh::isContiguous1D() const
3893 if(getMeshDimension()!=1)
3894 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense only for 1D mesh !");
3895 mcIdType nbCells=getNumberOfCells();
3897 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense for non empty mesh !");
3898 const mcIdType *connI(_nodal_connec_index->begin()),*conn(_nodal_connec->begin());
3899 mcIdType ref=conn[connI[0]+2];
3900 for(mcIdType i=1;i<nbCells;i++)
3902 if(conn[connI[i]+1]!=ref)
3904 ref=conn[connI[i]+2];
3910 * This method is only callable on mesh with meshdim == 1 containing only SEG2 and spaceDim==3.
3911 * This method projects this on the 3D line defined by (pt,v). This methods first checks that all SEG2 are along v vector.
3912 * \param pt reference point of the line
3913 * \param v normalized director vector of the line
3914 * \param eps max precision before throwing an exception
3915 * \param res output of size this->getNumberOfCells
3917 void MEDCouplingUMesh::project1D(const double *pt, const double *v, double eps, double *res) const
3919 if(getMeshDimension()!=1)
3920 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for project1D !");
3921 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3922 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for project1D !");
3923 if(getSpaceDimension()!=3)
3924 throw INTERP_KERNEL::Exception("Expected a umesh with spaceDim==3 for project1D !");
3925 MCAuto<MEDCouplingFieldDouble> f=buildDirectionVectorField();
3926 const double *fPtr=f->getArray()->getConstPointer();
3928 for(mcIdType i=0;i<getNumberOfCells();i++)
3930 const double *tmp1=fPtr+3*i;
3931 tmp[0]=tmp1[1]*v[2]-tmp1[2]*v[1];
3932 tmp[1]=tmp1[2]*v[0]-tmp1[0]*v[2];
3933 tmp[2]=tmp1[0]*v[1]-tmp1[1]*v[0];
3934 double n1=INTERP_KERNEL::norm<3>(tmp);
3935 n1/=INTERP_KERNEL::norm<3>(tmp1);
3937 throw INTERP_KERNEL::Exception("UMesh::Projection 1D failed !");
3939 const double *coo=getCoords()->getConstPointer();
3940 for(mcIdType i=0;i<getNumberOfNodes();i++)
3942 std::transform(coo+i*3,coo+i*3+3,pt,tmp,std::minus<double>());
3943 std::transform(tmp,tmp+3,v,tmp,std::multiplies<double>());
3944 res[i]=std::accumulate(tmp,tmp+3,0.);
3949 * 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.
3950 * \a this is expected to be a mesh so that its space dimension is equal to its
3951 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
3952 * 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).
3954 * 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
3955 * 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).
3956 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
3958 * So this method is more accurate (so, more costly) than simply searching for the closest point in \a this.
3959 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
3961 * \param [in] ptBg the start pointer (included) of the coordinates of the point
3962 * \param [in] ptEnd the end pointer (not included) of the coordinates of the point
3963 * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
3964 * \return the positive value of the distance.
3965 * \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
3967 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoints
3969 double MEDCouplingUMesh::distanceToPoint(const double *ptBg, const double *ptEnd, mcIdType& cellId) const
3971 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
3972 if(meshDim!=spaceDim-1)
3973 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint works only for spaceDim=meshDim+1 !");
3974 if(meshDim!=2 && meshDim!=1)
3975 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint : only mesh dimension 2 and 1 are implemented !");
3976 checkFullyDefined();
3977 if(ToIdType(std::distance(ptBg,ptEnd))!=spaceDim)
3978 { 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()); }
3979 DataArrayIdType *ret1=0;
3980 MCAuto<DataArrayDouble> pts=DataArrayDouble::New(); pts->useArray(ptBg,false,DeallocType::C_DEALLOC,1,spaceDim);
3981 MCAuto<DataArrayDouble> ret0=distanceToPoints(pts,ret1);
3982 MCAuto<DataArrayIdType> ret1Safe(ret1);
3983 cellId=*ret1Safe->begin();
3984 return *ret0->begin();
3988 * This method computes the distance from each point of points serie \a pts (stored in a DataArrayDouble in which each tuple represents a point)
3989 * to \a this and the first \a cellId in \a this corresponding to the returned distance.
3990 * 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
3991 * 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).
3992 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
3994 * \a this is expected to be a mesh so that its space dimension is equal to its
3995 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
3996 * 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).
3998 * So this method is more accurate (so, more costly) than simply searching for each point in \a pts the closest point in \a this.
3999 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4001 * \param [in] pts the list of points in which each tuple represents a point
4002 * \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.
4003 * \return a newly allocated object to be dealed by the caller that tells for each point in \a pts the distance to \a this.
4004 * \throw if number of components of \a pts is not equal to the space dimension.
4005 * \throw if mesh dimension of \a this is not equal to space dimension - 1.
4006 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoint
4008 DataArrayDouble *MEDCouplingUMesh::distanceToPoints(const DataArrayDouble *pts, DataArrayIdType *& cellIds) const
4011 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : input points pointer is NULL !");
4012 pts->checkAllocated();
4013 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4014 if(meshDim!=spaceDim-1)
4015 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints works only for spaceDim=meshDim+1 !");
4016 if(meshDim!=2 && meshDim!=1)
4017 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only mesh dimension 2 and 1 are implemented !");
4018 if(ToIdType(pts->getNumberOfComponents())!=spaceDim)
4020 std::ostringstream oss; oss << "MEDCouplingUMesh::distanceToPoints : input pts DataArrayDouble has " << pts->getNumberOfComponents() << " components whereas it should be equal to " << spaceDim << " (mesh spaceDimension) !";
4021 throw INTERP_KERNEL::Exception(oss.str());
4023 checkFullyDefined();
4024 mcIdType nbCells=getNumberOfCells();
4026 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : no cells in this !");
4027 mcIdType nbOfPts=pts->getNumberOfTuples();
4028 MCAuto<DataArrayDouble> ret0=DataArrayDouble::New(); ret0->alloc(nbOfPts,1);
4029 MCAuto<DataArrayIdType> ret1=DataArrayIdType::New(); ret1->alloc(nbOfPts,1);
4030 const mcIdType *nc=_nodal_connec->begin(),*ncI=_nodal_connec_index->begin(); const double *coords=_coords->begin();
4031 double *ret0Ptr=ret0->getPointer(); mcIdType *ret1Ptr=ret1->getPointer(); const double *ptsPtr=pts->begin();
4032 MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree());
4033 const double *bbox(bboxArr->begin());
4038 BBTreeDst<3> myTree(bbox,0,0,nbCells);
4039 for(mcIdType i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=3)
4041 double x=std::numeric_limits<double>::max();
4042 std::vector<mcIdType> elems;
4043 myTree.getMinDistanceOfMax(ptsPtr,x);
4044 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4045 DistanceToPoint3DSurfAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4051 BBTreeDst<2> myTree(bbox,0,0,nbCells);
4052 for(mcIdType i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=2)
4054 double x=std::numeric_limits<double>::max();
4055 std::vector<mcIdType> elems;
4056 myTree.getMinDistanceOfMax(ptsPtr,x);
4057 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4058 DistanceToPoint2DCurveAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4063 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only spacedim 2 and 3 supported !");
4065 cellIds=ret1.retn();
4074 * Finds cells in contact with a ball (i.e. a point with precision).
4075 * 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.
4076 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4078 * \warning This method is suitable if the caller intends to evaluate only one
4079 * point, for more points getCellsContainingPoints() is recommended as it is
4081 * \param [in] pos - array of coordinates of the ball central point.
4082 * \param [in] eps - ball radius.
4083 * \return mcIdType - a smallest id of cells being in contact with the ball, -1 in case
4084 * if there are no such cells.
4085 * \throw If the coordinates array is not set.
4086 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4088 mcIdType MEDCouplingUMesh::getCellContainingPoint(const double *pos, double eps) const
4090 std::vector<mcIdType> elts;
4091 getCellsContainingPoint(pos,eps,elts);
4094 return elts.front();
4098 * Finds cells in contact with a ball (i.e. a point with precision).
4099 * 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.
4100 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4101 * \warning This method is suitable if the caller intends to evaluate only one
4102 * point, for more points getCellsContainingPoints() is recommended as it is
4104 * \param [in] pos - array of coordinates of the ball central point.
4105 * \param [in] eps - ball radius.
4106 * \param [out] elts - vector returning ids of the found cells. It is cleared
4107 * before inserting ids.
4108 * \throw If the coordinates array is not set.
4109 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4111 * \if ENABLE_EXAMPLES
4112 * \ref cpp_mcumesh_getCellsContainingPoint "Here is a C++ example".<br>
4113 * \ref py_mcumesh_getCellsContainingPoint "Here is a Python example".
4116 void MEDCouplingUMesh::getCellsContainingPoint(const double *pos, double eps, std::vector<mcIdType>& elts) const
4118 MCAuto<DataArrayIdType> eltsUg,eltsIndexUg;
4119 getCellsContainingPoints(pos,1,eps,eltsUg,eltsIndexUg);
4120 elts.clear(); elts.insert(elts.end(),eltsUg->begin(),eltsUg->end());
4123 void MEDCouplingUMesh::getCellsContainingPointsZeAlg(const double *pos, mcIdType nbOfPoints, double eps,
4124 MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex,
4125 std::function<bool(INTERP_KERNEL::NormalizedCellType,mcIdType)> sensibilityTo2DQuadraticLinearCellsFunc) const
4127 int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
4132 const double *coords=_coords->getConstPointer();
4133 getCellsContainingPointsAlg<3>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4136 throw INTERP_KERNEL::Exception("For spaceDim==3 only meshDim==3 implemented for getelementscontainingpoints !");
4138 else if(spaceDim==2)
4142 const double *coords=_coords->getConstPointer();
4143 getCellsContainingPointsAlg<2>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4146 throw INTERP_KERNEL::Exception("For spaceDim==2 only meshDim==2 implemented for getelementscontainingpoints !");
4148 else if(spaceDim==1)
4152 const double *coords=_coords->getConstPointer();
4153 getCellsContainingPointsAlg<1>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4156 throw INTERP_KERNEL::Exception("For spaceDim==1 only meshDim==1 implemented for getelementscontainingpoints !");
4159 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPoints : not managed for mdim not in [1,2,3] !");
4163 * Finds cells in contact with several balls (i.e. points with precision).
4164 * This method is an extension of getCellContainingPoint() and
4165 * getCellsContainingPoint() for the case of multiple points.
4166 * 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.
4167 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4168 * \param [in] pos - an array of coordinates of points in full interlace mode :
4169 * X0,Y0,Z0,X1,Y1,Z1,... Size of the array must be \a
4170 * this->getSpaceDimension() * \a nbOfPoints
4171 * \param [in] nbOfPoints - number of points to locate within \a this mesh.
4172 * \param [in] eps - radius of balls (i.e. the precision).
4173 * \param [out] elts - vector returning ids of found cells.
4174 * \param [out] eltsIndex - an array, of length \a nbOfPoints + 1,
4175 * dividing cell ids in \a elts into groups each referring to one
4176 * point. Its every element (except the last one) is an index pointing to the
4177 * first id of a group of cells. For example cells in contact with the *i*-th
4178 * point are described by following range of indices:
4179 * [ \a eltsIndex[ *i* ], \a eltsIndex[ *i*+1 ] ) and the cell ids are
4180 * \a elts[ \a eltsIndex[ *i* ]], \a elts[ \a eltsIndex[ *i* ] + 1 ], ...
4181 * Number of cells in contact with the *i*-th point is
4182 * \a eltsIndex[ *i*+1 ] - \a eltsIndex[ *i* ].
4183 * \throw If the coordinates array is not set.
4184 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4186 * \if ENABLE_EXAMPLES
4187 * \ref cpp_mcumesh_getCellsContainingPoints "Here is a C++ example".<br>
4188 * \ref py_mcumesh_getCellsContainingPoints "Here is a Python example".
4191 void MEDCouplingUMesh::getCellsContainingPoints(const double *pos, mcIdType nbOfPoints, double eps,
4192 MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex) const
4194 auto yesImSensibleTo2DQuadraticLinearCellsFunc([](INTERP_KERNEL::NormalizedCellType ct, int mdim) { return INTERP_KERNEL::CellModel::GetCellModel(ct).isQuadratic() && mdim == 2; } );
4195 this->getCellsContainingPointsZeAlg(pos,nbOfPoints,eps,elts,eltsIndex,yesImSensibleTo2DQuadraticLinearCellsFunc);
4199 * Behaves like MEDCouplingMesh::getCellsContainingPoints for cells in \a this that are linear.
4200 * For quadratic cells in \a this, this method behaves by just considering linear part of cells.
4201 * This method is here only for backward compatibility (interpolation GaussPoints to GaussPoints).
4203 * \sa MEDCouplingUMesh::getCellsContainingPoints, MEDCouplingRemapper::prepareNotInterpKernelOnlyGaussGauss
4205 void MEDCouplingUMesh::getCellsContainingPointsLinearPartOnlyOnNonDynType(const double *pos, mcIdType nbOfPoints, double eps, MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex) const
4207 auto noImNotSensibleTo2DQuadraticLinearCellsFunc([](INTERP_KERNEL::NormalizedCellType,mcIdType) { return false; } );
4208 this->getCellsContainingPointsZeAlg(pos,nbOfPoints,eps,elts,eltsIndex,noImNotSensibleTo2DQuadraticLinearCellsFunc);
4212 * Finds butterfly cells in \a this mesh. A 2D cell is considered to be butterfly if at
4213 * least two its edges intersect each other anywhere except their extremities. An
4214 * INTERP_KERNEL::NORM_NORI3 cell can \b not be butterfly.
4215 * \param [in,out] cells - a vector returning ids of the found cells. It is not
4216 * cleared before filling in.
4217 * \param [in] eps - precision.
4218 * \throw If \a this->getMeshDimension() != 2.
4219 * \throw If \a this->getSpaceDimension() != 2 && \a this->getSpaceDimension() != 3.
4221 void MEDCouplingUMesh::checkButterflyCells(std::vector<mcIdType>& cells, double eps) const
4223 const char msg[]="Butterfly detection work only for 2D cells with spaceDim==2 or 3!";
4224 if(getMeshDimension()!=2)
4225 throw INTERP_KERNEL::Exception(msg);
4226 int spaceDim=getSpaceDimension();
4227 if(spaceDim!=2 && spaceDim!=3)
4228 throw INTERP_KERNEL::Exception(msg);
4229 const mcIdType *conn=_nodal_connec->getConstPointer();
4230 const mcIdType *connI=_nodal_connec_index->getConstPointer();
4231 mcIdType nbOfCells=getNumberOfCells();
4232 std::vector<double> cell2DinS2;
4233 for(mcIdType i=0;i<nbOfCells;i++)
4235 mcIdType offset=connI[i];
4236 mcIdType nbOfNodesForCell=connI[i+1]-offset-1;
4237 if(nbOfNodesForCell<=3)
4239 bool isQuad=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[offset]).isQuadratic();
4240 project2DCellOnXY(conn+offset+1,conn+connI[i+1],cell2DinS2);
4241 if(isButterfly2DCell(cell2DinS2,isQuad,eps))
4248 * This method is typically requested to unbutterfly 2D linear cells in \b this.
4250 * 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.
4251 * 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.
4253 * For each 2D linear cell in \b this, this method builds the convex envelop (or the convex hull) of the current cell.
4254 * This convex envelop is computed using Jarvis march algorithm.
4255 * The coordinates and the number of cells of \b this remain unchanged on invocation of this method.
4256 * 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)
4257 * 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.
4259 * \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.
4260 * \sa MEDCouplingUMesh::colinearize2D
4262 DataArrayIdType *MEDCouplingUMesh::convexEnvelop2D()
4264 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
4265 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convexEnvelop2D works only for meshDim=2 and spaceDim=2 !");
4266 checkFullyDefined();
4267 const double *coords=getCoords()->getConstPointer();
4268 mcIdType nbOfCells=getNumberOfCells();
4269 MCAuto<DataArrayIdType> nodalConnecIndexOut=DataArrayIdType::New();
4270 nodalConnecIndexOut->alloc(nbOfCells+1,1);
4271 MCAuto<DataArrayIdType> nodalConnecOut(DataArrayIdType::New());
4272 mcIdType *workIndexOut=nodalConnecIndexOut->getPointer();
4274 const mcIdType *nodalConnecIn=_nodal_connec->getConstPointer();
4275 const mcIdType *nodalConnecIndexIn=_nodal_connec_index->getConstPointer();
4276 std::set<INTERP_KERNEL::NormalizedCellType> types;
4277 MCAuto<DataArrayIdType> isChanged(DataArrayIdType::New());
4278 isChanged->alloc(0,1);
4279 for(mcIdType i=0;i<nbOfCells;i++,workIndexOut++)
4281 mcIdType pos=nodalConnecOut->getNumberOfTuples();
4282 if(BuildConvexEnvelopOf2DCellJarvis(coords,nodalConnecIn+nodalConnecIndexIn[i],nodalConnecIn+nodalConnecIndexIn[i+1],nodalConnecOut))
4283 isChanged->pushBackSilent(i);
4284 types.insert((INTERP_KERNEL::NormalizedCellType)nodalConnecOut->getIJ(pos,0));
4285 workIndexOut[1]=nodalConnecOut->getNumberOfTuples();
4287 if(isChanged->empty())
4289 setConnectivity(nodalConnecOut,nodalConnecIndexOut,false);
4291 return isChanged.retn();
4295 * This method is \b NOT const because it can modify \a this.
4296 * \a this is expected to be an unstructured mesh with meshDim==2 and spaceDim==3. If not an exception will be thrown.
4297 * \param mesh1D is an unstructured mesh with MeshDim==1 and spaceDim==3. If not an exception will be thrown.
4298 * \param policy specifies the type of extrusion chosen:
4299 * - \b 0 for translation only (most simple): the cells of the 1D mesh represent the vectors along which the 2D mesh
4300 * will be repeated to build each level
4301 * - \b 1 for translation and rotation: the translation is done as above. For each level, an arc of circle is fitted on
4302 * 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
4303 * 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
4305 * \return an unstructured mesh with meshDim==3 and spaceDim==3. The returned mesh has the same coords than \a this.
4307 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMesh(const MEDCouplingUMesh *mesh1D, int policy)
4309 checkFullyDefined();
4310 mesh1D->checkFullyDefined();
4311 if(!mesh1D->isContiguous1D())
4312 throw INTERP_KERNEL::Exception("buildExtrudedMesh : 1D mesh passed in parameter is not contiguous !");
4313 if(getSpaceDimension()!=mesh1D->getSpaceDimension())
4314 throw INTERP_KERNEL::Exception("Invalid call to buildExtrudedMesh this and mesh1D must have same space dimension !");
4315 if((getMeshDimension()!=2 || getSpaceDimension()!=3) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
4316 throw INTERP_KERNEL::Exception("Invalid 'this' for buildExtrudedMesh method : must be (meshDim==2 and spaceDim==3) or (meshDim==1 and spaceDim==2) !");
4317 if(mesh1D->getMeshDimension()!=1)
4318 throw INTERP_KERNEL::Exception("Invalid 'mesh1D' for buildExtrudedMesh method : must be meshDim==1 !");
4320 if(isPresenceOfQuadratic())
4322 if(mesh1D->isFullyQuadratic())
4325 throw INTERP_KERNEL::Exception("Invalid 2D mesh and 1D mesh because 2D mesh has quadratic cells and 1D is not fully quadratic !");
4327 mcIdType oldNbOfNodes(getNumberOfNodes());
4328 MCAuto<DataArrayDouble> newCoords;
4333 newCoords=fillExtCoordsUsingTranslation(mesh1D,isQuad);
4338 newCoords=fillExtCoordsUsingTranslAndAutoRotation(mesh1D,isQuad);
4342 throw INTERP_KERNEL::Exception("Not implemented extrusion policy : must be in (0) !");
4344 setCoords(newCoords);
4345 MCAuto<MEDCouplingUMesh> ret(buildExtrudedMeshFromThisLowLev(oldNbOfNodes,isQuad));
4352 * Checks if \a this mesh is constituted by only quadratic cells.
4353 * \return bool - \c true if there are only quadratic cells in \a this mesh.
4354 * \throw If the coordinates array is not set.
4355 * \throw If the nodal connectivity of cells is not defined.
4357 bool MEDCouplingUMesh::isFullyQuadratic() const
4359 checkFullyDefined();
4361 mcIdType nbOfCells=getNumberOfCells();
4362 for(mcIdType i=0;i<nbOfCells && ret;i++)
4364 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4365 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4366 ret=cm.isQuadratic();
4372 * Checks if \a this mesh includes any quadratic cell.
4373 * \return bool - \c true if there is at least one quadratic cells in \a this mesh.
4374 * \throw If the coordinates array is not set.
4375 * \throw If the nodal connectivity of cells is not defined.
4377 bool MEDCouplingUMesh::isPresenceOfQuadratic() const
4379 checkFullyDefined();
4381 mcIdType nbOfCells=getNumberOfCells();
4382 for(mcIdType i=0;i<nbOfCells && !ret;i++)
4384 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4385 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4386 ret=cm.isQuadratic();
4392 * Converts all quadratic cells to linear ones. If there are no quadratic cells in \a
4393 * this mesh, it remains unchanged.
4394 * \throw If the coordinates array is not set.
4395 * \throw If the nodal connectivity of cells is not defined.
4397 void MEDCouplingUMesh::convertQuadraticCellsToLinear()
4399 checkFullyDefined();
4400 mcIdType nbOfCells=getNumberOfCells();
4402 const mcIdType *iciptr=_nodal_connec_index->begin();
4403 for(mcIdType i=0;i<nbOfCells;i++)
4405 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4406 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4407 if(cm.isQuadratic())
4409 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4410 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4411 if(!cml.isDynamic())
4412 delta+=cm.getNumberOfNodes()-cml.getNumberOfNodes();
4414 delta+=(iciptr[i+1]-iciptr[i]-1)/2;
4419 MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()),newConnI(DataArrayIdType::New());
4420 const mcIdType *icptr(_nodal_connec->begin());
4421 newConn->alloc(getNodalConnectivityArrayLen()-delta,1);
4422 newConnI->alloc(nbOfCells+1,1);
4423 mcIdType *ocptr(newConn->getPointer()),*ociptr(newConnI->getPointer());
4426 for(mcIdType i=0;i<nbOfCells;i++,ociptr++)
4428 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)icptr[iciptr[i]];
4429 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4430 if(!cm.isQuadratic())
4432 _types.insert(type);
4433 ocptr=std::copy(icptr+iciptr[i],icptr+iciptr[i+1],ocptr);
4434 ociptr[1]=ociptr[0]+iciptr[i+1]-iciptr[i];
4438 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4439 _types.insert(typel);
4440 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4441 mcIdType newNbOfNodes=cml.getNumberOfNodes();
4443 newNbOfNodes=(iciptr[i+1]-iciptr[i]-1)/2;
4444 *ocptr++=ToIdType(typel);
4445 ocptr=std::copy(icptr+iciptr[i]+1,icptr+iciptr[i]+newNbOfNodes+1,ocptr);
4446 ociptr[1]=ociptr[0]+newNbOfNodes+1;
4449 setConnectivity(newConn,newConnI,false);
4453 * This method converts all linear cell in \a this to quadratic one.
4454 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, here it is needed to specify the target
4455 * 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)
4456 * 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.
4457 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, the coordinates in \a this can be become bigger. All created nodes will be put at the
4458 * end of the existing coordinates.
4460 * \param [in] conversionType specifies the type of conversion expected. Only 0 (default) and 1 are supported presently. 0 those that creates the 'most' simple
4461 * corresponding quadratic cells. 1 is those creating the 'most' complex.
4462 * \return a newly created DataArrayIdType instance that the caller should deal with containing cell ids of converted cells.
4464 * \throw if \a this is not fully defined. It throws too if \a conversionType is not in [0,1].
4466 * \sa MEDCouplingUMesh::convertQuadraticCellsToLinear
4468 DataArrayIdType *MEDCouplingUMesh::convertLinearCellsToQuadratic(int conversionType)
4470 DataArrayIdType *conn=0,*connI=0;
4471 DataArrayDouble *coords=0;
4472 std::set<INTERP_KERNEL::NormalizedCellType> types;
4473 checkFullyDefined();
4474 MCAuto<DataArrayIdType> ret,connSafe,connISafe;
4475 MCAuto<DataArrayDouble> coordsSafe;
4476 int meshDim=getMeshDimension();
4477 switch(conversionType)
4483 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);
4484 connSafe=conn; connISafe=connI; coordsSafe=coords;
4487 ret=convertLinearCellsToQuadratic2D0(conn,connI,coords,types);
4488 connSafe=conn; connISafe=connI; coordsSafe=coords;
4491 ret=convertLinearCellsToQuadratic3D0(conn,connI,coords,types);
4492 connSafe=conn; connISafe=connI; coordsSafe=coords;
4495 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 0 mesh dimensions available are [1,2,3] !");
4503 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);//it is not a bug. In 1D policy 0 and 1 are equals
4504 connSafe=conn; connISafe=connI; coordsSafe=coords;
4507 ret=convertLinearCellsToQuadratic2D1(conn,connI,coords,types);
4508 connSafe=conn; connISafe=connI; coordsSafe=coords;
4511 ret=convertLinearCellsToQuadratic3D1(conn,connI,coords,types);
4512 connSafe=conn; connISafe=connI; coordsSafe=coords;
4515 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 1 mesh dimensions available are [1,2,3] !");
4520 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion type available are 0 (default, the simplest) and 1 (the most complex) !");
4522 setConnectivity(connSafe,connISafe,false);
4524 setCoords(coordsSafe);
4529 * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
4530 * so that the number of cells remains the same. Quadratic faces are converted to
4531 * polygons. This method works only for 2D meshes in
4532 * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
4533 * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
4534 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
4535 * \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
4536 * a polylinized edge constituting the input polygon.
4537 * \throw If the coordinates array is not set.
4538 * \throw If the nodal connectivity of cells is not defined.
4539 * \throw If \a this->getMeshDimension() != 2.
4540 * \throw If \a this->getSpaceDimension() != 2.
4542 void MEDCouplingUMesh::tessellate2D(double eps)
4544 int meshDim(getMeshDimension()),spaceDim(getSpaceDimension());
4546 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : works only with space dimension equal to 2 !");
4550 return tessellate2DCurveInternal(eps);
4552 return tessellate2DInternal(eps);
4554 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : mesh dimension must be in [1,2] !");
4560 * This method only works if \a this has spaceDimension equal to 2 and meshDimension also equal to 2.
4561 * This method allows to modify connectivity of cells in \a this that shares some edges in \a edgeIdsToBeSplit.
4562 * The nodes to be added in those 2D cells are defined by the pair of \a nodeIdsToAdd and \a nodeIdsIndexToAdd.
4563 * Length of \a nodeIdsIndexToAdd is expected to equal to length of \a edgeIdsToBeSplit + 1.
4564 * The node ids in \a nodeIdsToAdd should be valid. Those nodes have to be sorted exactly following exactly the direction of the edge.
4565 * This method can be seen as the opposite method of colinearize2D.
4566 * 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
4567 * to avoid to modify the numbering of existing nodes.
4569 * \param [in] nodeIdsToAdd - the list of node ids to be added (\a nodeIdsIndexToAdd array allows to walk on this array)
4570 * \param [in] nodeIdsIndexToAdd - the entry point of \a nodeIdsToAdd to point to the corresponding nodes to be added.
4571 * \param [in] mesh1Desc - 1st output of buildDescendingConnectivity2 on \a this.
4572 * \param [in] desc - 2nd output of buildDescendingConnectivity2 on \a this.
4573 * \param [in] descI - 3rd output of buildDescendingConnectivity2 on \a this.
4574 * \param [in] revDesc - 4th output of buildDescendingConnectivity2 on \a this.
4575 * \param [in] revDescI - 5th output of buildDescendingConnectivity2 on \a this.
4577 * \sa buildDescendingConnectivity2
4579 void MEDCouplingUMesh::splitSomeEdgesOf2DMesh(const DataArrayIdType *nodeIdsToAdd, const DataArrayIdType *nodeIdsIndexToAdd, const DataArrayIdType *edgeIdsToBeSplit,
4580 const MEDCouplingUMesh *mesh1Desc, const DataArrayIdType *desc, const DataArrayIdType *descI, const DataArrayIdType *revDesc, const DataArrayIdType *revDescI)
4582 if(!nodeIdsToAdd || !nodeIdsIndexToAdd || !edgeIdsToBeSplit || !mesh1Desc || !desc || !descI || !revDesc || !revDescI)
4583 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : input pointers must be not NULL !");
4584 nodeIdsToAdd->checkAllocated(); nodeIdsIndexToAdd->checkAllocated(); edgeIdsToBeSplit->checkAllocated(); desc->checkAllocated(); descI->checkAllocated(); revDesc->checkAllocated(); revDescI->checkAllocated();
4585 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
4586 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : this must have spacedim=meshdim=2 !");
4587 if(mesh1Desc->getSpaceDimension()!=2 || mesh1Desc->getMeshDimension()!=1)
4588 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : mesh1Desc must be the explosion of this with spaceDim=2 and meshDim = 1 !");
4589 //DataArrayIdType *out0(0),*outi0(0);
4590 //MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
4591 //MCAuto<DataArrayIdType> out0s(out0),outi0s(outi0);
4592 //out0s=out0s->buildUnique(); out0s->sort(true);
4598 * Divides every cell of \a this mesh into simplices (triangles in 2D and tetrahedra in 3D).
4599 * In addition, returns an array mapping new cells to old ones. <br>
4600 * This method typically increases the number of cells in \a this mesh
4601 * but the number of nodes remains \b unchanged.
4602 * That's why the 3D splitting policies
4603 * INTERP_KERNEL::GENERAL_24 and INTERP_KERNEL::GENERAL_48 are not available here.
4604 * \param [in] policy - specifies a pattern used for splitting.
4605 * The semantic of \a policy is:
4606 * - 0 - to split QUAD4 by cutting it along 0-2 diagonal (for 2D mesh only).
4607 * - 1 - to split QUAD4 by cutting it along 1-3 diagonal (for 2D mesh only).
4608 * - INTERP_KERNEL::PLANAR_FACE_5 - to split HEXA8 into 5 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4609 * - INTERP_KERNEL::PLANAR_FACE_6 - to split HEXA8 into 6 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4612 * \return DataArrayIdType * - a new instance of DataArrayIdType holding, for each new cell,
4613 * an id of old cell producing it. The caller is to delete this array using
4614 * decrRef() as it is no more needed.
4616 * \throw If \a policy is 0 or 1 and \a this->getMeshDimension() != 2.
4617 * \throw If \a policy is INTERP_KERNEL::PLANAR_FACE_5 or INTERP_KERNEL::PLANAR_FACE_6
4618 * and \a this->getMeshDimension() != 3.
4619 * \throw If \a policy is not one of the four discussed above.
4620 * \throw If the nodal connectivity of cells is not defined.
4621 * \sa MEDCouplingUMesh::tetrahedrize, MEDCoupling1SGTUMesh::sortHexa8EachOther
4623 DataArrayIdType *MEDCouplingUMesh::simplexize(int policy)
4628 return simplexizePol0();
4630 return simplexizePol1();
4631 case INTERP_KERNEL::PLANAR_FACE_5:
4632 return simplexizePlanarFace5();
4633 case INTERP_KERNEL::PLANAR_FACE_6:
4634 return simplexizePlanarFace6();
4636 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)");
4641 * Checks if \a this mesh is constituted by simplex cells only. Simplex cells are:
4642 * - 1D: INTERP_KERNEL::NORM_SEG2
4643 * - 2D: INTERP_KERNEL::NORM_TRI3
4644 * - 3D: INTERP_KERNEL::NORM_TETRA4.
4646 * This method is useful for users that need to use P1 field services as
4647 * MEDCouplingFieldDouble::getValueOn(), MEDCouplingField::buildMeasureField() etc.
4648 * All these methods need mesh support containing only simplex cells.
4649 * \return bool - \c true if there are only simplex cells in \a this mesh.
4650 * \throw If the coordinates array is not set.
4651 * \throw If the nodal connectivity of cells is not defined.
4652 * \throw If \a this->getMeshDimension() < 1.
4654 bool MEDCouplingUMesh::areOnlySimplexCells() const
4656 checkFullyDefined();
4657 int mdim=getMeshDimension();
4658 if(mdim<1 || mdim>3)
4659 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::areOnlySimplexCells : only available with meshes having a meshdim 1, 2 or 3 !");
4660 mcIdType nbCells=getNumberOfCells();
4661 const mcIdType *conn=_nodal_connec->begin();
4662 const mcIdType *connI=_nodal_connec_index->begin();
4663 for(mcIdType i=0;i<nbCells;i++)
4665 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4675 * Converts degenerated 2D or 3D linear cells of \a this mesh into cells of simpler
4676 * type. For example an INTERP_KERNEL::NORM_QUAD4 cell having only three unique nodes in
4677 * its connectivity is transformed into an INTERP_KERNEL::NORM_TRI3 cell.
4678 * Quadratic cells in 2D are also handled. In those cells edges where start=end=midpoint are removed.
4679 * This method does \b not perform geometrical checks and checks only nodal connectivity of cells,
4680 * so it can be useful to call mergeNodes() before calling this method.
4681 * \throw If \a this->getMeshDimension() <= 1.
4682 * \throw If the coordinates array is not set.
4683 * \throw If the nodal connectivity of cells is not defined.
4685 void MEDCouplingUMesh::convertDegeneratedCells()
4687 checkFullyDefined();
4688 if(getMeshDimension()<=1)
4689 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4690 mcIdType nbOfCells=getNumberOfCells();
4693 mcIdType initMeshLgth=getNodalConnectivityArrayLen();
4694 mcIdType *conn=_nodal_connec->getPointer();
4695 mcIdType *index=_nodal_connec_index->getPointer();
4696 mcIdType posOfCurCell=0;
4698 mcIdType lgthOfCurCell;
4699 for(mcIdType i=0;i<nbOfCells;i++)
4701 lgthOfCurCell=index[i+1]-posOfCurCell;
4702 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4704 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
4705 conn+newPos+1,newLgth);
4706 conn[newPos]=newType;
4708 posOfCurCell=index[i+1];
4711 if(newPos!=initMeshLgth)
4712 _nodal_connec->reAlloc(newPos);
4717 * Same as MEDCouplingUMesh::convertDegeneratedCells() plus deletion of the flat cells.
4718 * A cell is flat in the following cases:
4719 * - for a linear cell, all points in the connectivity are equal
4720 * - for a quadratic cell, either the above, or a quadratic polygon with two (linear) points and two
4721 * identical quadratic points
4722 * \return a new instance of DataArrayIdType holding ids of removed cells. The caller is to delete
4723 * this array using decrRef() as it is no more needed.
4725 DataArrayIdType *MEDCouplingUMesh::convertDegeneratedCellsAndRemoveFlatOnes()
4727 checkFullyDefined();
4728 if(getMeshDimension()<=1)
4729 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4730 mcIdType nbOfCells=getNumberOfCells();
4731 MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(0,1);
4734 mcIdType initMeshLgth=getNodalConnectivityArrayLen();
4735 mcIdType *conn=_nodal_connec->getPointer();
4736 mcIdType *index=_nodal_connec_index->getPointer();
4737 mcIdType posOfCurCell=0;
4739 mcIdType lgthOfCurCell, nbDelCells(0);
4740 for(mcIdType i=0;i<nbOfCells;i++)
4742 lgthOfCurCell=index[i+1]-posOfCurCell;
4743 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4745 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
4746 conn+newPos+1,newLgth);
4747 // Shall we delete the cell if it is completely degenerated:
4748 bool delCell=INTERP_KERNEL::CellSimplify::isFlatCell(conn, newPos, newLgth, newType);
4752 ret->pushBackSilent(i);
4754 else //if the cell is to be deleted, simply stay at the same place
4756 conn[newPos]=newType;
4759 posOfCurCell=index[i+1];
4760 index[i+1-nbDelCells]=newPos;
4762 if(newPos!=initMeshLgth)
4763 _nodal_connec->reAlloc(newPos);
4764 const mcIdType nCellDel=ret->getNumberOfTuples();
4766 _nodal_connec_index->reAlloc(nbOfCells-nCellDel+1);
4772 * This method remove null 1D cells from \a this. A 1D cell is considered null if start node is equal to end node.
4773 * Only connectivity is considered here.
4775 bool MEDCouplingUMesh::removeDegenerated1DCells()
4777 checkConnectivityFullyDefined();
4778 if(getMeshDimension()!=1)
4779 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::removeDegenerated1DCells works on umeshes with meshdim equals to 1 !");
4780 std::size_t nbCells(getNumberOfCells()),newSize(0),newSize2(0);
4781 const mcIdType *conn(getNodalConnectivity()->begin()),*conni(getNodalConnectivityIndex()->begin());
4783 for(std::size_t i=0;i<nbCells;i++)
4785 INTERP_KERNEL::NormalizedCellType ct((INTERP_KERNEL::NormalizedCellType)conn[conni[i]]);
4786 if(ct==INTERP_KERNEL::NORM_SEG2 || ct==INTERP_KERNEL::NORM_SEG3)
4788 if(conn[conni[i]+1]!=conn[conni[i]+2])
4791 newSize2+=conni[i+1]-conni[i];
4796 std::ostringstream oss; oss << "MEDCouplingUMesh::removeDegenerated1DCells : cell #" << i << " in this is not of type SEG2/SEG3 !";
4797 throw INTERP_KERNEL::Exception(oss.str());
4801 if(newSize==nbCells)//no cells has been removed -> do nothing
4803 MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()),newConnI(DataArrayIdType::New()); newConnI->alloc(newSize+1,1); newConn->alloc(newSize2,1);
4804 mcIdType *newConnPtr(newConn->getPointer()),*newConnIPtr(newConnI->getPointer()); newConnIPtr[0]=0;
4805 for(std::size_t i=0;i<nbCells;i++)
4807 if(conn[conni[i]+1]!=conn[conni[i]+2])
4809 newConnIPtr[1]=newConnIPtr[0]+conni[i+1]-conni[i];
4810 newConnPtr=std::copy(conn+conni[i],conn+conni[i+1],newConnPtr);
4814 setConnectivity(newConn,newConnI,true);
4819 * Finds incorrectly oriented cells of this 2D mesh in 3D space.
4820 * A cell is considered to be oriented correctly if an angle between its
4821 * normal vector and a given vector is less than \c PI / \c 2.
4822 * \param [in] vec - 3 components of the vector specifying the correct orientation of
4824 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
4826 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
4827 * is not cleared before filling in.
4828 * \throw If \a this->getMeshDimension() != 2.
4829 * \throw If \a this->getSpaceDimension() != 3.
4831 * \if ENABLE_EXAMPLES
4832 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
4833 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
4836 void MEDCouplingUMesh::are2DCellsNotCorrectlyOriented(const double *vec, bool polyOnly, std::vector<mcIdType>& cells) const
4838 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
4839 throw INTERP_KERNEL::Exception("Invalid mesh to apply are2DCellsNotCorrectlyOriented on it : must be meshDim==2 and spaceDim==3 !");
4840 mcIdType nbOfCells=getNumberOfCells();
4841 const mcIdType *conn=_nodal_connec->begin();
4842 const mcIdType *connI=_nodal_connec_index->begin();
4843 const double *coordsPtr=_coords->begin();
4844 for(mcIdType i=0;i<nbOfCells;i++)
4846 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4847 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
4849 bool isQuadratic=INTERP_KERNEL::CellModel::GetCellModel(type).isQuadratic();
4850 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4857 * Reverse connectivity of 2D cells whose orientation is not correct. A cell is
4858 * considered to be oriented correctly if an angle between its normal vector and a
4859 * given vector is less than \c PI / \c 2.
4860 * \param [in] vec - 3 components of the vector specifying the correct orientation of
4862 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
4864 * \throw If \a this->getMeshDimension() != 2.
4865 * \throw If \a this->getSpaceDimension() != 3.
4867 * \if ENABLE_EXAMPLES
4868 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
4869 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
4872 * \sa changeOrientationOfCells
4874 void MEDCouplingUMesh::orientCorrectly2DCells(const double *vec, bool polyOnly)
4876 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
4877 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectly2DCells on it : must be meshDim==2 and spaceDim==3 !");
4878 mcIdType nbOfCells=getNumberOfCells();
4879 mcIdType *conn(_nodal_connec->getPointer());
4880 const mcIdType *connI(_nodal_connec_index->begin());
4881 const double *coordsPtr(_coords->begin());
4882 bool isModified(false);
4883 for(mcIdType i=0;i<nbOfCells;i++)
4885 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4886 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
4888 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
4889 bool isQuadratic(cm.isQuadratic());
4890 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4893 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
4898 _nodal_connec->declareAsNew();
4903 * This method change the orientation of cells in \a this without any consideration of coordinates. Only connectivity is impacted.
4905 * \sa orientCorrectly2DCells
4907 void MEDCouplingUMesh::changeOrientationOfCells()
4909 int mdim(getMeshDimension());
4910 if(mdim!=2 && mdim!=1)
4911 throw INTERP_KERNEL::Exception("Invalid mesh to apply changeOrientationOfCells on it : must be meshDim==2 or meshDim==1 !");
4912 mcIdType nbOfCells=getNumberOfCells();
4913 mcIdType *conn(_nodal_connec->getPointer());
4914 const mcIdType *connI(_nodal_connec_index->begin());
4917 for(mcIdType i=0;i<nbOfCells;i++)
4919 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4920 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
4921 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
4926 for(mcIdType i=0;i<nbOfCells;i++)
4928 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4929 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
4930 cm.changeOrientationOf1D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
4936 * Finds incorrectly oriented polyhedral cells, i.e. polyhedrons having correctly
4937 * oriented facets. The normal vector of the facet should point out of the cell.
4938 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
4939 * is not cleared before filling in.
4940 * \throw If \a this->getMeshDimension() != 3.
4941 * \throw If \a this->getSpaceDimension() != 3.
4942 * \throw If the coordinates array is not set.
4943 * \throw If the nodal connectivity of cells is not defined.
4945 * \if ENABLE_EXAMPLES
4946 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
4947 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
4950 void MEDCouplingUMesh::arePolyhedronsNotCorrectlyOriented(std::vector<mcIdType>& cells) const
4952 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
4953 throw INTERP_KERNEL::Exception("Invalid mesh to apply arePolyhedronsNotCorrectlyOriented on it : must be meshDim==3 and spaceDim==3 !");
4954 mcIdType nbOfCells=getNumberOfCells();
4955 const mcIdType *conn=_nodal_connec->begin();
4956 const mcIdType *connI=_nodal_connec_index->begin();
4957 const double *coordsPtr=_coords->begin();
4958 for(mcIdType i=0;i<nbOfCells;i++)
4960 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4961 if(type==INTERP_KERNEL::NORM_POLYHED)
4963 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4970 * Tries to fix connectivity of polyhedra, so that normal vector of all facets to point
4972 * \throw If \a this->getMeshDimension() != 3.
4973 * \throw If \a this->getSpaceDimension() != 3.
4974 * \throw If the coordinates array is not set.
4975 * \throw If the nodal connectivity of cells is not defined.
4976 * \throw If the reparation fails.
4978 * \if ENABLE_EXAMPLES
4979 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
4980 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
4982 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
4984 void MEDCouplingUMesh::orientCorrectlyPolyhedrons()
4986 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
4987 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectlyPolyhedrons on it : must be meshDim==3 and spaceDim==3 !");
4988 mcIdType nbOfCells=getNumberOfCells();
4989 mcIdType *conn=_nodal_connec->getPointer();
4990 const mcIdType *connI=_nodal_connec_index->begin();
4991 const double *coordsPtr=_coords->begin();
4992 for(mcIdType i=0;i<nbOfCells;i++)
4994 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4995 if(type==INTERP_KERNEL::NORM_POLYHED)
4999 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5000 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
5002 catch(INTERP_KERNEL::Exception& e)
5004 std::ostringstream oss; oss << "Something wrong in polyhedron #" << i << " : " << e.what();
5005 throw INTERP_KERNEL::Exception(oss.str());
5013 * This method invert orientation of all cells in \a this.
5014 * After calling this method the absolute value of measure of cells in \a this are the same than before calling.
5015 * This method only operates on the connectivity so coordinates are not touched at all.
5017 void MEDCouplingUMesh::invertOrientationOfAllCells()
5019 checkConnectivityFullyDefined();
5020 std::set<INTERP_KERNEL::NormalizedCellType> gts(getAllGeoTypes());
5021 mcIdType *conn(_nodal_connec->getPointer());
5022 const mcIdType *conni(_nodal_connec_index->begin());
5023 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator gt=gts.begin();gt!=gts.end();gt++)
5025 INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::OrientationInverter> oi(INTERP_KERNEL::OrientationInverter::BuildInstanceFrom(*gt));
5026 MCAuto<DataArrayIdType> cwt(giveCellsWithType(*gt));
5027 for(const mcIdType *it=cwt->begin();it!=cwt->end();it++)
5028 oi->operate(conn+conni[*it]+1,conn+conni[*it+1]);
5034 * Finds and fixes incorrectly oriented linear extruded volumes (INTERP_KERNEL::NORM_HEXA8,
5035 * INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXGP12 etc) to respect the MED convention
5036 * according to which the first facet of the cell should be oriented to have the normal vector
5037 * pointing out of cell.
5038 * \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of fixed
5039 * cells. The caller is to delete this array using decrRef() as it is no more
5041 * \throw If \a this->getMeshDimension() != 3.
5042 * \throw If \a this->getSpaceDimension() != 3.
5043 * \throw If the coordinates array is not set.
5044 * \throw If the nodal connectivity of cells is not defined.
5046 * \if ENABLE_EXAMPLES
5047 * \ref cpp_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a C++ example".<br>
5048 * \ref py_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a Python example".
5050 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
5052 DataArrayIdType *MEDCouplingUMesh::findAndCorrectBadOriented3DExtrudedCells()
5054 const char msg[]="check3DCellsWellOriented detection works only for 3D cells !";
5055 if(getMeshDimension()!=3)
5056 throw INTERP_KERNEL::Exception(msg);
5057 int spaceDim=getSpaceDimension();
5059 throw INTERP_KERNEL::Exception(msg);
5061 mcIdType nbOfCells=getNumberOfCells();
5062 mcIdType *conn=_nodal_connec->getPointer();
5063 const mcIdType *connI=_nodal_connec_index->begin();
5064 const double *coo=getCoords()->begin();
5065 MCAuto<DataArrayIdType> cells(DataArrayIdType::New()); cells->alloc(0,1);
5066 for(mcIdType i=0;i<nbOfCells;i++)
5068 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5069 if(cm.isExtruded() && !cm.isDynamic() && !cm.isQuadratic())
5071 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coo))
5073 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
5074 cells->pushBackSilent(i);
5078 return cells.retn();
5082 * This method is a faster method to correct orientation of all 3D cells in \a this.
5083 * 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.
5084 * This method makes the hypothesis that \a this a coherent that is to say MEDCouplingUMesh::checkConsistency should throw no exception.
5086 * \return a newly allocated mcIdType array with one components containing cell ids renumbered to fit the convention of MED (MED file and MEDCoupling)
5087 * \sa MEDCouplingUMesh::orientCorrectlyPolyhedrons,
5089 DataArrayIdType *MEDCouplingUMesh::findAndCorrectBadOriented3DCells()
5091 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
5092 throw INTERP_KERNEL::Exception("Invalid mesh to apply findAndCorrectBadOriented3DCells on it : must be meshDim==3 and spaceDim==3 !");
5093 mcIdType nbOfCells=getNumberOfCells();
5094 mcIdType *conn=_nodal_connec->getPointer();
5095 const mcIdType *connI=_nodal_connec_index->begin();
5096 const double *coordsPtr=_coords->begin();
5097 MCAuto<DataArrayIdType> ret=DataArrayIdType::New(); ret->alloc(0,1);
5098 for(mcIdType i=0;i<nbOfCells;i++)
5100 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5103 case INTERP_KERNEL::NORM_TETRA4:
5105 if(!IsTetra4WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5107 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+3));
5108 ret->pushBackSilent(i);
5112 case INTERP_KERNEL::NORM_PYRA5:
5114 if(!IsPyra5WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5116 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+4));
5117 ret->pushBackSilent(i);
5121 case INTERP_KERNEL::NORM_PENTA6:
5122 case INTERP_KERNEL::NORM_HEXA8:
5123 case INTERP_KERNEL::NORM_HEXGP12:
5125 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5127 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
5128 ret->pushBackSilent(i);
5132 case INTERP_KERNEL::NORM_POLYHED:
5134 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5136 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
5137 ret->pushBackSilent(i);
5142 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 !");
5150 * This method has a sense for meshes with spaceDim==3 and meshDim==2.
5151 * If it is not the case an exception will be thrown.
5152 * This method is fast because the first cell of \a this is used to compute the plane.
5153 * \param vec output of size at least 3 used to store the normal vector (with norm equal to Area ) of searched plane.
5154 * \param pos output of size at least 3 used to store a point owned of searched plane.
5156 void MEDCouplingUMesh::getFastAveragePlaneOfThis(double *vec, double *pos) const
5158 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
5159 throw INTERP_KERNEL::Exception("Invalid mesh to apply getFastAveragePlaneOfThis on it : must be meshDim==2 and spaceDim==3 !");
5160 const mcIdType *conn=_nodal_connec->begin();
5161 const mcIdType *connI=_nodal_connec_index->begin();
5162 const double *coordsPtr=_coords->begin();
5163 INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(conn+1,connI[1]-connI[0]-1,coordsPtr,vec);
5164 std::copy(coordsPtr+3*conn[1],coordsPtr+3*conn[1]+3,pos);
5168 * Creates a new MEDCouplingFieldDouble holding Edge Ratio values of all
5169 * cells. Currently cells of the following types are treated:
5170 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5171 * For a cell of other type an exception is thrown.
5172 * Space dimension of a 2D mesh can be either 2 or 3.
5173 * The Edge Ratio of a cell \f$t\f$ is:
5174 * \f$\frac{|t|_\infty}{|t|_0}\f$,
5175 * where \f$|t|_\infty\f$ and \f$|t|_0\f$ respectively denote the greatest and
5176 * the smallest edge lengths of \f$t\f$.
5177 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5178 * cells and one time, lying on \a this mesh. The caller is to delete this
5179 * field using decrRef() as it is no more needed.
5180 * \throw If the coordinates array is not set.
5181 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5182 * \throw If the connectivity data array has more than one component.
5183 * \throw If the connectivity data array has a named component.
5184 * \throw If the connectivity index data array has more than one component.
5185 * \throw If the connectivity index data array has a named component.
5186 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
5187 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5188 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5190 MEDCouplingFieldDouble *MEDCouplingUMesh::getEdgeRatioField() const
5192 checkConsistencyLight();
5193 int spaceDim=getSpaceDimension();
5194 int meshDim=getMeshDimension();
5195 if(spaceDim!=2 && spaceDim!=3)
5196 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : SpaceDimension must be equal to 2 or 3 !");
5197 if(meshDim!=2 && meshDim!=3)
5198 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : MeshDimension must be equal to 2 or 3 !");
5199 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5201 mcIdType nbOfCells=getNumberOfCells();
5202 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5203 arr->alloc(nbOfCells,1);
5204 double *pt=arr->getPointer();
5205 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5206 const mcIdType *conn=_nodal_connec->begin();
5207 const mcIdType *connI=_nodal_connec_index->begin();
5208 const double *coo=_coords->begin();
5210 for(mcIdType i=0;i<nbOfCells;i++,pt++)
5212 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5215 case INTERP_KERNEL::NORM_TRI3:
5217 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5218 *pt=INTERP_KERNEL::triEdgeRatio(tmp);
5221 case INTERP_KERNEL::NORM_QUAD4:
5223 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5224 *pt=INTERP_KERNEL::quadEdgeRatio(tmp);
5227 case INTERP_KERNEL::NORM_TETRA4:
5229 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5230 *pt=INTERP_KERNEL::tetraEdgeRatio(tmp);
5234 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5236 conn+=connI[i+1]-connI[i];
5238 ret->setName("EdgeRatio");
5239 ret->synchronizeTimeWithSupport();
5244 * Creates a new MEDCouplingFieldDouble holding Aspect Ratio values of all
5245 * cells. Currently cells of the following types are treated:
5246 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5247 * For a cell of other type an exception is thrown.
5248 * Space dimension of a 2D mesh can be either 2 or 3.
5249 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5250 * cells and one time, lying on \a this mesh. The caller is to delete this
5251 * field using decrRef() as it is no more needed.
5252 * \throw If the coordinates array is not set.
5253 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5254 * \throw If the connectivity data array has more than one component.
5255 * \throw If the connectivity data array has a named component.
5256 * \throw If the connectivity index data array has more than one component.
5257 * \throw If the connectivity index data array has a named component.
5258 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
5259 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5260 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5262 MEDCouplingFieldDouble *MEDCouplingUMesh::getAspectRatioField() const
5264 checkConsistencyLight();
5265 int spaceDim=getSpaceDimension();
5266 int meshDim=getMeshDimension();
5267 if(spaceDim!=2 && spaceDim!=3)
5268 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : SpaceDimension must be equal to 2 or 3 !");
5269 if(meshDim!=2 && meshDim!=3)
5270 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : MeshDimension must be equal to 2 or 3 !");
5271 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5273 mcIdType nbOfCells=getNumberOfCells();
5274 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5275 arr->alloc(nbOfCells,1);
5276 double *pt=arr->getPointer();
5277 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5278 const mcIdType *conn=_nodal_connec->begin();
5279 const mcIdType *connI=_nodal_connec_index->begin();
5280 const double *coo=_coords->begin();
5282 for(mcIdType i=0;i<nbOfCells;i++,pt++)
5284 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5287 case INTERP_KERNEL::NORM_TRI3:
5289 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5290 *pt=INTERP_KERNEL::triAspectRatio(tmp);
5293 case INTERP_KERNEL::NORM_QUAD4:
5295 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5296 *pt=INTERP_KERNEL::quadAspectRatio(tmp);
5299 case INTERP_KERNEL::NORM_TETRA4:
5301 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5302 *pt=INTERP_KERNEL::tetraAspectRatio(tmp);
5306 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5308 conn+=connI[i+1]-connI[i];
5310 ret->setName("AspectRatio");
5311 ret->synchronizeTimeWithSupport();
5316 * Creates a new MEDCouplingFieldDouble holding Warping factor values of all
5317 * cells of \a this 2D mesh in 3D space. It is a measure of the "planarity" of 2D cell
5318 * in 3D space. Currently only cells of the following types are
5319 * treated: INTERP_KERNEL::NORM_QUAD4.
5320 * For a cell of other type an exception is thrown.
5321 * The warp field is computed as follows: let (a,b,c,d) be the points of the quad.
5323 * \f$t=\vec{da}\times\vec{ab}\f$,
5324 * \f$u=\vec{ab}\times\vec{bc}\f$
5325 * \f$v=\vec{bc}\times\vec{cd}\f$
5326 * \f$w=\vec{cd}\times\vec{da}\f$, the warp is defined as \f$W^3\f$ with
5328 * W=min(\frac{t}{|t|}\cdot\frac{v}{|v|}, \frac{u}{|u|}\cdot\frac{w}{|w|})
5330 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5331 * cells and one time, lying on \a this mesh. The caller is to delete this
5332 * field using decrRef() as it is no more needed.
5333 * \throw If the coordinates array is not set.
5334 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5335 * \throw If the connectivity data array has more than one component.
5336 * \throw If the connectivity data array has a named component.
5337 * \throw If the connectivity index data array has more than one component.
5338 * \throw If the connectivity index data array has a named component.
5339 * \throw If \a this->getMeshDimension() != 2.
5340 * \throw If \a this->getSpaceDimension() != 3.
5341 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5343 MEDCouplingFieldDouble *MEDCouplingUMesh::getWarpField() const
5345 checkConsistencyLight();
5346 int spaceDim=getSpaceDimension();
5347 int meshDim=getMeshDimension();
5349 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : SpaceDimension must be equal to 3 !");
5351 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : MeshDimension must be equal to 2 !");
5352 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5354 mcIdType nbOfCells=getNumberOfCells();
5355 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5356 arr->alloc(nbOfCells,1);
5357 double *pt=arr->getPointer();
5358 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5359 const mcIdType *conn=_nodal_connec->begin();
5360 const mcIdType *connI=_nodal_connec_index->begin();
5361 const double *coo=_coords->begin();
5363 for(mcIdType i=0;i<nbOfCells;i++,pt++)
5365 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5368 case INTERP_KERNEL::NORM_QUAD4:
5370 FillInCompact3DMode(3,4,conn+1,coo,tmp);
5371 *pt=INTERP_KERNEL::quadWarp(tmp);
5375 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : A cell with not manged type (NORM_QUAD4) has been detected !");
5377 conn+=connI[i+1]-connI[i];
5379 ret->setName("Warp");
5380 ret->synchronizeTimeWithSupport();
5386 * Creates a new MEDCouplingFieldDouble holding Skew factor values of all
5387 * cells of \a this 2D mesh in 3D space. Currently cells of the following types are
5388 * treated: INTERP_KERNEL::NORM_QUAD4.
5389 * The skew is computed as follow for a quad with points (a,b,c,d): let
5390 * \f$u=\vec{ab}+\vec{dc}\f$ and \f$v=\vec{ac}+\vec{bd}\f$
5391 * then the skew is computed as:
5393 * s=\frac{u}{|u|}\cdot\frac{v}{|v|}
5396 * For a cell of other type an exception is thrown.
5397 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5398 * cells and one time, lying on \a this mesh. The caller is to delete this
5399 * field using decrRef() as it is no more needed.
5400 * \throw If the coordinates array is not set.
5401 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5402 * \throw If the connectivity data array has more than one component.
5403 * \throw If the connectivity data array has a named component.
5404 * \throw If the connectivity index data array has more than one component.
5405 * \throw If the connectivity index data array has a named component.
5406 * \throw If \a this->getMeshDimension() != 2.
5407 * \throw If \a this->getSpaceDimension() != 3.
5408 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5410 MEDCouplingFieldDouble *MEDCouplingUMesh::getSkewField() const
5412 checkConsistencyLight();
5413 int spaceDim=getSpaceDimension();
5414 int meshDim=getMeshDimension();
5416 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : SpaceDimension must be equal to 3 !");
5418 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : MeshDimension must be equal to 2 !");
5419 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5421 mcIdType nbOfCells=getNumberOfCells();
5422 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5423 arr->alloc(nbOfCells,1);
5424 double *pt=arr->getPointer();
5425 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5426 const mcIdType *conn=_nodal_connec->begin();
5427 const mcIdType *connI=_nodal_connec_index->begin();
5428 const double *coo=_coords->begin();
5430 for(mcIdType i=0;i<nbOfCells;i++,pt++)
5432 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5435 case INTERP_KERNEL::NORM_QUAD4:
5437 FillInCompact3DMode(3,4,conn+1,coo,tmp);
5438 *pt=INTERP_KERNEL::quadSkew(tmp);
5442 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : A cell with not manged type (NORM_QUAD4) has been detected !");
5444 conn+=connI[i+1]-connI[i];
5446 ret->setName("Skew");
5447 ret->synchronizeTimeWithSupport();
5452 * 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.
5454 * \return a new instance of field containing the result. The returned instance has to be deallocated by the caller.
5456 * \sa getSkewField, getWarpField, getAspectRatioField, getEdgeRatioField
5458 MEDCouplingFieldDouble *MEDCouplingUMesh::computeDiameterField() const
5460 checkConsistencyLight();
5461 MCAuto<MEDCouplingFieldDouble> ret(MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME));
5463 std::set<INTERP_KERNEL::NormalizedCellType> types;
5464 ComputeAllTypesInternal(types,_nodal_connec,_nodal_connec_index);
5465 int spaceDim(getSpaceDimension());
5466 mcIdType nbCells(getNumberOfCells());
5467 MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
5468 arr->alloc(nbCells,1);
5469 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++)
5471 INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::DiameterCalculator> dc(INTERP_KERNEL::CellModel::GetCellModel(*it).buildInstanceOfDiameterCalulator(spaceDim));
5472 MCAuto<DataArrayIdType> cellIds(giveCellsWithType(*it));
5473 dc->computeForListOfCellIdsUMeshFrmt(cellIds->begin(),cellIds->end(),_nodal_connec_index->begin(),_nodal_connec->begin(),getCoords()->begin(),arr->getPointer());
5476 ret->setName("Diameter");
5481 * This method aggregate the bbox of each cell and put it into bbox parameter (xmin,xmax,ymin,ymax,zmin,zmax).
5483 * \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)
5484 * For all other cases this input parameter is ignored.
5485 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5487 * \throw If \a this is not fully set (coordinates and connectivity).
5488 * \throw If a cell in \a this has no valid nodeId.
5489 * \sa MEDCouplingUMesh::getBoundingBoxForBBTreeFast, MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5491 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree(double arcDetEps) const
5493 int mDim(getMeshDimension()),sDim(getSpaceDimension());
5494 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.
5495 return getBoundingBoxForBBTreeFast();
5496 if((mDim==2 && sDim==2) || (mDim==1 && sDim==2))
5498 bool presenceOfQuadratic(false);
5499 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=_types.begin();it!=_types.end();it++)
5501 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(*it));
5502 if(cm.isQuadratic())
5503 presenceOfQuadratic=true;
5505 if(!presenceOfQuadratic)
5506 return getBoundingBoxForBBTreeFast();
5507 if(mDim==2 && sDim==2)
5508 return getBoundingBoxForBBTree2DQuadratic(arcDetEps);
5510 return getBoundingBoxForBBTree1DQuadratic(arcDetEps);
5512 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) !");
5516 * This method aggregate the bbox of each cell only considering the nodes constituting each cell and put it into bbox parameter.
5517 * So meshes having quadratic cells the computed bounding boxes can be invalid !
5519 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5521 * \throw If \a this is not fully set (coordinates and connectivity).
5522 * \throw If a cell in \a this has no valid nodeId.
5524 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTreeFast() const
5526 checkFullyDefined();
5527 int spaceDim(getSpaceDimension());
5528 mcIdType nbOfCells(getNumberOfCells()), nbOfNodes(getNumberOfNodes());
5529 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5530 double *bbox(ret->getPointer());
5531 for(mcIdType i=0;i<nbOfCells*spaceDim;i++)
5533 bbox[2*i]=std::numeric_limits<double>::max();
5534 bbox[2*i+1]=-std::numeric_limits<double>::max();
5536 const double *coordsPtr(_coords->begin());
5537 const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5538 for(mcIdType i=0;i<nbOfCells;i++)
5540 mcIdType offset=connI[i]+1;
5541 mcIdType nbOfNodesForCell(connI[i+1]-offset),kk(0);
5542 for(mcIdType j=0;j<nbOfNodesForCell;j++)
5544 mcIdType nodeId=conn[offset+j];
5545 if(nodeId>=0 && nodeId<nbOfNodes)
5547 for(int k=0;k<spaceDim;k++)
5549 bbox[2*spaceDim*i+2*k]=std::min(bbox[2*spaceDim*i+2*k],coordsPtr[spaceDim*nodeId+k]);
5550 bbox[2*spaceDim*i+2*k+1]=std::max(bbox[2*spaceDim*i+2*k+1],coordsPtr[spaceDim*nodeId+k]);
5557 std::ostringstream oss; oss << "MEDCouplingUMesh::getBoundingBoxForBBTree : cell #" << i << " contains no valid nodeId !";
5558 throw INTERP_KERNEL::Exception(oss.str());
5565 * This method aggregates the bbox of each 2D cell in \a this considering the whole shape. This method is particularly
5566 * useful for 2D meshes having quadratic cells
5567 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5568 * the two extremities of the arc of circle).
5570 * \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)
5571 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5572 * \throw If \a this is not fully defined.
5573 * \throw If \a this is not a mesh with meshDimension equal to 2.
5574 * \throw If \a this is not a mesh with spaceDimension equal to 2.
5575 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic
5577 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic(double arcDetEps) const
5579 checkFullyDefined();
5580 INTERP_KERNEL::QuadraticPlanarPrecision arcPrec(arcDetEps);
5582 int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
5583 mcIdType nbOfCells=getNumberOfCells();
5584 if(spaceDim!=2 || mDim!=2)
5585 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!");
5586 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5587 double *bbox(ret->getPointer());
5588 const double *coords(_coords->begin());
5589 const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5590 for(mcIdType i=0;i<nbOfCells;i++,bbox+=4,connI++)
5592 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5593 mcIdType sz(connI[1]-connI[0]-1);
5594 std::vector<INTERP_KERNEL::Node *> nodes(sz);
5595 INTERP_KERNEL::QuadraticPolygon *pol(0);
5596 for(mcIdType j=0;j<sz;j++)
5598 mcIdType nodeId(conn[*connI+1+j]);
5599 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5601 if(!cm.isQuadratic())
5602 pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
5604 pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
5605 INTERP_KERNEL::Bounds b; b.prepareForAggregation(); pol->fillBounds(b); delete pol;
5606 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax();
5612 * This method aggregates the bbox of each 1D cell in \a this considering the whole shape. This method is particularly
5613 * useful for 2D meshes having quadratic cells
5614 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5615 * the two extremities of the arc of circle).
5617 * \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)
5618 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5619 * \throw If \a this is not fully defined.
5620 * \throw If \a this is not a mesh with meshDimension equal to 1.
5621 * \throw If \a this is not a mesh with spaceDimension equal to 2.
5622 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5624 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic(double arcDetEps) const
5626 checkFullyDefined();
5627 int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
5628 mcIdType nbOfCells=getNumberOfCells();
5629 if(spaceDim!=2 || mDim!=1)
5630 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!");
5631 INTERP_KERNEL::QuadraticPlanarPrecision arcPrec(arcDetEps);
5632 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5633 double *bbox(ret->getPointer());
5634 const double *coords(_coords->begin());
5635 const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5636 for(mcIdType i=0;i<nbOfCells;i++,bbox+=4,connI++)
5638 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5639 mcIdType sz(connI[1]-connI[0]-1);
5640 std::vector<INTERP_KERNEL::Node *> nodes(sz);
5641 INTERP_KERNEL::Edge *edge(0);
5642 for(mcIdType j=0;j<sz;j++)
5644 mcIdType nodeId(conn[*connI+1+j]);
5645 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5647 if(!cm.isQuadratic())
5648 edge=INTERP_KERNEL::QuadraticPolygon::BuildLinearEdge(nodes);
5650 edge=INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(nodes);
5651 const INTERP_KERNEL::Bounds& b(edge->getBounds());
5652 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax(); edge->decrRef();
5659 namespace MEDCouplingImpl
5664 ConnReader(const mcIdType *c, mcIdType val):_conn(c),_val(val) { }
5665 bool operator() (const mcIdType& pos) { return _conn[pos]!=_val; }
5667 const mcIdType *_conn;
5674 ConnReader2(const mcIdType *c, mcIdType val):_conn(c),_val(val) { }
5675 bool operator() (const mcIdType& pos) { return _conn[pos]==_val; }
5677 const mcIdType *_conn;
5685 * This method expects that \a this is sorted by types. If not an exception will be thrown.
5686 * This method returns in the same format as code (see MEDCouplingUMesh::checkTypeConsistencyAndContig or MEDCouplingUMesh::splitProfilePerType) how
5687 * \a this is composed in cell types.
5688 * The returned array is of size 3*n where n is the number of different types present in \a this.
5689 * For every k in [0,n] ret[3*k+2]==-1 because it has no sense here.
5690 * This parameter is kept only for compatibility with other method listed above.
5692 std::vector<mcIdType> MEDCouplingUMesh::getDistributionOfTypes() const
5694 checkConnectivityFullyDefined();
5695 const mcIdType *conn=_nodal_connec->begin();
5696 const mcIdType *connI=_nodal_connec_index->begin();
5697 const mcIdType *work=connI;
5698 mcIdType nbOfCells=getNumberOfCells();
5699 std::size_t n=getAllGeoTypes().size();
5700 std::vector<mcIdType> ret(3*n,-1); //ret[3*k+2]==-1 because it has no sense here
5701 std::set<INTERP_KERNEL::NormalizedCellType> types;
5702 for(std::size_t i=0;work!=connI+nbOfCells;i++)
5704 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn[*work];
5705 if(types.find(typ)!=types.end())
5707 std::ostringstream oss; oss << "MEDCouplingUMesh::getDistributionOfTypes : Type " << INTERP_KERNEL::CellModel::GetCellModel(typ).getRepr();
5708 oss << " is not contiguous !";
5709 throw INTERP_KERNEL::Exception(oss.str());
5713 const mcIdType *work2=std::find_if(work+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,typ));
5714 ret[3*i+1]=ToIdType(std::distance(work,work2));
5721 * This method is used to check that this has contiguous cell type in same order than described in \a code.
5722 * only for types cell, type node is not managed.
5723 * Format of \a code is the following. \a code should be of size 3*n and non empty. If not an exception is thrown.
5724 * foreach k in [0,n) on 3*k pos represent the geometric type and 3*k+1 number of elements of type 3*k.
5725 * 3*k+2 refers if different from -1 the pos in 'idsPerType' to get the corresponding array.
5726 * If 2 or more same geometric type is in \a code and exception is thrown too.
5728 * This method firstly checks
5729 * If it exists k so that 3*k geometric type is not in geometric types of this an exception will be thrown.
5730 * If it exists k so that 3*k geometric type exists but the number of consecutive cell types does not match,
5731 * an exception is thrown too.
5733 * If all geometric types in \a code are exactly those in \a this null pointer is returned.
5734 * If it exists a geometric type in \a this \b not in \a code \b no exception is thrown
5735 * and a DataArrayIdType instance is returned that the user has the responsibility to deallocate.
5737 DataArrayIdType *MEDCouplingUMesh::checkTypeConsistencyAndContig(const std::vector<mcIdType>& code, const std::vector<const DataArrayIdType *>& idsPerType) const
5740 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code is empty, should not !");
5741 std::size_t sz=code.size();
5744 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code size is NOT %3 !");
5745 std::vector<INTERP_KERNEL::NormalizedCellType> types;
5747 bool isNoPflUsed=true;
5748 for(std::size_t i=0;i<n;i++)
5749 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)code[3*i])==types.end())
5751 types.push_back((INTERP_KERNEL::NormalizedCellType)code[3*i]);
5753 if(_types.find((INTERP_KERNEL::NormalizedCellType)code[3*i])==_types.end())
5754 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : expected geo types not in this !");
5755 isNoPflUsed=isNoPflUsed && (code[3*i+2]==-1);
5758 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code contains duplication of types in unstructured mesh !");
5761 if(!checkConsecutiveCellTypesAndOrder(&types[0],&types[0]+types.size()))
5762 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : non contiguous type !");
5763 if(types.size()==_types.size())
5766 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
5768 mcIdType *retPtr=ret->getPointer();
5769 const mcIdType *connI=_nodal_connec_index->begin();
5770 const mcIdType *conn=_nodal_connec->begin();
5771 mcIdType nbOfCells=getNumberOfCells();
5772 const mcIdType *i=connI;
5774 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++,kk++)
5776 i=std::find_if(i,connI+nbOfCells,MEDCouplingImpl::ConnReader2(conn,ToIdType((*it))));
5777 mcIdType offset=ToIdType(std::distance(connI,i));
5778 const mcIdType *j=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType((*it))));
5779 mcIdType nbOfCellsOfCurType=ToIdType(std::distance(i,j));
5780 if(code[3*kk+2]==-1)
5781 for(mcIdType k=0;k<nbOfCellsOfCurType;k++)
5785 mcIdType idInIdsPerType=code[3*kk+2];
5786 if(idInIdsPerType>=0 && idInIdsPerType<ToIdType(idsPerType.size()))
5788 const DataArrayIdType *zePfl=idsPerType[idInIdsPerType];
5791 zePfl->checkAllocated();
5792 if(zePfl->getNumberOfComponents()==1)
5794 for(const mcIdType *k=zePfl->begin();k!=zePfl->end();k++,retPtr++)
5796 if(*k>=0 && *k<nbOfCellsOfCurType)
5797 *retPtr=(*k)+offset;
5800 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : the section " << kk << " points to the profile #" << idInIdsPerType;
5801 oss << ", and this profile contains a value " << *k << " should be in [0," << nbOfCellsOfCurType << ") !";
5802 throw INTERP_KERNEL::Exception(oss.str());
5807 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of a profile with nb of compo != 1 !");
5810 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of null profile !");
5814 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : at section " << kk << " of code it points to the array #" << idInIdsPerType;
5815 oss << " should be in [0," << idsPerType.size() << ") !";
5816 throw INTERP_KERNEL::Exception(oss.str());
5825 * This method makes the hypothesis that \a this is sorted by type. If not an exception will be thrown.
5826 * 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.
5827 * 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.
5828 * This method has 1 input \a profile and 3 outputs \a code \a idsInPflPerType and \a idsPerType.
5830 * \param [in] profile list of IDs constituing the profile
5831 * \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.
5832 * \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,
5833 * \a idsInPflPerType[i] stores the tuple ids in \a profile that correspond to the geometric type code[3*i+0]
5834 * \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.
5835 * This vector can be empty in case of all geometric type cells are fully covered in ascending in the given input \a profile.
5836 * \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
5838 void MEDCouplingUMesh::splitProfilePerType(const DataArrayIdType *profile, std::vector<mcIdType>& code, std::vector<DataArrayIdType *>& idsInPflPerType, std::vector<DataArrayIdType *>& idsPerType, bool smartPflKiller) const
5841 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile is NULL !");
5842 if(profile->getNumberOfComponents()!=1)
5843 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile should have exactly one component !");
5844 checkConnectivityFullyDefined();
5845 const mcIdType *conn=_nodal_connec->begin();
5846 const mcIdType *connI=_nodal_connec_index->begin();
5847 mcIdType nbOfCells=getNumberOfCells();
5848 std::vector<INTERP_KERNEL::NormalizedCellType> types;
5849 std::vector<mcIdType> typeRangeVals(1);
5850 for(const mcIdType *i=connI;i!=connI+nbOfCells;)
5852 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5853 if(std::find(types.begin(),types.end(),curType)!=types.end())
5855 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : current mesh is not sorted by type !");
5857 types.push_back(curType);
5858 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
5859 typeRangeVals.push_back(ToIdType(std::distance(connI,i)));
5862 DataArrayIdType *castArr=0,*rankInsideCast=0,*castsPresent=0;
5863 profile->splitByValueRange(&typeRangeVals[0],&typeRangeVals[0]+typeRangeVals.size(),castArr,rankInsideCast,castsPresent);
5864 MCAuto<DataArrayIdType> tmp0=castArr;
5865 MCAuto<DataArrayIdType> tmp1=rankInsideCast;
5866 MCAuto<DataArrayIdType> tmp2=castsPresent;
5868 mcIdType nbOfCastsFinal=castsPresent->getNumberOfTuples();
5869 code.resize(3*nbOfCastsFinal);
5870 std::vector< MCAuto<DataArrayIdType> > idsInPflPerType2;
5871 std::vector< MCAuto<DataArrayIdType> > idsPerType2;
5872 for(mcIdType i=0;i<nbOfCastsFinal;i++)
5874 mcIdType castId=castsPresent->getIJ(i,0);
5875 MCAuto<DataArrayIdType> tmp3=castArr->findIdsEqual(castId);
5876 idsInPflPerType2.push_back(tmp3);
5877 code[3*i]=ToIdType(types[castId]);
5878 code[3*i+1]=tmp3->getNumberOfTuples();
5879 MCAuto<DataArrayIdType> tmp4=rankInsideCast->selectByTupleId(tmp3->begin(),tmp3->begin()+tmp3->getNumberOfTuples());
5880 if(!smartPflKiller || !tmp4->isIota(typeRangeVals[castId+1]-typeRangeVals[castId]))
5882 tmp4->copyStringInfoFrom(*profile);
5883 idsPerType2.push_back(tmp4);
5884 code[3*i+2]=ToIdType(idsPerType2.size())-1;
5891 std::size_t sz2=idsInPflPerType2.size();
5892 idsInPflPerType.resize(sz2);
5893 for(std::size_t i=0;i<sz2;i++)
5895 DataArrayIdType *locDa=idsInPflPerType2[i];
5897 idsInPflPerType[i]=locDa;
5899 std::size_t sz=idsPerType2.size();
5900 idsPerType.resize(sz);
5901 for(std::size_t i=0;i<sz;i++)
5903 DataArrayIdType *locDa=idsPerType2[i];
5905 idsPerType[i]=locDa;
5910 * This method is here too emulate the MEDMEM behaviour on BDC (buildDescendingConnectivity). Hoping this method becomes deprecated very soon.
5911 * This method make the assumption that \a this and 'nM1LevMesh' mesh lyies on same coords (same pointer) as MED and MEDMEM does.
5912 * The following equality should be verified 'nM1LevMesh->getMeshDimension()==this->getMeshDimension()-1'
5913 * 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.
5915 MEDCouplingUMesh *MEDCouplingUMesh::emulateMEDMEMBDC(const MEDCouplingUMesh *nM1LevMesh, DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *&revDesc, DataArrayIdType *&revDescIndx, DataArrayIdType *& nM1LevMeshIds, DataArrayIdType *&meshnM1Old2New) const
5917 checkFullyDefined();
5918 nM1LevMesh->checkFullyDefined();
5919 if(getMeshDimension()-1!=nM1LevMesh->getMeshDimension())
5920 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : The mesh passed as first argument should have a meshDim equal to this->getMeshDimension()-1 !" );
5921 if(_coords!=nM1LevMesh->getCoords())
5922 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : 'this' and mesh in first argument should share the same coords : Use tryToShareSameCoords method !");
5923 MCAuto<DataArrayIdType> tmp0=DataArrayIdType::New();
5924 MCAuto<DataArrayIdType> tmp1=DataArrayIdType::New();
5925 MCAuto<MEDCouplingUMesh> ret1=buildDescendingConnectivity(desc,descIndx,tmp0,tmp1);
5926 MCAuto<DataArrayIdType> ret0=ret1->sortCellsInMEDFileFrmt();
5927 desc->transformWithIndArr(ret0->begin(),ret0->begin()+ret0->getNbOfElems());
5928 MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
5929 tmp->setConnectivity(tmp0,tmp1);
5930 tmp->renumberCells(ret0->begin(),false);
5931 revDesc=tmp->getNodalConnectivity();
5932 revDescIndx=tmp->getNodalConnectivityIndex();
5933 DataArrayIdType *ret=0;
5934 if(!ret1->areCellsIncludedIn(nM1LevMesh,2,ret))
5937 ret->getMaxValue(tmp2);
5939 std::ostringstream oss; oss << "MEDCouplingUMesh::emulateMEDMEMBDC : input N-1 mesh present a cell not in descending mesh ... Id of cell is " << tmp2 << " !";
5940 throw INTERP_KERNEL::Exception(oss.str());
5945 revDescIndx->incrRef();
5948 meshnM1Old2New=ret0;
5953 * Permutes the nodal connectivity arrays so that the cells are sorted by type, which is
5954 * necessary for writing the mesh to MED file. Additionally returns a permutation array
5955 * in "Old to New" mode.
5956 * \return DataArrayIdType * - a new instance of DataArrayIdType. The caller is to delete
5957 * this array using decrRef() as it is no more needed.
5958 * \throw If the nodal connectivity of cells is not defined.
5960 DataArrayIdType *MEDCouplingUMesh::sortCellsInMEDFileFrmt()
5962 checkConnectivityFullyDefined();
5963 MCAuto<DataArrayIdType> ret=getRenumArrForMEDFileFrmt();
5964 renumberCells(ret->begin(),false);
5969 * This methods checks that cells are sorted by their types.
5970 * This method makes asumption (no check) that connectivity is correctly set before calling.
5972 bool MEDCouplingUMesh::checkConsecutiveCellTypes() const
5974 checkFullyDefined();
5975 const mcIdType *conn=_nodal_connec->begin();
5976 const mcIdType *connI=_nodal_connec_index->begin();
5977 mcIdType nbOfCells=getNumberOfCells();
5978 std::set<INTERP_KERNEL::NormalizedCellType> types;
5979 for(const mcIdType *i=connI;i!=connI+nbOfCells;)
5981 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5982 if(types.find(curType)!=types.end())
5984 types.insert(curType);
5985 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
5991 * This method is a specialization of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method that is called here.
5992 * The geometric type order is specified by MED file.
5994 * \sa MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder
5996 bool MEDCouplingUMesh::checkConsecutiveCellTypesForMEDFileFrmt() const
5998 return checkConsecutiveCellTypesAndOrder(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
6002 * This method performs the same job as checkConsecutiveCellTypes except that the order of types sequence is analyzed to check
6003 * that the order is specified in array defined by [ \a orderBg , \a orderEnd ).
6004 * If there is some geo types in \a this \b NOT in [ \a orderBg, \a orderEnd ) it is OK (return true) if contiguous.
6005 * If there is some geo types in [ \a orderBg, \a orderEnd ) \b NOT in \a this it is OK too (return true) if contiguous.
6007 bool MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
6009 checkFullyDefined();
6010 const mcIdType *conn=_nodal_connec->begin();
6011 const mcIdType *connI=_nodal_connec_index->begin();
6012 mcIdType nbOfCells=getNumberOfCells();
6015 mcIdType lastPos=-1;
6016 std::set<INTERP_KERNEL::NormalizedCellType> sg;
6017 for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6019 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6020 const INTERP_KERNEL::NormalizedCellType *isTypeExists=std::find(orderBg,orderEnd,curType);
6021 if(isTypeExists!=orderEnd)
6023 mcIdType pos=ToIdType(std::distance(orderBg,isTypeExists));
6027 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6031 if(sg.find(curType)==sg.end())
6033 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6044 * This method returns 2 newly allocated DataArrayIdType instances. The first is an array of size 'this->getNumberOfCells()' with one component,
6045 * 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
6046 * 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'.
6048 DataArrayIdType *MEDCouplingUMesh::getLevArrPerCellTypes(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd, DataArrayIdType *&nbPerType) const
6050 checkConnectivityFullyDefined();
6051 mcIdType nbOfCells=getNumberOfCells();
6052 const mcIdType *conn=_nodal_connec->begin();
6053 const mcIdType *connI=_nodal_connec_index->begin();
6054 MCAuto<DataArrayIdType> tmpa=DataArrayIdType::New();
6055 MCAuto<DataArrayIdType> tmpb=DataArrayIdType::New();
6056 tmpa->alloc(nbOfCells,1);
6057 tmpb->alloc(std::distance(orderBg,orderEnd),1);
6058 tmpb->fillWithZero();
6059 mcIdType *tmp=tmpa->getPointer();
6060 mcIdType *tmp2=tmpb->getPointer();
6061 for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6063 const INTERP_KERNEL::NormalizedCellType *where=std::find(orderBg,orderEnd,(INTERP_KERNEL::NormalizedCellType)conn[*i]);
6066 mcIdType pos=ToIdType(std::distance(orderBg,where));
6068 tmp[std::distance(connI,i)]=pos;
6072 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*i]);
6073 std::ostringstream oss; oss << "MEDCouplingUMesh::getLevArrPerCellTypes : Cell #" << std::distance(connI,i);
6074 oss << " has a type " << cm.getRepr() << " not in input array of type !";
6075 throw INTERP_KERNEL::Exception(oss.str());
6078 nbPerType=tmpb.retn();
6083 * This method behaves exactly as MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec but the order is those defined in MED file spec.
6085 * \return a new object containing the old to new correspondence.
6087 * \sa MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec, MEDCouplingUMesh::sortCellsInMEDFileFrmt.
6089 DataArrayIdType *MEDCouplingUMesh::getRenumArrForMEDFileFrmt() const
6091 return getRenumArrForConsecutiveCellTypesSpec(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
6095 * 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.
6096 * This method returns an array of size getNumberOfCells() that gives a renumber array old2New that can be used as input of MEDCouplingMesh::renumberCells.
6097 * The mesh after this call to MEDCouplingMesh::renumberCells will pass the test of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder with the same inputs.
6098 * The returned array minimizes the permutations that is to say the order of cells inside same geometric type remains the same.
6100 DataArrayIdType *MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
6102 DataArrayIdType *nbPerType=0;
6103 MCAuto<DataArrayIdType> tmpa=getLevArrPerCellTypes(orderBg,orderEnd,nbPerType);
6104 nbPerType->decrRef();
6105 return tmpa->buildPermArrPerLevel();
6109 * This method reorganize the cells of \a this so that the cells with same geometric types are put together.
6110 * The number of cells remains unchanged after the call of this method.
6111 * This method tries to minimizes the number of needed permutations. So, this method behaves not exactly as
6112 * MEDCouplingUMesh::sortCellsInMEDFileFrmt.
6114 * \return the array giving the correspondence old to new.
6116 DataArrayIdType *MEDCouplingUMesh::rearrange2ConsecutiveCellTypes()
6118 checkFullyDefined();
6120 const mcIdType *conn=_nodal_connec->begin();
6121 const mcIdType *connI=_nodal_connec_index->begin();
6122 mcIdType nbOfCells=getNumberOfCells();
6123 std::vector<INTERP_KERNEL::NormalizedCellType> types;
6124 for(const mcIdType *i=connI;i!=connI+nbOfCells && (types.size()!=_types.size());)
6125 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)conn[*i])==types.end())
6127 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6128 types.push_back(curType);
6129 for(i++;i!=connI+nbOfCells && (INTERP_KERNEL::NormalizedCellType)conn[*i]==curType;i++);
6131 DataArrayIdType *ret=DataArrayIdType::New();
6132 ret->alloc(nbOfCells,1);
6133 mcIdType *retPtr=ret->getPointer();
6134 std::fill(retPtr,retPtr+nbOfCells,-1);
6135 mcIdType newCellId=0;
6136 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
6138 for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6139 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
6140 retPtr[std::distance(connI,i)]=newCellId++;
6142 renumberCells(retPtr,false);
6147 * This method splits \a this into as mush as untructured meshes that consecutive set of same type cells.
6148 * So this method has typically a sense if MEDCouplingUMesh::checkConsecutiveCellTypes has a sense.
6149 * This method makes asumption that connectivity is correctly set before calling.
6151 std::vector<MEDCouplingUMesh *> MEDCouplingUMesh::splitByType() const
6153 checkConnectivityFullyDefined();
6154 const mcIdType *conn=_nodal_connec->begin();
6155 const mcIdType *connI=_nodal_connec_index->begin();
6156 mcIdType nbOfCells=getNumberOfCells();
6157 std::vector<MEDCouplingUMesh *> ret;
6158 for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6160 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6161 mcIdType beginCellId=ToIdType(std::distance(connI,i));
6162 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6163 mcIdType endCellId=ToIdType(std::distance(connI,i));
6164 mcIdType sz=endCellId-beginCellId;
6165 mcIdType *cells=new mcIdType[sz];
6166 for(mcIdType j=0;j<sz;j++)
6167 cells[j]=beginCellId+j;
6168 MEDCouplingUMesh *m=(MEDCouplingUMesh *)buildPartOfMySelf(cells,cells+sz,true);
6176 * This method performs the opposite operation than those in MEDCoupling1SGTUMesh::buildUnstructured.
6177 * If \a this is a single geometric type unstructured mesh, it will be converted into a more compact data structure,
6178 * MEDCoupling1GTUMesh instance. The returned instance will aggregate the same DataArrayDouble instance of coordinates than \a this.
6180 * \return a newly allocated instance, that the caller must manage.
6181 * \throw If \a this contains more than one geometric type.
6182 * \throw If the nodal connectivity of \a this is not fully defined.
6183 * \throw If the internal data is not coherent.
6185 MEDCoupling1GTUMesh *MEDCouplingUMesh::convertIntoSingleGeoTypeMesh() const
6187 checkConnectivityFullyDefined();
6188 if(_types.size()!=1)
6189 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6190 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6191 MCAuto<MEDCoupling1GTUMesh> ret=MEDCoupling1GTUMesh::New(getName(),typ);
6192 ret->setCoords(getCoords());
6193 MEDCoupling1SGTUMesh *retC=dynamic_cast<MEDCoupling1SGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6196 MCAuto<DataArrayIdType> c=convertNodalConnectivityToStaticGeoTypeMesh();
6197 retC->setNodalConnectivity(c);
6201 MEDCoupling1DGTUMesh *retD=dynamic_cast<MEDCoupling1DGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6203 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : Internal error !");
6204 DataArrayIdType *c=0,*ci=0;
6205 convertNodalConnectivityToDynamicGeoTypeMesh(c,ci);
6206 MCAuto<DataArrayIdType> cs(c),cis(ci);
6207 retD->setNodalConnectivity(cs,cis);
6212 DataArrayIdType *MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh() const
6214 checkConnectivityFullyDefined();
6215 if(_types.size()!=1)
6216 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6217 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6218 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6221 std::ostringstream oss; oss << "MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : this contains a single geo type (" << cm.getRepr() << ") but ";
6222 oss << "this type is dynamic ! Only static geometric type is possible for that type ! call convertNodalConnectivityToDynamicGeoTypeMesh instead !";
6223 throw INTERP_KERNEL::Exception(oss.str());
6225 mcIdType nbCells=getNumberOfCells();
6226 mcIdType typi=ToIdType(typ);
6227 mcIdType nbNodesPerCell=ToIdType(cm.getNumberOfNodes());
6228 MCAuto<DataArrayIdType> connOut=DataArrayIdType::New(); connOut->alloc(nbCells*nbNodesPerCell,1);
6229 mcIdType *outPtr=connOut->getPointer();
6230 const mcIdType *conn=_nodal_connec->begin();
6231 const mcIdType *connI=_nodal_connec_index->begin();
6233 for(mcIdType i=0;i<nbCells;i++,connI++)
6235 if(conn[connI[0]]==typi && connI[1]-connI[0]==nbNodesPerCell)
6236 outPtr=std::copy(conn+connI[0]+1,conn+connI[1],outPtr);
6239 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 << ") !";
6240 throw INTERP_KERNEL::Exception(oss.str());
6243 return connOut.retn();
6247 * Convert the nodal connectivity of the mesh so that all the cells are of dynamic types (polygon or quadratic
6248 * polygon). This returns the corresponding new nodal connectivity in \ref numbering-indirect format.
6249 * \param nodalConn nodal connectivity
6250 * \param nodalConnIndex nodal connectivity indices
6252 void MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh(DataArrayIdType *&nodalConn, DataArrayIdType *&nodalConnIndex) const
6254 static const char msg0[]="MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : nodal connectivity in this are invalid ! Call checkConsistency !";
6255 checkConnectivityFullyDefined();
6256 if(_types.size()!=1)
6257 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6258 mcIdType nbCells=getNumberOfCells(),
6259 lgth=_nodal_connec->getNumberOfTuples();
6261 throw INTERP_KERNEL::Exception(msg0);
6262 MCAuto<DataArrayIdType> c(DataArrayIdType::New()),ci(DataArrayIdType::New());
6263 c->alloc(lgth-nbCells,1); ci->alloc(nbCells+1,1);
6264 mcIdType *cp(c->getPointer()),*cip(ci->getPointer());
6265 const mcIdType *incp(_nodal_connec->begin()),*incip(_nodal_connec_index->begin());
6267 for(mcIdType i=0;i<nbCells;i++,cip++,incip++)
6269 mcIdType strt(incip[0]+1),stop(incip[1]);//+1 to skip geo type
6270 mcIdType delta(stop-strt);
6273 if((strt>=0 && strt<lgth) && (stop>=0 && stop<=lgth))
6274 cp=std::copy(incp+strt,incp+stop,cp);
6276 throw INTERP_KERNEL::Exception(msg0);
6279 throw INTERP_KERNEL::Exception(msg0);
6280 cip[1]=cip[0]+delta;
6282 nodalConn=c.retn(); nodalConnIndex=ci.retn();
6286 * This method takes in input a vector of MEDCouplingUMesh instances lying on the same coordinates with same mesh dimensions.
6287 * Each mesh in \b ms must be sorted by type with the same order (typically using MEDCouplingUMesh::sortCellsInMEDFileFrmt).
6288 * This method is particularly useful for MED file interaction. It allows to aggregate several meshes and keeping the type sorting
6289 * and the track of the permutation by chunk of same geotype cells to retrieve it. The traditional formats old2new and new2old
6290 * are not used here to avoid the build of big permutation array.
6292 * \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
6293 * those specified in MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6294 * \param [out] szOfCellGrpOfSameType is a newly allocated DataArrayIdType instance whose number of tuples is equal to the number of chunks of same geotype
6295 * in all meshes in \b ms. The accumulation of all values of this array is equal to the number of cells of returned mesh.
6296 * \param [out] idInMsOfCellGrpOfSameType is a newly allocated DataArrayIdType instance having the same size than \b szOfCellGrpOfSameType. This
6297 * output array gives for each chunck of same type the corresponding mesh id in \b ms.
6298 * \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
6299 * is sorted by type following the geo cell types order of MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6301 MEDCouplingUMesh *MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& ms,
6302 DataArrayIdType *&szOfCellGrpOfSameType,
6303 DataArrayIdType *&idInMsOfCellGrpOfSameType)
6305 std::vector<const MEDCouplingUMesh *> ms2;
6306 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms.begin();it!=ms.end();it++)
6309 (*it)->checkConnectivityFullyDefined();
6313 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : input vector is empty !");
6314 const DataArrayDouble *refCoo=ms2[0]->getCoords();
6315 int meshDim=ms2[0]->getMeshDimension();
6316 std::vector<const MEDCouplingUMesh *> m1ssm;
6317 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmAuto;
6319 std::vector<const MEDCouplingUMesh *> m1ssmSingle;
6320 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmSingleAuto;
6321 mcIdType fake=0,rk=0;
6322 MCAuto<DataArrayIdType> ret1(DataArrayIdType::New()),ret2(DataArrayIdType::New());
6323 ret1->alloc(0,1); ret2->alloc(0,1);
6324 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms2.begin();it!=ms2.end();it++,rk++)
6326 if(meshDim!=(*it)->getMeshDimension())
6327 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshdims mismatch !");
6328 if(refCoo!=(*it)->getCoords())
6329 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshes are not shared by a single coordinates coords !");
6330 std::vector<MEDCouplingUMesh *> sp=(*it)->splitByType();
6331 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<const MEDCouplingUMesh *> >(m1ssm));
6332 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<MCAuto<MEDCouplingUMesh> > >(m1ssmAuto));
6333 for(std::vector<MEDCouplingUMesh *>::const_iterator it2=sp.begin();it2!=sp.end();it2++)
6335 MEDCouplingUMesh *singleCell=static_cast<MEDCouplingUMesh *>((*it2)->buildPartOfMySelf(&fake,&fake+1,true));
6336 m1ssmSingleAuto.push_back(singleCell);
6337 m1ssmSingle.push_back(singleCell);
6338 ret1->pushBackSilent((*it2)->getNumberOfCells()); ret2->pushBackSilent(rk);
6341 MCAuto<MEDCouplingUMesh> m1ssmSingle2=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmSingle);
6342 MCAuto<DataArrayIdType> renum=m1ssmSingle2->sortCellsInMEDFileFrmt();
6343 std::vector<const MEDCouplingUMesh *> m1ssmfinal(m1ssm.size());
6344 for(mcIdType i=0;i<ToIdType(m1ssm.size());i++)
6345 m1ssmfinal[renum->getIJ(i,0)]=m1ssm[i];
6346 MCAuto<MEDCouplingUMesh> ret0=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmfinal);
6347 szOfCellGrpOfSameType=ret1->renumber(renum->begin());
6348 idInMsOfCellGrpOfSameType=ret2->renumber(renum->begin());
6353 * This method returns a newly created DataArrayIdType instance.
6354 * This method retrieves cell ids in [ \a begin, \a end ) that have the type \a type.
6356 DataArrayIdType *MEDCouplingUMesh::keepCellIdsByType(INTERP_KERNEL::NormalizedCellType type, const mcIdType *begin, const mcIdType *end) const
6358 checkFullyDefined();
6359 const mcIdType *conn=_nodal_connec->begin();
6360 const mcIdType *connIndex=_nodal_connec_index->begin();
6361 MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(0,1);
6362 for(const mcIdType *w=begin;w!=end;w++)
6363 if((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]==type)
6364 ret->pushBackSilent(*w);
6369 * This method makes the assumption that da->getNumberOfTuples()<this->getNumberOfCells(). This method makes the assumption that ids contained in 'da'
6370 * are in [0:getNumberOfCells())
6372 DataArrayIdType *MEDCouplingUMesh::convertCellArrayPerGeoType(const DataArrayIdType *da) const
6374 checkFullyDefined();
6375 const mcIdType *conn=_nodal_connec->begin();
6376 const mcIdType *connI=_nodal_connec_index->begin();
6377 mcIdType nbOfCells=getNumberOfCells();
6378 std::set<INTERP_KERNEL::NormalizedCellType> types(getAllGeoTypes());
6379 mcIdType *tmp=new mcIdType[nbOfCells];
6380 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
6383 for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6384 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
6385 tmp[std::distance(connI,i)]=j++;
6387 DataArrayIdType *ret=DataArrayIdType::New();
6388 ret->alloc(da->getNumberOfTuples(),da->getNumberOfComponents());
6389 ret->copyStringInfoFrom(*da);
6390 mcIdType *retPtr=ret->getPointer();
6391 const mcIdType *daPtr=da->begin();
6392 mcIdType nbOfElems=da->getNbOfElems();
6393 for(mcIdType k=0;k<nbOfElems;k++)
6394 retPtr[k]=tmp[daPtr[k]];
6400 * This method reduced number of cells of this by keeping cells whose type is different from 'type' and if type=='type'
6401 * This method \b works \b for mesh sorted by type.
6402 * cells whose ids is in 'idsPerGeoType' array.
6403 * This method conserves coords and name of mesh.
6405 MEDCouplingUMesh *MEDCouplingUMesh::keepSpecifiedCells(INTERP_KERNEL::NormalizedCellType type, const mcIdType *idsPerGeoTypeBg, const mcIdType *idsPerGeoTypeEnd) const
6407 std::vector<mcIdType> code=getDistributionOfTypes();
6408 std::size_t nOfTypesInThis=code.size()/3;
6409 mcIdType sz=0,szOfType=0;
6410 for(std::size_t i=0;i<nOfTypesInThis;i++)
6415 szOfType=code[3*i+1];
6417 for(const mcIdType *work=idsPerGeoTypeBg;work!=idsPerGeoTypeEnd;work++)
6418 if(*work<0 || *work>=szOfType)
6420 std::ostringstream oss; oss << "MEDCouplingUMesh::keepSpecifiedCells : Request on type " << type << " at place #" << std::distance(idsPerGeoTypeBg,work) << " value " << *work;
6421 oss << ". It should be in [0," << szOfType << ") !";
6422 throw INTERP_KERNEL::Exception(oss.str());
6424 MCAuto<DataArrayIdType> idsTokeep=DataArrayIdType::New(); idsTokeep->alloc(sz+std::distance(idsPerGeoTypeBg,idsPerGeoTypeEnd),1);
6425 mcIdType *idsPtr=idsTokeep->getPointer();
6427 for(std::size_t i=0;i<nOfTypesInThis;i++)
6430 for(mcIdType j=0;j<code[3*i+1];j++)
6433 idsPtr=std::transform(idsPerGeoTypeBg,idsPerGeoTypeEnd,idsPtr,std::bind(std::plus<mcIdType>(),std::placeholders::_1,offset));
6434 offset+=code[3*i+1];
6436 MCAuto<MEDCouplingUMesh> ret=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(idsTokeep->begin(),idsTokeep->end(),true));
6437 ret->copyTinyInfoFrom(this);
6442 * This method returns a vector of size 'this->getNumberOfCells()'.
6443 * This method retrieves for each cell in \a this if it is linear (false) or quadratic(true).
6445 std::vector<bool> MEDCouplingUMesh::getQuadraticStatus() const
6447 mcIdType ncell=getNumberOfCells();
6448 std::vector<bool> ret(ncell);
6449 const mcIdType *cI=getNodalConnectivityIndex()->begin();
6450 const mcIdType *c=getNodalConnectivity()->begin();
6451 for(mcIdType i=0;i<ncell;i++)
6453 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[i]];
6454 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6455 ret[i]=cm.isQuadratic();
6461 * Returns a newly created mesh (with ref count ==1) that contains merge of \a this and \a other.
6463 MEDCouplingMesh *MEDCouplingUMesh::mergeMyselfWith(const MEDCouplingMesh *other) const
6465 if(other->getType()!=UNSTRUCTURED)
6466 throw INTERP_KERNEL::Exception("Merge of umesh only available with umesh each other !");
6467 const MEDCouplingUMesh *otherC=static_cast<const MEDCouplingUMesh *>(other);
6468 return MergeUMeshes(this,otherC);
6472 * Returns a new DataArrayDouble holding barycenters of all cells. The barycenter is
6473 * computed by averaging coordinates of cell nodes, so this method is not a right
6474 * choice for degenerated meshes (not well oriented, cells with measure close to zero).
6475 * Beware also that for quadratic meshes, degenerated arc of circles are turned into linear edges for the computation.
6476 * This happens with a default detection precision of eps=1.0e-14. If you need control over this use computeCellCenterOfMassWithPrecision().
6477 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
6478 * this->getNumberOfCells() tuples per \a this->getSpaceDimension()
6479 * components. The caller is to delete this array using decrRef() as it is
6481 * \throw If the coordinates array is not set.
6482 * \throw If the nodal connectivity of cells is not defined.
6483 * \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
6484 * \sa MEDCouplingUMesh::computeCellCenterOfMassWithPrecision
6486 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMass() const
6488 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6489 int spaceDim=getSpaceDimension();
6490 mcIdType nbOfCells=getNumberOfCells();
6491 ret->alloc(nbOfCells,spaceDim);
6492 ret->copyStringInfoFrom(*getCoords());
6493 double *ptToFill=ret->getPointer();
6494 const mcIdType *nodal=_nodal_connec->begin();
6495 const mcIdType *nodalI=_nodal_connec_index->begin();
6496 const double *coor=_coords->begin();
6497 for(mcIdType i=0;i<nbOfCells;i++)
6499 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6500 INTERP_KERNEL::computeBarycenter2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[i]+1,nodalI[i+1]-nodalI[i]-1,coor,spaceDim,ptToFill);
6508 * See computeCellCenterOfMass().
6509 * \param eps a precision for the detection of degenerated arc of circles.
6510 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
6511 * this->getNumberOfCells() tuples per \a this->getSpaceDimension()
6512 * components. The caller is to delete this array using decrRef() as it is
6514 * \throw If the coordinates array is not set.
6515 * \throw If the nodal connectivity of cells is not defined.
6516 * \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
6517 * \sa MEDCouplingUMesh::computeCellCenterOfMassWithPrecision
6519 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMassWithPrecision(double eps) const
6521 INTERP_KERNEL::QuadraticPlanarPrecision prec(eps);
6522 MCAuto<DataArrayDouble> ret = computeCellCenterOfMass();
6528 * This method computes for each cell in \a this, the location of the iso barycenter of nodes constituting
6529 * the cell. Contrary to badly named MEDCouplingUMesh::computeCellCenterOfMass method that returns the center of inertia of the
6531 * \return a newly allocated DataArrayDouble instance that the caller has to deal with. The returned
6532 * DataArrayDouble instance will have \c this->getNumberOfCells() tuples and \c this->getSpaceDimension() components.
6534 * \sa MEDCouplingUMesh::computeCellCenterOfMass
6535 * \throw If \a this is not fully defined (coordinates and connectivity)
6536 * \throw If there is presence in nodal connectivity in \a this of node ids not in [0, \c this->getNumberOfNodes() )
6538 DataArrayDouble *MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell() const
6540 checkFullyDefined();
6541 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6542 int spaceDim=getSpaceDimension();
6543 mcIdType nbOfCells=getNumberOfCells();
6544 mcIdType nbOfNodes=getNumberOfNodes();
6545 ret->alloc(nbOfCells,spaceDim);
6546 double *ptToFill=ret->getPointer();
6547 const mcIdType *nodal=_nodal_connec->begin();
6548 const mcIdType *nodalI=_nodal_connec_index->begin();
6549 const double *coor=_coords->begin();
6550 for(mcIdType i=0;i<nbOfCells;i++,ptToFill+=spaceDim)
6552 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6553 std::fill(ptToFill,ptToFill+spaceDim,0.);
6554 if(type!=INTERP_KERNEL::NORM_POLYHED)
6556 for(const mcIdType *conn=nodal+nodalI[i]+1;conn!=nodal+nodalI[i+1];conn++)
6558 if(*conn>=0 && *conn<nbOfNodes)
6559 std::transform(coor+spaceDim*conn[0],coor+spaceDim*(conn[0]+1),ptToFill,ptToFill,std::plus<double>());
6562 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of nodeId #" << *conn << " should be in [0," << nbOfNodes << ") !";
6563 throw INTERP_KERNEL::Exception(oss.str());
6566 mcIdType nbOfNodesInCell=nodalI[i+1]-nodalI[i]-1;
6567 if(nbOfNodesInCell>0)
6568 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind(std::multiplies<double>(),std::placeholders::_1,1./(double)nbOfNodesInCell));
6571 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of cell with no nodes !";
6572 throw INTERP_KERNEL::Exception(oss.str());
6577 std::set<mcIdType> s(nodal+nodalI[i]+1,nodal+nodalI[i+1]);
6579 for(std::set<mcIdType>::const_iterator it=s.begin();it!=s.end();it++)
6581 if(*it>=0 && *it<nbOfNodes)
6582 std::transform(coor+spaceDim*(*it),coor+spaceDim*((*it)+1),ptToFill,ptToFill,std::plus<double>());
6585 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell polyhedron cell #" << i << " presence of nodeId #" << *it << " should be in [0," << nbOfNodes << ") !";
6586 throw INTERP_KERNEL::Exception(oss.str());
6590 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind(std::multiplies<double>(),std::placeholders::_1,1./(double)s.size()));
6593 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on polyhedron cell #" << i << " there are no nodes !";
6594 throw INTERP_KERNEL::Exception(oss.str());
6602 * Returns a new DataArrayDouble holding barycenters of specified cells. The
6603 * barycenter is computed by averaging coordinates of cell nodes. The cells to treat
6604 * are specified via an array of cell ids.
6605 * \warning Validity of the specified cell ids is not checked!
6606 * Valid range is [ 0, \a this->getNumberOfCells() ).
6607 * \param [in] begin - an array of cell ids of interest.
6608 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
6609 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size ( \a
6610 * end - \a begin ) tuples per \a this->getSpaceDimension() components. The
6611 * caller is to delete this array using decrRef() as it is no more needed.
6612 * \throw If the coordinates array is not set.
6613 * \throw If the nodal connectivity of cells is not defined.
6615 * \if ENABLE_EXAMPLES
6616 * \ref cpp_mcumesh_getPartBarycenterAndOwner "Here is a C++ example".<br>
6617 * \ref py_mcumesh_getPartBarycenterAndOwner "Here is a Python example".
6620 DataArrayDouble *MEDCouplingUMesh::getPartBarycenterAndOwner(const mcIdType *begin, const mcIdType *end) const
6622 DataArrayDouble *ret=DataArrayDouble::New();
6623 int spaceDim=getSpaceDimension();
6624 std::size_t nbOfTuple=std::distance(begin,end);
6625 ret->alloc(nbOfTuple,spaceDim);
6626 double *ptToFill=ret->getPointer();
6627 double *tmp=new double[spaceDim];
6628 const mcIdType *nodal=_nodal_connec->begin();
6629 const mcIdType *nodalI=_nodal_connec_index->begin();
6630 const double *coor=_coords->begin();
6631 for(const mcIdType *w=begin;w!=end;w++)
6633 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[*w]];
6634 INTERP_KERNEL::computeBarycenter2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[*w]+1,nodalI[*w+1]-nodalI[*w]-1,coor,spaceDim,ptToFill);
6642 * 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".
6643 * So the returned instance will have 4 components and \c this->getNumberOfCells() tuples.
6644 * So this method expects that \a this has a spaceDimension equal to 3 and meshDimension equal to 2.
6645 * The computation of the plane equation is done using each time the 3 first nodes of 2D cells.
6646 * This method is useful to detect 2D cells in 3D space that are not coplanar.
6648 * \return DataArrayDouble * - a new instance of DataArrayDouble having 4 components and a number of tuples equal to number of cells in \a this.
6649 * \throw If spaceDim!=3 or meshDim!=2.
6650 * \throw If connectivity of \a this is invalid.
6651 * \throw If connectivity of a cell in \a this points to an invalid node.
6653 DataArrayDouble *MEDCouplingUMesh::computePlaneEquationOf3DFaces() const
6655 MCAuto<DataArrayDouble> ret(DataArrayDouble::New());
6656 mcIdType nbOfCells=getNumberOfCells();
6657 mcIdType nbOfNodes(getNumberOfNodes());
6658 if(getSpaceDimension()!=3 || getMeshDimension()!=2)
6659 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computePlaneEquationOf3DFaces : This method must be applied on a mesh having meshDimension equal 2 and a spaceDimension equal to 3 !");
6660 ret->alloc(nbOfCells,4);
6661 double *retPtr(ret->getPointer());
6662 const mcIdType *nodal(_nodal_connec->begin()),*nodalI(_nodal_connec_index->begin());
6663 const double *coor(_coords->begin());
6664 for(mcIdType i=0;i<nbOfCells;i++,nodalI++,retPtr+=4)
6666 double matrix[16]={0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,0},matrix2[16];
6667 if(nodalI[1]-nodalI[0]>=4)
6669 double aa[3]={coor[nodal[nodalI[0]+1+1]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6670 coor[nodal[nodalI[0]+1+1]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6671 coor[nodal[nodalI[0]+1+1]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]}
6672 ,bb[3]={coor[nodal[nodalI[0]+1+2]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6673 coor[nodal[nodalI[0]+1+2]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6674 coor[nodal[nodalI[0]+1+2]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]};
6675 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]};
6676 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]));
6677 for(int j=0;j<3;j++)
6679 mcIdType nodeId(nodal[nodalI[0]+1+j]);
6680 if(nodeId>=0 && nodeId<nbOfNodes)
6681 std::copy(coor+nodeId*3,coor+(nodeId+1)*3,matrix+4*j);
6684 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! This cell points to an invalid nodeId : " << nodeId << " !";
6685 throw INTERP_KERNEL::Exception(oss.str());
6688 if(sqrt(cc[0]*cc[0]+cc[1]*cc[1]+cc[2]*cc[2])>(1e-3*aa_norm*bb_norm))
6690 INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6691 retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6695 if(nodalI[1]-nodalI[0]==4)
6697 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : cell" << i << " : Presence of The 3 colinear points !";
6698 throw INTERP_KERNEL::Exception(oss.str());
6701 double dd[3]={0.,0.,0.};
6702 for(mcIdType offset=nodalI[0]+1;offset<nodalI[1];offset++)
6703 std::transform(coor+3*nodal[offset],coor+3*(nodal[offset]+1),dd,dd,std::plus<double>());
6704 mcIdType nbOfNodesInCell(nodalI[1]-nodalI[0]-1);
6705 std::transform(dd,dd+3,dd,std::bind(std::multiplies<double>(),std::placeholders::_1,1./(double)nbOfNodesInCell));
6706 std::copy(dd,dd+3,matrix+4*2);
6707 INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6708 retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6713 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! Must be constitued by more than 3 nodes !";
6714 throw INTERP_KERNEL::Exception(oss.str());
6721 * This method expects as input a DataArrayDouble non nul instance 'da' that should be allocated. If not an exception is thrown.
6724 MEDCouplingUMesh *MEDCouplingUMesh::Build0DMeshFromCoords(DataArrayDouble *da)
6727 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build0DMeshFromCoords : instance of DataArrayDouble must be not null !");
6728 da->checkAllocated();
6729 std::string name(da->getName());
6730 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New(name,0));
6732 ret->setName("Mesh");
6734 mcIdType nbOfTuples(da->getNumberOfTuples());
6735 MCAuto<DataArrayIdType> c(DataArrayIdType::New()),cI(DataArrayIdType::New());
6736 c->alloc(2*nbOfTuples,1);
6737 cI->alloc(nbOfTuples+1,1);
6738 mcIdType *cp(c->getPointer()),*cip(cI->getPointer());
6740 for(mcIdType i=0;i<nbOfTuples;i++)
6742 *cp++=INTERP_KERNEL::NORM_POINT1;
6746 ret->setConnectivity(c,cI,true);
6750 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::Build1DMeshFromCoords(DataArrayDouble *da)
6753 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build01MeshFromCoords : instance of DataArrayDouble must be not null !");
6754 da->checkAllocated();
6755 std::string name(da->getName());
6756 MCAuto<MEDCouplingUMesh> ret;
6758 MCAuto<MEDCouplingCMesh> tmp(MEDCouplingCMesh::New());
6759 MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
6760 arr->alloc(da->getNumberOfTuples());
6761 tmp->setCoordsAt(0,arr);
6762 ret=tmp->buildUnstructured();
6766 ret->setName("Mesh");
6773 * Creates a new MEDCouplingUMesh by concatenating two given meshes of the same dimension.
6774 * Cells and nodes of
6775 * the first mesh precede cells and nodes of the second mesh within the result mesh.
6776 * \param [in] mesh1 - the first mesh.
6777 * \param [in] mesh2 - the second mesh.
6778 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6779 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6780 * is no more needed.
6781 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
6782 * \throw If the coordinates array is not set in none of the meshes.
6783 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
6784 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
6786 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
6788 std::vector<const MEDCouplingUMesh *> tmp(2);
6789 tmp[0]=const_cast<MEDCouplingUMesh *>(mesh1); tmp[1]=const_cast<MEDCouplingUMesh *>(mesh2);
6790 return MergeUMeshes(tmp);
6794 * Creates a new MEDCouplingUMesh by concatenating all given meshes of the same dimension.
6795 * Cells and nodes of
6796 * the *i*-th mesh precede cells and nodes of the (*i*+1)-th mesh within the result mesh.
6797 * \param [in] a - a vector of meshes (MEDCouplingUMesh) to concatenate.
6798 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6799 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6800 * is no more needed.
6801 * \throw If \a a.size() == 0.
6802 * \throw If \a a[ *i* ] == NULL.
6803 * \throw If the coordinates array is not set in none of the meshes.
6804 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
6805 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
6807 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const std::vector<const MEDCouplingUMesh *>& a)
6809 std::size_t sz=a.size();
6811 return MergeUMeshesLL(a);
6812 for(std::size_t ii=0;ii<sz;ii++)
6815 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshes : item #" << ii << " in input array of size "<< sz << " is empty !";
6816 throw INTERP_KERNEL::Exception(oss.str());
6818 std::vector< MCAuto<MEDCouplingUMesh> > bb(sz);
6819 std::vector< const MEDCouplingUMesh * > aa(sz);
6821 for(std::size_t i=0;i<sz && spaceDim==-3;i++)
6823 const MEDCouplingUMesh *cur=a[i];
6824 const DataArrayDouble *coo=cur->getCoords();
6826 spaceDim=int(coo->getNumberOfComponents());
6829 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : no spaceDim specified ! unable to perform merge !");
6830 for(std::size_t i=0;i<sz;i++)
6832 bb[i]=a[i]->buildSetInstanceFromThis(spaceDim);
6835 return MergeUMeshesLL(aa);
6839 * Creates a new MEDCouplingUMesh by concatenating cells of two given meshes of same
6840 * dimension and sharing the node coordinates array.
6841 * All cells of the first mesh precede all cells of the second mesh
6842 * within the result mesh.
6843 * \param [in] mesh1 - the first mesh.
6844 * \param [in] mesh2 - the second mesh.
6845 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6846 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6847 * is no more needed.
6848 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
6849 * \throw If the meshes do not share the node coordinates array.
6850 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
6851 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
6853 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
6855 std::vector<const MEDCouplingUMesh *> tmp(2);
6856 tmp[0]=mesh1; tmp[1]=mesh2;
6857 return MergeUMeshesOnSameCoords(tmp);
6861 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
6862 * dimension and sharing the node coordinates array.
6863 * All cells of the *i*-th mesh precede all cells of the
6864 * (*i*+1)-th mesh within the result mesh.
6865 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
6866 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6867 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6868 * is no more needed.
6869 * \throw If \a a.size() == 0.
6870 * \throw If \a a[ *i* ] == NULL.
6871 * \throw If the meshes do not share the node coordinates array.
6872 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
6873 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
6875 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes)
6878 throw INTERP_KERNEL::Exception("meshes input parameter is expected to be non empty.");
6879 for(std::size_t ii=0;ii<meshes.size();ii++)
6882 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshesOnSameCoords : item #" << ii << " in input array of size "<< meshes.size() << " is empty !";
6883 throw INTERP_KERNEL::Exception(oss.str());
6885 const DataArrayDouble *coords=meshes.front()->getCoords();
6886 int meshDim=meshes.front()->getMeshDimension();
6887 std::vector<const MEDCouplingUMesh *>::const_iterator iter=meshes.begin();
6888 mcIdType meshLgth=0;
6889 mcIdType meshIndexLgth=0;
6890 for(;iter!=meshes.end();iter++)
6892 if(coords!=(*iter)->getCoords())
6893 throw INTERP_KERNEL::Exception("meshes does not share the same coords ! Try using tryToShareSameCoords method !");
6894 if(meshDim!=(*iter)->getMeshDimension())
6895 throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, FuseUMeshesOnSameCoords impossible !");
6896 meshLgth+=(*iter)->getNodalConnectivityArrayLen();
6897 meshIndexLgth+=(*iter)->getNumberOfCells();
6899 MCAuto<DataArrayIdType> nodal=DataArrayIdType::New();
6900 nodal->alloc(meshLgth,1);
6901 mcIdType *nodalPtr=nodal->getPointer();
6902 MCAuto<DataArrayIdType> nodalIndex=DataArrayIdType::New();
6903 nodalIndex->alloc(meshIndexLgth+1,1);
6904 mcIdType *nodalIndexPtr=nodalIndex->getPointer();
6906 for(iter=meshes.begin();iter!=meshes.end();iter++)
6908 const mcIdType *nod=(*iter)->getNodalConnectivity()->begin();
6909 const mcIdType *index=(*iter)->getNodalConnectivityIndex()->begin();
6910 mcIdType nbOfCells=(*iter)->getNumberOfCells();
6911 mcIdType meshLgth2=(*iter)->getNodalConnectivityArrayLen();
6912 nodalPtr=std::copy(nod,nod+meshLgth2,nodalPtr);
6913 if(iter!=meshes.begin())
6914 nodalIndexPtr=std::transform(index+1,index+nbOfCells+1,nodalIndexPtr,std::bind(std::plus<mcIdType>(),std::placeholders::_1,offset));
6916 nodalIndexPtr=std::copy(index,index+nbOfCells+1,nodalIndexPtr);
6919 MEDCouplingUMesh *ret=MEDCouplingUMesh::New();
6920 ret->setName("merge");
6921 ret->setMeshDimension(meshDim);
6922 ret->setConnectivity(nodal,nodalIndex,true);
6923 ret->setCoords(coords);
6928 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
6929 * dimension and sharing the node coordinates array. Cells of the *i*-th mesh precede
6930 * cells of the (*i*+1)-th mesh within the result mesh. Duplicates of cells are
6931 * removed from \a this mesh and arrays mapping between new and old cell ids in "Old to
6932 * New" mode are returned for each input mesh.
6933 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
6934 * \param [in] compType - specifies a cell comparison technique. For meaning of its
6935 * valid values [0,1,2], see zipConnectivityTraducer().
6936 * \param [in,out] corr - an array of DataArrayIdType, of the same size as \a
6937 * meshes. The *i*-th array describes cell ids mapping for \a meshes[ *i* ]
6938 * mesh. The caller is to delete each of the arrays using decrRef() as it is
6940 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6941 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6942 * is no more needed.
6943 * \throw If \a meshes.size() == 0.
6944 * \throw If \a meshes[ *i* ] == NULL.
6945 * \throw If the meshes do not share the node coordinates array.
6946 * \throw If \a meshes[ *i* ]->getMeshDimension() < 0.
6947 * \throw If the \a meshes are of different dimension (getMeshDimension()).
6948 * \throw If the nodal connectivity of cells of any of \a meshes is not defined.
6949 * \throw If the nodal connectivity any of \a meshes includes an invalid id.
6951 MEDCouplingUMesh *MEDCouplingUMesh::FuseUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes, int compType, std::vector<DataArrayIdType *>& corr)
6953 //All checks are delegated to MergeUMeshesOnSameCoords
6954 MCAuto<MEDCouplingUMesh> ret=MergeUMeshesOnSameCoords(meshes);
6955 MCAuto<DataArrayIdType> o2n=ret->zipConnectivityTraducer(compType);
6956 corr.resize(meshes.size());
6957 std::size_t nbOfMeshes=meshes.size();
6959 const mcIdType *o2nPtr=o2n->begin();
6960 for(std::size_t i=0;i<nbOfMeshes;i++)
6962 DataArrayIdType *tmp=DataArrayIdType::New();
6963 mcIdType curNbOfCells=meshes[i]->getNumberOfCells();
6964 tmp->alloc(curNbOfCells,1);
6965 std::copy(o2nPtr+offset,o2nPtr+offset+curNbOfCells,tmp->getPointer());
6966 offset+=curNbOfCells;
6967 tmp->setName(meshes[i]->getName());
6974 * Makes all given meshes share the nodal connectivity array. The common connectivity
6975 * array is created by concatenating the connectivity arrays of all given meshes. All
6976 * the given meshes must be of the same space dimension but dimension of cells **can
6977 * differ**. This method is particularly useful in MEDLoader context to build a \ref
6978 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
6979 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
6980 * \param [in,out] meshes - a vector of meshes to update.
6981 * \throw If any of \a meshes is NULL.
6982 * \throw If the coordinates array is not set in any of \a meshes.
6983 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
6984 * \throw If \a meshes are of different space dimension.
6986 void MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords(const std::vector<MEDCouplingUMesh *>& meshes)
6988 std::size_t sz=meshes.size();
6991 std::vector< const DataArrayDouble * > coords(meshes.size());
6992 std::vector< const DataArrayDouble * >::iterator it2=coords.begin();
6993 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++,it2++)
6997 (*it)->checkConnectivityFullyDefined();
6998 const DataArrayDouble *coo=(*it)->getCoords();
7003 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
7004 oss << " has no coordinate array defined !";
7005 throw INTERP_KERNEL::Exception(oss.str());
7010 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
7011 oss << " is null !";
7012 throw INTERP_KERNEL::Exception(oss.str());
7015 MCAuto<DataArrayDouble> res=DataArrayDouble::Aggregate(coords);
7016 std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();
7017 mcIdType offset=(*it)->getNumberOfNodes();
7018 (*it++)->setCoords(res);
7019 for(;it!=meshes.end();it++)
7021 mcIdType oldNumberOfNodes=(*it)->getNumberOfNodes();
7022 (*it)->setCoords(res);
7023 (*it)->shiftNodeNumbersInConn(offset);
7024 offset+=oldNumberOfNodes;
7029 * Merges nodes coincident with a given precision within all given meshes that share
7030 * the nodal connectivity array. The given meshes **can be of different** mesh
7031 * dimension. This method is particularly useful in MEDLoader context to build a \ref
7032 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
7033 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
7034 * \param [in,out] meshes - a vector of meshes to update.
7035 * \param [in] eps - the precision used to detect coincident nodes (infinite norm).
7036 * \throw If any of \a meshes is NULL.
7037 * \throw If the \a meshes do not share the same node coordinates array.
7038 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
7040 void MEDCouplingUMesh::MergeNodesOnUMeshesSharingSameCoords(const std::vector<MEDCouplingUMesh *>& meshes, double eps)
7044 std::set<const DataArrayDouble *> s;
7045 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
7048 s.insert((*it)->getCoords());
7051 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 !";
7052 throw INTERP_KERNEL::Exception(oss.str());
7057 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 !";
7058 throw INTERP_KERNEL::Exception(oss.str());
7060 const DataArrayDouble *coo=*(s.begin());
7064 DataArrayIdType *comm,*commI;
7065 coo->findCommonTuples(eps,-1,comm,commI);
7066 MCAuto<DataArrayIdType> tmp1(comm),tmp2(commI);
7067 mcIdType oldNbOfNodes=coo->getNumberOfTuples();
7068 mcIdType newNbOfNodes;
7069 MCAuto<DataArrayIdType> o2n=DataArrayIdType::ConvertIndexArrayToO2N(oldNbOfNodes,comm->begin(),commI->begin(),commI->end(),newNbOfNodes);
7070 if(oldNbOfNodes==newNbOfNodes)
7072 MCAuto<DataArrayDouble> newCoords=coo->renumberAndReduce(o2n->begin(),newNbOfNodes);
7073 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
7075 (*it)->renumberNodesInConn(o2n->begin());
7076 (*it)->setCoords(newCoords);
7082 * This static operates only for coords in 3D. The polygon is specified by its connectivity nodes in [ \a begin , \a end ).
7084 bool MEDCouplingUMesh::IsPolygonWellOriented(bool isQuadratic, const double *vec, const mcIdType *begin, const mcIdType *end, const double *coords)
7087 double v[3]={0.,0.,0.};
7088 std::size_t sz=std::distance(begin,end);
7092 // Algorithm: sum in v the cross products of (e1, e2) where e_i it the vector between (0,0,0) and point i
7093 // and e2 is linear point directly following e1 in the connectivity. All points are used.
7094 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];
7095 v[1]+=coords[3*begin[i]+2]*coords[3*begin[(i+1)%sz]]-coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+2];
7096 v[2]+=coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+1]-coords[3*begin[i]+1]*coords[3*begin[(i+1)%sz]];
7100 // Same algorithm as above but also using intermediate quadratic points.
7101 // (taking only linear points might lead to issues if the linearized version of the
7102 // polygon is not convex or self-intersecting ... see testCellOrientation4)
7103 std::size_t hsz = sz/2;
7104 for(std::size_t j=0;j<sz;j++)
7106 if (j%2) // current point i is quadratic, next point i+1 is standard
7109 ip1 = ((j-1)/2 + 1)%hsz; // ip1 means "i+1", i.e. next point
7111 else // current point i is standard, next point i+1 is quadratic
7116 v[0]+=coords[3*begin[i]+1]*coords[3*begin[ip1]+2]-coords[3*begin[i]+2]*coords[3*begin[ip1]+1];
7117 v[1]+=coords[3*begin[i]+2]*coords[3*begin[ip1]]-coords[3*begin[i]]*coords[3*begin[ip1]+2];
7118 v[2]+=coords[3*begin[i]]*coords[3*begin[ip1]+1]-coords[3*begin[i]+1]*coords[3*begin[ip1]];
7121 double ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
7126 * The polyhedron is specified by its connectivity nodes in [ \a begin , \a end ).
7128 bool MEDCouplingUMesh::IsPolyhedronWellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7130 std::vector<std::pair<mcIdType,mcIdType> > edges;
7131 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
7132 const mcIdType *bgFace=begin;
7133 for(std::size_t i=0;i<nbOfFaces;i++)
7135 const mcIdType *endFace=std::find(bgFace+1,end,-1);
7136 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
7137 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7139 std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7140 if(std::find(edges.begin(),edges.end(),p1)!=edges.end())
7142 edges.push_back(p1);
7146 return INTERP_KERNEL::calculateVolumeForPolyh2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,ToIdType(std::distance(begin,end)),coords)>-EPS_FOR_POLYH_ORIENTATION;
7150 * The 3D extruded static cell (PENTA6,HEXA8,HEXAGP12...) its connectivity nodes in [ \a begin , \a end ).
7152 bool MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7154 double vec0[3],vec1[3];
7155 std::size_t sz=std::distance(begin,end);
7157 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented : the length of nodal connectivity of extruded cell is not even !");
7158 mcIdType nbOfNodes=ToIdType(sz/2);
7159 INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,nbOfNodes,coords,vec0);
7160 const double *pt0=coords+3*begin[0];
7161 const double *pt1=coords+3*begin[nbOfNodes];
7162 vec1[0]=pt1[0]-pt0[0]; vec1[1]=pt1[1]-pt0[1]; vec1[2]=pt1[2]-pt0[2];
7163 return (vec0[0]*vec1[0]+vec0[1]*vec1[1]+vec0[2]*vec1[2])<0.;
7166 void MEDCouplingUMesh::CorrectExtrudedStaticCell(mcIdType *begin, mcIdType *end)
7168 std::size_t sz=std::distance(begin,end);
7169 INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz];
7170 std::size_t nbOfNodes(sz/2);
7171 std::copy(begin,end,(mcIdType *)tmp);
7172 for(std::size_t j=1;j<nbOfNodes;j++)
7174 begin[j]=tmp[nbOfNodes-j];
7175 begin[j+nbOfNodes]=tmp[nbOfNodes+nbOfNodes-j];
7179 bool MEDCouplingUMesh::IsTetra4WellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7181 std::size_t sz=std::distance(begin,end);
7183 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsTetra4WellOriented : Tetra4 cell with not 4 nodes ! Call checkConsistency !");
7184 double vec0[3],vec1[3];
7185 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[1],*pt2=coords+3*begin[2],*pt3=coords+3*begin[3];
7186 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];
7187 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;
7190 bool MEDCouplingUMesh::IsPyra5WellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7192 std::size_t sz=std::distance(begin,end);
7194 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsPyra5WellOriented : Pyra5 cell with not 5 nodes ! Call checkConsistency !");
7196 INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,4,coords,vec0);
7197 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[4];
7198 return (vec0[0]*(pt1[0]-pt0[0])+vec0[1]*(pt1[1]-pt0[1])+vec0[2]*(pt1[2]-pt0[2]))<0.;
7202 * 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 )
7203 * 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
7206 * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not.
7207 * \param [in] coords the coordinates with nb of components exactly equal to 3
7208 * \param [in] index begin of the nodal connectivity (geometric type included) of a single polyhedron cell
7209 * \param [out] res the result is put at the end of the vector without any alteration of the data.
7211 void MEDCouplingUMesh::SimplifyPolyhedronCell(double eps, const DataArrayDouble *coords, mcIdType index, DataArrayIdType *res, MEDCouplingUMesh *faces,
7212 DataArrayIdType *E_Fi, DataArrayIdType *E_F, DataArrayIdType *F_Ei, DataArrayIdType *F_E)
7214 mcIdType nbFaces = E_Fi->getIJ(index + 1, 0) - E_Fi->getIJ(index, 0);
7215 MCAuto<DataArrayDouble> v=DataArrayDouble::New(); v->alloc(nbFaces,3);
7216 double *vPtr=v->getPointer();
7217 MCAuto<DataArrayDouble> p=DataArrayDouble::New(); p->alloc(nbFaces,2);
7218 double *pPtr=p->getPointer();
7219 mcIdType *e_fi = E_Fi->getPointer(), *e_f = E_F->getPointer(), *f_ei = F_Ei->getPointer(), *f_e = F_E->getPointer();
7220 const mcIdType *f_idx = faces->getNodalConnectivityIndex()->getPointer(), *f_cnn = faces->getNodalConnectivity()->getPointer();
7221 for(mcIdType i=0;i<nbFaces;i++,vPtr+=3,pPtr++)
7223 mcIdType face = e_f[e_fi[index] + i];
7224 ComputeVecAndPtOfFace(eps, coords->begin(), f_cnn + f_idx[face] + 1, f_cnn + f_idx[face + 1], vPtr, pPtr);
7225 // to differentiate faces going to different cells:
7227 for (mcIdType j = f_ei[face]; j < f_ei[face + 1]; j++)
7228 *pPtr += FromIdType<double>(f_e[j]);
7230 pPtr=p->getPointer(); vPtr=v->getPointer();
7231 DataArrayIdType *comm1=0,*commI1=0;
7232 v->findCommonTuples(eps,-1,comm1,commI1);
7233 for (mcIdType i = 0; i < nbFaces; i++)
7234 if (comm1->findIdFirstEqual(i) < 0)
7236 comm1->pushBackSilent(i);
7237 commI1->pushBackSilent(comm1->getNumberOfTuples());
7239 MCAuto<DataArrayIdType> comm1Auto(comm1),commI1Auto(commI1);
7240 const mcIdType *comm1Ptr=comm1->begin();
7241 const mcIdType *commI1Ptr=commI1->begin();
7242 mcIdType nbOfGrps1=commI1Auto->getNumberOfTuples()-1;
7243 res->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYHED));
7245 for(mcIdType i=0;i<nbOfGrps1;i++)
7247 mcIdType vecId=comm1Ptr[commI1Ptr[i]];
7248 MCAuto<DataArrayDouble> tmpgrp2=p->selectByTupleId(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7249 DataArrayIdType *comm2=0,*commI2=0;
7250 tmpgrp2->findCommonTuples(eps,-1,comm2,commI2);
7251 for (mcIdType j = 0; j < commI1Ptr[i+1] - commI1Ptr[i]; j++)
7252 if (comm2->findIdFirstEqual(j) < 0)
7254 comm2->pushBackSilent(j);
7255 commI2->pushBackSilent(comm2->getNumberOfTuples());
7257 MCAuto<DataArrayIdType> comm2Auto(comm2),commI2Auto(commI2);
7258 const mcIdType *comm2Ptr=comm2->begin();
7259 const mcIdType *commI2Ptr=commI2->begin();
7260 mcIdType nbOfGrps2=commI2Auto->getNumberOfTuples()-1;
7261 for(mcIdType j=0;j<nbOfGrps2;j++)
7263 if(commI2Ptr[j+1] == commI2Ptr[j] + 1)
7265 mcIdType face = e_f[e_fi[index] + comm1Ptr[commI1Ptr[i] + comm2Ptr[commI2Ptr[j]]]]; //hmmm
7266 res->insertAtTheEnd(f_cnn + f_idx[face] + 1, f_cnn + f_idx[face + 1]);
7267 res->pushBackSilent(-1);
7271 mcIdType pointId=comm1Ptr[commI1Ptr[i]+comm2Ptr[commI2Ptr[j]]];
7272 MCAuto<DataArrayIdType> ids2=comm2->selectByTupleIdSafeSlice(commI2Ptr[j],commI2Ptr[j+1],1);
7273 ids2->transformWithIndArr(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7274 ids2->transformWithIndArr(e_f + e_fi[index], e_f + e_fi[index + 1]);
7275 MCAuto<MEDCouplingUMesh> mm3=static_cast<MEDCouplingUMesh *>(faces->buildPartOfMySelf(ids2->begin(),ids2->end(),true));
7276 MCAuto<DataArrayIdType> idsNodeTmp=mm3->zipCoordsTraducer();
7277 MCAuto<DataArrayIdType> idsNode=idsNodeTmp->invertArrayO2N2N2O(mm3->getNumberOfNodes());
7278 const mcIdType *idsNodePtr=idsNode->begin();
7279 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];
7280 double vec[3]; vec[0]=vPtr[3*vecId+1]; vec[1]=-vPtr[3*vecId]; vec[2]=0.;
7281 double norm=vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2];
7282 if(std::abs(norm)>eps)
7284 double angle=INTERP_KERNEL::EdgeArcCircle::SafeAsin(norm);
7285 mm3->rotate(center,vec,angle);
7287 mm3->changeSpaceDimension(2);
7288 MCAuto<MEDCouplingUMesh> mm4=mm3->buildSpreadZonesWithPoly();
7289 const mcIdType *conn4=mm4->getNodalConnectivity()->begin();
7290 const mcIdType *connI4=mm4->getNodalConnectivityIndex()->begin();
7291 mcIdType nbOfCells=mm4->getNumberOfCells();
7292 for(mcIdType k=0;k<nbOfCells;k++)
7295 for(const mcIdType *work=conn4+connI4[k]+1;work!=conn4+connI4[k+1];work++,l++)
7296 res->pushBackSilent(idsNodePtr[*work]);
7297 res->pushBackSilent(-1);
7302 res->popBackSilent();
7306 * 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
7307 * through origin. The plane is defined by its nodal connectivity [ \b begin, \b end ).
7309 * \param [in] eps below that value the dot product of 2 vectors is considered as colinears
7310 * \param [in] coords coordinates expected to have 3 components.
7311 * \param [in] begin start of the nodal connectivity of the face.
7312 * \param [in] end end of the nodal connectivity (excluded) of the face.
7313 * \param [out] v the normalized vector of size 3
7314 * \param [out] p the pos of plane
7316 void MEDCouplingUMesh::ComputeVecAndPtOfFace(double eps, const double *coords, const mcIdType *begin, const mcIdType *end, double *v, double *p)
7318 std::size_t nbPoints=std::distance(begin,end);
7320 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeVecAndPtOfFace : < of 3 points in face ! not able to find a plane on that face !");
7321 double vec[3]={0.,0.,0.};
7323 bool refFound=false;
7324 for(;j<nbPoints-1 && !refFound;j++)
7326 vec[0]=coords[3*begin[j+1]]-coords[3*begin[j]];
7327 vec[1]=coords[3*begin[j+1]+1]-coords[3*begin[j]+1];
7328 vec[2]=coords[3*begin[j+1]+2]-coords[3*begin[j]+2];
7329 double norm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
7333 vec[0]/=norm; vec[1]/=norm; vec[2]/=norm;
7336 for(std::size_t i=j;i<nbPoints-1;i++)
7339 curVec[0]=coords[3*begin[i+1]]-coords[3*begin[i]];
7340 curVec[1]=coords[3*begin[i+1]+1]-coords[3*begin[i]+1];
7341 curVec[2]=coords[3*begin[i+1]+2]-coords[3*begin[i]+2];
7342 double norm=sqrt(curVec[0]*curVec[0]+curVec[1]*curVec[1]+curVec[2]*curVec[2]);
7345 curVec[0]/=norm; curVec[1]/=norm; curVec[2]/=norm;
7346 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];
7347 norm=sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
7350 v[0]/=norm; v[1]/=norm; v[2]/=norm;
7351 *p=v[0]*coords[3*begin[i]]+v[1]*coords[3*begin[i]+1]+v[2]*coords[3*begin[i]+2];
7355 throw INTERP_KERNEL::Exception("Not able to find a normal vector of that 3D face !");
7359 * This method tries to obtain a well oriented polyhedron.
7360 * If the algorithm fails, an exception will be thrown.
7362 void MEDCouplingUMesh::TryToCorrectPolyhedronOrientation(mcIdType *begin, mcIdType *end, const double *coords)
7364 std::list< std::pair<mcIdType,mcIdType> > edgesOK,edgesFinished;
7365 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
7366 std::vector<bool> isPerm(nbOfFaces,false);//field on faces False: I don't know, True : oriented
7368 mcIdType *bgFace=begin,*endFace=std::find(begin+1,end,-1);
7369 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
7370 for(std::size_t l=0;l<nbOfEdgesInFace;l++) { std::pair<mcIdType,mcIdType> p1(bgFace[l],bgFace[(l+1)%nbOfEdgesInFace]); edgesOK.push_back(p1); }
7372 while(std::find(isPerm.begin(),isPerm.end(),false)!=isPerm.end())
7375 std::size_t smthChanged=0;
7376 for(std::size_t i=0;i<nbOfFaces;i++)
7378 endFace=std::find(bgFace+1,end,-1);
7379 nbOfEdgesInFace=std::distance(bgFace,endFace);
7383 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7385 std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7386 std::pair<mcIdType,mcIdType> p2(p1.second,p1.first);
7387 bool b1=std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end();
7388 bool b2=std::find(edgesOK.begin(),edgesOK.end(),p2)!=edgesOK.end();
7389 if(b1 || b2) { b=b2; isPerm[i]=true; smthChanged++; break; }
7394 std::reverse(bgFace+1,endFace);
7395 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7397 std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7398 std::pair<mcIdType,mcIdType> p2(p1.second,p1.first);
7399 if(std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end())
7400 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7401 if(std::find(edgesFinished.begin(),edgesFinished.end(),p1)!=edgesFinished.end() || std::find(edgesFinished.begin(),edgesFinished.end(),p2)!=edgesFinished.end())
7402 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7403 std::list< std::pair<mcIdType,mcIdType> >::iterator it=std::find(edgesOK.begin(),edgesOK.end(),p2);
7404 if(it!=edgesOK.end())
7407 edgesFinished.push_back(p1);
7410 edgesOK.push_back(p1);
7417 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired !"); }
7419 if(!edgesOK.empty())
7420 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired : Some edges are shared only once !"); }
7421 if(INTERP_KERNEL::calculateVolumeForPolyh2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,ToIdType(std::distance(begin,end)),coords)<-EPS_FOR_POLYH_ORIENTATION)
7422 {//not lucky ! The first face was not correctly oriented : reorient all faces...
7424 for(std::size_t i=0;i<nbOfFaces;i++)
7426 endFace=std::find(bgFace+1,end,-1);
7427 std::reverse(bgFace+1,endFace);
7435 * This method makes the assumption spacedimension == meshdimension == 2.
7436 * This method works only for linear cells.
7438 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYGON in pos#0)
7440 DataArrayIdType *MEDCouplingUMesh::buildUnionOf2DMesh() const
7442 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
7443 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : meshdimension, spacedimension must be equal to 2 !");
7444 MCAuto<MEDCouplingUMesh> skin(computeSkin());
7445 mcIdType oldNbOfNodes(skin->getNumberOfNodes());
7446 MCAuto<DataArrayIdType> o2n(skin->zipCoordsTraducer());
7447 mcIdType nbOfNodesExpected(skin->getNumberOfNodes());
7448 MCAuto<DataArrayIdType> n2o(o2n->invertArrayO2N2N2O(oldNbOfNodes));
7449 mcIdType nbCells=skin->getNumberOfCells();
7450 if(nbCells==nbOfNodesExpected)
7451 return buildUnionOf2DMeshLinear(skin,n2o);
7452 else if(2*nbCells==nbOfNodesExpected)
7453 return buildUnionOf2DMeshQuadratic(skin,n2o);
7455 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : the mesh 2D in input appears to be not in a single part of a 2D mesh !");
7459 * This method makes the assumption spacedimension == meshdimension == 3.
7460 * This method works only for linear cells.
7462 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYHED in pos#0)
7464 DataArrayIdType *MEDCouplingUMesh::buildUnionOf3DMesh() const
7466 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
7467 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf3DMesh : meshdimension, spacedimension must be equal to 2 !");
7468 MCAuto<MEDCouplingUMesh> m=computeSkin();
7469 const mcIdType *conn=m->getNodalConnectivity()->begin();
7470 const mcIdType *connI=m->getNodalConnectivityIndex()->begin();
7471 mcIdType nbOfCells=m->getNumberOfCells();
7472 MCAuto<DataArrayIdType> ret=DataArrayIdType::New(); ret->alloc(m->getNodalConnectivity()->getNumberOfTuples(),1);
7473 mcIdType *work=ret->getPointer(); *work++=INTERP_KERNEL::NORM_POLYHED;
7476 work=std::copy(conn+connI[0]+1,conn+connI[1],work);
7477 for(mcIdType i=1;i<nbOfCells;i++)
7480 work=std::copy(conn+connI[i]+1,conn+connI[i+1],work);
7486 * \brief Creates a graph of cell neighbors
7487 * \return MEDCouplingSkyLineArray * - an sky line array the user should delete.
7488 * In the sky line array, graph arcs are stored in terms of (index,value) notation.
7490 * - index: 0 3 5 6 6
7491 * - value: 1 2 3 2 3 3
7492 * means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7493 * Arcs are not doubled but reflexive (1,1) arcs are present for each cell
7495 MEDCouplingSkyLineArray* MEDCouplingUMesh::generateGraph() const
7497 checkConnectivityFullyDefined();
7499 int meshDim = this->getMeshDimension();
7500 MEDCoupling::DataArrayIdType* indexr=MEDCoupling::DataArrayIdType::New();
7501 MEDCoupling::DataArrayIdType* revConn=MEDCoupling::DataArrayIdType::New();
7502 this->getReverseNodalConnectivity(revConn,indexr);
7503 const mcIdType* indexr_ptr=indexr->begin();
7504 const mcIdType* revConn_ptr=revConn->begin();
7506 const MEDCoupling::DataArrayIdType* index;
7507 const MEDCoupling::DataArrayIdType* conn;
7508 conn=this->getNodalConnectivity(); // it includes a type as the 1st element!!!
7509 index=this->getNodalConnectivityIndex();
7510 mcIdType nbCells=this->getNumberOfCells();
7511 const mcIdType* index_ptr=index->begin();
7512 const mcIdType* conn_ptr=conn->begin();
7514 //creating graph arcs (cell to cell relations)
7515 //arcs are stored in terms of (index,value) notation
7518 // means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7519 // in present version arcs are not doubled but reflexive (1,1) arcs are present for each cell
7521 //warning here one node have less than or equal effective number of cell with it
7522 //but cell could have more than effective nodes
7523 //because other equals nodes in other domain (with other global inode)
7524 std::vector <mcIdType> cell2cell_index(nbCells+1,0);
7525 std::vector <mcIdType> cell2cell;
7526 cell2cell.reserve(3*nbCells);
7528 for (mcIdType icell=0; icell<nbCells;icell++)
7530 std::map<mcIdType,mcIdType > counter;
7531 for (mcIdType iconn=index_ptr[icell]+1; iconn<index_ptr[icell+1];iconn++)
7533 mcIdType inode=conn_ptr[iconn];
7534 for (mcIdType iconnr=indexr_ptr[inode]; iconnr<indexr_ptr[inode+1];iconnr++)
7536 mcIdType icell2=revConn_ptr[iconnr];
7537 std::map<mcIdType,mcIdType>::iterator iter=counter.find(icell2);
7538 if (iter!=counter.end()) (iter->second)++;
7539 else counter.insert(std::make_pair(icell2,1));
7542 for (std::map<mcIdType,mcIdType>::const_iterator iter=counter.begin();
7543 iter!=counter.end(); iter++)
7544 if (iter->second >= meshDim)
7546 cell2cell_index[icell+1]++;
7547 cell2cell.push_back(iter->first);
7552 cell2cell_index[0]=0;
7553 for (mcIdType icell=0; icell<nbCells;icell++)
7554 cell2cell_index[icell+1]=cell2cell_index[icell]+cell2cell_index[icell+1];
7556 //filling up index and value to create skylinearray structure
7557 MEDCouplingSkyLineArray * array(MEDCouplingSkyLineArray::New(cell2cell_index,cell2cell));
7562 void MEDCouplingUMesh::writeVTKLL(std::ostream& ofs, const std::string& cellData, const std::string& pointData, DataArrayByte *byteData) const
7564 mcIdType nbOfCells=getNumberOfCells();
7566 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::writeVTK : the unstructured mesh has no cells !");
7567 ofs << " <" << getVTKDataSetType() << ">\n";
7568 ofs << " <Piece NumberOfPoints=\"" << getNumberOfNodes() << "\" NumberOfCells=\"" << nbOfCells << "\">\n";
7569 ofs << " <PointData>\n" << pointData << std::endl;
7570 ofs << " </PointData>\n";
7571 ofs << " <CellData>\n" << cellData << std::endl;
7572 ofs << " </CellData>\n";
7573 ofs << " <Points>\n";
7574 if(getSpaceDimension()==3)
7575 _coords->writeVTK(ofs,8,"Points",byteData);
7578 MCAuto<DataArrayDouble> coo=_coords->changeNbOfComponents(3,0.);
7579 coo->writeVTK(ofs,8,"Points",byteData);
7581 ofs << " </Points>\n";
7582 ofs << " <Cells>\n";
7583 const mcIdType *cPtr=_nodal_connec->begin();
7584 const mcIdType *cIPtr=_nodal_connec_index->begin();
7585 MCAuto<DataArrayIdType> faceoffsets=DataArrayIdType::New(); faceoffsets->alloc(nbOfCells,1);
7586 MCAuto<DataArrayIdType> types=DataArrayIdType::New(); types->alloc(nbOfCells,1);
7587 MCAuto<DataArrayIdType> offsets=DataArrayIdType::New(); offsets->alloc(nbOfCells,1);
7588 MCAuto<DataArrayIdType> connectivity=DataArrayIdType::New(); connectivity->alloc(_nodal_connec->getNumberOfTuples()-nbOfCells,1);
7589 mcIdType *w1=faceoffsets->getPointer(),*w2=types->getPointer(),*w3=offsets->getPointer(),*w4=connectivity->getPointer();
7590 mcIdType szFaceOffsets=0,szConn=0;
7591 for(mcIdType i=0;i<nbOfCells;i++,w1++,w2++,w3++)
7594 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]!=INTERP_KERNEL::NORM_POLYHED)
7597 *w3=szConn+cIPtr[i+1]-cIPtr[i]-1; szConn+=cIPtr[i+1]-cIPtr[i]-1;
7598 w4=std::copy(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],w4);
7602 mcIdType deltaFaceOffset=cIPtr[i+1]-cIPtr[i]+1;
7603 *w1=szFaceOffsets+deltaFaceOffset; szFaceOffsets+=deltaFaceOffset;
7604 std::set<mcIdType> c(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1]); c.erase(-1);
7605 *w3=szConn+ToIdType(c.size()); szConn+=ToIdType(c.size());
7606 w4=std::copy(c.begin(),c.end(),w4);
7609 std::unique_ptr<mcIdType[]> medcoupling2vtkTypeTraducer_mcIdType(new mcIdType[MEDCOUPLING2VTKTYPETRADUCER_LGTH]);
7610 for(auto ii = 0; ii<MEDCOUPLING2VTKTYPETRADUCER_LGTH ; ++ii)
7611 medcoupling2vtkTypeTraducer_mcIdType[ii] = MEDCOUPLING2VTKTYPETRADUCER[ii]!=MEDCOUPLING2VTKTYPETRADUCER_NONE?MEDCOUPLING2VTKTYPETRADUCER[ii] : -1;
7612 types->transformWithIndArr(medcoupling2vtkTypeTraducer_mcIdType.get(),medcoupling2vtkTypeTraducer_mcIdType.get()+MEDCOUPLING2VTKTYPETRADUCER_LGTH);
7613 types->writeVTK(ofs,8,"UInt8","types",byteData);
7614 std::string vtkTypeName = Traits<mcIdType>::VTKReprStr;
7615 offsets->writeVTK(ofs,8,vtkTypeName,"offsets",byteData);
7616 if(szFaceOffsets!=0)
7617 {//presence of Polyhedra
7618 connectivity->reAlloc(szConn);
7619 faceoffsets->writeVTK(ofs,8,vtkTypeName,"faceoffsets",byteData);
7620 MCAuto<DataArrayIdType> faces=DataArrayIdType::New(); faces->alloc(szFaceOffsets,1);
7621 w1=faces->getPointer();
7622 for(mcIdType i=0;i<nbOfCells;i++)
7623 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]==INTERP_KERNEL::NORM_POLYHED)
7625 mcIdType nbFaces=ToIdType(std::count(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],-1))+1;
7627 const mcIdType *w6=cPtr+cIPtr[i]+1,*w5=0;
7628 for(mcIdType j=0;j<nbFaces;j++)
7630 w5=std::find(w6,cPtr+cIPtr[i+1],-1);
7631 *w1++=ToIdType(std::distance(w6,w5));
7632 w1=std::copy(w6,w5,w1);
7636 faces->writeVTK(ofs,8,vtkTypeName,"faces",byteData);
7638 connectivity->writeVTK(ofs,8,vtkTypeName,"connectivity",byteData);
7639 ofs << " </Cells>\n";
7640 ofs << " </Piece>\n";
7641 ofs << " </" << getVTKDataSetType() << ">\n";
7644 void MEDCouplingUMesh::reprQuickOverview(std::ostream& stream) const
7646 stream << "MEDCouplingUMesh C++ instance at " << this << ". Name : \"" << getName() << "\".";
7648 { stream << " Not set !"; return ; }
7649 stream << " Mesh dimension : " << _mesh_dim << ".";
7653 { stream << " No coordinates set !"; return ; }
7654 if(!_coords->isAllocated())
7655 { stream << " Coordinates set but not allocated !"; return ; }
7656 stream << " Space dimension : " << _coords->getNumberOfComponents() << "." << std::endl;
7657 stream << "Number of nodes : " << _coords->getNumberOfTuples() << ".";
7658 if(!_nodal_connec_index)
7659 { stream << std::endl << "Nodal connectivity NOT set !"; return ; }
7660 if(!_nodal_connec_index->isAllocated())
7661 { stream << std::endl << "Nodal connectivity set but not allocated !"; return ; }
7662 mcIdType lgth=_nodal_connec_index->getNumberOfTuples();
7663 std::size_t cpt=_nodal_connec_index->getNumberOfComponents();
7664 if(cpt!=1 || lgth<1)
7666 stream << std::endl << "Number of cells : " << lgth-1 << ".";
7669 std::string MEDCouplingUMesh::getVTKDataSetType() const
7671 return std::string("UnstructuredGrid");
7674 std::string MEDCouplingUMesh::getVTKFileExtension() const
7676 return std::string("vtu");
7682 * Provides a renumbering of the cells of this (which has to be a piecewise connected 1D line), so that
7683 * the segments of the line are indexed in consecutive order (i.e. cells \a i and \a i+1 are neighbors).
7684 * This doesn't modify the mesh. This method only works using nodal connectivity consideration. Coordinates of nodes are ignored here.
7685 * The caller is to deal with the resulting DataArrayIdType.
7686 * \throw If the coordinate array is not set.
7687 * \throw If the nodal connectivity of the cells is not defined.
7688 * \throw If m1 is not a mesh of dimension 2, or m1 is not a mesh of dimension 1
7689 * \throw If m2 is not a (piecewise) line (i.e. if a point has more than 2 adjacent segments)
7691 * \sa DataArrayIdType::sortEachPairToMakeALinkedList
7693 DataArrayIdType *MEDCouplingUMesh::orderConsecutiveCells1D() const
7695 checkFullyDefined();
7696 if(getMeshDimension()!=1)
7697 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D works on unstructured mesh with meshdim = 1 !");
7699 // Check that this is a line (and not a more complex 1D mesh) - each point is used at most by 2 segments:
7700 MCAuto<DataArrayIdType> _d(DataArrayIdType::New()),_dI(DataArrayIdType::New());
7701 MCAuto<DataArrayIdType> _rD(DataArrayIdType::New()),_rDI(DataArrayIdType::New());
7702 MCAuto<MEDCouplingUMesh> m_points(buildDescendingConnectivity(_d, _dI, _rD, _rDI));
7703 const mcIdType *d(_d->begin()), *dI(_dI->begin());
7704 const mcIdType *rD(_rD->begin()), *rDI(_rDI->begin());
7705 MCAuto<DataArrayIdType> _dsi(_rDI->deltaShiftIndex());
7706 const mcIdType * dsi(_dsi->begin());
7707 MCAuto<DataArrayIdType> dsii = _dsi->findIdsNotInRange(0,3);
7709 if (dsii->getNumberOfTuples())
7710 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D only work with a mesh being a (piecewise) connected line!");
7712 mcIdType nc=getNumberOfCells();
7713 MCAuto<DataArrayIdType> result(DataArrayIdType::New());
7714 result->alloc(nc,1);
7716 // set of edges not used so far
7717 std::set<mcIdType> edgeSet;
7718 for (mcIdType i=0; i<nc; edgeSet.insert(i), i++);
7720 mcIdType startSeg=0;
7722 // while we have points with only one neighbor segments
7725 std::list<mcIdType> linePiece;
7726 // fills a list of consecutive segment linked to startSeg. This can go forward or backward.
7727 for (int direction=0;direction<2;direction++) // direction=0 --> forward, direction=1 --> backward
7729 // Fill the list forward (resp. backward) from the start segment:
7730 mcIdType activeSeg = startSeg;
7731 mcIdType prevPointId = -20;
7733 while (!edgeSet.empty())
7735 if (!(direction == 1 && prevPointId==-20)) // prevent adding twice startSeg
7738 linePiece.push_back(activeSeg);
7740 linePiece.push_front(activeSeg);
7741 edgeSet.erase(activeSeg);
7744 mcIdType ptId1 = d[dI[activeSeg]], ptId2 = d[dI[activeSeg]+1];
7745 ptId = direction ? (ptId1 == prevPointId ? ptId2 : ptId1) : (ptId2 == prevPointId ? ptId1 : ptId2);
7746 if (dsi[ptId] == 1) // hitting the end of the line
7749 mcIdType seg1 = rD[rDI[ptId]], seg2 = rD[rDI[ptId]+1];
7750 activeSeg = (seg1 == activeSeg) ? seg2 : seg1;
7753 // Done, save final piece into DA:
7754 std::copy(linePiece.begin(), linePiece.end(), result->getPointer()+newIdx);
7755 newIdx += ToIdType(linePiece.size());
7757 // identify next valid start segment (one which is not consumed)
7758 if(!edgeSet.empty())
7759 startSeg = *(edgeSet.begin());
7761 while (!edgeSet.empty());
7762 return result.retn();
7766 * This method split some of edges of 2D cells in \a this. The edges to be split are specified in \a subNodesInSeg
7767 * and in \a subNodesInSegI using \ref numbering-indirect storage mode.
7768 * To do the work this method can optionally needs information about middle of subedges for quadratic cases if
7769 * a minimal creation of new nodes is wanted.
7770 * So this method try to reduce at most the number of new nodes. The only case that can lead this method to add
7771 * nodes if a SEG3 is split without information of middle.
7772 * \b WARNING : is returned value is different from 0 a call to MEDCouplingUMesh::mergeNodes is necessary to
7773 * avoid to have a non conform mesh.
7775 * \return mcIdType - the number of new nodes created (in most of cases 0).
7777 * \throw If \a this is not coherent.
7778 * \throw If \a this has not spaceDim equal to 2.
7779 * \throw If \a this has not meshDim equal to 2.
7780 * \throw If some subcells needed to be split are orphan.
7781 * \sa MEDCouplingUMesh::conformize2D
7783 mcIdType MEDCouplingUMesh::split2DCells(const DataArrayIdType *desc, const DataArrayIdType *descI, const DataArrayIdType *subNodesInSeg, const DataArrayIdType *subNodesInSegI, const DataArrayIdType *midOpt, const DataArrayIdType *midOptI)
7785 if(!desc || !descI || !subNodesInSeg || !subNodesInSegI)
7786 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : the 4 first arrays must be not null !");
7787 desc->checkAllocated(); descI->checkAllocated(); subNodesInSeg->checkAllocated(); subNodesInSegI->checkAllocated();
7788 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
7789 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : This method only works for meshes with spaceDim=2 and meshDim=2 !");
7790 if(midOpt==0 && midOptI==0)
7792 split2DCellsLinear(desc,descI,subNodesInSeg,subNodesInSegI);
7795 else if(midOpt!=0 && midOptI!=0)
7796 return split2DCellsQuadratic(desc,descI,subNodesInSeg,subNodesInSegI,midOpt,midOptI);
7798 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : middle parameters must be set to null for all or not null for all.");
7802 * 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
7803 * 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
7804 * the geometric cell type set to INTERP_KERNEL::NORM_POLYGON.
7805 * 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
7806 * 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.
7808 * \return false if the input connectivity represents already the convex hull, true if the input cell needs to be reordered.
7810 bool MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis(const double *coords, const mcIdType *nodalConnBg, const mcIdType *nodalConnEnd, DataArrayIdType *nodalConnecOut)
7812 std::size_t sz=std::distance(nodalConnBg,nodalConnEnd);
7815 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)*nodalConnBg);
7816 if(cm.getDimension()==2)
7818 const mcIdType *node=nodalConnBg+1;
7819 mcIdType startNode=*node++;
7820 double refX=coords[2*startNode];
7821 for(;node!=nodalConnEnd;node++)
7823 if(coords[2*(*node)]<refX)
7826 refX=coords[2*startNode];
7829 std::vector<mcIdType> tmpOut; tmpOut.reserve(sz); tmpOut.push_back(startNode);
7833 double angle0=-M_PI/2;
7835 mcIdType nextNode=-1;
7836 mcIdType prevNode=-1;
7838 double angleNext=0.;
7839 while(nextNode!=startNode)
7843 for(node=nodalConnBg+1;node!=nodalConnEnd;node++)
7845 if(*node!=tmpOut.back() && *node!=prevNode)
7847 tmp2[0]=coords[2*(*node)]-coords[2*tmpOut.back()]; tmp2[1]=coords[2*(*node)+1]-coords[2*tmpOut.back()+1];
7848 double angleM=INTERP_KERNEL::EdgeArcCircle::GetAbsoluteAngle(tmp2,tmp1);
7853 res=angle0-angleM+2.*M_PI;
7862 if(nextNode!=startNode)
7864 angle0=angleNext-M_PI;
7867 prevNode=tmpOut.back();
7868 tmpOut.push_back(nextNode);
7871 std::vector<mcIdType> tmp3(2*(sz-1));
7872 std::vector<mcIdType>::iterator it=std::copy(nodalConnBg+1,nodalConnEnd,tmp3.begin());
7873 std::copy(nodalConnBg+1,nodalConnEnd,it);
7874 if(std::search(tmp3.begin(),tmp3.end(),tmpOut.begin(),tmpOut.end())!=tmp3.end())
7876 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
7879 if(std::search(tmp3.rbegin(),tmp3.rend(),tmpOut.begin(),tmpOut.end())!=tmp3.rend())
7881 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
7886 nodalConnecOut->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYGON));
7887 nodalConnecOut->insertAtTheEnd(tmpOut.begin(),tmpOut.end());
7892 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
7895 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
7899 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
7900 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
7901 * 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]].
7902 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
7903 * A negative value in \b arrIn means that it is ignored.
7904 * 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.
7906 * \param [in] arrIn arr origin array from which the extraction will be done.
7907 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7908 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
7909 * \sa MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed, MEDCouplingUMesh::partitionBySpreadZone
7911 DataArrayIdType *MEDCouplingUMesh::ComputeSpreadZoneGradually(const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn)
7913 mcIdType seed=0,nbOfDepthPeelingPerformed=0;
7914 return ComputeSpreadZoneGraduallyFromSeed(&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfDepthPeelingPerformed);
7918 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
7919 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
7920 * 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]].
7921 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
7922 * A negative value in \b arrIn means that it is ignored.
7923 * 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.
7924 * \param [in] seedBg the begin pointer (included) of an array containing the seed of the search zone
7925 * \param [in] seedEnd the end pointer (not included) of an array containing the seed of the search zone
7926 * \param [in] arrIn arr origin array from which the extraction will be done.
7927 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7928 * \param [in] nbOfDepthPeeling the max number of peels requested in search. By default -1, that is to say, no limit.
7929 * \param [out] nbOfDepthPeelingPerformed the number of peels effectively performed. May be different from \a nbOfDepthPeeling
7930 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
7931 * \sa MEDCouplingUMesh::partitionBySpreadZone
7933 DataArrayIdType *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(const mcIdType *seedBg, const mcIdType *seedEnd, const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn, mcIdType nbOfDepthPeeling, mcIdType& nbOfDepthPeelingPerformed)
7935 nbOfDepthPeelingPerformed=0;
7937 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed : arrIndxIn input pointer is NULL !");
7938 mcIdType nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
7941 DataArrayIdType *ret=DataArrayIdType::New(); ret->alloc(0,1);
7945 std::vector<bool> fetched(nbOfTuples,false);
7946 return ComputeSpreadZoneGraduallyFromSeedAlg(fetched,seedBg,seedEnd,arrIn,arrIndxIn,nbOfDepthPeeling,nbOfDepthPeelingPerformed);
7952 * \b this is expected to be a mesh fully defined whose spaceDim==meshDim.
7953 * It returns a new allocated mesh having the same mesh dimension and lying on same coordinates.
7954 * The returned mesh contains as poly cells as number of contiguous zone (regarding connectivity).
7955 * A spread contiguous zone is built using poly cells (polyhedra in 3D, polygons in 2D and polyline in 1D).
7956 * The sum of measure field of returned mesh is equal to the sum of measure field of this.
7958 * \return a newly allocated mesh lying on the same coords than \b this with same meshdimension than \b this.
7960 MEDCouplingUMesh *MEDCouplingUMesh::buildSpreadZonesWithPoly() const
7962 checkFullyDefined();
7963 int mdim=getMeshDimension();
7964 int spaceDim=getSpaceDimension();
7966 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension and spacedimension do not match !");
7967 std::vector<DataArrayIdType *> partition=partitionBySpreadZone();
7968 std::vector< MCAuto<DataArrayIdType> > partitionAuto; partitionAuto.reserve(partition.size());
7969 std::copy(partition.begin(),partition.end(),std::back_insert_iterator<std::vector< MCAuto<DataArrayIdType> > >(partitionAuto));
7970 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
7971 ret->setCoords(getCoords());
7972 ret->allocateCells(ToIdType(partition.size()));
7974 for(std::vector<DataArrayIdType *>::const_iterator it=partition.begin();it!=partition.end();it++)
7976 MCAuto<MEDCouplingUMesh> tmp=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf((*it)->begin(),(*it)->end(),true));
7977 MCAuto<DataArrayIdType> cell;
7981 cell=tmp->buildUnionOf2DMesh();
7984 cell=tmp->buildUnionOf3DMesh();
7987 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension supported are [2,3] ! Not implemented yet for others !");
7990 ret->insertNextCell((INTERP_KERNEL::NormalizedCellType)cell->getIJSafe(0,0),cell->getNumberOfTuples()-1,cell->begin()+1);
7993 ret->finishInsertingCells();
7998 * This method partitions \b this into contiguous zone.
7999 * This method only needs a well defined connectivity. Coordinates are not considered here.
8000 * This method returns a vector of \b newly allocated arrays that the caller has to deal with.
8002 std::vector<DataArrayIdType *> MEDCouplingUMesh::partitionBySpreadZone() const
8004 DataArrayIdType *neigh=0,*neighI=0;
8005 computeNeighborsOfCells(neigh,neighI);
8006 MCAuto<DataArrayIdType> neighAuto(neigh),neighIAuto(neighI);
8007 return PartitionBySpreadZone(neighAuto,neighIAuto);
8010 std::vector<DataArrayIdType *> MEDCouplingUMesh::PartitionBySpreadZone(const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn)
8012 if(!arrIn || !arrIndxIn)
8013 throw INTERP_KERNEL::Exception("PartitionBySpreadZone : null input pointers !");
8014 arrIn->checkAllocated(); arrIndxIn->checkAllocated();
8015 mcIdType nbOfTuples(arrIndxIn->getNumberOfTuples());
8016 if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1 || nbOfTuples<1)
8017 throw INTERP_KERNEL::Exception("PartitionBySpreadZone : invalid arrays in input !");
8018 mcIdType nbOfCellsCur(nbOfTuples-1);
8019 std::vector<DataArrayIdType *> ret;
8022 std::vector<bool> fetchedCells(nbOfCellsCur,false);
8023 std::vector< MCAuto<DataArrayIdType> > ret2;
8025 while(seed<nbOfCellsCur)
8027 mcIdType nbOfPeelPerformed=0;
8028 ret2.push_back(ComputeSpreadZoneGraduallyFromSeedAlg(fetchedCells,&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfPeelPerformed));
8029 seed=ToIdType(std::distance(fetchedCells.begin(),std::find(fetchedCells.begin()+seed,fetchedCells.end(),false)));
8031 for(std::vector< MCAuto<DataArrayIdType> >::iterator it=ret2.begin();it!=ret2.end();it++)
8032 ret.push_back((*it).retn());
8037 * This method returns given a distribution of cell type (returned for example by MEDCouplingUMesh::getDistributionOfTypes method and customized after) a
8038 * newly allocated DataArrayIdType instance with 2 components ready to be interpreted as input of DataArrayIdType::findRangeIdForEachTuple method.
8040 * \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.
8041 * \return a newly allocated DataArrayIdType to be managed by the caller.
8042 * \throw In case of \a code has not the right format (typically of size 3*n)
8044 DataArrayIdType *MEDCouplingUMesh::ComputeRangesFromTypeDistribution(const std::vector<mcIdType>& code)
8046 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
8047 std::size_t nb=code.size()/3;
8048 if(code.size()%3!=0)
8049 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeRangesFromTypeDistribution : invalid input code !");
8051 mcIdType *retPtr=ret->getPointer();
8052 for(std::size_t i=0;i<nb;i++,retPtr+=2)
8054 retPtr[0]=code[3*i+2];
8055 retPtr[1]=code[3*i+2]+code[3*i+1];
8061 * This method expects that \a this a 3D mesh (spaceDim=3 and meshDim=3) with all coordinates and connectivities set.
8062 * All cells in \a this are expected to be linear 3D cells.
8063 * This method will split **all** 3D cells in \a this into INTERP_KERNEL::NORM_TETRA4 cells and put them in the returned mesh.
8064 * It leads to an increase to number of cells.
8065 * This method contrary to MEDCouplingUMesh::simplexize can append coordinates in \a this to perform its work.
8066 * The \a nbOfAdditionalPoints returned value informs about it. If > 0, the coordinates array in returned mesh will have \a nbOfAdditionalPoints
8067 * more tuples (nodes) than in \a this. Anyway, all the nodes in \a this (with the same order) will be in the returned mesh.
8069 * \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.
8070 * For all other cells, the splitting policy will be ignored. See INTERP_KERNEL::SplittingPolicy for the images.
8071 * \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.
8072 * \param [out] n2oCells - A new instance of DataArrayIdType holding, for each new cell,
8073 * an id of old cell producing it. The caller is to delete this array using
8074 * decrRef() as it is no more needed.
8075 * \return MEDCoupling1SGTUMesh * - the mesh containing only INTERP_KERNEL::NORM_TETRA4 cells.
8077 * \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
8078 * the policy PLANAR_FACE_6 should be used on a mesh sorted with MEDCoupling1SGTUMesh::sortHexa8EachOther.
8080 * \throw If \a this is not a 3D mesh (spaceDim==3 and meshDim==3).
8081 * \throw If \a this is not fully constituted with linear 3D cells.
8082 * \sa MEDCouplingUMesh::simplexize, MEDCoupling1SGTUMesh::sortHexa8EachOther
8084 MEDCoupling1SGTUMesh *MEDCouplingUMesh::tetrahedrize(int policy, DataArrayIdType *& n2oCells, mcIdType& nbOfAdditionalPoints) const
8086 INTERP_KERNEL::SplittingPolicy pol((INTERP_KERNEL::SplittingPolicy)policy);
8087 checkConnectivityFullyDefined();
8088 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
8089 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tetrahedrize : only available for mesh with meshdim == 3 and spacedim == 3 !");
8090 mcIdType nbOfCells=getNumberOfCells();
8091 mcIdType nbNodes(getNumberOfNodes());
8092 MCAuto<MEDCoupling1SGTUMesh> ret0(MEDCoupling1SGTUMesh::New(getName(),INTERP_KERNEL::NORM_TETRA4));
8093 MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(nbOfCells,1);
8094 mcIdType *retPt(ret->getPointer());
8095 MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()); newConn->alloc(0,1);
8096 MCAuto<DataArrayDouble> addPts(DataArrayDouble::New()); addPts->alloc(0,1);
8097 const mcIdType *oldc(_nodal_connec->begin());
8098 const mcIdType *oldci(_nodal_connec_index->begin());
8099 const double *coords(_coords->begin());
8100 for(mcIdType i=0;i<nbOfCells;i++,oldci++,retPt++)
8102 std::vector<mcIdType> a; std::vector<double> b;
8103 INTERP_KERNEL::SplitIntoTetras(pol,(INTERP_KERNEL::NormalizedCellType)oldc[oldci[0]],oldc+oldci[0]+1,oldc+oldci[1],coords,a,b);
8104 std::size_t nbOfTet(a.size()/4); *retPt=ToIdType(nbOfTet);
8105 const mcIdType *aa(&a[0]);
8108 for(std::vector<mcIdType>::iterator it=a.begin();it!=a.end();it++)
8110 *it=(-(*(it))-1+nbNodes);
8111 addPts->insertAtTheEnd(b.begin(),b.end());
8112 nbNodes+=ToIdType(b.size()/3);
8114 for(std::size_t j=0;j<nbOfTet;j++,aa+=4)
8115 newConn->insertAtTheEnd(aa,aa+4);
8117 if(!addPts->empty())
8119 addPts->rearrange(3);
8120 nbOfAdditionalPoints=addPts->getNumberOfTuples();
8121 addPts=DataArrayDouble::Aggregate(getCoords(),addPts);
8122 ret0->setCoords(addPts);
8126 nbOfAdditionalPoints=0;
8127 ret0->setCoords(getCoords());
8129 ret0->setNodalConnectivity(newConn);
8131 ret->computeOffsetsFull();
8132 n2oCells=ret->buildExplicitArrOfSliceOnScaledArr(0,nbOfCells,1);
8136 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),
8137 _own_cell(true),_cell_id(-1),_nb_cell(0)
8142 _nb_cell=mesh->getNumberOfCells();
8146 MEDCouplingUMeshCellIterator::~MEDCouplingUMeshCellIterator()
8154 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh, MEDCouplingUMeshCell *itc, mcIdType bg, mcIdType end):_mesh(mesh),_cell(itc),
8155 _own_cell(false),_cell_id(bg-1),
8162 MEDCouplingUMeshCell *MEDCouplingUMeshCellIterator::nextt()
8165 if(_cell_id<_nb_cell)
8174 MEDCouplingUMeshCellByTypeEntry::MEDCouplingUMeshCellByTypeEntry(MEDCouplingUMesh *mesh):_mesh(mesh)
8180 MEDCouplingUMeshCellByTypeIterator *MEDCouplingUMeshCellByTypeEntry::iterator()
8182 return new MEDCouplingUMeshCellByTypeIterator(_mesh);
8185 MEDCouplingUMeshCellByTypeEntry::~MEDCouplingUMeshCellByTypeEntry()
8191 MEDCouplingUMeshCellEntry::MEDCouplingUMeshCellEntry(MEDCouplingUMesh *mesh, INTERP_KERNEL::NormalizedCellType type, MEDCouplingUMeshCell *itc, mcIdType bg, mcIdType end):_mesh(mesh),_type(type),
8199 MEDCouplingUMeshCellEntry::~MEDCouplingUMeshCellEntry()
8205 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCellEntry::getType() const
8210 mcIdType MEDCouplingUMeshCellEntry::getNumberOfElems() const
8215 MEDCouplingUMeshCellIterator *MEDCouplingUMeshCellEntry::iterator()
8217 return new MEDCouplingUMeshCellIterator(_mesh,_itc,_bg,_end);
8220 MEDCouplingUMeshCellByTypeIterator::MEDCouplingUMeshCellByTypeIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),_cell_id(0),_nb_cell(0)
8225 _nb_cell=mesh->getNumberOfCells();
8229 MEDCouplingUMeshCellByTypeIterator::~MEDCouplingUMeshCellByTypeIterator()
8236 MEDCouplingUMeshCellEntry *MEDCouplingUMeshCellByTypeIterator::nextt()
8238 const mcIdType *c=_mesh->getNodalConnectivity()->begin();
8239 const mcIdType *ci=_mesh->getNodalConnectivityIndex()->begin();
8240 if(_cell_id<_nb_cell)
8242 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[_cell_id]];
8243 mcIdType nbOfElems=ToIdType(std::distance(ci+_cell_id,std::find_if(ci+_cell_id,ci+_nb_cell,MEDCouplingImpl::ConnReader(c,type))));
8244 mcIdType startId=_cell_id;
8245 _cell_id+=nbOfElems;
8246 return new MEDCouplingUMeshCellEntry(_mesh,type,_cell,startId,_cell_id);
8252 MEDCouplingUMeshCell::MEDCouplingUMeshCell(MEDCouplingUMesh *mesh):_conn(0),_conn_indx(0),_conn_lgth(NOTICABLE_FIRST_VAL)
8256 _conn=mesh->getNodalConnectivity()->getPointer();
8257 _conn_indx=mesh->getNodalConnectivityIndex()->getPointer();
8261 void MEDCouplingUMeshCell::next()
8263 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8268 _conn_lgth=_conn_indx[1]-_conn_indx[0];
8271 std::string MEDCouplingUMeshCell::repr() const
8273 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8275 std::ostringstream oss; oss << "Cell Type " << INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)_conn[0]).getRepr();
8277 std::copy(_conn+1,_conn+_conn_lgth,std::ostream_iterator<mcIdType>(oss," "));
8281 return std::string("MEDCouplingUMeshCell::repr : Invalid pos");
8284 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCell::getType() const
8286 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8287 return (INTERP_KERNEL::NormalizedCellType)_conn[0];
8289 return INTERP_KERNEL::NORM_ERROR;
8292 const mcIdType *MEDCouplingUMeshCell::getAllConn(mcIdType& lgth) const
8295 if(_conn_lgth!=NOTICABLE_FIRST_VAL)