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);
793 * Given a set of identifiers indexed by the node IDs of the mesh (and given in the (\ref numbering-indirect format) ,
794 * re-arrange the data to produce a set indexed by cell IDs. The mapping between a node ID and a cell ID is done using the connectivity
795 * of the mesh (e.g. a triangular element will receive the information from its three vertices).
796 * Doublons are eliminated. If present in the inital dataset, the ID of the cell itself is also remooved.
798 * \param [in] nodeNeigh a set of identifiers (mcIdType) stored by node index (\ref numbering-indirect format)
799 * \param [in] nodeNeighI a set of identifiers (mcIdType) stored by node index (\ref numbering-indirect format)
800 * \param [out] cellNeigh This array is newly allocated and should be dealt by the caller. It contains the initial identifiers
801 * provided in the input parameters but stored now by cell index (See 2nd output parameter and \ref numbering-indirect).
802 * \param [out] cellNeighI is an array of size this->getNumberOfCells()+1 newly allocated and should be
803 * dealt by the caller. This arrays allow to use the first output parameter \b neighbors (\ref numbering-indirect).
805 * \raise if the number of tuples in nodeNeighI is not equal to the number of nodes in the mesh.
807 void MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne(const DataArrayIdType *nodeNeigh, const DataArrayIdType *nodeNeighI,
808 MCAuto<DataArrayIdType>& cellNeigh, MCAuto<DataArrayIdType>& cellNeighIndex) const
810 if(!nodeNeigh || !nodeNeighI)
811 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : null pointer !");
812 checkConsistencyLight();
813 nodeNeigh->checkAllocated(); nodeNeighI->checkAllocated();
814 nodeNeigh->checkNbOfComps(1,"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : node neigh");
815 nodeNeighI->checkNbOfComps(1,"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : node neigh index");
816 nodeNeighI->checkNbOfTuples(1+getNumberOfNodes(),"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : invalid length");
817 mcIdType nbCells=getNumberOfCells();
818 const mcIdType *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin()),*ne(nodeNeigh->begin()),*nei(nodeNeighI->begin());
819 cellNeigh=DataArrayIdType::New(); cellNeigh->alloc(0,1); cellNeighIndex=DataArrayIdType::New(); cellNeighIndex->alloc(1,1); cellNeighIndex->setIJ(0,0,0);
820 for(mcIdType i=0;i<nbCells;i++)
822 std::set<mcIdType> s;
823 for(const mcIdType *it=c+ci[i]+1;it!=c+ci[i+1];it++)
824 if(*it>=0) // avoid -1 in polygons or polyedrons
825 s.insert(ne+nei[*it],ne+nei[*it+1]);
827 cellNeigh->insertAtTheEnd(s.begin(),s.end());
828 cellNeighIndex->pushBackSilent(cellNeigh->getNumberOfTuples());
833 * This method is called by MEDCouplingUMesh::computeNeighborsOfCells. This methods performs the algorithm
834 * of MEDCouplingUMesh::computeNeighborsOfCells.
835 * This method is useful for users that want to reduce along a criterion the set of neighbours cell. This is
836 * typically the case to extract a set a neighbours,
837 * excluding a set of meshdim-1 cells in input descending connectivity.
838 * Typically \b desc, \b descIndx, \b revDesc and \b revDescIndx (\ref numbering-indirect) input params are
839 * the result of MEDCouplingUMesh::buildDescendingConnectivity.
840 * This method lists cell by cell in \b this which are its neighbors. To compute the result only connectivities
842 * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
844 * \param [in] desc descending connectivity array.
845 * \param [in] descIndx descending connectivity index array used to walk through \b desc (\ref numbering-indirect).
846 * \param [in] revDesc reverse descending connectivity array.
847 * \param [in] revDescIndx reverse descending connectivity index array used to walk through \b revDesc (\ref numbering-indirect).
848 * \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
849 * parameter allows to select the right part in this array. The number of tuples is equal to the last values in \b neighborsIndx.
850 * \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.
852 void MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(const DataArrayIdType *desc, const DataArrayIdType *descIndx, const DataArrayIdType *revDesc, const DataArrayIdType *revDescIndx,
853 DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIndx)
855 if(!desc || !descIndx || !revDesc || !revDescIndx)
856 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeNeighborsOfCellsAdv some input array is empty !");
857 const mcIdType *descPtr=desc->begin();
858 const mcIdType *descIPtr=descIndx->begin();
859 const mcIdType *revDescPtr=revDesc->begin();
860 const mcIdType *revDescIPtr=revDescIndx->begin();
862 mcIdType nbCells=descIndx->getNumberOfTuples()-1;
863 MCAuto<DataArrayIdType> out0=DataArrayIdType::New();
864 MCAuto<DataArrayIdType> out1=DataArrayIdType::New(); out1->alloc(nbCells+1,1);
865 mcIdType *out1Ptr=out1->getPointer();
867 out0->reserve(desc->getNumberOfTuples());
868 for(mcIdType i=0;i<nbCells;i++,descIPtr++,out1Ptr++)
870 for(const mcIdType *w1=descPtr+descIPtr[0];w1!=descPtr+descIPtr[1];w1++)
872 std::set<mcIdType> s(revDescPtr+revDescIPtr[*w1],revDescPtr+revDescIPtr[(*w1)+1]);
874 out0->insertAtTheEnd(s.begin(),s.end());
876 *out1Ptr=out0->getNumberOfTuples();
878 neighbors=out0.retn();
879 neighborsIndx=out1.retn();
883 * Explodes \a this into edges whatever its dimension.
885 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::explodeIntoEdges(MCAuto<DataArrayIdType>& desc, MCAuto<DataArrayIdType>& descIndex, MCAuto<DataArrayIdType>& revDesc, MCAuto<DataArrayIdType>& revDescIndx) const
888 int mdim(getMeshDimension());
889 desc=DataArrayIdType::New(); descIndex=DataArrayIdType::New(); revDesc=DataArrayIdType::New(); revDescIndx=DataArrayIdType::New();
890 MCAuto<MEDCouplingUMesh> mesh1D;
895 mesh1D=explode3DMeshTo1D(desc,descIndex,revDesc,revDescIndx);
900 mesh1D=buildDescendingConnectivity(desc,descIndex,revDesc,revDescIndx);
905 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2] !");
912 * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
913 * For speed reasons no check of this will be done. This method calls
914 * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
915 * This method lists node by node in \b this which are its neighbors. To compute the result
916 * only connectivities are considered.
917 * The neighbor nodes of node having id 'nodeId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
919 * \param [out] neighbors is an array storing all the neighbors of all nodes in \b this. This array
920 * is newly allocated and should be dealt by the caller. \b neighborsIndx 2nd output
921 * parameter allows to select the right part in this array (\ref numbering-indirect).
922 * The number of tuples is equal to the last values in \b neighborsIndx.
923 * \param [out] neighborsIdx is an array of size this->getNumberOfCells()+1 newly allocated and should
924 * be dealt by the caller. This arrays allow to use the first output parameter \b neighbors.
926 * \sa MEDCouplingUMesh::computeEnlargedNeighborsOfNodes
928 void MEDCouplingUMesh::computeNeighborsOfNodes(DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIdx) const
931 mcIdType mdim(getMeshDimension()),nbNodes(getNumberOfNodes());
932 MCAuto<DataArrayIdType> desc(DataArrayIdType::New()),descIndx(DataArrayIdType::New()),revDesc(DataArrayIdType::New()),revDescIndx(DataArrayIdType::New());
933 MCConstAuto<MEDCouplingUMesh> mesh1D;
938 mesh1D=explode3DMeshTo1D(desc,descIndx,revDesc,revDescIndx);
943 mesh1D=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
948 mesh1D.takeRef(this);
953 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2,1] !");
956 desc=DataArrayIdType::New(); descIndx=DataArrayIdType::New(); revDesc=0; revDescIndx=0;
957 mesh1D->getReverseNodalConnectivity(desc,descIndx);
958 MCAuto<DataArrayIdType> ret0(DataArrayIdType::New());
959 ret0->alloc(desc->getNumberOfTuples(),1);
960 mcIdType *r0Pt(ret0->getPointer());
961 const mcIdType *c1DPtr(mesh1D->getNodalConnectivity()->begin()),*rn(desc->begin()),*rni(descIndx->begin());
962 for(mcIdType i=0;i<nbNodes;i++,rni++)
964 for(const mcIdType *oneDCellIt=rn+rni[0];oneDCellIt!=rn+rni[1];oneDCellIt++)
965 *r0Pt++=c1DPtr[3*(*oneDCellIt)+1]==i?c1DPtr[3*(*oneDCellIt)+2]:c1DPtr[3*(*oneDCellIt)+1];
967 neighbors=ret0.retn();
968 neighborsIdx=descIndx.retn();
972 * 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.
973 * 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.
974 * This method is useful to find ghost cells of a part of a mesh with a code based on fields on nodes.
976 * \sa MEDCouplingUMesh::computeNeighborsOfNodes
978 void MEDCouplingUMesh::computeEnlargedNeighborsOfNodes(MCAuto<DataArrayIdType> &neighbors, MCAuto<DataArrayIdType>& neighborsIdx) const
981 mcIdType nbOfNodes(getNumberOfNodes());
982 const mcIdType *conn(_nodal_connec->begin()),*connIndex(_nodal_connec_index->begin());
983 mcIdType nbOfCells=getNumberOfCells();
984 std::vector< std::set<mcIdType> > st0(nbOfNodes);
985 for(mcIdType eltId=0;eltId<nbOfCells;eltId++)
987 const mcIdType *strtNdlConnOfCurCell(conn+connIndex[eltId]+1),*endNdlConnOfCurCell(conn+connIndex[eltId+1]);
988 std::set<mcIdType> s(strtNdlConnOfCurCell,endNdlConnOfCurCell); s.erase(-1); //for polyhedrons
989 for(std::set<mcIdType>::const_iterator iter2=s.begin();iter2!=s.end();iter2++)
990 st0[*iter2].insert(s.begin(),s.end());
992 neighborsIdx=DataArrayIdType::New(); neighborsIdx->alloc(nbOfNodes+1,1); neighborsIdx->setIJ(0,0,0);
994 mcIdType *neighIdx(neighborsIdx->getPointer());
995 for(std::vector< std::set<mcIdType> >::const_iterator it=st0.begin();it!=st0.end();it++,neighIdx++)
998 neighIdx[1]=neighIdx[0];
1000 neighIdx[1]=neighIdx[0]+ToIdType((*it).size())-1;
1003 neighbors=DataArrayIdType::New(); neighbors->alloc(neighborsIdx->back(),1);
1005 const mcIdType *neighIdx(neighborsIdx->begin());
1006 mcIdType *neigh(neighbors->getPointer()),nodeId(0);
1007 for(std::vector< std::set<mcIdType> >::const_iterator it=st0.begin();it!=st0.end();it++,neighIdx++,nodeId++)
1009 std::set<mcIdType> s(*it); s.erase(nodeId);
1010 std::copy(s.begin(),s.end(),neigh+*neighIdx);
1016 * Converts specified cells to either polygons (if \a this is a 2D mesh) or
1017 * polyhedrons (if \a this is a 3D mesh). The cells to convert are specified by an
1018 * array of cell ids. Pay attention that after conversion all algorithms work slower
1019 * with \a this mesh than before conversion. <br> If an exception is thrown during the
1020 * conversion due presence of invalid ids in the array of cells to convert, as a
1021 * result \a this mesh contains some already converted elements. In this case the 2D
1022 * mesh remains valid but 3D mesh becomes \b inconsistent!
1023 * \warning This method can significantly modify the order of geometric types in \a this,
1024 * hence, to write this mesh to the MED file, its cells must be sorted using
1025 * sortCellsInMEDFileFrmt().
1026 * \param [in] cellIdsToConvertBg - the array holding ids of cells to convert.
1027 * \param [in] cellIdsToConvertEnd - a pointer to the last-plus-one-th element of \a
1028 * cellIdsToConvertBg.
1029 * \throw If the coordinates array is not set.
1030 * \throw If the nodal connectivity of cells is node defined.
1031 * \throw If dimension of \a this mesh is not either 2 or 3.
1033 * \if ENABLE_EXAMPLES
1034 * \ref cpp_mcumesh_convertToPolyTypes "Here is a C++ example".<br>
1035 * \ref py_mcumesh_convertToPolyTypes "Here is a Python example".
1038 void MEDCouplingUMesh::convertToPolyTypes(const mcIdType *cellIdsToConvertBg, const mcIdType *cellIdsToConvertEnd)
1040 checkFullyDefined();
1041 int dim=getMeshDimension();
1043 throw INTERP_KERNEL::Exception("Invalid mesh dimension : must be 2 or 3 !");
1044 mcIdType nbOfCells=getNumberOfCells();
1047 const mcIdType *connIndex=_nodal_connec_index->begin();
1048 mcIdType *conn=_nodal_connec->getPointer();
1049 for(const mcIdType *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1051 if(*iter>=0 && *iter<nbOfCells)
1053 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*iter]]);
1054 if(!cm.isQuadratic())
1055 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_POLYGON;
1057 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_QPOLYG;
1061 std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1062 oss << " in range [0," << nbOfCells << ") !";
1063 throw INTERP_KERNEL::Exception(oss.str());
1069 mcIdType *connIndex(_nodal_connec_index->getPointer());
1070 const mcIdType *connOld(_nodal_connec->getConstPointer());
1071 MCAuto<DataArrayIdType> connNew(DataArrayIdType::New()),connNewI(DataArrayIdType::New()); connNew->alloc(0,1); connNewI->alloc(1,1); connNewI->setIJ(0,0,0);
1072 std::vector<bool> toBeDone(nbOfCells,false);
1073 for(const mcIdType *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1075 if(*iter>=0 && *iter<nbOfCells)
1076 toBeDone[*iter]=true;
1079 std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1080 oss << " in range [0," << nbOfCells << ") !";
1081 throw INTERP_KERNEL::Exception(oss.str());
1084 for(mcIdType cellId=0;cellId<nbOfCells;cellId++)
1086 mcIdType pos(connIndex[cellId]),posP1(connIndex[cellId+1]);
1087 mcIdType lgthOld(posP1-pos-1);
1088 if(toBeDone[cellId])
1090 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connOld[pos]);
1091 unsigned nbOfFaces(cm.getNumberOfSons2(connOld+pos+1,lgthOld));
1092 mcIdType *tmp(new mcIdType[nbOfFaces*lgthOld+1]);
1093 mcIdType *work=tmp; *work++=INTERP_KERNEL::NORM_POLYHED;
1094 for(unsigned j=0;j<nbOfFaces;j++)
1096 INTERP_KERNEL::NormalizedCellType type;
1097 unsigned offset=cm.fillSonCellNodalConnectivity2(j,connOld+pos+1,lgthOld,work,type);
1101 std::size_t newLgth(std::distance(tmp,work)-1);//-1 for last -1
1102 connNew->pushBackValsSilent(tmp,tmp+newLgth);
1103 connNewI->pushBackSilent(connNewI->back()+ToIdType(newLgth));
1108 connNew->pushBackValsSilent(connOld+pos,connOld+posP1);
1109 connNewI->pushBackSilent(connNewI->back()+posP1-pos);
1112 setConnectivity(connNew,connNewI,false);//false because computeTypes called just behind.
1118 * Converts all cells to either polygons (if \a this is a 2D mesh) or
1119 * polyhedrons (if \a this is a 3D mesh).
1120 * \warning As this method is purely for user-friendliness and no optimization is
1121 * done to avoid construction of a useless vector, this method can be costly
1123 * \throw If the coordinates array is not set.
1124 * \throw If the nodal connectivity of cells is node defined.
1125 * \throw If dimension of \a this mesh is not either 2 or 3.
1127 void MEDCouplingUMesh::convertAllToPoly()
1129 mcIdType nbOfCells=getNumberOfCells();
1130 std::vector<mcIdType> cellIds(nbOfCells);
1131 for(mcIdType i=0;i<nbOfCells;i++)
1133 convertToPolyTypes(&cellIds[0],&cellIds[0]+ToIdType(cellIds.size()));
1137 * Fixes nodal connectivity of invalid cells of type NORM_POLYHED. This method
1138 * expects that all NORM_POLYHED cells have connectivity similar to that of prismatic
1139 * volumes like NORM_HEXA8, NORM_PENTA6 etc., i.e. the first half of nodes describes a
1140 * base facet of the volume and the second half of nodes describes an opposite facet
1141 * having the same number of nodes as the base one. This method converts such
1142 * connectivity to a valid polyhedral format where connectivity of each facet is
1143 * explicitly described and connectivity of facets are separated by -1. If \a this mesh
1144 * contains a NORM_POLYHED cell with a valid connectivity, or an invalid connectivity is
1145 * not as expected, an exception is thrown and the mesh remains unchanged. Care of
1146 * a correct orientation of the first facet of a polyhedron, else orientation of a
1147 * corrected cell is reverse.<br>
1148 * This method is useful to build an extruded unstructured mesh with polyhedrons as
1149 * it releases the user from boring description of polyhedra connectivity in the valid
1151 * \throw If \a this->getMeshDimension() != 3.
1152 * \throw If \a this->getSpaceDimension() != 3.
1153 * \throw If the nodal connectivity of cells is not defined.
1154 * \throw If the coordinates array is not set.
1155 * \throw If \a this mesh contains polyhedrons with the valid connectivity.
1156 * \throw If \a this mesh contains polyhedrons with odd number of nodes.
1158 * \if ENABLE_EXAMPLES
1159 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
1160 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
1163 void MEDCouplingUMesh::convertExtrudedPolyhedra()
1165 checkFullyDefined();
1166 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1167 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertExtrudedPolyhedra works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
1168 mcIdType nbOfCells=getNumberOfCells();
1169 MCAuto<DataArrayIdType> newCi=DataArrayIdType::New();
1170 newCi->alloc(nbOfCells+1,1);
1171 mcIdType *newci=newCi->getPointer();
1172 const mcIdType *ci=_nodal_connec_index->getConstPointer();
1173 const mcIdType *c=_nodal_connec->getConstPointer();
1175 for(mcIdType i=0;i<nbOfCells;i++)
1177 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1178 if(type==INTERP_KERNEL::NORM_POLYHED)
1180 if(std::count(c+ci[i]+1,c+ci[i+1],-1)!=0)
1182 std::ostringstream oss; oss << "MEDCouplingUMesh::convertExtrudedPolyhedra : cell # " << i << " is a polhedron BUT it has NOT exactly 1 face !";
1183 throw INTERP_KERNEL::Exception(oss.str());
1185 std::size_t n2=std::distance(c+ci[i]+1,c+ci[i+1]);
1188 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 !";
1189 throw INTERP_KERNEL::Exception(oss.str());
1191 mcIdType n1=ToIdType(n2/2);
1192 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)
1195 newci[i+1]=(ci[i+1]-ci[i])+newci[i];
1197 MCAuto<DataArrayIdType> newC=DataArrayIdType::New();
1198 newC->alloc(newci[nbOfCells],1);
1199 mcIdType *newc=newC->getPointer();
1200 for(mcIdType i=0;i<nbOfCells;i++)
1202 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1203 if(type==INTERP_KERNEL::NORM_POLYHED)
1205 std::size_t n1=std::distance(c+ci[i]+1,c+ci[i+1])/2;
1206 newc=std::copy(c+ci[i],c+ci[i]+n1+1,newc);
1208 for(std::size_t j=0;j<n1;j++)
1210 newc[j]=c[ci[i]+1+n1+(n1-j)%n1];
1212 newc[n1+5*j+1]=c[ci[i]+1+j];
1213 newc[n1+5*j+2]=c[ci[i]+1+j+n1];
1214 newc[n1+5*j+3]=c[ci[i]+1+(j+1)%n1+n1];
1215 newc[n1+5*j+4]=c[ci[i]+1+(j+1)%n1];
1220 newc=std::copy(c+ci[i],c+ci[i+1],newc);
1222 _nodal_connec_index->decrRef(); _nodal_connec_index=newCi.retn();
1223 _nodal_connec->decrRef(); _nodal_connec=newC.retn();
1228 * Converts all polygons (if \a this is a 2D mesh) or polyhedrons (if \a this is a 3D
1229 * mesh) to cells of classical types. This method is opposite to convertToPolyTypes().
1230 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
1231 * to write this mesh to the MED file, its cells must be sorted using
1232 * sortCellsInMEDFileFrmt().
1233 * \warning Cells (and most notably polyhedrons) must be correctly oriented for this to work
1234 * properly. See orientCorrectlyPolyhedrons() and arePolyhedronsNotCorrectlyOriented().
1235 * \return \c true if at least one cell has been converted, \c false else. In the
1236 * last case the nodal connectivity remains unchanged.
1237 * \throw If the coordinates array is not set.
1238 * \throw If the nodal connectivity of cells is not defined.
1239 * \throw If \a this->getMeshDimension() < 0.
1241 bool MEDCouplingUMesh::unPolyze()
1243 checkFullyDefined();
1244 int mdim=getMeshDimension();
1246 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::unPolyze works on umeshes with meshdim equals to 0, 1 2 or 3 !");
1249 mcIdType nbOfCells=getNumberOfCells();
1252 mcIdType initMeshLgth=getNodalConnectivityArrayLen();
1253 mcIdType *conn=_nodal_connec->getPointer();
1254 mcIdType *index=_nodal_connec_index->getPointer();
1255 mcIdType posOfCurCell=0;
1257 mcIdType lgthOfCurCell;
1259 for(mcIdType i=0;i<nbOfCells;i++)
1261 lgthOfCurCell=index[i+1]-posOfCurCell;
1262 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
1263 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
1264 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::NORM_ERROR;
1268 switch(cm.getDimension())
1272 INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[lgthOfCurCell-1];
1273 std::copy(conn+posOfCurCell+1,conn+posOfCurCell+lgthOfCurCell,(mcIdType *)tmp);
1274 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly2D(cm.isQuadratic(),tmp,lgthOfCurCell-1,conn+newPos+1,newLgth);
1279 mcIdType nbOfFaces,lgthOfPolyhConn;
1280 INTERP_KERNEL::AutoPtr<mcIdType> zipFullReprOfPolyh=INTERP_KERNEL::CellSimplify::getFullPolyh3DCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,nbOfFaces,lgthOfPolyhConn);
1281 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly3D(zipFullReprOfPolyh,nbOfFaces,lgthOfPolyhConn,conn+newPos+1,newLgth);
1284 /* case 1: // Not supported yet
1286 newType=(lgthOfCurCell==3)?INTERP_KERNEL::NORM_SEG2:INTERP_KERNEL::NORM_POLYL;
1291 ret=ret || (newType!=type);
1292 conn[newPos]=newType;
1294 posOfCurCell=index[i+1];
1299 std::copy(conn+posOfCurCell,conn+posOfCurCell+lgthOfCurCell,conn+newPos);
1300 newPos+=lgthOfCurCell;
1301 posOfCurCell+=lgthOfCurCell;
1305 if(newPos!=initMeshLgth)
1306 _nodal_connec->reAlloc(newPos);
1313 * This method expects that spaceDimension is equal to 3 and meshDimension equal to 3.
1314 * This method performs operation only on polyhedrons in \b this. If no polyhedrons exists in \b this, \b this remains unchanged.
1315 * This method allows to merge if any coplanar 3DSurf cells that may appear in some polyhedrons cells.
1317 * \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
1320 void MEDCouplingUMesh::simplifyPolyhedra(double eps)
1322 checkFullyDefined();
1323 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1324 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplifyPolyhedra : works on meshdimension 3 and spaceDimension 3 !");
1325 MCAuto<DataArrayDouble> coords=getCoords()->deepCopy();
1326 coords->recenterForMaxPrecision(eps);
1328 mcIdType nbOfCells=getNumberOfCells();
1329 const mcIdType *conn=_nodal_connec->getConstPointer();
1330 const mcIdType *index=_nodal_connec_index->getConstPointer();
1331 MCAuto<DataArrayIdType> connINew=DataArrayIdType::New();
1332 connINew->alloc(nbOfCells+1,1);
1333 mcIdType *connINewPtr=connINew->getPointer(); *connINewPtr++=0;
1334 MCAuto<DataArrayIdType> connNew=DataArrayIdType::New(); connNew->alloc(0,1);
1335 MCAuto<DataArrayIdType> E_Fi(DataArrayIdType::New()), E_F(DataArrayIdType::New()), F_Ei(DataArrayIdType::New()), F_E(DataArrayIdType::New());
1336 MCAuto<MEDCouplingUMesh> m_faces(buildDescendingConnectivity(E_F, E_Fi, F_E, F_Ei));
1338 for(mcIdType i=0;i<nbOfCells;i++,connINewPtr++)
1340 if(conn[index[i]]==ToIdType(INTERP_KERNEL::NORM_POLYHED))
1342 SimplifyPolyhedronCell(eps,coords, i,connNew, m_faces, E_Fi, E_F, F_Ei, F_E);
1346 connNew->insertAtTheEnd(conn+index[i],conn+index[i+1]);
1347 *connINewPtr=connNew->getNumberOfTuples();
1350 setConnectivity(connNew,connINew,false);
1354 * This method returns all node ids used in the connectivity of \b this. The data array returned has to be dealt by the caller.
1355 * The returned node ids are sorted ascendingly. This method is close to MEDCouplingUMesh::getNodeIdsInUse except
1356 * the format of the returned DataArrayIdType instance.
1358 * \return a newly allocated DataArrayIdType sorted ascendingly of fetched node ids.
1359 * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1361 DataArrayIdType *MEDCouplingUMesh::computeFetchedNodeIds() const
1363 checkConnectivityFullyDefined();
1364 const mcIdType *maxEltPt(std::max_element(_nodal_connec->begin(),_nodal_connec->end()));
1365 mcIdType maxElt(maxEltPt==_nodal_connec->end()?0:std::abs(*maxEltPt)+1);
1366 std::vector<bool> retS(maxElt,false);
1367 computeNodeIdsAlg(retS);
1368 return DataArrayIdType::BuildListOfSwitchedOn(retS);
1372 * \param [in,out] nodeIdsInUse an array of size typically equal to nbOfNodes.
1373 * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1375 void MEDCouplingUMesh::computeNodeIdsAlg(std::vector<bool>& nodeIdsInUse) const
1377 mcIdType nbOfNodes=ToIdType(nodeIdsInUse.size()),
1378 nbOfCells=getNumberOfCells();
1379 const mcIdType *connIndex(_nodal_connec_index->getConstPointer()),*conn(_nodal_connec->getConstPointer());
1380 for(mcIdType i=0;i<nbOfCells;i++)
1381 for(mcIdType j=connIndex[i]+1;j<connIndex[i+1];j++)
1384 if(conn[j]<nbOfNodes)
1385 nodeIdsInUse[conn[j]]=true;
1388 std::ostringstream oss; oss << "MEDCouplingUMesh::computeNodeIdsAlg : In cell #" << i << " presence of node id " << conn[j] << " not in [0," << nbOfNodes << ") !";
1389 throw INTERP_KERNEL::Exception(oss.str());
1396 struct MEDCouplingAccVisit
1398 MEDCouplingAccVisit():_new_nb_of_nodes(0) { }
1399 mcIdType operator()(mcIdType val) { if(val!=-1) return _new_nb_of_nodes++; else return -1; }
1400 mcIdType _new_nb_of_nodes;
1406 * Finds nodes not used in any cell and returns an array giving a new id to every node
1407 * by excluding the unused nodes, for which the array holds -1. The result array is
1408 * a mapping in "Old to New" mode.
1409 * \param [out] nbrOfNodesInUse - number of node ids present in the nodal connectivity.
1410 * \return DataArrayIdType * - a new instance of DataArrayIdType. Its length is \a
1411 * this->getNumberOfNodes(). It holds for each node of \a this mesh either -1
1412 * if the node is unused or a new id else. The caller is to delete this
1413 * array using decrRef() as it is no more needed.
1414 * \throw If the coordinates array is not set.
1415 * \throw If the nodal connectivity of cells is not defined.
1416 * \throw If the nodal connectivity includes an invalid id.
1418 * \if ENABLE_EXAMPLES
1419 * \ref cpp_mcumesh_getNodeIdsInUse "Here is a C++ example".<br>
1420 * \ref py_mcumesh_getNodeIdsInUse "Here is a Python example".
1422 * \sa computeFetchedNodeIds, computeNodeIdsAlg()
1424 DataArrayIdType *MEDCouplingUMesh::getNodeIdsInUse(mcIdType& nbrOfNodesInUse) const
1427 mcIdType nbOfNodes(getNumberOfNodes());
1428 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1429 ret->alloc(nbOfNodes,1);
1430 mcIdType *traducer=ret->getPointer();
1431 std::fill(traducer,traducer+nbOfNodes,-1);
1432 mcIdType nbOfCells=getNumberOfCells();
1433 const mcIdType *connIndex=_nodal_connec_index->getConstPointer();
1434 const mcIdType *conn=_nodal_connec->getConstPointer();
1435 for(mcIdType i=0;i<nbOfCells;i++)
1436 for(mcIdType j=connIndex[i]+1;j<connIndex[i+1];j++)
1439 if(conn[j]<nbOfNodes)
1440 traducer[conn[j]]=1;
1443 std::ostringstream oss; oss << "MEDCouplingUMesh::getNodeIdsInUse : In cell #" << i << " presence of node id " << conn[j] << " not in [0," << nbOfNodes << ") !";
1444 throw INTERP_KERNEL::Exception(oss.str());
1447 nbrOfNodesInUse=ToIdType(std::count(traducer,traducer+nbOfNodes,1));
1448 std::transform(traducer,traducer+nbOfNodes,traducer,MEDCouplingAccVisit());
1453 * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1454 * For each cell in \b this the number of nodes constituting cell is computed.
1455 * For each polyhedron cell, the sum of the number of nodes of each face constituting polyhedron cell is returned.
1456 * So for pohyhedrons some nodes can be counted several times in the returned result.
1458 * \return a newly allocated array
1459 * \sa MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell
1461 DataArrayIdType *MEDCouplingUMesh::computeNbOfNodesPerCell() const
1463 checkConnectivityFullyDefined();
1464 mcIdType nbOfCells=getNumberOfCells();
1465 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1466 ret->alloc(nbOfCells,1);
1467 mcIdType *retPtr=ret->getPointer();
1468 const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1469 const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1470 for(mcIdType i=0;i<nbOfCells;i++,retPtr++)
1472 if(conn[connI[i]]!=ToIdType(INTERP_KERNEL::NORM_POLYHED))
1473 *retPtr=connI[i+1]-connI[i]-1;
1475 *retPtr=connI[i+1]-connI[i]-1-ToIdType(std::count(conn+connI[i]+1,conn+connI[i+1],-1));
1481 * This method computes effective number of nodes per cell. That is to say nodes appearing several times in nodal connectivity of a cell,
1482 * will be counted only once here whereas it will be counted several times in MEDCouplingUMesh::computeNbOfNodesPerCell method.
1484 * \return DataArrayIdType * - new object to be deallocated by the caller.
1485 * \sa MEDCouplingUMesh::computeNbOfNodesPerCell
1487 DataArrayIdType *MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell() const
1489 checkConnectivityFullyDefined();
1490 mcIdType nbOfCells=getNumberOfCells();
1491 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1492 ret->alloc(nbOfCells,1);
1493 mcIdType *retPtr=ret->getPointer();
1494 const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1495 const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1496 for(mcIdType i=0;i<nbOfCells;i++,retPtr++)
1498 std::set<mcIdType> s(conn+connI[i]+1,conn+connI[i+1]);
1499 if(conn[connI[i]]!=ToIdType(INTERP_KERNEL::NORM_POLYHED))
1500 *retPtr=ToIdType(s.size());
1504 *retPtr=ToIdType(s.size());
1511 * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1512 * For each cell in \b this the number of faces constituting (entity of dimension this->getMeshDimension()-1) cell is computed.
1514 * \return a newly allocated array
1516 DataArrayIdType *MEDCouplingUMesh::computeNbOfFacesPerCell() const
1518 checkConnectivityFullyDefined();
1519 mcIdType nbOfCells=getNumberOfCells();
1520 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1521 ret->alloc(nbOfCells,1);
1522 mcIdType *retPtr=ret->getPointer();
1523 const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1524 const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1525 for(mcIdType i=0;i<nbOfCells;i++,retPtr++,connI++)
1527 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]);
1528 *retPtr=cm.getNumberOfSons2(conn+connI[0]+1,connI[1]-connI[0]-1);
1534 * Removes unused nodes (the node coordinates array is shorten) and returns an array
1535 * mapping between new and old node ids in "Old to New" mode. -1 values in the returned
1536 * array mean that the corresponding old node is no more used.
1537 * \return DataArrayIdType * - a new instance of DataArrayIdType of length \a
1538 * this->getNumberOfNodes() before call of this method. The caller is to
1539 * delete this array using decrRef() as it is no more needed.
1540 * \throw If the coordinates array is not set.
1541 * \throw If the nodal connectivity of cells is not defined.
1542 * \throw If the nodal connectivity includes an invalid id.
1543 * \sa areAllNodesFetched
1545 * \if ENABLE_EXAMPLES
1546 * \ref cpp_mcumesh_zipCoordsTraducer "Here is a C++ example".<br>
1547 * \ref py_mcumesh_zipCoordsTraducer "Here is a Python example".
1550 DataArrayIdType *MEDCouplingUMesh::zipCoordsTraducer()
1552 return MEDCouplingPointSet::zipCoordsTraducer();
1556 * This method stands if 'cell1' and 'cell2' are equals regarding 'compType' policy.
1557 * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1559 int MEDCouplingUMesh::AreCellsEqual(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2, int compType)
1564 return AreCellsEqualPolicy0(conn,connI,cell1,cell2);
1566 return AreCellsEqualPolicy1(conn,connI,cell1,cell2);
1568 return AreCellsEqualPolicy2(conn,connI,cell1,cell2);
1570 return AreCellsEqualPolicy2NoType(conn,connI,cell1,cell2);
1572 return AreCellsEqualPolicy7(conn,connI,cell1,cell2);
1574 throw INTERP_KERNEL::Exception("Unknown comparison asked ! Must be in 0,1,2,3 or 7.");
1578 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 0.
1580 int MEDCouplingUMesh::AreCellsEqualPolicy0(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1582 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1583 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;
1588 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 1.
1590 int MEDCouplingUMesh::AreCellsEqualPolicy1(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1592 mcIdType sz=connI[cell1+1]-connI[cell1];
1593 if(sz==connI[cell2+1]-connI[cell2])
1595 if(conn[connI[cell1]]==conn[connI[cell2]])
1597 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1598 unsigned dim=cm.getDimension();
1603 mcIdType sz1=2*(sz-1);
1604 INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz1];
1605 mcIdType *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(mcIdType *)tmp);
1606 std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1607 work=std::search((mcIdType *)tmp,(mcIdType *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1608 return work!=tmp+sz1?1:0;
1611 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;//case of SEG2 and SEG3
1614 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy1 : not implemented yet for meshdim == 3 !");
1621 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 2.
1623 int MEDCouplingUMesh::AreCellsEqualPolicy2(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1625 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1627 if(conn[connI[cell1]]==conn[connI[cell2]])
1629 std::set<mcIdType> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1630 std::set<mcIdType> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1638 * This method is less restrictive than AreCellsEqualPolicy2. Here the geometric type is absolutely not taken into account !
1640 int MEDCouplingUMesh::AreCellsEqualPolicy2NoType(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1642 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1644 std::set<mcIdType> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1645 std::set<mcIdType> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1652 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 7.
1654 int MEDCouplingUMesh::AreCellsEqualPolicy7(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1656 mcIdType sz=connI[cell1+1]-connI[cell1];
1657 if(sz==connI[cell2+1]-connI[cell2])
1659 if(conn[connI[cell1]]==conn[connI[cell2]])
1661 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1662 unsigned dim=cm.getDimension();
1667 mcIdType sz1=2*(sz-1);
1668 INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz1];
1669 mcIdType *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(mcIdType *)tmp);
1670 std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1671 work=std::search((mcIdType *)tmp,(mcIdType *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1676 std::reverse_iterator<mcIdType *> it1((mcIdType *)tmp+sz1);
1677 std::reverse_iterator<mcIdType *> it2((mcIdType *)tmp);
1678 if(std::search(it1,it2,conn+connI[cell2]+1,conn+connI[cell2+1])!=it2)
1685 {//case of SEG2 and SEG3
1686 if(std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1))
1688 if(!cm.isQuadratic())
1690 std::reverse_iterator<const mcIdType *> it1(conn+connI[cell1+1]);
1691 std::reverse_iterator<const mcIdType *> it2(conn+connI[cell1]+1);
1692 if(std::equal(it1,it2,conn+connI[cell2]+1))
1698 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])
1705 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy7 : not implemented yet for meshdim == 3 !");
1713 * This method find cells that are equal (regarding \a compType) in \a this. The comparison is specified by \a compType (see zipConnectivityTraducer).
1714 * This method keeps the coordinates of \a this. The comparison starts at rank \a startCellId cell id (included).
1715 * 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.
1716 * If \a startCellId is greater than 0 algorithm starts at cell #startCellId but for each cell all candidates are considered.
1717 * This method is time consuming.
1719 * \param [in] compType input specifying the technique used to compare cells each other.
1720 * - 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.
1721 * - 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)
1722 * and their type equal. For 1D mesh the policy 1 is equivalent to 0.
1723 * - 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
1724 * can be used for users not sensitive to orientation of cell
1725 * \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.
1726 * \param [out] commonCellsArr common cells ids (\ref numbering-indirect)
1727 * \param [out] commonCellsIArr common cells ids (\ref numbering-indirect)
1730 void MEDCouplingUMesh::findCommonCells(int compType, mcIdType startCellId, DataArrayIdType *& commonCellsArr, DataArrayIdType *& commonCellsIArr) const
1732 MCAuto<DataArrayIdType> revNodal=DataArrayIdType::New(),revNodalI=DataArrayIdType::New();
1733 getReverseNodalConnectivity(revNodal,revNodalI);
1734 FindCommonCellsAlg(compType,startCellId,_nodal_connec,_nodal_connec_index,revNodal,revNodalI,commonCellsArr,commonCellsIArr);
1737 void MEDCouplingUMesh::FindCommonCellsAlg(int compType, mcIdType startCellId, const DataArrayIdType *nodal, const DataArrayIdType *nodalI, const DataArrayIdType *revNodal, const DataArrayIdType *revNodalI,
1738 DataArrayIdType *& commonCellsArr, DataArrayIdType *& commonCellsIArr)
1740 MCAuto<DataArrayIdType> commonCells=DataArrayIdType::New(),commonCellsI=DataArrayIdType::New(); commonCells->alloc(0,1);
1741 mcIdType nbOfCells=nodalI->getNumberOfTuples()-1;
1742 commonCellsI->reserve(1); commonCellsI->pushBackSilent(0);
1743 const mcIdType *revNodalPtr=revNodal->getConstPointer(),*revNodalIPtr=revNodalI->getConstPointer();
1744 const mcIdType *connPtr=nodal->getConstPointer(),*connIPtr=nodalI->getConstPointer();
1745 std::vector<bool> isFetched(nbOfCells,false);
1748 for(mcIdType i=startCellId;i<nbOfCells;i++)
1752 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));
1753 std::vector<mcIdType> v,v2;
1754 if(connOfNode!=connPtr+connIPtr[i+1])
1756 const mcIdType *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1757 v2.insert(v2.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1]);
1760 for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1764 const mcIdType *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1765 std::vector<mcIdType>::iterator it=std::set_intersection(v.begin(),v.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1766 v2.resize(std::distance(v2.begin(),it));
1770 if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1772 mcIdType pos=commonCellsI->back();
1773 commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1774 for(const mcIdType *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1775 isFetched[*it]=true;
1783 for(mcIdType i=startCellId;i<nbOfCells;i++)
1787 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));
1788 // v2 contains the result of successive intersections using rev nodal on on each node of cell #i
1789 std::vector<mcIdType> v,v2;
1790 if(connOfNode!=connPtr+connIPtr[i+1])
1792 v2.insert(v2.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1]);
1795 for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1799 std::vector<mcIdType>::iterator it=std::set_intersection(v.begin(),v.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1800 v2.resize(std::distance(v2.begin(),it));
1802 // v2 contains now candidates. Problem candidates are sorted using id rank.
1807 auto it(std::find(v2.begin(),v2.end(),i));
1808 std::swap(*v2.begin(),*it);
1810 if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1812 mcIdType newPos(commonCells->getNumberOfTuples());
1813 mcIdType pos(commonCellsI->back());
1814 std::sort(commonCells->getPointerSilent()+pos,commonCells->getPointerSilent()+newPos);
1815 commonCellsI->pushBackSilent(newPos);
1816 for(const mcIdType *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1817 isFetched[*it]=true;
1823 commonCellsArr=commonCells.retn();
1824 commonCellsIArr=commonCellsI.retn();
1828 * Checks if \a this mesh includes all cells of an \a other mesh, and returns an array
1829 * giving for each cell of the \a other an id of a cell in \a this mesh. A value larger
1830 * than \a this->getNumberOfCells() in the returned array means that there is no
1831 * corresponding cell in \a this mesh.
1832 * It is expected that \a this and \a other meshes share the same node coordinates
1833 * array, if it is not so an exception is thrown.
1834 * \param [in] other - the mesh to compare with.
1835 * \param [in] compType - specifies a cell comparison technique. For meaning of its
1836 * valid values [0,1,2], see zipConnectivityTraducer().
1837 * \param [out] arr - a new instance of DataArrayIdType returning correspondence
1838 * between cells of the two meshes. It contains \a other->getNumberOfCells()
1839 * values. The caller is to delete this array using
1840 * decrRef() as it is no more needed.
1841 * \return bool - \c true if all cells of \a other mesh are present in the \a this
1844 * \if ENABLE_EXAMPLES
1845 * \ref cpp_mcumesh_areCellsIncludedIn "Here is a C++ example".<br>
1846 * \ref py_mcumesh_areCellsIncludedIn "Here is a Python example".
1848 * \sa checkDeepEquivalOnSameNodesWith()
1849 * \sa checkGeoEquivalWith()
1851 bool MEDCouplingUMesh::areCellsIncludedIn(const MEDCouplingUMesh *other, int compType, DataArrayIdType *& arr) const
1853 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1854 mcIdType nbOfCells=getNumberOfCells();
1855 static const int possibleCompType[]={0,1,2};
1856 if(std::find(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),compType)==possibleCompType+sizeof(possibleCompType)/sizeof(int))
1858 std::ostringstream oss; oss << "MEDCouplingUMesh::areCellsIncludedIn : only following policies are possible : ";
1859 std::copy(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),std::ostream_iterator<int>(oss," "));
1861 throw INTERP_KERNEL::Exception(oss.str());
1864 if(other->getNumberOfCells()==0)
1866 MCAuto<DataArrayIdType> dftRet(DataArrayIdType::New()); dftRet->alloc(0,1); arr=dftRet.retn(); arr->setName(other->getName());
1869 DataArrayIdType *commonCells(nullptr),*commonCellsI(nullptr);
1870 mesh->findCommonCells(compType,nbOfCells,commonCells,commonCellsI);
1871 MCAuto<DataArrayIdType> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1872 mcIdType newNbOfCells=-1;
1873 MCAuto<DataArrayIdType> o2n = DataArrayIdType::ConvertIndexArrayToO2N(ToIdType(mesh->getNumberOfCells()),commonCells->begin(),commonCellsI->begin(),commonCellsI->end(),newNbOfCells);
1874 MCAuto<DataArrayIdType> p0(o2n->selectByTupleIdSafeSlice(0,nbOfCells,1));
1875 mcIdType maxPart(p0->getMaxValueInArray());
1876 bool ret(maxPart==newNbOfCells-1);
1877 MCAuto<DataArrayIdType> p1(p0->invertArrayO2N2N2O(newNbOfCells));
1878 // fill p1 array in case of presence of cells in other not in this
1879 mcIdType *pt(p1->getPointer());
1880 for(mcIdType i = maxPart ; i < newNbOfCells-1 ; ++i )
1883 MCAuto<DataArrayIdType> p2(o2n->subArray(nbOfCells));
1884 p2->transformWithIndArr(p1->begin(),p1->end()); p2->setName(other->getName());
1890 * This method makes the assumption that \a this and \a other share the same coords. If not an exception will be thrown !
1891 * This method tries to determine if \b other is fully included in \b this.
1892 * The main difference is that this method is not expected to throw exception.
1893 * This method has two outputs :
1895 * \param other other mesh
1896 * \param arr is an output parameter that returns a \b newly created instance. This array is of size 'other->getNumberOfCells()'.
1897 * \return If \a other is fully included in 'this 'true is returned. If not false is returned.
1899 bool MEDCouplingUMesh::areCellsIncludedInPolicy7(const MEDCouplingUMesh *other, DataArrayIdType *& arr) const
1901 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1902 DataArrayIdType *commonCells=0,*commonCellsI=0;
1903 mcIdType thisNbCells=getNumberOfCells();
1904 mesh->findCommonCells(7,thisNbCells,commonCells,commonCellsI);
1905 MCAuto<DataArrayIdType> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1906 const mcIdType *commonCellsPtr=commonCells->getConstPointer(),*commonCellsIPtr=commonCellsI->getConstPointer();
1907 mcIdType otherNbCells=other->getNumberOfCells();
1908 MCAuto<DataArrayIdType> arr2=DataArrayIdType::New();
1909 arr2->alloc(otherNbCells,1);
1910 arr2->fillWithZero();
1911 mcIdType *arr2Ptr=arr2->getPointer();
1912 mcIdType nbOfCommon=commonCellsI->getNumberOfTuples()-1;
1913 for(mcIdType i=0;i<nbOfCommon;i++)
1915 mcIdType start=commonCellsPtr[commonCellsIPtr[i]];
1916 if(start<thisNbCells)
1918 for(mcIdType j=commonCellsIPtr[i]+1;j!=commonCellsIPtr[i+1];j++)
1920 mcIdType sig=commonCellsPtr[j]>0?1:-1;
1921 mcIdType val=std::abs(commonCellsPtr[j])-1;
1922 if(val>=thisNbCells)
1923 arr2Ptr[val-thisNbCells]=sig*(start+1);
1927 arr2->setName(other->getName());
1928 if(arr2->presenceOfValue(0))
1934 MEDCouplingUMesh *MEDCouplingUMesh::mergeMyselfWithOnSameCoords(const MEDCouplingPointSet *other) const
1937 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : input other is null !");
1938 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
1940 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : the input other mesh is not of type unstructured !");
1941 std::vector<const MEDCouplingUMesh *> ms(2);
1944 return MergeUMeshesOnSameCoords(ms);
1948 * Build a sub part of \b this lying or not on the same coordinates than \b this (regarding value of \b keepCoords).
1949 * By default coordinates are kept. This method is close to MEDCouplingUMesh::buildPartOfMySelf except that here input
1950 * cellIds is not given explicitly but by a range python like.
1952 * \param start starting ID
1953 * \param end end ID (excluded)
1954 * \param step step size
1955 * \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.
1956 * \return a newly allocated
1958 * \warning This method modifies can generate an unstructured mesh whose cells are not sorted by geometric type order.
1959 * In view of the MED file writing, a renumbering of cells of returned unstructured mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
1961 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfSlice(mcIdType start, mcIdType end, mcIdType step, bool keepCoords) const
1963 if(getMeshDimension()!=-1)
1964 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelfSlice(start,end,step,keepCoords));
1967 mcIdType newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfSlice for -1 dimension mesh ");
1969 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
1971 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
1973 return const_cast<MEDCouplingUMesh *>(this);
1978 * Creates a new MEDCouplingUMesh containing specified cells of \a this mesh.
1979 * The result mesh shares or not the node coordinates array with \a this mesh depending
1980 * on \a keepCoords parameter.
1981 * \warning Cells of the result mesh can be \b not sorted by geometric type, hence,
1982 * to write this mesh to the MED file, its cells must be sorted using
1983 * sortCellsInMEDFileFrmt().
1984 * \param [in] begin - an array of cell ids to include to the new mesh.
1985 * \param [in] end - a pointer to last-plus-one-th element of \a begin.
1986 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
1987 * array of \a this mesh, else "free" nodes are removed from the result mesh
1988 * by calling zipCoords().
1989 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
1990 * to delete this mesh using decrRef() as it is no more needed.
1991 * \throw If the coordinates array is not set.
1992 * \throw If the nodal connectivity of cells is not defined.
1993 * \throw If any cell id in the array \a begin is not valid.
1995 * \if ENABLE_EXAMPLES
1996 * \ref cpp_mcumesh_buildPartOfMySelf "Here is a C++ example".<br>
1997 * \ref py_mcumesh_buildPartOfMySelf "Here is a Python example".
2000 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelf(const mcIdType *begin, const mcIdType *end, bool keepCoords) const
2002 if(getMeshDimension()!=-1)
2003 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelf(begin,end,keepCoords));
2007 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
2009 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
2011 return const_cast<MEDCouplingUMesh *>(this);
2016 * This method operates only on nodal connectivity on \b this. Coordinates of \b this is completely ignored here.
2018 * 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.
2019 * Size of [ \b cellIdsBg, \b cellIdsEnd ) ) must be equal to the number of cells of otherOnSameCoordsThanThis.
2020 * The number of cells of \b this will remain the same with this method.
2022 * \param [in] cellIdsBg begin of cell ids (included) of cells in this to assign
2023 * \param [in] cellIdsEnd end of cell ids (excluded) of cells in this to assign
2024 * \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 ).
2025 * Coordinate pointer of \b this and those of \b otherOnSameCoordsThanThis must be the same
2027 void MEDCouplingUMesh::setPartOfMySelf(const mcIdType *cellIdsBg, const mcIdType *cellIdsEnd, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2029 checkConnectivityFullyDefined();
2030 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2031 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2032 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelf : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2033 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2035 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2036 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2037 throw INTERP_KERNEL::Exception(oss.str());
2039 mcIdType nbOfCellsToModify( ToIdType((std::distance(cellIdsBg,cellIdsEnd))));
2040 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2042 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2043 throw INTERP_KERNEL::Exception(oss.str());
2045 mcIdType nbOfCells(getNumberOfCells());
2046 bool easyAssign(true);
2047 const mcIdType *connI(_nodal_connec_index->begin());
2048 const mcIdType *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->begin();
2049 for(const mcIdType *it=cellIdsBg;it!=cellIdsEnd && easyAssign;it++,connIOther++)
2051 if(*it>=0 && *it<nbOfCells)
2053 easyAssign=(connIOther[1]-connIOther[0])==(connI[*it+1]-connI[*it]);
2057 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : On pos #" << std::distance(cellIdsBg,it) << " id is equal to " << *it << " which is not in [0," << nbOfCells << ") !";
2058 throw INTERP_KERNEL::Exception(oss.str());
2063 DataArrayIdType::SetPartOfIndexedArraysSameIdx(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2068 DataArrayIdType *arrOut=0,*arrIOut=0;
2069 DataArrayIdType::SetPartOfIndexedArrays(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2071 MCAuto<DataArrayIdType> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2072 setConnectivity(arrOut,arrIOut,true);
2076 void MEDCouplingUMesh::setPartOfMySelfSlice(mcIdType start, mcIdType end, mcIdType step, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2078 checkConnectivityFullyDefined();
2079 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2080 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2081 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelfSlice : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2082 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2084 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2085 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2086 throw INTERP_KERNEL::Exception(oss.str());
2088 mcIdType nbOfCellsToModify=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::setPartOfMySelfSlice : ");
2089 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2091 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2092 throw INTERP_KERNEL::Exception(oss.str());
2094 mcIdType nbOfCells=getNumberOfCells();
2095 bool easyAssign=true;
2096 const mcIdType *connI=_nodal_connec_index->getConstPointer();
2097 const mcIdType *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2099 for(mcIdType i=0;i<nbOfCellsToModify && easyAssign;i++,it+=step,connIOther++)
2101 if(it>=0 && it<nbOfCells)
2103 easyAssign=(connIOther[1]-connIOther[0])==(connI[it+1]-connI[it]);
2107 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : On pos #" << i << " id is equal to " << it << " which is not in [0," << nbOfCells << ") !";
2108 throw INTERP_KERNEL::Exception(oss.str());
2113 DataArrayIdType::SetPartOfIndexedArraysSameIdxSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2118 DataArrayIdType *arrOut=0,*arrIOut=0;
2119 DataArrayIdType::SetPartOfIndexedArraysSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2121 MCAuto<DataArrayIdType> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2122 setConnectivity(arrOut,arrIOut,true);
2128 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2129 * this->getMeshDimension(), that bound some cells of \a this mesh.
2130 * The cells of lower dimension to include to the result mesh are selected basing on
2131 * specified node ids and the value of \a fullyIn parameter. If \a fullyIn ==\c true, a
2132 * cell is copied if its all nodes are in the array \a begin of node ids. If \a fullyIn
2133 * ==\c false, a cell is copied if any its node is in the array of node ids. The
2134 * created mesh shares the node coordinates array with \a this mesh.
2135 * \param [in] begin - the array of node ids.
2136 * \param [in] end - a pointer to the (last+1)-th element of \a begin.
2137 * \param [in] fullyIn - if \c true, then cells whose all nodes are in the
2138 * array \a begin are added, else cells whose any node is in the
2139 * array \a begin are added.
2140 * \return MEDCouplingUMesh * - new instance of MEDCouplingUMesh. The caller is
2141 * to delete this mesh using decrRef() as it is no more needed.
2142 * \throw If the coordinates array is not set.
2143 * \throw If the nodal connectivity of cells is not defined.
2144 * \throw If any node id in \a begin is not valid.
2146 * \if ENABLE_EXAMPLES
2147 * \ref cpp_mcumesh_buildFacePartOfMySelfNode "Here is a C++ example".<br>
2148 * \ref py_mcumesh_buildFacePartOfMySelfNode "Here is a Python example".
2151 MEDCouplingUMesh *MEDCouplingUMesh::buildFacePartOfMySelfNode(const mcIdType *begin, const mcIdType *end, bool fullyIn) const
2153 MCAuto<DataArrayIdType> desc,descIndx,revDesc,revDescIndx;
2154 desc=DataArrayIdType::New(); descIndx=DataArrayIdType::New(); revDesc=DataArrayIdType::New(); revDescIndx=DataArrayIdType::New();
2155 MCAuto<MEDCouplingUMesh> subMesh=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2156 desc=0; descIndx=0; revDesc=0; revDescIndx=0;
2157 return static_cast<MEDCouplingUMesh*>(subMesh->buildPartOfMySelfNode(begin,end,fullyIn));
2161 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2162 * this->getMeshDimension(), which bound only one cell of \a this mesh.
2163 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2164 * array of \a this mesh, else "free" nodes are removed from the result mesh
2165 * by calling zipCoords().
2166 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2167 * to delete this mesh using decrRef() as it is no more needed.
2168 * \throw If the coordinates array is not set.
2169 * \throw If the nodal connectivity of cells is not defined.
2171 * \if ENABLE_EXAMPLES
2172 * \ref cpp_mcumesh_buildBoundaryMesh "Here is a C++ example".<br>
2173 * \ref py_mcumesh_buildBoundaryMesh "Here is a Python example".
2176 MEDCouplingUMesh *MEDCouplingUMesh::buildBoundaryMesh(bool keepCoords) const
2178 DataArrayIdType *desc=DataArrayIdType::New();
2179 DataArrayIdType *descIndx=DataArrayIdType::New();
2180 DataArrayIdType *revDesc=DataArrayIdType::New();
2181 DataArrayIdType *revDescIndx=DataArrayIdType::New();
2183 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2186 descIndx->decrRef();
2187 mcIdType nbOfCells=meshDM1->getNumberOfCells();
2188 const mcIdType *revDescIndxC=revDescIndx->getConstPointer();
2189 std::vector<mcIdType> boundaryCells;
2190 for(mcIdType i=0;i<nbOfCells;i++)
2191 if(revDescIndxC[i+1]-revDescIndxC[i]==1)
2192 boundaryCells.push_back(i);
2193 revDescIndx->decrRef();
2194 MEDCouplingUMesh *ret=meshDM1->buildPartOfMySelf(&boundaryCells[0],&boundaryCells[0]+boundaryCells.size(),keepCoords);
2199 * This method returns a newly created DataArrayIdType instance containing ids of cells located in boundary.
2200 * A cell is detected to be on boundary if it contains one or more than one face having only one father.
2201 * This method makes the assumption that \a this is fully defined (coords,connectivity). If not an exception will be thrown.
2203 DataArrayIdType *MEDCouplingUMesh::findCellIdsOnBoundary() const
2205 checkFullyDefined();
2206 MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
2207 MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
2208 MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
2209 MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
2211 buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx)->decrRef();
2212 desc=(DataArrayIdType*)0; descIndx=(DataArrayIdType*)0;
2214 MCAuto<DataArrayIdType> tmp=revDescIndx->deltaShiftIndex();
2215 MCAuto<DataArrayIdType> faceIds=tmp->findIdsEqual(1); tmp=(DataArrayIdType*)0;
2216 const mcIdType *revDescPtr=revDesc->getConstPointer();
2217 const mcIdType *revDescIndxPtr=revDescIndx->getConstPointer();
2218 mcIdType nbOfCells=getNumberOfCells();
2219 std::vector<bool> ret1(nbOfCells,false);
2221 for(const mcIdType *pt=faceIds->begin();pt!=faceIds->end();pt++)
2222 if(!ret1[revDescPtr[revDescIndxPtr[*pt]]])
2223 { ret1[revDescPtr[revDescIndxPtr[*pt]]]=true; sz++; }
2225 DataArrayIdType *ret2=DataArrayIdType::New();
2227 mcIdType *ret2Ptr=ret2->getPointer();
2229 for(std::vector<bool>::const_iterator it=ret1.begin();it!=ret1.end();it++,sz++)
2232 ret2->setName("BoundaryCells");
2237 * This method finds in \b this the cell ids that lie on mesh \b otherDimM1OnSameCoords.
2238 * \b this and \b otherDimM1OnSameCoords have to lie on the same coordinate array pointer. The coherency of that coords array with connectivity
2239 * of \b this and \b otherDimM1OnSameCoords is not important here because this method works only on connectivity.
2240 * this->getMeshDimension() - 1 must be equal to otherDimM1OnSameCoords.getMeshDimension()
2242 * s0 is the cell ids set in \b this lying on at least one node in the fetched nodes in \b otherDimM1OnSameCoords.
2243 * 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
2244 * equals a cell in \b otherDimM1OnSameCoords.
2246 * \throw if \b otherDimM1OnSameCoords is not part of constituent of \b this, or if coordinate pointer of \b this and \b otherDimM1OnSameCoords
2247 * are not same, or if this->getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension()
2249 * \param [in] otherDimM1OnSameCoords other mesh
2250 * \param [out] cellIdsRk0 a newly allocated array containing the cell ids of s0 (which are cell ids of \b this) in the above algorithm.
2251 * \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
2252 * cellIdsRk1->transformWithIndArr(cellIdsRk0->begin(),cellIdsRk0->end());
2254 void MEDCouplingUMesh::findCellIdsLyingOn(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayIdType *&cellIdsRk0, DataArrayIdType *&cellIdsRk1) const
2256 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2257 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : coordinates pointer are not the same ! Use tryToShareSameCoords method !");
2258 checkConnectivityFullyDefined();
2259 otherDimM1OnSameCoords.checkConnectivityFullyDefined();
2260 if(getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension())
2261 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : invalid mesh dimension of input mesh regarding meshdimesion of this !");
2262 MCAuto<DataArrayIdType> fetchedNodeIds1=otherDimM1OnSameCoords.computeFetchedNodeIds();
2263 MCAuto<DataArrayIdType> s0arr=getCellIdsLyingOnNodes(fetchedNodeIds1->begin(),fetchedNodeIds1->end(),false);
2264 MCAuto<MEDCouplingUMesh> thisPart=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(s0arr->begin(),s0arr->end(),true));
2265 MCAuto<DataArrayIdType> descThisPart=DataArrayIdType::New(),descIThisPart=DataArrayIdType::New(),revDescThisPart=DataArrayIdType::New(),revDescIThisPart=DataArrayIdType::New();
2266 MCAuto<MEDCouplingUMesh> thisPartConsti=thisPart->buildDescendingConnectivity(descThisPart,descIThisPart,revDescThisPart,revDescIThisPart);
2267 const mcIdType *revDescThisPartPtr=revDescThisPart->getConstPointer(),*revDescIThisPartPtr=revDescIThisPart->getConstPointer();
2268 DataArrayIdType *idsOtherInConsti=0;
2269 bool b=thisPartConsti->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsOtherInConsti);
2270 MCAuto<DataArrayIdType> idsOtherInConstiAuto(idsOtherInConsti);
2272 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : the given mdim-1 mesh in other is not a constituent of this !");
2273 std::set<mcIdType> s1;
2274 for(const mcIdType *idOther=idsOtherInConsti->begin();idOther!=idsOtherInConsti->end();idOther++)
2275 s1.insert(revDescThisPartPtr+revDescIThisPartPtr[*idOther],revDescThisPartPtr+revDescIThisPartPtr[*idOther+1]);
2276 MCAuto<DataArrayIdType> s1arr_renum1=DataArrayIdType::New(); s1arr_renum1->alloc(s1.size(),1); std::copy(s1.begin(),s1.end(),s1arr_renum1->getPointer());
2277 s1arr_renum1->sort();
2278 cellIdsRk0=s0arr.retn();
2279 //cellIdsRk1=s_renum1.retn();
2280 cellIdsRk1=s1arr_renum1.retn();
2284 * 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
2285 * returned. This subpart of meshdim-1 mesh is built using meshdim-1 cells in it shared only one cell in \b this.
2287 * \return a newly allocated mesh lying on the same coordinates than \b this. The caller has to deal with returned mesh.
2289 MEDCouplingUMesh *MEDCouplingUMesh::computeSkin() const
2291 MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
2292 MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
2293 MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
2294 MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
2296 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2297 revDesc=0; desc=0; descIndx=0;
2298 MCAuto<DataArrayIdType> revDescIndx2=revDescIndx->deltaShiftIndex();
2299 MCAuto<DataArrayIdType> part=revDescIndx2->findIdsEqual(1);
2300 return static_cast<MEDCouplingUMesh *>(meshDM1->buildPartOfMySelf(part->begin(),part->end(),true));
2304 * Finds nodes lying on the boundary of \a this mesh.
2305 * \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of found
2306 * nodes. The caller is to delete this array using decrRef() as it is no
2308 * \throw If the coordinates array is not set.
2309 * \throw If the nodal connectivity of cells is node defined.
2311 * \if ENABLE_EXAMPLES
2312 * \ref cpp_mcumesh_findBoundaryNodes "Here is a C++ example".<br>
2313 * \ref py_mcumesh_findBoundaryNodes "Here is a Python example".
2316 DataArrayIdType *MEDCouplingUMesh::findBoundaryNodes() const
2318 MCAuto<MEDCouplingUMesh> skin=computeSkin();
2319 return skin->computeFetchedNodeIds();
2322 MEDCouplingUMesh *MEDCouplingUMesh::buildUnstructured() const
2325 return const_cast<MEDCouplingUMesh *>(this);
2329 * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2330 * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2331 * 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.
2332 * 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.
2333 * 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.
2335 * \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
2336 * parameter is altered during the call.
2337 * \param [out] nodeIdsToDuplicate node ids needed to be duplicated following the algorithm explain above.
2338 * \param [out] cellIdsNeededToBeRenum cell ids in \b this in which the renumber of nodes should be performed.
2339 * \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.
2342 void MEDCouplingUMesh::findNodesToDuplicate(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayIdType *& nodeIdsToDuplicate,
2343 DataArrayIdType *& cellIdsNeededToBeRenum, DataArrayIdType *& cellIdsNotModified) const
2345 typedef MCAuto<DataArrayIdType> DAInt;
2346 typedef MCAuto<MEDCouplingUMesh> MCUMesh;
2348 checkFullyDefined();
2349 otherDimM1OnSameCoords.checkFullyDefined();
2350 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2351 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : meshes do not share the same coords array !");
2352 if(otherDimM1OnSameCoords.getMeshDimension()!=getMeshDimension()-1)
2353 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the mesh given in other parameter must have this->getMeshDimension()-1 !");
2355 // Checking star-shaped M1 group:
2356 DAInt dt0=DataArrayIdType::New(),dit0=DataArrayIdType::New(),rdt0=DataArrayIdType::New(),rdit0=DataArrayIdType::New();
2357 MCUMesh meshM2 = otherDimM1OnSameCoords.buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); // 2D: a mesh of points, 3D: a mesh of segs
2358 DAInt dsi = rdit0->deltaShiftIndex();
2359 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.
2360 if(idsTmp0->getNumberOfTuples())
2361 throw INTERP_KERNEL::Exception("MEDFileUMesh::buildInnerBoundaryAlongM1Group: group is too complex: some points (or edges) have more than two connected segments (or faces)!");
2362 dt0=0; dit0=0; rdt0=0; rdit0=0; idsTmp0=0;
2364 // Get extreme nodes from the group (they won't be duplicated except if they also lie on bound of M0 -- see below),
2365 // ie nodes belonging to the boundary "cells" (might be points) of M1
2366 DAInt xtremIdsM2 = dsi->findIdsEqual(1); dsi = 0;
2367 MCUMesh meshM2Part = static_cast<MEDCouplingUMesh *>(meshM2->buildPartOfMySelf(xtremIdsM2->begin(), xtremIdsM2->end(),true));
2368 DAInt xtrem = meshM2Part->computeFetchedNodeIds();
2369 // Remove from the list points on the boundary of the M0 mesh (those need duplication!)
2370 dt0=DataArrayIdType::New(),dit0=DataArrayIdType::New(),rdt0=DataArrayIdType::New(),rdit0=DataArrayIdType::New();
2371 MCUMesh m0desc = buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); dt0=0; dit0=0; rdt0=0;
2372 dsi = rdit0->deltaShiftIndex();
2373 DAInt boundSegs = dsi->findIdsEqual(1); dsi = 0; // boundary segs/faces of the M0 mesh
2374 MCUMesh m0descSkin = static_cast<MEDCouplingUMesh *>(m0desc->buildPartOfMySelf(boundSegs->begin(),boundSegs->end(), true));
2375 DAInt fNodes = m0descSkin->computeFetchedNodeIds();
2376 // 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)
2377 // 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
2378 // although they are technically on the skin of the cube.
2380 if (getMeshDimension() == 3)
2382 DAInt dnu1=DataArrayIdType::New(), dnu2=DataArrayIdType::New(), dnu3=DataArrayIdType::New(), dnu4=DataArrayIdType::New();
2383 MCUMesh m0descSkinDesc = m0descSkin->buildDescendingConnectivity(dnu1, dnu2, dnu3, dnu4); // all segments of the skin of the 3D (M0) mesh
2384 dnu1=0;dnu2=0;dnu3=0;dnu4=0;
2385 DataArrayIdType * corresp=0;
2386 meshM2->areCellsIncludedIn(m0descSkinDesc,2,corresp);
2387 DAInt validIds = corresp->findIdsInRange(0, meshM2->getNumberOfCells());
2389 if (validIds->getNumberOfTuples())
2391 // 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:
2392 MCUMesh m1IntersecSkin = static_cast<MEDCouplingUMesh *>(m0descSkinDesc->buildPartOfMySelf(validIds->begin(), validIds->end(), true));
2393 // Its boundary nodes should no be duplicated (this is for example the tip of the crack inside the cube described above)
2394 DAInt notDuplSkin = m1IntersecSkin->findBoundaryNodes();
2395 DAInt fNodes1 = fNodes->buildSubstraction(notDuplSkin);
2397 // Also, in this (segment) mesh, nodes connected to more than 3 segs should not be dup either (singular points - see testBuildInnerBoundary6())
2398 dt0=DataArrayIdType::New(),dit0=DataArrayIdType::New(),rdt0=DataArrayIdType::New(),rdit0=DataArrayIdType::New();
2399 MCUMesh meshM2Desc = meshM2->buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); dt0=0; dit0=0; rdt0=0; // a mesh made of node cells
2400 dsi = rdit0->deltaShiftIndex();
2401 DAInt singPoints = dsi->findIdsNotInRange(-1,4); // points connected to (strictly) more than 3 segments
2402 const mcIdType *cc = meshM2Desc->getNodalConnectivity()->begin(), *ccI = meshM2Desc->getNodalConnectivityIndex()->begin();
2403 mcIdType * singPointsP = singPoints->rwBegin();
2404 for (mcIdType j=0; j < singPoints->getNumberOfTuples(); j++) // replace ids in singPoints by real coordinate index (was index of cells in notDuplSkin)
2406 mcIdType nodeCellIdx = singPointsP[j];
2407 singPointsP[j] = cc[ccI[nodeCellIdx]+1]; // +1 to skip type
2409 DAInt fNodes2 = fNodes1->buildSubstraction(singPoints);
2410 notDup = xtrem->buildSubstraction(fNodes2);
2413 notDup = xtrem->buildSubstraction(fNodes);
2416 notDup = xtrem->buildSubstraction(fNodes);
2418 // Now compute cells around group (i.e. cells where we will do the propagation to identify the two sub-sets delimited by the group)
2419 DAInt m1Nodes = otherDimM1OnSameCoords.computeFetchedNodeIds();
2420 DAInt dupl = m1Nodes->buildSubstraction(notDup);
2421 DAInt cellsAroundGroup = getCellIdsLyingOnNodes(dupl->begin(), dupl->end(), false); // false= take cell in, even if not all nodes are in notDup
2424 MCUMesh m0Part2=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(cellsAroundGroup->begin(),cellsAroundGroup->end(),true));
2425 mcIdType nCells2 = m0Part2->getNumberOfCells();
2426 DAInt desc00=DataArrayIdType::New(),descI00=DataArrayIdType::New(),revDesc00=DataArrayIdType::New(),revDescI00=DataArrayIdType::New();
2427 MCUMesh m01=m0Part2->buildDescendingConnectivity(desc00,descI00,revDesc00,revDescI00);
2429 // Neighbor information of the mesh without considering the crack (serves to count how many connex pieces it is made of)
2430 DataArrayIdType *tmp00=0,*tmp11=0;
2431 MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00, tmp00, tmp11);
2432 DAInt neighInit00(tmp00);
2433 DAInt neighIInit00(tmp11);
2434 // Neighbor information of the mesh WITH the crack (some neighbors are removed):
2435 DataArrayIdType *idsTmp=0;
2436 m01->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsTmp);
2438 // In the neighbor information remove the connection between high dimension cells and its low level constituents which are part
2439 // of the frontier given in parameter (i.e. the cells of low dimension from the group delimiting the crack):
2440 DataArrayIdType::RemoveIdsFromIndexedArrays(ids->begin(),ids->end(),desc00,descI00);
2441 DataArrayIdType *tmp0=0,*tmp1=0;
2442 // Compute the neighbor of each cell in m0Part2, taking into account the broken link above. Two
2443 // cells on either side of the crack (defined by the mesh of low dimension) are not neighbor anymore.
2444 ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00,tmp0,tmp1);
2445 DAInt neigh00(tmp0);
2446 DAInt neighI00(tmp1);
2448 // For each initial connex part of the sub-mesh (or said differently for each independent crack):
2449 mcIdType seed = 0, nIter = 0;
2450 mcIdType nIterMax = nCells2+1; // Safety net for the loop
2451 DAInt hitCells = DataArrayIdType::New(); hitCells->alloc(nCells2);
2452 hitCells->fillWithValue(-1);
2453 DAInt cellsToModifyConn0_torenum = DataArrayIdType::New();
2454 cellsToModifyConn0_torenum->alloc(0,1);
2455 while (nIter < nIterMax)
2457 DAInt t = hitCells->findIdsEqual(-1);
2458 if (!t->getNumberOfTuples())
2460 // Connex zone without the crack (to compute the next seed really)
2462 DAInt connexCheck = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neighInit00,neighIInit00, -1, dnu);
2464 for (mcIdType * ptr = connexCheck->getPointer(); cnt < connexCheck->getNumberOfTuples(); ptr++, cnt++)
2465 hitCells->setIJ(*ptr,0,1);
2466 // Connex zone WITH the crack (to identify cells lying on either part of the crack)
2467 DAInt spreadZone = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neigh00,neighI00, -1, dnu);
2468 cellsToModifyConn0_torenum = DataArrayIdType::Aggregate(cellsToModifyConn0_torenum, spreadZone, 0);
2469 // Compute next seed, i.e. a cell in another connex part, which was not covered by the previous iterations
2470 DAInt comple = cellsToModifyConn0_torenum->buildComplement(nCells2);
2471 DAInt nonHitCells = hitCells->findIdsEqual(-1);
2472 DAInt intersec = nonHitCells->buildIntersection(comple);
2473 if (intersec->getNumberOfTuples())
2474 { seed = intersec->getIJ(0,0); }
2479 if (nIter >= nIterMax)
2480 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate(): internal error - too many iterations.");
2482 DAInt cellsToModifyConn1_torenum=cellsToModifyConn0_torenum->buildComplement(neighI00->getNumberOfTuples()-1);
2483 cellsToModifyConn0_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2484 cellsToModifyConn1_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2486 cellIdsNeededToBeRenum=cellsToModifyConn0_torenum.retn();
2487 cellIdsNotModified=cellsToModifyConn1_torenum.retn();
2488 nodeIdsToDuplicate=dupl.retn();
2492 * This method operates a modification of the connectivity and coords in \b this.
2493 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2494 * its ids will be modified to id this->getNumberOfNodes()+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2495 * 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
2496 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id this->getNumberOfNodes()+0, node id nodeIdsToDuplicateBg[1] will have id this->getNumberOfNodes()+1,
2497 * node id nodeIdsToDuplicateBg[2] will have id this->getNumberOfNodes()+2...
2499 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2501 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2502 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2504 void MEDCouplingUMesh::duplicateNodes(const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd)
2506 mcIdType nbOfNodes=getNumberOfNodes();
2507 duplicateNodesInCoords(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd);
2508 duplicateNodesInConn(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,nbOfNodes);
2512 * This method renumbers only nodal connectivity in \a this. The renumbering is only an offset applied. So this method is a specialization of
2513 * \a renumberNodesInConn. \b WARNING, this method does not check that the resulting node ids in the nodal connectivity is in a valid range !
2515 * \param [in] offset - specifies the offset to be applied on each element of connectivity.
2517 * \sa renumberNodesInConn
2519 void MEDCouplingUMesh::renumberNodesWithOffsetInConn(mcIdType offset)
2521 checkConnectivityFullyDefined();
2522 mcIdType *conn(getNodalConnectivity()->getPointer());
2523 const mcIdType *connIndex(getNodalConnectivityIndex()->getConstPointer());
2524 mcIdType nbOfCells=getNumberOfCells();
2525 for(mcIdType i=0;i<nbOfCells;i++)
2526 for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2528 mcIdType& node=conn[iconn];
2529 if(node>=0)//avoid polyhedron separator
2534 _nodal_connec->declareAsNew();
2539 * Same than renumberNodesInConn(const mcIdType *) except that here the format of old-to-new traducer is using map instead
2540 * 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
2543 void MEDCouplingUMesh::renumberNodesInConn(const INTERP_KERNEL::HashMap<mcIdType,mcIdType>& newNodeNumbersO2N)
2545 this->renumberNodesInConnT< INTERP_KERNEL::HashMap<mcIdType,mcIdType> >(newNodeNumbersO2N);
2549 * Same than renumberNodesInConn(const mcIdType *) except that here the format of old-to-new traducer is using map instead
2550 * 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
2553 void MEDCouplingUMesh::renumberNodesInConn(const std::map<mcIdType,mcIdType>& newNodeNumbersO2N)
2555 this->renumberNodesInConnT< std::map<mcIdType,mcIdType> >(newNodeNumbersO2N);
2559 * Changes ids of nodes within the nodal connectivity arrays according to a permutation
2560 * array in "Old to New" mode. The node coordinates array is \b not changed by this method.
2561 * This method is a generalization of shiftNodeNumbersInConn().
2562 * \warning This method performs no check of validity of new ids. **Use it with care !**
2563 * \param [in] newNodeNumbersO2N - a permutation array, of length \a
2564 * this->getNumberOfNodes(), in "Old to New" mode.
2565 * See \ref numbering for more info on renumbering modes.
2566 * \throw If the nodal connectivity of cells is not defined.
2568 * \if ENABLE_EXAMPLES
2569 * \ref cpp_mcumesh_renumberNodesInConn "Here is a C++ example".<br>
2570 * \ref py_mcumesh_renumberNodesInConn "Here is a Python example".
2573 void MEDCouplingUMesh::renumberNodesInConn(const mcIdType *newNodeNumbersO2N)
2575 checkConnectivityFullyDefined();
2576 mcIdType *conn=getNodalConnectivity()->getPointer();
2577 const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2578 mcIdType nbOfCells=getNumberOfCells();
2579 for(mcIdType i=0;i<nbOfCells;i++)
2580 for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2582 mcIdType& node=conn[iconn];
2583 if(node>=0)//avoid polyhedron separator
2585 node=newNodeNumbersO2N[node];
2588 _nodal_connec->declareAsNew();
2593 * This method renumbers nodes \b in \b connectivity \b only \b without \b any \b reference \b to \b coords.
2594 * This method performs no check on the fact that new coordinate ids are valid. \b Use \b it \b with \b care !
2595 * This method is an specialization of \ref MEDCoupling::MEDCouplingUMesh::renumberNodesInConn "renumberNodesInConn method".
2597 * \param [in] delta specifies the shift size applied to nodeId in nodal connectivity in \b this.
2599 void MEDCouplingUMesh::shiftNodeNumbersInConn(mcIdType delta)
2601 checkConnectivityFullyDefined();
2602 mcIdType *conn=getNodalConnectivity()->getPointer();
2603 const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2604 mcIdType nbOfCells=getNumberOfCells();
2605 for(mcIdType i=0;i<nbOfCells;i++)
2606 for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2608 mcIdType& node=conn[iconn];
2609 if(node>=0)//avoid polyhedron separator
2614 _nodal_connec->declareAsNew();
2619 * This method operates a modification of the connectivity in \b this.
2620 * 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.
2621 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2622 * its ids will be modified to id offset+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2623 * 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
2624 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id offset+0, node id nodeIdsToDuplicateBg[1] will have id offset+1,
2625 * node id nodeIdsToDuplicateBg[2] will have id offset+2...
2627 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2628 * As an another consequense after the call of this method \b this can be transiently non cohrent.
2630 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2631 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2632 * \param [in] offset the offset applied to all node ids in connectivity that are in [ \a nodeIdsToDuplicateBg, \a nodeIdsToDuplicateEnd ).
2634 void MEDCouplingUMesh::duplicateNodesInConn(const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd, mcIdType offset)
2636 checkConnectivityFullyDefined();
2637 std::map<mcIdType,mcIdType> m;
2638 mcIdType val=offset;
2639 for(const mcIdType *work=nodeIdsToDuplicateBg;work!=nodeIdsToDuplicateEnd;work++,val++)
2641 mcIdType *conn=getNodalConnectivity()->getPointer();
2642 const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2643 mcIdType nbOfCells=getNumberOfCells();
2644 for(mcIdType i=0;i<nbOfCells;i++)
2645 for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2647 mcIdType& node=conn[iconn];
2648 if(node>=0)//avoid polyhedron separator
2650 std::map<mcIdType,mcIdType>::iterator it=m.find(node);
2659 * This method renumbers cells of \a this using the array specified by [old2NewBg;old2NewBg+getNumberOfCells())
2661 * Contrary to MEDCouplingPointSet::renumberNodes, this method makes a permutation without any fuse of cell.
2662 * After the call of this method the number of cells remains the same as before.
2664 * If 'check' equals true the method will check that any elements in [ \a old2NewBg; \a old2NewEnd ) is unique ; if not
2665 * an INTERP_KERNEL::Exception will be thrown. When 'check' equals true [ \a old2NewBg ; \a old2NewEnd ) is not expected to
2666 * be strictly in [0;this->getNumberOfCells()).
2668 * If 'check' equals false the method will not check the content of [ \a old2NewBg ; \a old2NewEnd ).
2669 * To avoid any throw of SIGSEGV when 'check' equals false, the elements in [ \a old2NewBg ; \a old2NewEnd ) should be unique and
2670 * should be contained in[0;this->getNumberOfCells()).
2672 * \param [in] old2NewBg is expected to be a dynamically allocated pointer of size at least equal to this->getNumberOfCells()
2673 * \param check whether to check content of old2NewBg
2675 void MEDCouplingUMesh::renumberCells(const mcIdType *old2NewBg, bool check)
2677 checkConnectivityFullyDefined();
2678 mcIdType nbCells=getNumberOfCells();
2679 const mcIdType *array=old2NewBg;
2681 array=DataArrayIdType::CheckAndPreparePermutation(old2NewBg,old2NewBg+nbCells);
2683 const mcIdType *conn=_nodal_connec->getConstPointer();
2684 const mcIdType *connI=_nodal_connec_index->getConstPointer();
2685 MCAuto<DataArrayIdType> o2n=DataArrayIdType::New(); o2n->useArray(array,false,DeallocType::C_DEALLOC,nbCells,1);
2686 MCAuto<DataArrayIdType> n2o=o2n->invertArrayO2N2N2O(nbCells);
2687 const mcIdType *n2oPtr=n2o->begin();
2688 MCAuto<DataArrayIdType> newConn=DataArrayIdType::New();
2689 newConn->alloc(_nodal_connec->getNumberOfTuples(),_nodal_connec->getNumberOfComponents());
2690 newConn->copyStringInfoFrom(*_nodal_connec);
2691 MCAuto<DataArrayIdType> newConnI=DataArrayIdType::New();
2692 newConnI->alloc(_nodal_connec_index->getNumberOfTuples(),_nodal_connec_index->getNumberOfComponents());
2693 newConnI->copyStringInfoFrom(*_nodal_connec_index);
2695 mcIdType *newC=newConn->getPointer();
2696 mcIdType *newCI=newConnI->getPointer();
2699 for(mcIdType i=0;i<nbCells;i++)
2701 mcIdType pos=n2oPtr[i];
2702 mcIdType nbOfElts=connI[pos+1]-connI[pos];
2703 newC=std::copy(conn+connI[pos],conn+connI[pos+1],newC);
2708 setConnectivity(newConn,newConnI);
2710 free(const_cast<mcIdType *>(array));
2714 * Finds cells whose bounding boxes intersect a given bounding box.
2715 * \param [in] bbox - an array defining the bounding box via coordinates of its
2716 * extremum points in "no interlace" mode, i.e. xMin, xMax, yMin, yMax, zMin,
2718 * \param [in] eps - a factor used to increase size of the bounding box of cell
2719 * before comparing it with \a bbox. This factor is multiplied by the maximal
2720 * extent of the bounding box of cell to produce an addition to this bounding box.
2721 * \return DataArrayIdType * - a new instance of DataArrayIdType holding ids for found
2722 * cells. The caller is to delete this array using decrRef() as it is no more
2724 * \throw If the coordinates array is not set.
2725 * \throw If the nodal connectivity of cells is not defined.
2727 * \if ENABLE_EXAMPLES
2728 * \ref cpp_mcumesh_getCellsInBoundingBox "Here is a C++ example".<br>
2729 * \ref py_mcumesh_getCellsInBoundingBox "Here is a Python example".
2732 DataArrayIdType *MEDCouplingUMesh::getCellsInBoundingBox(const double *bbox, double eps) const
2734 MCAuto<DataArrayIdType> elems=DataArrayIdType::New(); elems->alloc(0,1);
2735 if(getMeshDimension()==-1)
2737 elems->pushBackSilent(0);
2738 return elems.retn();
2740 int dim=getSpaceDimension();
2741 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2742 const mcIdType* conn = getNodalConnectivity()->getConstPointer();
2743 const mcIdType* conn_index= getNodalConnectivityIndex()->getConstPointer();
2744 const double* coords = getCoords()->getConstPointer();
2745 mcIdType nbOfCells=getNumberOfCells();
2746 for ( mcIdType ielem=0; ielem<nbOfCells;ielem++ )
2748 for (int i=0; i<dim; i++)
2750 elem_bb[i*2]=std::numeric_limits<double>::max();
2751 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2754 for (mcIdType inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2756 mcIdType node= conn[inode];
2757 if(node>=0)//avoid polyhedron separator
2759 for (int idim=0; idim<dim; idim++)
2761 if ( coords[node*dim+idim] < elem_bb[idim*2] )
2763 elem_bb[idim*2] = coords[node*dim+idim] ;
2765 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2767 elem_bb[idim*2+1] = coords[node*dim+idim] ;
2772 if (intersectsBoundingBox(elem_bb, bbox, dim, eps))
2773 elems->pushBackSilent(ielem);
2775 return elems.retn();
2779 * Given a boundary box 'bbox' returns elements 'elems' contained in this 'bbox' or touching 'bbox' (within 'eps' distance).
2780 * Warning 'elems' is incremented during the call so if elems is not empty before call returned elements will be
2781 * added in 'elems' parameter.
2783 DataArrayIdType *MEDCouplingUMesh::getCellsInBoundingBox(const INTERP_KERNEL::DirectedBoundingBox& bbox, double eps)
2785 MCAuto<DataArrayIdType> elems=DataArrayIdType::New(); elems->alloc(0,1);
2786 if(getMeshDimension()==-1)
2788 elems->pushBackSilent(0);
2789 return elems.retn();
2791 int dim=getSpaceDimension();
2792 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2793 const mcIdType* conn = getNodalConnectivity()->getConstPointer();
2794 const mcIdType* conn_index= getNodalConnectivityIndex()->getConstPointer();
2795 const double* coords = getCoords()->getConstPointer();
2796 mcIdType nbOfCells=getNumberOfCells();
2797 for ( mcIdType ielem=0; ielem<nbOfCells;ielem++ )
2799 for (int i=0; i<dim; i++)
2801 elem_bb[i*2]=std::numeric_limits<double>::max();
2802 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2805 for (mcIdType inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2807 mcIdType node= conn[inode];
2808 if(node>=0)//avoid polyhedron separator
2810 for (int idim=0; idim<dim; idim++)
2812 if ( coords[node*dim+idim] < elem_bb[idim*2] )
2814 elem_bb[idim*2] = coords[node*dim+idim] ;
2816 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2818 elem_bb[idim*2+1] = coords[node*dim+idim] ;
2823 if(intersectsBoundingBox(bbox, elem_bb, dim, eps))
2824 elems->pushBackSilent(ielem);
2826 return elems.retn();
2830 * Returns a type of a cell by its id.
2831 * \param [in] cellId - the id of the cell of interest.
2832 * \return INTERP_KERNEL::NormalizedCellType - enumeration item describing the cell type.
2833 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2835 INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::getTypeOfCell(mcIdType cellId) const
2837 const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
2838 if(cellId<_nodal_connec_index->getNbOfElems()-1)
2839 return (INTERP_KERNEL::NormalizedCellType) pt[ptI[cellId]];
2842 std::ostringstream oss; oss << "MEDCouplingUMesh::getTypeOfCell : Requesting type of cell #" << cellId << " but it should be in [0," << _nodal_connec_index->getNbOfElems()-1 << ") !";
2843 throw INTERP_KERNEL::Exception(oss.str());
2848 * This method returns a newly allocated array containing cell ids (ascendingly sorted) whose geometric type are equal to type.
2849 * This method does not throw exception if geometric type \a type is not in \a this.
2850 * This method throws an INTERP_KERNEL::Exception if meshdimension of \b this is not equal to those of \b type.
2851 * The coordinates array is not considered here.
2853 * \param [in] type the geometric type
2854 * \return cell ids in this having geometric type \a type.
2856 DataArrayIdType *MEDCouplingUMesh::giveCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2859 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
2861 checkConnectivityFullyDefined();
2862 mcIdType nbCells=getNumberOfCells();
2863 int mdim=getMeshDimension();
2864 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
2865 if(mdim!=ToIdType(cm.getDimension()))
2866 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::giveCellsWithType : Mismatch between mesh dimension and dimension of the cell !");
2867 const mcIdType *ptI=_nodal_connec_index->getConstPointer();
2868 const mcIdType *pt=_nodal_connec->getConstPointer();
2869 for(mcIdType i=0;i<nbCells;i++)
2871 if((INTERP_KERNEL::NormalizedCellType)pt[ptI[i]]==type)
2872 ret->pushBackSilent(i);
2878 * Returns nb of cells having the geometric type \a type. No throw if no cells in \a this has the geometric type \a type.
2880 mcIdType MEDCouplingUMesh::getNumberOfCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2882 const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
2883 mcIdType nbOfCells(getNumberOfCells()),ret(0);
2884 for(mcIdType i=0;i<nbOfCells;i++)
2885 if((INTERP_KERNEL::NormalizedCellType) pt[ptI[i]]==type)
2891 * Returns the nodal connectivity of a given cell.
2892 * The separator of faces within polyhedron connectivity (-1) is not returned, thus
2893 * all returned node ids can be used in getCoordinatesOfNode().
2894 * \param [in] cellId - an id of the cell of interest.
2895 * \param [in,out] conn - a vector where the node ids are appended. It is not
2896 * cleared before the appending.
2897 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2899 void MEDCouplingUMesh::getNodeIdsOfCell(mcIdType cellId, std::vector<mcIdType>& conn) const
2901 const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
2902 for(const mcIdType *w=pt+ptI[cellId]+1;w!=pt+ptI[cellId+1];w++)
2907 std::string MEDCouplingUMesh::simpleRepr() const
2909 static const char msg0[]="No coordinates specified !";
2910 std::ostringstream ret;
2911 ret << "Unstructured mesh with name : \"" << getName() << "\"\n";
2912 ret << "Description of mesh : \"" << getDescription() << "\"\n";
2914 double tt=getTime(tmpp1,tmpp2);
2915 ret << "Time attached to the mesh [unit] : " << tt << " [" << getTimeUnit() << "]\n";
2916 ret << "Iteration : " << tmpp1 << " Order : " << tmpp2 << "\n";
2918 { ret << "Mesh dimension : " << _mesh_dim << "\nSpace dimension : "; }
2920 { ret << " Mesh dimension has not been set or is invalid !"; }
2923 const int spaceDim=getSpaceDimension();
2924 ret << spaceDim << "\nInfo attached on space dimension : ";
2925 for(int i=0;i<spaceDim;i++)
2926 ret << "\"" << _coords->getInfoOnComponent(i) << "\" ";
2930 ret << msg0 << "\n";
2931 ret << "Number of nodes : ";
2933 ret << getNumberOfNodes() << "\n";
2935 ret << msg0 << "\n";
2936 ret << "Number of cells : ";
2937 if(_nodal_connec!=0 && _nodal_connec_index!=0)
2938 ret << getNumberOfCells() << "\n";
2940 ret << "No connectivity specified !" << "\n";
2941 ret << "Cell types present : ";
2942 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
2944 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter);
2945 ret << cm.getRepr() << " ";
2951 std::string MEDCouplingUMesh::advancedRepr() const
2953 std::ostringstream ret;
2954 ret << simpleRepr();
2955 ret << "\nCoordinates array : \n___________________\n\n";
2957 _coords->reprWithoutNameStream(ret);
2959 ret << "No array set !\n";
2960 ret << "\n\nConnectivity arrays : \n_____________________\n\n";
2961 reprConnectivityOfThisLL(ret);
2966 * This method returns a C++ code that is a dump of \a this.
2967 * This method will throw if this is not fully defined.
2969 std::string MEDCouplingUMesh::cppRepr() const
2971 static const char coordsName[]="coords";
2972 static const char connName[]="conn";
2973 static const char connIName[]="connI";
2974 checkFullyDefined();
2975 std::ostringstream ret; ret << "// coordinates" << std::endl;
2976 _coords->reprCppStream(coordsName,ret); ret << std::endl << "// connectivity" << std::endl;
2977 _nodal_connec->reprCppStream(connName,ret); ret << std::endl;
2978 _nodal_connec_index->reprCppStream(connIName,ret); ret << std::endl;
2979 ret << "MEDCouplingUMesh *mesh=MEDCouplingUMesh::New(\"" << getName() << "\"," << getMeshDimension() << ");" << std::endl;
2980 ret << "mesh->setCoords(" << coordsName << ");" << std::endl;
2981 ret << "mesh->setConnectivity(" << connName << "," << connIName << ",true);" << std::endl;
2982 ret << coordsName << "->decrRef(); " << connName << "->decrRef(); " << connIName << "->decrRef();" << std::endl;
2986 std::string MEDCouplingUMesh::reprConnectivityOfThis() const
2988 std::ostringstream ret;
2989 reprConnectivityOfThisLL(ret);
2994 * This method builds a newly allocated instance (with the same name than \a this) that the caller has the responsibility to deal with.
2995 * This method returns an instance with all arrays allocated (connectivity, connectivity index, coordinates)
2996 * but with length of these arrays set to 0. It allows to define an "empty" mesh (with nor cells nor nodes but compliant with
2999 * This method expects that \a this has a mesh dimension set and higher or equal to 0. If not an exception will be thrown.
3000 * 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
3001 * with number of tuples set to 0, if not the array is taken as this in the returned instance.
3003 MEDCouplingUMesh *MEDCouplingUMesh::buildSetInstanceFromThis(std::size_t spaceDim) const
3005 int mdim=getMeshDimension();
3007 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSetInstanceFromThis : invalid mesh dimension ! Should be >= 0 !");
3008 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
3009 MCAuto<DataArrayIdType> tmp1,tmp2;
3010 bool needToCpyCT=true;
3013 tmp1=DataArrayIdType::New(); tmp1->alloc(0,1);
3021 if(!_nodal_connec_index)
3023 tmp2=DataArrayIdType::New(); tmp2->alloc(1,1); tmp2->setIJ(0,0,0);
3028 tmp2=_nodal_connec_index;
3031 ret->setConnectivity(tmp1,tmp2,false);
3036 MCAuto<DataArrayDouble> coords=DataArrayDouble::New(); coords->alloc(0,spaceDim);
3037 ret->setCoords(coords);
3040 ret->setCoords(_coords);
3044 mcIdType MEDCouplingUMesh::getNumberOfNodesInCell(mcIdType cellId) const
3046 const mcIdType *ptI=_nodal_connec_index->getConstPointer();
3047 const mcIdType *pt=_nodal_connec->getConstPointer();
3048 if(pt[ptI[cellId]]!=INTERP_KERNEL::NORM_POLYHED)
3049 return ptI[cellId+1]-ptI[cellId]-1;
3051 return ToIdType(std::count_if(pt+ptI[cellId]+1,pt+ptI[cellId+1],std::bind(std::not_equal_to<mcIdType>(),std::placeholders::_1,-1)));
3055 * Returns types of cells of the specified part of \a this mesh.
3056 * This method avoids computing sub-mesh explicitly to get its types.
3057 * \param [in] begin - an array of cell ids of interest.
3058 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3059 * \return std::set<INTERP_KERNEL::NormalizedCellType> - a set of enumeration items
3060 * describing the cell types.
3061 * \throw If the coordinates array is not set.
3062 * \throw If the nodal connectivity of cells is not defined.
3063 * \sa getAllGeoTypes()
3065 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getTypesOfPart(const mcIdType *begin, const mcIdType *end) const
3067 checkFullyDefined();
3068 std::set<INTERP_KERNEL::NormalizedCellType> ret;
3069 const mcIdType *conn=_nodal_connec->getConstPointer();
3070 const mcIdType *connIndex=_nodal_connec_index->getConstPointer();
3071 for(const mcIdType *w=begin;w!=end;w++)
3072 ret.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]);
3077 * Defines the nodal connectivity using given connectivity arrays in \ref numbering-indirect format.
3078 * Optionally updates
3079 * a set of types of cells constituting \a this mesh.
3080 * This method is for advanced users having prepared their connectivity before. For
3081 * more info on using this method see \ref MEDCouplingUMeshAdvBuild.
3082 * \param [in] conn - the nodal connectivity array.
3083 * \param [in] connIndex - the nodal connectivity index array.
3084 * \param [in] isComputingTypes - if \c true, the set of types constituting \a this
3087 void MEDCouplingUMesh::setConnectivity(DataArrayIdType *conn, DataArrayIdType *connIndex, bool isComputingTypes)
3089 DataArrayIdType::SetArrayIn(conn,_nodal_connec);
3090 DataArrayIdType::SetArrayIn(connIndex,_nodal_connec_index);
3091 if(isComputingTypes)
3097 * Copy constructor. If 'deepCopy' is false \a this is a shallow copy of other.
3098 * If 'deeCpy' is true all arrays (coordinates and connectivities) are deeply copied.
3100 MEDCouplingUMesh::MEDCouplingUMesh(const MEDCouplingUMesh& other, bool deepCpy):MEDCouplingPointSet(other,deepCpy),_mesh_dim(other._mesh_dim),
3101 _nodal_connec(0),_nodal_connec_index(0),
3102 _types(other._types)
3104 if(other._nodal_connec)
3105 _nodal_connec=other._nodal_connec->performCopyOrIncrRef(deepCpy);
3106 if(other._nodal_connec_index)
3107 _nodal_connec_index=other._nodal_connec_index->performCopyOrIncrRef(deepCpy);
3110 MEDCouplingUMesh::~MEDCouplingUMesh()
3113 _nodal_connec->decrRef();
3114 if(_nodal_connec_index)
3115 _nodal_connec_index->decrRef();
3119 * Recomputes a set of cell types of \a this mesh. For more info see
3120 * \ref MEDCouplingUMeshNodalConnectivity.
3122 void MEDCouplingUMesh::computeTypes()
3124 ComputeAllTypesInternal(_types,_nodal_connec,_nodal_connec_index);
3129 * Returns a number of cells constituting \a this mesh.
3130 * \return mcIdType - the number of cells in \a this mesh.
3131 * \throw If the nodal connectivity of cells is not defined.
3133 mcIdType MEDCouplingUMesh::getNumberOfCells() const
3135 if(_nodal_connec_index)
3136 return _nodal_connec_index->getNumberOfTuples()-1;
3141 throw INTERP_KERNEL::Exception("Unable to get number of cells because no connectivity specified !");
3145 * Returns a dimension of \a this mesh, i.e. a dimension of cells constituting \a this
3146 * mesh. For more info see \ref meshes.
3147 * \return int - the dimension of \a this mesh.
3148 * \throw If the mesh dimension is not defined using setMeshDimension().
3150 int MEDCouplingUMesh::getMeshDimension() const
3153 throw INTERP_KERNEL::Exception("No mesh dimension specified !");
3158 * Returns a length of the nodal connectivity array.
3159 * This method is for test reason. Normally the integer returned is not useable by
3160 * user. For more info see \ref MEDCouplingUMeshNodalConnectivity.
3161 * \return mcIdType - the length of the nodal connectivity array.
3163 mcIdType MEDCouplingUMesh::getNodalConnectivityArrayLen() const
3165 return _nodal_connec->getNbOfElems();
3169 * First step of serialization process. Used by ParaMEDMEM and MEDCouplingCorba to transfert data between process.
3171 void MEDCouplingUMesh::getTinySerializationInformation(std::vector<double>& tinyInfoD, std::vector<mcIdType>& tinyInfo, std::vector<std::string>& littleStrings) const
3173 MEDCouplingPointSet::getTinySerializationInformation(tinyInfoD,tinyInfo,littleStrings);
3174 tinyInfo.push_back(ToIdType(getMeshDimension()));
3175 tinyInfo.push_back(getNumberOfCells());
3177 tinyInfo.push_back(getNodalConnectivityArrayLen());
3179 tinyInfo.push_back(-1);
3183 * First step of unserialization process.
3185 bool MEDCouplingUMesh::isEmptyMesh(const std::vector<mcIdType>& tinyInfo) const
3187 return tinyInfo[6]<=0;
3191 * Second step of serialization process.
3192 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3193 * \param a1 DataArrayDouble
3194 * \param a2 DataArrayDouble
3195 * \param littleStrings string vector
3197 void MEDCouplingUMesh::resizeForUnserialization(const std::vector<mcIdType>& tinyInfo, DataArrayIdType *a1, DataArrayDouble *a2, std::vector<std::string>& littleStrings) const
3199 MEDCouplingPointSet::resizeForUnserialization(tinyInfo,a1,a2,littleStrings);
3201 a1->alloc(tinyInfo[7]+tinyInfo[6]+1,1);
3205 * Third and final step of serialization process.
3207 void MEDCouplingUMesh::serialize(DataArrayIdType *&a1, DataArrayDouble *&a2) const
3209 MEDCouplingPointSet::serialize(a1,a2);
3210 if(getMeshDimension()>-1)
3212 a1=DataArrayIdType::New();
3213 a1->alloc(getNodalConnectivityArrayLen()+getNumberOfCells()+1,1);
3214 mcIdType *ptA1=a1->getPointer();
3215 const mcIdType *conn=getNodalConnectivity()->getConstPointer();
3216 const mcIdType *index=getNodalConnectivityIndex()->getConstPointer();
3217 ptA1=std::copy(index,index+getNumberOfCells()+1,ptA1);
3218 std::copy(conn,conn+getNodalConnectivityArrayLen(),ptA1);
3225 * Second and final unserialization process.
3226 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3228 void MEDCouplingUMesh::unserialization(const std::vector<double>& tinyInfoD, const std::vector<mcIdType>& tinyInfo, const DataArrayIdType *a1, DataArrayDouble *a2, const std::vector<std::string>& littleStrings)
3230 MEDCouplingPointSet::unserialization(tinyInfoD,tinyInfo,a1,a2,littleStrings);
3231 setMeshDimension(FromIdType<int>(tinyInfo[5]));
3235 const mcIdType *recvBuffer=a1->getConstPointer();
3236 MCAuto<DataArrayIdType> myConnecIndex=DataArrayIdType::New();
3237 myConnecIndex->alloc(tinyInfo[6]+1,1);
3238 std::copy(recvBuffer,recvBuffer+tinyInfo[6]+1,myConnecIndex->getPointer());
3239 MCAuto<DataArrayIdType> myConnec=DataArrayIdType::New();
3240 myConnec->alloc(tinyInfo[7],1);
3241 std::copy(recvBuffer+tinyInfo[6]+1,recvBuffer+tinyInfo[6]+1+tinyInfo[7],myConnec->getPointer());
3242 setConnectivity(myConnec, myConnecIndex);
3249 * Returns a new MEDCouplingFieldDouble containing volumes of cells constituting \a this
3251 * For 1D cells, the returned field contains lengths.<br>
3252 * For 2D cells, the returned field contains areas.<br>
3253 * For 3D cells, the returned field contains volumes.
3254 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3255 * orientation, i.e. the volume is always positive.
3256 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on cells
3257 * and one time . The caller is to delete this field using decrRef() as it is no
3260 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureField(bool isAbs) const
3262 std::string name="MeasureOfMesh_";
3264 mcIdType nbelem=getNumberOfCells();
3265 MCAuto<MEDCouplingFieldDouble> field=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3266 field->setName(name);
3267 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3268 array->alloc(nbelem,1);
3269 double *area_vol=array->getPointer();
3270 field->setArray(array) ; array=0;
3271 field->setMesh(const_cast<MEDCouplingUMesh *>(this));
3272 field->synchronizeTimeWithMesh();
3273 if(getMeshDimension()!=-1)
3276 INTERP_KERNEL::NormalizedCellType type;
3277 int dim_space=getSpaceDimension();
3278 const double *coords=getCoords()->getConstPointer();
3279 const mcIdType *connec=getNodalConnectivity()->getConstPointer();
3280 const mcIdType *connec_index=getNodalConnectivityIndex()->getConstPointer();
3281 for(mcIdType iel=0;iel<nbelem;iel++)
3283 ipt=connec_index[iel];
3284 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3285 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);
3288 std::transform(area_vol,area_vol+nbelem,area_vol,[](double c){return fabs(c);});
3292 area_vol[0]=std::numeric_limits<double>::max();
3294 return field.retn();
3298 * Returns a new DataArrayDouble containing volumes of specified cells of \a this
3300 * For 1D cells, the returned array contains lengths.<br>
3301 * For 2D cells, the returned array contains areas.<br>
3302 * For 3D cells, the returned array contains volumes.
3303 * This method avoids building explicitly a part of \a this mesh to perform the work.
3304 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3305 * orientation, i.e. the volume is always positive.
3306 * \param [in] begin - an array of cell ids of interest.
3307 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3308 * \return DataArrayDouble * - a new instance of DataArrayDouble. The caller is to
3309 * delete this array using decrRef() as it is no more needed.
3311 * \if ENABLE_EXAMPLES
3312 * \ref cpp_mcumesh_getPartMeasureField "Here is a C++ example".<br>
3313 * \ref py_mcumesh_getPartMeasureField "Here is a Python example".
3315 * \sa getMeasureField()
3317 DataArrayDouble *MEDCouplingUMesh::getPartMeasureField(bool isAbs, const mcIdType *begin, const mcIdType *end) const
3319 std::string name="PartMeasureOfMesh_";
3321 std::size_t nbelem=std::distance(begin,end);
3322 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3323 array->setName(name);
3324 array->alloc(nbelem,1);
3325 double *area_vol=array->getPointer();
3326 if(getMeshDimension()!=-1)
3329 INTERP_KERNEL::NormalizedCellType type;
3330 int dim_space=getSpaceDimension();
3331 const double *coords=getCoords()->getConstPointer();
3332 const mcIdType *connec=getNodalConnectivity()->getConstPointer();
3333 const mcIdType *connec_index=getNodalConnectivityIndex()->getConstPointer();
3334 for(const mcIdType *iel=begin;iel!=end;iel++)
3336 ipt=connec_index[*iel];
3337 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3338 *area_vol++=INTERP_KERNEL::computeVolSurfOfCell2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,connec+ipt+1,connec_index[*iel+1]-ipt-1,coords,dim_space);
3341 std::transform(array->getPointer(),area_vol,array->getPointer(),[](double c){return fabs(c);});
3345 area_vol[0]=std::numeric_limits<double>::max();
3347 return array.retn();
3351 * Returns a new MEDCouplingFieldDouble containing volumes of cells of a dual mesh of
3352 * \a this one. The returned field contains the dual cell volume for each corresponding
3353 * node in \a this mesh. In other words, the field returns the getMeasureField() of
3354 * the dual mesh in P1 sens of \a this.<br>
3355 * For 1D cells, the returned field contains lengths.<br>
3356 * For 2D cells, the returned field contains areas.<br>
3357 * For 3D cells, the returned field contains volumes.
3358 * This method is useful to check "P1*" conservative interpolators.
3359 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3360 * orientation, i.e. the volume is always positive.
3361 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3362 * nodes and one time. The caller is to delete this array using decrRef() as
3363 * it is no more needed.
3365 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureFieldOnNode(bool isAbs) const
3367 MCAuto<MEDCouplingFieldDouble> tmp=getMeasureField(isAbs);
3368 std::string name="MeasureOnNodeOfMesh_";
3370 mcIdType nbNodes=getNumberOfNodes();
3371 MCAuto<DataArrayDouble> nnpc;
3373 MCAuto<DataArrayIdType> tmp2(computeNbOfNodesPerCell());
3374 nnpc=tmp2->convertToDblArr();
3376 std::for_each(nnpc->rwBegin(),nnpc->rwEnd(),[](double& v) { v=1./v; });
3377 const double *nnpcPtr(nnpc->begin());
3378 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_NODES);
3379 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3380 array->alloc(nbNodes,1);
3381 double *valsToFill=array->getPointer();
3382 std::fill(valsToFill,valsToFill+nbNodes,0.);
3383 const double *values=tmp->getArray()->getConstPointer();
3384 MCAuto<DataArrayIdType> da=DataArrayIdType::New();
3385 MCAuto<DataArrayIdType> daInd=DataArrayIdType::New();
3386 getReverseNodalConnectivity(da,daInd);
3387 const mcIdType *daPtr=da->getConstPointer();
3388 const mcIdType *daIPtr=daInd->getConstPointer();
3389 for(mcIdType i=0;i<nbNodes;i++)
3390 for(const mcIdType *cell=daPtr+daIPtr[i];cell!=daPtr+daIPtr[i+1];cell++)
3391 valsToFill[i]+=nnpcPtr[*cell]*values[*cell];
3393 ret->setArray(array);
3398 * Returns a new MEDCouplingFieldDouble holding normal vectors to cells of \a this
3399 * mesh. The returned normal vectors to each cell have a norm2 equal to 1.
3400 * The computed vectors have <em> this->getMeshDimension()+1 </em> components
3401 * and are normalized.
3402 * <br> \a this can be either
3403 * - a 2D mesh in 2D or 3D space or
3404 * - an 1D mesh in 2D space.
3406 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3407 * cells and one time. The caller is to delete this field using decrRef() as
3408 * it is no more needed.
3409 * \throw If the nodal connectivity of cells is not defined.
3410 * \throw If the coordinates array is not set.
3411 * \throw If the mesh dimension is not set.
3412 * \throw If the mesh and space dimension is not as specified above.
3414 MEDCouplingFieldDouble *MEDCouplingUMesh::buildOrthogonalField() const
3416 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3417 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3418 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3419 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3420 mcIdType nbOfCells=getNumberOfCells();
3421 int nbComp=getMeshDimension()+1;
3422 array->alloc(nbOfCells,nbComp);
3423 double *vals=array->getPointer();
3424 const mcIdType *connI=_nodal_connec_index->getConstPointer();
3425 const mcIdType *conn=_nodal_connec->getConstPointer();
3426 const double *coords=_coords->getConstPointer();
3427 if(getMeshDimension()==2)
3429 if(getSpaceDimension()==3)
3431 MCAuto<DataArrayDouble> loc=computeCellCenterOfMass();
3432 const double *locPtr=loc->getConstPointer();
3433 for(mcIdType i=0;i<nbOfCells;i++,vals+=3)
3435 mcIdType offset=connI[i];
3436 INTERP_KERNEL::crossprod<3>(locPtr+3*i,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3437 double n=INTERP_KERNEL::norm<3>(vals);
3438 std::transform(vals,vals+3,vals,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3443 MCAuto<MEDCouplingFieldDouble> isAbs=getMeasureField(false);
3444 const double *isAbsPtr=isAbs->getArray()->begin();
3445 for(mcIdType i=0;i<nbOfCells;i++,isAbsPtr++)
3446 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=*isAbsPtr>0.?1.:-1.; }
3449 else//meshdimension==1
3452 for(mcIdType i=0;i<nbOfCells;i++)
3454 mcIdType offset=connI[i];
3455 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3456 double n=INTERP_KERNEL::norm<2>(tmp);
3457 std::transform(tmp,tmp+2,tmp,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3462 ret->setArray(array);
3464 ret->synchronizeTimeWithSupport();
3469 * Returns a new MEDCouplingFieldDouble holding normal vectors to specified cells of
3470 * \a this mesh. The computed vectors have <em> this->getMeshDimension()+1 </em> components
3471 * and are normalized.
3472 * <br> \a this can be either
3473 * - a 2D mesh in 2D or 3D space or
3474 * - an 1D mesh in 2D space.
3476 * This method avoids building explicitly a part of \a this mesh to perform the work.
3477 * \param [in] begin - an array of cell ids of interest.
3478 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3479 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3480 * cells and one time. The caller is to delete this field using decrRef() as
3481 * it is no more needed.
3482 * \throw If the nodal connectivity of cells is not defined.
3483 * \throw If the coordinates array is not set.
3484 * \throw If the mesh dimension is not set.
3485 * \throw If the mesh and space dimension is not as specified above.
3486 * \sa buildOrthogonalField()
3488 * \if ENABLE_EXAMPLES
3489 * \ref cpp_mcumesh_buildPartOrthogonalField "Here is a C++ example".<br>
3490 * \ref py_mcumesh_buildPartOrthogonalField "Here is a Python example".
3493 MEDCouplingFieldDouble *MEDCouplingUMesh::buildPartOrthogonalField(const mcIdType *begin, const mcIdType *end) const
3495 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3496 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3497 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3498 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3499 std::size_t nbelems=std::distance(begin,end);
3500 int nbComp=getMeshDimension()+1;
3501 array->alloc(nbelems,nbComp);
3502 double *vals=array->getPointer();
3503 const mcIdType *connI=_nodal_connec_index->getConstPointer();
3504 const mcIdType *conn=_nodal_connec->getConstPointer();
3505 const double *coords=_coords->getConstPointer();
3506 if(getMeshDimension()==2)
3508 if(getSpaceDimension()==3)
3510 MCAuto<DataArrayDouble> loc=getPartBarycenterAndOwner(begin,end);
3511 const double *locPtr=loc->getConstPointer();
3512 for(const mcIdType *i=begin;i!=end;i++,vals+=3,locPtr+=3)
3514 mcIdType offset=connI[*i];
3515 INTERP_KERNEL::crossprod<3>(locPtr,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3516 double n=INTERP_KERNEL::norm<3>(vals);
3517 std::transform(vals,vals+3,vals,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3522 for(std::size_t i=0;i<nbelems;i++)
3523 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=1.; }
3526 else//meshdimension==1
3529 for(const mcIdType *i=begin;i!=end;i++)
3531 mcIdType offset=connI[*i];
3532 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3533 double n=INTERP_KERNEL::norm<2>(tmp);
3534 std::transform(tmp,tmp+2,tmp,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3539 ret->setArray(array);
3541 ret->synchronizeTimeWithSupport();
3546 * Returns a new MEDCouplingFieldDouble holding a direction vector for each SEG2 in \a
3547 * this 1D mesh. The computed vectors have <em> this->getSpaceDimension() </em> components
3548 * and are \b not normalized.
3549 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3550 * cells and one time. The caller is to delete this field using decrRef() as
3551 * it is no more needed.
3552 * \throw If the nodal connectivity of cells is not defined.
3553 * \throw If the coordinates array is not set.
3554 * \throw If \a this->getMeshDimension() != 1.
3555 * \throw If \a this mesh includes cells of type other than SEG2.
3557 MEDCouplingFieldDouble *MEDCouplingUMesh::buildDirectionVectorField() const
3559 if(getMeshDimension()!=1)
3560 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for buildDirectionVectorField !");
3561 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3562 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for buildDirectionVectorField !");
3563 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3564 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3565 mcIdType nbOfCells=getNumberOfCells();
3566 int spaceDim=getSpaceDimension();
3567 array->alloc(nbOfCells,spaceDim);
3568 double *pt=array->getPointer();
3569 const double *coo=getCoords()->getConstPointer();
3570 std::vector<mcIdType> conn;
3572 for(mcIdType i=0;i<nbOfCells;i++)
3575 getNodeIdsOfCell(i,conn);
3576 pt=std::transform(coo+conn[1]*spaceDim,coo+(conn[1]+1)*spaceDim,coo+conn[0]*spaceDim,pt,std::minus<double>());
3578 ret->setArray(array);
3580 ret->synchronizeTimeWithSupport();
3585 * Creates a 2D mesh by cutting \a this 3D mesh with a plane. In addition to the mesh,
3586 * returns a new DataArrayIdType, of length equal to the number of 2D cells in the result
3587 * mesh, holding, for each cell in the result mesh, an id of a 3D cell it comes
3588 * from. If a result face is shared by two 3D cells, then the face in included twice in
3590 * \param [in] origin - 3 components of a point defining location of the plane.
3591 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3592 * must be greater than 1e-6.
3593 * \param [in] eps - half-thickness of the plane.
3594 * \param [out] cellIds - a new instance of DataArrayIdType holding ids of 3D cells
3595 * producing correspondent 2D cells. The caller is to delete this array
3596 * using decrRef() as it is no more needed.
3597 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This mesh does
3598 * not share the node coordinates array with \a this mesh. The caller is to
3599 * delete this mesh using decrRef() as it is no more needed.
3600 * \throw If the coordinates array is not set.
3601 * \throw If the nodal connectivity of cells is not defined.
3602 * \throw If \a this->getMeshDimension() != 3 or \a this->getSpaceDimension() != 3.
3603 * \throw If magnitude of \a vec is less than 1e-6.
3604 * \throw If the plane does not intersect any 3D cell of \a this mesh.
3605 * \throw If \a this includes quadratic cells.
3607 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3D(const double *origin, const double *vec, double eps, DataArrayIdType *&cellIds) const
3609 checkFullyDefined();
3610 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3611 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3612 MCAuto<DataArrayIdType> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3613 if(candidates->empty())
3614 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane considering bounding boxes !");
3615 std::vector<mcIdType> nodes;
3616 DataArrayIdType *cellIds1D=0;
3617 MCAuto<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3618 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3619 MCAuto<DataArrayIdType> desc1=DataArrayIdType::New(),desc2=DataArrayIdType::New();
3620 MCAuto<DataArrayIdType> descIndx1=DataArrayIdType::New(),descIndx2=DataArrayIdType::New();
3621 MCAuto<DataArrayIdType> revDesc1=DataArrayIdType::New(),revDesc2=DataArrayIdType::New();
3622 MCAuto<DataArrayIdType> revDescIndx1=DataArrayIdType::New(),revDescIndx2=DataArrayIdType::New();
3623 MCAuto<MEDCouplingUMesh> mDesc2=subMesh->buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2);//meshDim==2 spaceDim==3
3624 revDesc2=0; revDescIndx2=0;
3625 MCAuto<MEDCouplingUMesh> mDesc1=mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3626 revDesc1=0; revDescIndx1=0;
3627 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3628 MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3630 std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3631 for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3633 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3634 std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(mDesc2->getNumberOfCells());
3635 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->getConstPointer(),mDesc2->getNodalConnectivityIndex()->getConstPointer(),
3636 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3637 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3638 MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New()),cellIds2(DataArrayIdType::New());
3639 connI->pushBackSilent(0); conn->alloc(0,1); cellIds2->alloc(0,1);
3640 subMesh->assemblyForSplitFrom3DSurf(cut3DSurf,desc2->getConstPointer(),descIndx2->getConstPointer(),conn,connI,cellIds2);
3641 if(cellIds2->empty())
3642 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3643 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3D",2);
3644 ret->setCoords(mDesc1->getCoords());
3645 ret->setConnectivity(conn,connI,true);
3646 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3651 * Creates an 1D mesh by cutting \a this 2D mesh in 3D space with a plane. In
3652 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
3653 from. If a result segment is shared by two 2D cells, then the segment in included twice in
3655 * \param [in] origin - 3 components of a point defining location of the plane.
3656 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3657 * must be greater than 1e-6.
3658 * \param [in] eps - half-thickness of the plane.
3659 * \param [out] cellIds - a new instance of DataArrayIdType holding ids of faces
3660 * producing correspondent segments. The caller is to delete this array
3661 * using decrRef() as it is no more needed.
3662 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This is an 1D
3663 * mesh in 3D space. This mesh does not share the node coordinates array with
3664 * \a this mesh. The caller is to delete this mesh using decrRef() as it is
3666 * \throw If the coordinates array is not set.
3667 * \throw If the nodal connectivity of cells is not defined.
3668 * \throw If \a this->getMeshDimension() != 2 or \a this->getSpaceDimension() != 3.
3669 * \throw If magnitude of \a vec is less than 1e-6.
3670 * \throw If the plane does not intersect any 2D cell of \a this mesh.
3671 * \throw If \a this includes quadratic cells.
3673 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3DSurf(const double *origin, const double *vec, double eps, DataArrayIdType *&cellIds) const
3675 checkFullyDefined();
3676 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
3677 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf works on umeshes with meshdim equal to 2 and spaceDim equal to 3 !");
3678 MCAuto<DataArrayIdType> candidates(getCellIdsCrossingPlane(origin,vec,eps));
3679 if(candidates->empty())
3680 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3D surf cells in this intercepts the specified plane considering bounding boxes !");
3681 std::vector<mcIdType> nodes;
3682 DataArrayIdType *cellIds1D(0);
3683 MCAuto<MEDCouplingUMesh> subMesh(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3684 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3685 MCAuto<DataArrayIdType> desc1(DataArrayIdType::New()),descIndx1(DataArrayIdType::New()),revDesc1(DataArrayIdType::New()),revDescIndx1(DataArrayIdType::New());
3686 MCAuto<MEDCouplingUMesh> mDesc1(subMesh->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3687 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3688 MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3690 std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3691 for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3693 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3694 mcIdType ncellsSub=subMesh->getNumberOfCells();
3695 std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(ncellsSub);
3696 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,subMesh->getNodalConnectivity()->getConstPointer(),subMesh->getNodalConnectivityIndex()->getConstPointer(),
3697 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3698 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3699 MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New()),cellIds2(DataArrayIdType::New()); connI->pushBackSilent(0);
3701 const mcIdType *nodal=subMesh->getNodalConnectivity()->getConstPointer();
3702 const mcIdType *nodalI=subMesh->getNodalConnectivityIndex()->getConstPointer();
3703 for(mcIdType i=0;i<ncellsSub;i++)
3705 if(cut3DSurf[i].first!=-1 && cut3DSurf[i].second!=-1)
3707 if(cut3DSurf[i].first!=-2)
3709 conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_SEG2)); conn->pushBackSilent(cut3DSurf[i].first); conn->pushBackSilent(cut3DSurf[i].second);
3710 connI->pushBackSilent(conn->getNumberOfTuples());
3711 cellIds2->pushBackSilent(i);
3715 mcIdType cellId3DSurf=cut3DSurf[i].second;
3716 mcIdType offset=nodalI[cellId3DSurf]+1;
3717 mcIdType nbOfEdges=nodalI[cellId3DSurf+1]-offset;
3718 for(mcIdType j=0;j<nbOfEdges;j++)
3720 conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_SEG2)); conn->pushBackSilent(nodal[offset+j]); conn->pushBackSilent(nodal[offset+(j+1)%nbOfEdges]);
3721 connI->pushBackSilent(conn->getNumberOfTuples());
3722 cellIds2->pushBackSilent(cellId3DSurf);
3727 if(cellIds2->empty())
3728 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3DSurf cells in this intercepts the specified plane !");
3729 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3DSurf",1);
3730 ret->setCoords(mDesc1->getCoords());
3731 ret->setConnectivity(conn,connI,true);
3732 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3736 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::clipSingle3DCellByPlane(const double origin[3], const double vec[3], double eps) const
3738 checkFullyDefined();
3739 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3740 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3741 if(getNumberOfCells()!=1)
3742 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works only on mesh containing exactly one cell !");
3744 std::vector<mcIdType> nodes;
3745 findNodesOnPlane(origin,vec,eps,nodes);
3746 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());
3747 MCAuto<MEDCouplingUMesh> mDesc2(buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2));//meshDim==2 spaceDim==3
3748 revDesc2=0; revDescIndx2=0;
3749 MCAuto<MEDCouplingUMesh> mDesc1(mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3750 revDesc1=0; revDescIndx1=0;
3751 DataArrayIdType *cellIds1D(0);
3752 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3753 MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3754 std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3755 for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3759 mcIdType oldNbNodes(mDesc1->getNumberOfNodes());
3760 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3761 sameNbNodes=(mDesc1->getNumberOfNodes()==oldNbNodes);
3763 std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(mDesc2->getNumberOfCells());
3764 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->begin(),mDesc2->getNodalConnectivityIndex()->begin(),
3765 mDesc1->getNodalConnectivity()->begin(),mDesc1->getNodalConnectivityIndex()->begin(),
3766 desc1->begin(),descIndx1->begin(),cut3DSurf);
3767 MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New());
3768 connI->pushBackSilent(0); conn->alloc(0,1);
3770 MCAuto<DataArrayIdType> cellIds2(DataArrayIdType::New()); cellIds2->alloc(0,1);
3771 assemblyForSplitFrom3DSurf(cut3DSurf,desc2->begin(),descIndx2->begin(),conn,connI,cellIds2);
3772 if(cellIds2->empty())
3773 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3775 std::vector<std::vector<mcIdType> > res;
3776 buildSubCellsFromCut(cut3DSurf,desc2->begin(),descIndx2->begin(),mDesc1->getCoords()->begin(),eps,res);
3777 std::size_t sz(res.size());
3778 if(ToIdType(res.size())==mDesc1->getNumberOfCells() && sameNbNodes)
3779 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane : cell is not clipped !");
3780 for(std::size_t i=0;i<sz;i++)
3782 conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYGON));
3783 conn->insertAtTheEnd(res[i].begin(),res[i].end());
3784 connI->pushBackSilent(conn->getNumberOfTuples());
3786 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
3787 ret->setCoords(mDesc1->getCoords());
3788 ret->setConnectivity(conn,connI,true);
3789 mcIdType nbCellsRet(ret->getNumberOfCells());
3791 MCAuto<DataArrayDouble> vec2(DataArrayDouble::New()); vec2->alloc(1,3); std::copy(vec,vec+3,vec2->getPointer());
3792 MCAuto<MEDCouplingFieldDouble> ortho(ret->buildOrthogonalField());
3793 MCAuto<DataArrayDouble> ortho2(ortho->getArray()->selectByTupleIdSafeSlice(0,1,1));
3794 MCAuto<DataArrayDouble> dott(DataArrayDouble::Dot(ortho2,vec2));
3795 MCAuto<DataArrayDouble> ccm(ret->computeCellCenterOfMass());
3796 MCAuto<DataArrayDouble> occm;
3798 MCAuto<DataArrayDouble> pt(DataArrayDouble::New()); pt->alloc(1,3); std::copy(origin,origin+3,pt->getPointer());
3799 occm=DataArrayDouble::Substract(ccm,pt);
3801 vec2=DataArrayDouble::New(); vec2->alloc(nbCellsRet,3);
3802 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);
3803 MCAuto<DataArrayDouble> dott2(DataArrayDouble::Dot(occm,vec2));
3805 const mcIdType *cPtr(ret->getNodalConnectivity()->begin()),*ciPtr(ret->getNodalConnectivityIndex()->begin());
3806 MCAuto<MEDCouplingUMesh> ret2(MEDCouplingUMesh::New("Clip3D",3));
3807 ret2->setCoords(mDesc1->getCoords());
3808 MCAuto<DataArrayIdType> conn2(DataArrayIdType::New()),conn2I(DataArrayIdType::New());
3809 conn2I->pushBackSilent(0); conn2->alloc(0,1);
3810 std::vector<mcIdType> cell0(1,ToIdType(INTERP_KERNEL::NORM_POLYHED));
3811 std::vector<mcIdType> cell1(1,ToIdType(INTERP_KERNEL::NORM_POLYHED));
3812 if(dott->getIJ(0,0)>0)
3814 cell0.insert(cell0.end(),cPtr+1,cPtr+ciPtr[1]);
3815 std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell1,cell1.end()));
3819 cell1.insert(cell1.end(),cPtr+1,cPtr+ciPtr[1]);
3820 std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell0,cell0.end()));
3822 for(mcIdType i=1;i<nbCellsRet;i++)
3824 if(dott2->getIJ(i,0)<0)
3826 if(ciPtr[i+1]-ciPtr[i]>=4)
3828 cell0.push_back(-1);
3829 cell0.insert(cell0.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
3834 if(ciPtr[i+1]-ciPtr[i]>=4)
3836 cell1.push_back(-1);
3837 cell1.insert(cell1.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
3841 conn2->insertAtTheEnd(cell0.begin(),cell0.end());
3842 conn2I->pushBackSilent(conn2->getNumberOfTuples());
3843 conn2->insertAtTheEnd(cell1.begin(),cell1.end());
3844 conn2I->pushBackSilent(conn2->getNumberOfTuples());
3845 ret2->setConnectivity(conn2,conn2I,true);
3846 ret2->checkConsistencyLight();
3847 ret2->orientCorrectlyPolyhedrons();
3852 * Finds cells whose bounding boxes intersect a given plane.
3853 * \param [in] origin - 3 components of a point defining location of the plane.
3854 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3855 * must be greater than 1e-6.
3856 * \param [in] eps - half-thickness of the plane.
3857 * \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of the found
3858 * cells. The caller is to delete this array using decrRef() as it is no more
3860 * \throw If the coordinates array is not set.
3861 * \throw If the nodal connectivity of cells is not defined.
3862 * \throw If \a this->getSpaceDimension() != 3.
3863 * \throw If magnitude of \a vec is less than 1e-6.
3864 * \sa buildSlice3D()
3866 DataArrayIdType *MEDCouplingUMesh::getCellIdsCrossingPlane(const double *origin, const double *vec, double eps) const
3868 checkFullyDefined();
3869 if(getSpaceDimension()!=3)
3870 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with spaceDim equal to 3 !");
3871 double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
3873 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellIdsCrossingPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
3875 vec2[0]=vec[1]; vec2[1]=-vec[0]; vec2[2]=0.;//vec2 is the result of cross product of vec with (0,0,1)
3876 double angle=acos(vec[2]/normm);
3877 MCAuto<DataArrayIdType> cellIds;
3881 MCAuto<DataArrayDouble> coo=_coords->deepCopy();
3882 double normm2(sqrt(vec2[0]*vec2[0]+vec2[1]*vec2[1]+vec2[2]*vec2[2]));
3883 if(normm2/normm>1e-6)
3884 DataArrayDouble::Rotate3DAlg(origin,vec2,angle,coo->getNumberOfTuples(),coo->getPointer(),coo->getPointer());
3885 MCAuto<MEDCouplingUMesh> mw=clone(false);//false -> shallow copy
3887 mw->getBoundingBox(bbox);
3888 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3889 cellIds=mw->getCellsInBoundingBox(bbox,eps);
3893 getBoundingBox(bbox);
3894 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3895 cellIds=getCellsInBoundingBox(bbox,eps);
3897 return cellIds.retn();
3901 * This method checks that \a this is a contiguous mesh. The user is expected to call this method on a mesh with meshdim==1.
3902 * If not an exception will thrown. If this is an empty mesh with no cell an exception will be thrown too.
3903 * No consideration of coordinate is done by this method.
3904 * 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)
3905 * If not false is returned. In case that false is returned a call to MEDCoupling::MEDCouplingUMesh::mergeNodes could be useful.
3907 bool MEDCouplingUMesh::isContiguous1D() const
3909 if(getMeshDimension()!=1)
3910 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense only for 1D mesh !");
3911 mcIdType nbCells=getNumberOfCells();
3913 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense for non empty mesh !");
3914 const mcIdType *connI(_nodal_connec_index->begin()),*conn(_nodal_connec->begin());
3915 mcIdType ref=conn[connI[0]+2];
3916 for(mcIdType i=1;i<nbCells;i++)
3918 if(conn[connI[i]+1]!=ref)
3920 ref=conn[connI[i]+2];
3926 * This method is only callable on mesh with meshdim == 1 containing only SEG2 and spaceDim==3.
3927 * This method projects this on the 3D line defined by (pt,v). This methods first checks that all SEG2 are along v vector.
3928 * \param pt reference point of the line
3929 * \param v normalized director vector of the line
3930 * \param eps max precision before throwing an exception
3931 * \param res output of size this->getNumberOfCells
3933 void MEDCouplingUMesh::project1D(const double *pt, const double *v, double eps, double *res) const
3935 if(getMeshDimension()!=1)
3936 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for project1D !");
3937 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3938 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for project1D !");
3939 if(getSpaceDimension()!=3)
3940 throw INTERP_KERNEL::Exception("Expected a umesh with spaceDim==3 for project1D !");
3941 MCAuto<MEDCouplingFieldDouble> f=buildDirectionVectorField();
3942 const double *fPtr=f->getArray()->getConstPointer();
3944 for(mcIdType i=0;i<getNumberOfCells();i++)
3946 const double *tmp1=fPtr+3*i;
3947 tmp[0]=tmp1[1]*v[2]-tmp1[2]*v[1];
3948 tmp[1]=tmp1[2]*v[0]-tmp1[0]*v[2];
3949 tmp[2]=tmp1[0]*v[1]-tmp1[1]*v[0];
3950 double n1=INTERP_KERNEL::norm<3>(tmp);
3951 n1/=INTERP_KERNEL::norm<3>(tmp1);
3953 throw INTERP_KERNEL::Exception("UMesh::Projection 1D failed !");
3955 const double *coo=getCoords()->getConstPointer();
3956 for(mcIdType i=0;i<getNumberOfNodes();i++)
3958 std::transform(coo+i*3,coo+i*3+3,pt,tmp,std::minus<double>());
3959 std::transform(tmp,tmp+3,v,tmp,std::multiplies<double>());
3960 res[i]=std::accumulate(tmp,tmp+3,0.);
3965 * 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.
3966 * \a this is expected to be a mesh so that its space dimension is equal to its
3967 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
3968 * 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).
3970 * 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
3971 * 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).
3972 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
3974 * So this method is more accurate (so, more costly) than simply searching for the closest point in \a this.
3975 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
3977 * \param [in] ptBg the start pointer (included) of the coordinates of the point
3978 * \param [in] ptEnd the end pointer (not included) of the coordinates of the point
3979 * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
3980 * \return the positive value of the distance.
3981 * \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
3983 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoints
3985 double MEDCouplingUMesh::distanceToPoint(const double *ptBg, const double *ptEnd, mcIdType& cellId) const
3987 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
3988 if(meshDim!=spaceDim-1)
3989 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint works only for spaceDim=meshDim+1 !");
3990 if(meshDim!=2 && meshDim!=1)
3991 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint : only mesh dimension 2 and 1 are implemented !");
3992 checkFullyDefined();
3993 if(ToIdType(std::distance(ptBg,ptEnd))!=spaceDim)
3994 { 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()); }
3995 DataArrayIdType *ret1=0;
3996 MCAuto<DataArrayDouble> pts=DataArrayDouble::New(); pts->useArray(ptBg,false,DeallocType::C_DEALLOC,1,spaceDim);
3997 MCAuto<DataArrayDouble> ret0=distanceToPoints(pts,ret1);
3998 MCAuto<DataArrayIdType> ret1Safe(ret1);
3999 cellId=*ret1Safe->begin();
4000 return *ret0->begin();
4004 * This method computes the distance from each point of points serie \a pts (stored in a DataArrayDouble in which each tuple represents a point)
4005 * to \a this and the first \a cellId in \a this corresponding to the returned distance.
4006 * 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
4007 * 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).
4008 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4010 * \a this is expected to be a mesh so that its space dimension is equal to its
4011 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4012 * 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).
4014 * So this method is more accurate (so, more costly) than simply searching for each point in \a pts the closest point in \a this.
4015 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4017 * \param [in] pts the list of points in which each tuple represents a point
4018 * \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.
4019 * \return a newly allocated object to be dealed by the caller that tells for each point in \a pts the distance to \a this.
4020 * \throw if number of components of \a pts is not equal to the space dimension.
4021 * \throw if mesh dimension of \a this is not equal to space dimension - 1.
4022 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoint
4024 DataArrayDouble *MEDCouplingUMesh::distanceToPoints(const DataArrayDouble *pts, DataArrayIdType *& cellIds) const
4027 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : input points pointer is NULL !");
4028 pts->checkAllocated();
4029 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4030 if(meshDim!=spaceDim-1)
4031 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints works only for spaceDim=meshDim+1 !");
4032 if(meshDim!=2 && meshDim!=1)
4033 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only mesh dimension 2 and 1 are implemented !");
4034 if(ToIdType(pts->getNumberOfComponents())!=spaceDim)
4036 std::ostringstream oss; oss << "MEDCouplingUMesh::distanceToPoints : input pts DataArrayDouble has " << pts->getNumberOfComponents() << " components whereas it should be equal to " << spaceDim << " (mesh spaceDimension) !";
4037 throw INTERP_KERNEL::Exception(oss.str());
4039 checkFullyDefined();
4040 mcIdType nbCells=getNumberOfCells();
4042 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : no cells in this !");
4043 mcIdType nbOfPts=pts->getNumberOfTuples();
4044 MCAuto<DataArrayDouble> ret0=DataArrayDouble::New(); ret0->alloc(nbOfPts,1);
4045 MCAuto<DataArrayIdType> ret1=DataArrayIdType::New(); ret1->alloc(nbOfPts,1);
4046 const mcIdType *nc=_nodal_connec->begin(),*ncI=_nodal_connec_index->begin(); const double *coords=_coords->begin();
4047 double *ret0Ptr=ret0->getPointer(); mcIdType *ret1Ptr=ret1->getPointer(); const double *ptsPtr=pts->begin();
4048 MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree());
4049 const double *bbox(bboxArr->begin());
4054 BBTreeDst<3> myTree(bbox,0,0,nbCells);
4055 for(mcIdType i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=3)
4057 double x=std::numeric_limits<double>::max();
4058 std::vector<mcIdType> elems;
4059 myTree.getMinDistanceOfMax(ptsPtr,x);
4060 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4061 DistanceToPoint3DSurfAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4067 BBTreeDst<2> myTree(bbox,0,0,nbCells);
4068 for(mcIdType i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=2)
4070 double x=std::numeric_limits<double>::max();
4071 std::vector<mcIdType> elems;
4072 myTree.getMinDistanceOfMax(ptsPtr,x);
4073 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4074 DistanceToPoint2DCurveAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4079 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only spacedim 2 and 3 supported !");
4081 cellIds=ret1.retn();
4090 * Finds cells in contact with a ball (i.e. a point with precision).
4091 * 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.
4092 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4094 * \warning This method is suitable if the caller intends to evaluate only one
4095 * point, for more points getCellsContainingPoints() is recommended as it is
4097 * \param [in] pos - array of coordinates of the ball central point.
4098 * \param [in] eps - ball radius.
4099 * \return mcIdType - a smallest id of cells being in contact with the ball, -1 in case
4100 * if there are no such cells.
4101 * \throw If the coordinates array is not set.
4102 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4104 mcIdType MEDCouplingUMesh::getCellContainingPoint(const double *pos, double eps) const
4106 std::vector<mcIdType> elts;
4107 getCellsContainingPoint(pos,eps,elts);
4110 return elts.front();
4114 * Finds cells in contact with a ball (i.e. a point with precision).
4115 * 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.
4116 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4117 * \warning This method is suitable if the caller intends to evaluate only one
4118 * point, for more points getCellsContainingPoints() is recommended as it is
4120 * \param [in] pos - array of coordinates of the ball central point.
4121 * \param [in] eps - ball radius.
4122 * \param [out] elts - vector returning ids of the found cells. It is cleared
4123 * before inserting ids.
4124 * \throw If the coordinates array is not set.
4125 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4127 * \if ENABLE_EXAMPLES
4128 * \ref cpp_mcumesh_getCellsContainingPoint "Here is a C++ example".<br>
4129 * \ref py_mcumesh_getCellsContainingPoint "Here is a Python example".
4132 void MEDCouplingUMesh::getCellsContainingPoint(const double *pos, double eps, std::vector<mcIdType>& elts) const
4134 MCAuto<DataArrayIdType> eltsUg,eltsIndexUg;
4135 getCellsContainingPoints(pos,1,eps,eltsUg,eltsIndexUg);
4136 elts.clear(); elts.insert(elts.end(),eltsUg->begin(),eltsUg->end());
4139 void MEDCouplingUMesh::getCellsContainingPointsZeAlg(const double *pos, mcIdType nbOfPoints, double eps,
4140 MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex,
4141 std::function<bool(INTERP_KERNEL::NormalizedCellType,mcIdType)> sensibilityTo2DQuadraticLinearCellsFunc) const
4143 int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
4148 const double *coords=_coords->getConstPointer();
4149 getCellsContainingPointsAlg<3>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4152 throw INTERP_KERNEL::Exception("For spaceDim==3 only meshDim==3 implemented for getelementscontainingpoints !");
4154 else if(spaceDim==2)
4158 const double *coords=_coords->getConstPointer();
4159 getCellsContainingPointsAlg<2>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4162 throw INTERP_KERNEL::Exception("For spaceDim==2 only meshDim==2 implemented for getelementscontainingpoints !");
4164 else if(spaceDim==1)
4168 const double *coords=_coords->getConstPointer();
4169 getCellsContainingPointsAlg<1>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4172 throw INTERP_KERNEL::Exception("For spaceDim==1 only meshDim==1 implemented for getelementscontainingpoints !");
4175 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPoints : not managed for mdim not in [1,2,3] !");
4179 * Finds cells in contact with several balls (i.e. points with precision).
4180 * This method is an extension of getCellContainingPoint() and
4181 * getCellsContainingPoint() for the case of multiple points.
4182 * 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.
4183 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4184 * \param [in] pos - an array of coordinates of points in full interlace mode :
4185 * X0,Y0,Z0,X1,Y1,Z1,... Size of the array must be \a
4186 * this->getSpaceDimension() * \a nbOfPoints
4187 * \param [in] nbOfPoints - number of points to locate within \a this mesh.
4188 * \param [in] eps - radius of balls (i.e. the precision).
4189 * \param [out] elts - vector returning ids of found cells.
4190 * \param [out] eltsIndex - an array, of length \a nbOfPoints + 1,
4191 * dividing cell ids in \a elts into groups each referring to one
4192 * point. Its every element (except the last one) is an index pointing to the
4193 * first id of a group of cells. For example cells in contact with the *i*-th
4194 * point are described by following range of indices:
4195 * [ \a eltsIndex[ *i* ], \a eltsIndex[ *i*+1 ] ) and the cell ids are
4196 * \a elts[ \a eltsIndex[ *i* ]], \a elts[ \a eltsIndex[ *i* ] + 1 ], ...
4197 * Number of cells in contact with the *i*-th point is
4198 * \a eltsIndex[ *i*+1 ] - \a eltsIndex[ *i* ].
4199 * \throw If the coordinates array is not set.
4200 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4202 * \if ENABLE_EXAMPLES
4203 * \ref cpp_mcumesh_getCellsContainingPoints "Here is a C++ example".<br>
4204 * \ref py_mcumesh_getCellsContainingPoints "Here is a Python example".
4207 void MEDCouplingUMesh::getCellsContainingPoints(const double *pos, mcIdType nbOfPoints, double eps,
4208 MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex) const
4210 auto yesImSensibleTo2DQuadraticLinearCellsFunc([](INTERP_KERNEL::NormalizedCellType ct, int mdim) { return INTERP_KERNEL::CellModel::GetCellModel(ct).isQuadratic() && mdim == 2; } );
4211 this->getCellsContainingPointsZeAlg(pos,nbOfPoints,eps,elts,eltsIndex,yesImSensibleTo2DQuadraticLinearCellsFunc);
4215 * Behaves like MEDCouplingMesh::getCellsContainingPoints for cells in \a this that are linear.
4216 * For quadratic cells in \a this, this method behaves by just considering linear part of cells.
4217 * This method is here only for backward compatibility (interpolation GaussPoints to GaussPoints).
4219 * \sa MEDCouplingUMesh::getCellsContainingPoints, MEDCouplingRemapper::prepareNotInterpKernelOnlyGaussGauss
4221 void MEDCouplingUMesh::getCellsContainingPointsLinearPartOnlyOnNonDynType(const double *pos, mcIdType nbOfPoints, double eps, MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex) const
4223 auto noImNotSensibleTo2DQuadraticLinearCellsFunc([](INTERP_KERNEL::NormalizedCellType,mcIdType) { return false; } );
4224 this->getCellsContainingPointsZeAlg(pos,nbOfPoints,eps,elts,eltsIndex,noImNotSensibleTo2DQuadraticLinearCellsFunc);
4228 * Finds butterfly cells in \a this mesh. A 2D cell is considered to be butterfly if at
4229 * least two its edges intersect each other anywhere except their extremities. An
4230 * INTERP_KERNEL::NORM_NORI3 cell can \b not be butterfly.
4231 * \param [in,out] cells - a vector returning ids of the found cells. It is not
4232 * cleared before filling in.
4233 * \param [in] eps - precision.
4234 * \throw If \a this->getMeshDimension() != 2.
4235 * \throw If \a this->getSpaceDimension() != 2 && \a this->getSpaceDimension() != 3.
4237 void MEDCouplingUMesh::checkButterflyCells(std::vector<mcIdType>& cells, double eps) const
4239 const char msg[]="Butterfly detection work only for 2D cells with spaceDim==2 or 3!";
4240 if(getMeshDimension()!=2)
4241 throw INTERP_KERNEL::Exception(msg);
4242 int spaceDim=getSpaceDimension();
4243 if(spaceDim!=2 && spaceDim!=3)
4244 throw INTERP_KERNEL::Exception(msg);
4245 const mcIdType *conn=_nodal_connec->getConstPointer();
4246 const mcIdType *connI=_nodal_connec_index->getConstPointer();
4247 mcIdType nbOfCells=getNumberOfCells();
4248 std::vector<double> cell2DinS2;
4249 for(mcIdType i=0;i<nbOfCells;i++)
4251 mcIdType offset=connI[i];
4252 mcIdType nbOfNodesForCell=connI[i+1]-offset-1;
4253 if(nbOfNodesForCell<=3)
4255 bool isQuad=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[offset]).isQuadratic();
4256 project2DCellOnXY(conn+offset+1,conn+connI[i+1],cell2DinS2);
4257 if(isButterfly2DCell(cell2DinS2,isQuad,eps))
4264 * This method is typically requested to unbutterfly 2D linear cells in \b this.
4266 * 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.
4267 * 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.
4269 * For each 2D linear cell in \b this, this method builds the convex envelop (or the convex hull) of the current cell.
4270 * This convex envelop is computed using Jarvis march algorithm.
4271 * The coordinates and the number of cells of \b this remain unchanged on invocation of this method.
4272 * 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)
4273 * 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.
4275 * \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.
4276 * \sa MEDCouplingUMesh::colinearize2D
4278 DataArrayIdType *MEDCouplingUMesh::convexEnvelop2D()
4280 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
4281 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convexEnvelop2D works only for meshDim=2 and spaceDim=2 !");
4282 checkFullyDefined();
4283 const double *coords=getCoords()->getConstPointer();
4284 mcIdType nbOfCells=getNumberOfCells();
4285 MCAuto<DataArrayIdType> nodalConnecIndexOut=DataArrayIdType::New();
4286 nodalConnecIndexOut->alloc(nbOfCells+1,1);
4287 MCAuto<DataArrayIdType> nodalConnecOut(DataArrayIdType::New());
4288 mcIdType *workIndexOut=nodalConnecIndexOut->getPointer();
4290 const mcIdType *nodalConnecIn=_nodal_connec->getConstPointer();
4291 const mcIdType *nodalConnecIndexIn=_nodal_connec_index->getConstPointer();
4292 std::set<INTERP_KERNEL::NormalizedCellType> types;
4293 MCAuto<DataArrayIdType> isChanged(DataArrayIdType::New());
4294 isChanged->alloc(0,1);
4295 for(mcIdType i=0;i<nbOfCells;i++,workIndexOut++)
4297 mcIdType pos=nodalConnecOut->getNumberOfTuples();
4298 if(BuildConvexEnvelopOf2DCellJarvis(coords,nodalConnecIn+nodalConnecIndexIn[i],nodalConnecIn+nodalConnecIndexIn[i+1],nodalConnecOut))
4299 isChanged->pushBackSilent(i);
4300 types.insert((INTERP_KERNEL::NormalizedCellType)nodalConnecOut->getIJ(pos,0));
4301 workIndexOut[1]=nodalConnecOut->getNumberOfTuples();
4303 if(isChanged->empty())
4305 setConnectivity(nodalConnecOut,nodalConnecIndexOut,false);
4307 return isChanged.retn();
4311 * This method is \b NOT const because it can modify \a this.
4312 * \a this is expected to be an unstructured mesh with meshDim==2 and spaceDim==3. If not an exception will be thrown.
4313 * \param mesh1D is an unstructured mesh with MeshDim==1 and spaceDim==3. If not an exception will be thrown.
4314 * \param policy specifies the type of extrusion chosen:
4315 * - \b 0 for translation only (most simple): the cells of the 1D mesh represent the vectors along which the 2D mesh
4316 * will be repeated to build each level
4317 * - \b 1 for translation and rotation: the translation is done as above. For each level, an arc of circle is fitted on
4318 * 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
4319 * 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
4321 * \return an unstructured mesh with meshDim==3 and spaceDim==3. The returned mesh has the same coords than \a this.
4323 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMesh(const MEDCouplingUMesh *mesh1D, int policy)
4325 checkFullyDefined();
4326 mesh1D->checkFullyDefined();
4327 if(!mesh1D->isContiguous1D())
4328 throw INTERP_KERNEL::Exception("buildExtrudedMesh : 1D mesh passed in parameter is not contiguous !");
4329 if(getSpaceDimension()!=mesh1D->getSpaceDimension())
4330 throw INTERP_KERNEL::Exception("Invalid call to buildExtrudedMesh this and mesh1D must have same space dimension !");
4331 if((getMeshDimension()!=2 || getSpaceDimension()!=3) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
4332 throw INTERP_KERNEL::Exception("Invalid 'this' for buildExtrudedMesh method : must be (meshDim==2 and spaceDim==3) or (meshDim==1 and spaceDim==2) !");
4333 if(mesh1D->getMeshDimension()!=1)
4334 throw INTERP_KERNEL::Exception("Invalid 'mesh1D' for buildExtrudedMesh method : must be meshDim==1 !");
4336 if(isPresenceOfQuadratic())
4338 if(mesh1D->isFullyQuadratic())
4341 throw INTERP_KERNEL::Exception("Invalid 2D mesh and 1D mesh because 2D mesh has quadratic cells and 1D is not fully quadratic !");
4343 mcIdType oldNbOfNodes(getNumberOfNodes());
4344 MCAuto<DataArrayDouble> newCoords;
4349 newCoords=fillExtCoordsUsingTranslation(mesh1D,isQuad);
4354 newCoords=fillExtCoordsUsingTranslAndAutoRotation(mesh1D,isQuad);
4358 throw INTERP_KERNEL::Exception("Not implemented extrusion policy : must be in (0) !");
4360 setCoords(newCoords);
4361 MCAuto<MEDCouplingUMesh> ret(buildExtrudedMeshFromThisLowLev(oldNbOfNodes,isQuad));
4368 * Checks if \a this mesh is constituted by only quadratic cells.
4369 * \return bool - \c true if there are only quadratic cells in \a this mesh.
4370 * \throw If the coordinates array is not set.
4371 * \throw If the nodal connectivity of cells is not defined.
4373 bool MEDCouplingUMesh::isFullyQuadratic() const
4375 checkFullyDefined();
4377 mcIdType nbOfCells=getNumberOfCells();
4378 for(mcIdType i=0;i<nbOfCells && ret;i++)
4380 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4381 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4382 ret=cm.isQuadratic();
4388 * Checks if \a this mesh includes any quadratic cell.
4389 * \return bool - \c true if there is at least one quadratic cells in \a this mesh.
4390 * \throw If the coordinates array is not set.
4391 * \throw If the nodal connectivity of cells is not defined.
4393 bool MEDCouplingUMesh::isPresenceOfQuadratic() const
4395 checkFullyDefined();
4397 mcIdType nbOfCells=getNumberOfCells();
4398 for(mcIdType i=0;i<nbOfCells && !ret;i++)
4400 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4401 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4402 ret=cm.isQuadratic();
4408 * Converts all quadratic cells to linear ones. If there are no quadratic cells in \a
4409 * this mesh, it remains unchanged.
4410 * \throw If the coordinates array is not set.
4411 * \throw If the nodal connectivity of cells is not defined.
4413 void MEDCouplingUMesh::convertQuadraticCellsToLinear()
4415 checkFullyDefined();
4416 mcIdType nbOfCells=getNumberOfCells();
4418 const mcIdType *iciptr=_nodal_connec_index->begin();
4419 for(mcIdType i=0;i<nbOfCells;i++)
4421 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4422 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4423 if(cm.isQuadratic())
4425 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4426 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4427 if(!cml.isDynamic())
4428 delta+=cm.getNumberOfNodes()-cml.getNumberOfNodes();
4430 delta+=(iciptr[i+1]-iciptr[i]-1)/2;
4435 MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()),newConnI(DataArrayIdType::New());
4436 const mcIdType *icptr(_nodal_connec->begin());
4437 newConn->alloc(getNodalConnectivityArrayLen()-delta,1);
4438 newConnI->alloc(nbOfCells+1,1);
4439 mcIdType *ocptr(newConn->getPointer()),*ociptr(newConnI->getPointer());
4442 for(mcIdType i=0;i<nbOfCells;i++,ociptr++)
4444 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)icptr[iciptr[i]];
4445 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4446 if(!cm.isQuadratic())
4448 _types.insert(type);
4449 ocptr=std::copy(icptr+iciptr[i],icptr+iciptr[i+1],ocptr);
4450 ociptr[1]=ociptr[0]+iciptr[i+1]-iciptr[i];
4454 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4455 _types.insert(typel);
4456 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4457 mcIdType newNbOfNodes=cml.getNumberOfNodes();
4459 newNbOfNodes=(iciptr[i+1]-iciptr[i]-1)/2;
4460 *ocptr++=ToIdType(typel);
4461 ocptr=std::copy(icptr+iciptr[i]+1,icptr+iciptr[i]+newNbOfNodes+1,ocptr);
4462 ociptr[1]=ociptr[0]+newNbOfNodes+1;
4465 setConnectivity(newConn,newConnI,false);
4469 * This method converts all linear cell in \a this to quadratic one.
4470 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, here it is needed to specify the target
4471 * 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)
4472 * 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.
4473 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, the coordinates in \a this can be become bigger. All created nodes will be put at the
4474 * end of the existing coordinates.
4476 * \param [in] conversionType specifies the type of conversion expected. Only 0 (default) and 1 are supported presently. 0 those that creates the 'most' simple
4477 * corresponding quadratic cells. 1 is those creating the 'most' complex.
4478 * \return a newly created DataArrayIdType instance that the caller should deal with containing cell ids of converted cells.
4480 * \throw if \a this is not fully defined. It throws too if \a conversionType is not in [0,1].
4482 * \sa MEDCouplingUMesh::convertQuadraticCellsToLinear
4484 DataArrayIdType *MEDCouplingUMesh::convertLinearCellsToQuadratic(int conversionType)
4486 DataArrayIdType *conn=0,*connI=0;
4487 DataArrayDouble *coords=0;
4488 std::set<INTERP_KERNEL::NormalizedCellType> types;
4489 checkFullyDefined();
4490 MCAuto<DataArrayIdType> ret,connSafe,connISafe;
4491 MCAuto<DataArrayDouble> coordsSafe;
4492 int meshDim=getMeshDimension();
4493 switch(conversionType)
4499 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);
4500 connSafe=conn; connISafe=connI; coordsSafe=coords;
4503 ret=convertLinearCellsToQuadratic2D0(conn,connI,coords,types);
4504 connSafe=conn; connISafe=connI; coordsSafe=coords;
4507 ret=convertLinearCellsToQuadratic3D0(conn,connI,coords,types);
4508 connSafe=conn; connISafe=connI; coordsSafe=coords;
4511 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 0 mesh dimensions available are [1,2,3] !");
4519 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);//it is not a bug. In 1D policy 0 and 1 are equals
4520 connSafe=conn; connISafe=connI; coordsSafe=coords;
4523 ret=convertLinearCellsToQuadratic2D1(conn,connI,coords,types);
4524 connSafe=conn; connISafe=connI; coordsSafe=coords;
4527 ret=convertLinearCellsToQuadratic3D1(conn,connI,coords,types);
4528 connSafe=conn; connISafe=connI; coordsSafe=coords;
4531 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 1 mesh dimensions available are [1,2,3] !");
4536 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion type available are 0 (default, the simplest) and 1 (the most complex) !");
4538 setConnectivity(connSafe,connISafe,false);
4540 setCoords(coordsSafe);
4545 * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
4546 * so that the number of cells remains the same. Quadratic faces are converted to
4547 * polygons. This method works only for 2D meshes in
4548 * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
4549 * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
4550 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
4551 * \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
4552 * a polylinized edge constituting the input polygon.
4553 * \throw If the coordinates array is not set.
4554 * \throw If the nodal connectivity of cells is not defined.
4555 * \throw If \a this->getMeshDimension() != 2.
4556 * \throw If \a this->getSpaceDimension() != 2.
4558 void MEDCouplingUMesh::tessellate2D(double eps)
4560 int meshDim(getMeshDimension()),spaceDim(getSpaceDimension());
4562 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : works only with space dimension equal to 2 !");
4566 return tessellate2DCurveInternal(eps);
4568 return tessellate2DInternal(eps);
4570 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : mesh dimension must be in [1,2] !");
4576 * This method only works if \a this has spaceDimension equal to 2 and meshDimension also equal to 2.
4577 * This method allows to modify connectivity of cells in \a this that shares some edges in \a edgeIdsToBeSplit.
4578 * The nodes to be added in those 2D cells are defined by the pair of \a nodeIdsToAdd and \a nodeIdsIndexToAdd.
4579 * Length of \a nodeIdsIndexToAdd is expected to equal to length of \a edgeIdsToBeSplit + 1.
4580 * The node ids in \a nodeIdsToAdd should be valid. Those nodes have to be sorted exactly following exactly the direction of the edge.
4581 * This method can be seen as the opposite method of colinearize2D.
4582 * 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
4583 * to avoid to modify the numbering of existing nodes.
4585 * \param [in] nodeIdsToAdd - the list of node ids to be added (\a nodeIdsIndexToAdd array allows to walk on this array)
4586 * \param [in] nodeIdsIndexToAdd - the entry point of \a nodeIdsToAdd to point to the corresponding nodes to be added.
4587 * \param [in] mesh1Desc - 1st output of buildDescendingConnectivity2 on \a this.
4588 * \param [in] desc - 2nd output of buildDescendingConnectivity2 on \a this.
4589 * \param [in] descI - 3rd output of buildDescendingConnectivity2 on \a this.
4590 * \param [in] revDesc - 4th output of buildDescendingConnectivity2 on \a this.
4591 * \param [in] revDescI - 5th output of buildDescendingConnectivity2 on \a this.
4593 * \sa buildDescendingConnectivity2
4595 void MEDCouplingUMesh::splitSomeEdgesOf2DMesh(const DataArrayIdType *nodeIdsToAdd, const DataArrayIdType *nodeIdsIndexToAdd, const DataArrayIdType *edgeIdsToBeSplit,
4596 const MEDCouplingUMesh *mesh1Desc, const DataArrayIdType *desc, const DataArrayIdType *descI, const DataArrayIdType *revDesc, const DataArrayIdType *revDescI)
4598 if(!nodeIdsToAdd || !nodeIdsIndexToAdd || !edgeIdsToBeSplit || !mesh1Desc || !desc || !descI || !revDesc || !revDescI)
4599 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : input pointers must be not NULL !");
4600 nodeIdsToAdd->checkAllocated(); nodeIdsIndexToAdd->checkAllocated(); edgeIdsToBeSplit->checkAllocated(); desc->checkAllocated(); descI->checkAllocated(); revDesc->checkAllocated(); revDescI->checkAllocated();
4601 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
4602 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : this must have spacedim=meshdim=2 !");
4603 if(mesh1Desc->getSpaceDimension()!=2 || mesh1Desc->getMeshDimension()!=1)
4604 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : mesh1Desc must be the explosion of this with spaceDim=2 and meshDim = 1 !");
4605 //DataArrayIdType *out0(0),*outi0(0);
4606 //MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
4607 //MCAuto<DataArrayIdType> out0s(out0),outi0s(outi0);
4608 //out0s=out0s->buildUnique(); out0s->sort(true);
4614 * Divides every cell of \a this mesh into simplices (triangles in 2D and tetrahedra in 3D).
4615 * In addition, returns an array mapping new cells to old ones. <br>
4616 * This method typically increases the number of cells in \a this mesh
4617 * but the number of nodes remains \b unchanged.
4618 * That's why the 3D splitting policies
4619 * INTERP_KERNEL::GENERAL_24 and INTERP_KERNEL::GENERAL_48 are not available here.
4620 * \param [in] policy - specifies a pattern used for splitting.
4621 * The semantic of \a policy is:
4622 * - 0 - to split QUAD4 by cutting it along 0-2 diagonal (for 2D mesh only).
4623 * - 1 - to split QUAD4 by cutting it along 1-3 diagonal (for 2D mesh only).
4624 * - INTERP_KERNEL::PLANAR_FACE_5 - to split HEXA8 into 5 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4625 * - INTERP_KERNEL::PLANAR_FACE_6 - to split HEXA8 into 6 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4628 * \return DataArrayIdType * - a new instance of DataArrayIdType holding, for each new cell,
4629 * an id of old cell producing it. The caller is to delete this array using
4630 * decrRef() as it is no more needed.
4632 * \throw If \a policy is 0 or 1 and \a this->getMeshDimension() != 2.
4633 * \throw If \a policy is INTERP_KERNEL::PLANAR_FACE_5 or INTERP_KERNEL::PLANAR_FACE_6
4634 * and \a this->getMeshDimension() != 3.
4635 * \throw If \a policy is not one of the four discussed above.
4636 * \throw If the nodal connectivity of cells is not defined.
4637 * \sa MEDCouplingUMesh::tetrahedrize, MEDCoupling1SGTUMesh::sortHexa8EachOther
4639 DataArrayIdType *MEDCouplingUMesh::simplexize(int policy)
4644 return simplexizePol0();
4646 return simplexizePol1();
4647 case INTERP_KERNEL::PLANAR_FACE_5:
4648 return simplexizePlanarFace5();
4649 case INTERP_KERNEL::PLANAR_FACE_6:
4650 return simplexizePlanarFace6();
4652 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)");
4657 * Checks if \a this mesh is constituted by simplex cells only. Simplex cells are:
4658 * - 1D: INTERP_KERNEL::NORM_SEG2
4659 * - 2D: INTERP_KERNEL::NORM_TRI3
4660 * - 3D: INTERP_KERNEL::NORM_TETRA4.
4662 * This method is useful for users that need to use P1 field services as
4663 * MEDCouplingFieldDouble::getValueOn(), MEDCouplingField::buildMeasureField() etc.
4664 * All these methods need mesh support containing only simplex cells.
4665 * \return bool - \c true if there are only simplex cells in \a this mesh.
4666 * \throw If the coordinates array is not set.
4667 * \throw If the nodal connectivity of cells is not defined.
4668 * \throw If \a this->getMeshDimension() < 1.
4670 bool MEDCouplingUMesh::areOnlySimplexCells() const
4672 checkFullyDefined();
4673 int mdim=getMeshDimension();
4674 if(mdim<1 || mdim>3)
4675 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::areOnlySimplexCells : only available with meshes having a meshdim 1, 2 or 3 !");
4676 mcIdType nbCells=getNumberOfCells();
4677 const mcIdType *conn=_nodal_connec->begin();
4678 const mcIdType *connI=_nodal_connec_index->begin();
4679 for(mcIdType i=0;i<nbCells;i++)
4681 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4691 * Converts degenerated 2D or 3D linear cells of \a this mesh into cells of simpler
4692 * type. For example an INTERP_KERNEL::NORM_QUAD4 cell having only three unique nodes in
4693 * its connectivity is transformed into an INTERP_KERNEL::NORM_TRI3 cell.
4694 * Quadratic cells in 2D are also handled. In those cells edges where start=end=midpoint are removed.
4695 * This method does \b not perform geometrical checks and checks only nodal connectivity of cells,
4696 * so it can be useful to call mergeNodes() before calling this method.
4697 * \throw If \a this->getMeshDimension() <= 1.
4698 * \throw If the coordinates array is not set.
4699 * \throw If the nodal connectivity of cells is not defined.
4701 void MEDCouplingUMesh::convertDegeneratedCells()
4703 checkFullyDefined();
4704 if(getMeshDimension()<=1)
4705 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4706 mcIdType nbOfCells=getNumberOfCells();
4709 mcIdType initMeshLgth=getNodalConnectivityArrayLen();
4710 mcIdType *conn=_nodal_connec->getPointer();
4711 mcIdType *index=_nodal_connec_index->getPointer();
4712 mcIdType posOfCurCell=0;
4714 mcIdType lgthOfCurCell;
4715 for(mcIdType i=0;i<nbOfCells;i++)
4717 lgthOfCurCell=index[i+1]-posOfCurCell;
4718 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4720 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
4721 conn+newPos+1,newLgth);
4722 conn[newPos]=newType;
4724 posOfCurCell=index[i+1];
4727 if(newPos!=initMeshLgth)
4728 _nodal_connec->reAlloc(newPos);
4733 * Same as MEDCouplingUMesh::convertDegeneratedCells() plus deletion of the flat cells.
4734 * A cell is flat in the following cases:
4735 * - for a linear cell, all points in the connectivity are equal
4736 * - for a quadratic cell, either the above, or a quadratic polygon with two (linear) points and two
4737 * identical quadratic points
4738 * \return a new instance of DataArrayIdType holding ids of removed cells. The caller is to delete
4739 * this array using decrRef() as it is no more needed.
4741 DataArrayIdType *MEDCouplingUMesh::convertDegeneratedCellsAndRemoveFlatOnes()
4743 checkFullyDefined();
4744 if(getMeshDimension()<=1)
4745 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4746 mcIdType nbOfCells=getNumberOfCells();
4747 MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(0,1);
4750 mcIdType initMeshLgth=getNodalConnectivityArrayLen();
4751 mcIdType *conn=_nodal_connec->getPointer();
4752 mcIdType *index=_nodal_connec_index->getPointer();
4753 mcIdType posOfCurCell=0;
4755 mcIdType lgthOfCurCell, nbDelCells(0);
4756 for(mcIdType i=0;i<nbOfCells;i++)
4758 lgthOfCurCell=index[i+1]-posOfCurCell;
4759 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4761 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
4762 conn+newPos+1,newLgth);
4763 // Shall we delete the cell if it is completely degenerated:
4764 bool delCell=INTERP_KERNEL::CellSimplify::isFlatCell(conn, newPos, newLgth, newType);
4768 ret->pushBackSilent(i);
4770 else //if the cell is to be deleted, simply stay at the same place
4772 conn[newPos]=newType;
4775 posOfCurCell=index[i+1];
4776 index[i+1-nbDelCells]=newPos;
4778 if(newPos!=initMeshLgth)
4779 _nodal_connec->reAlloc(newPos);
4780 const mcIdType nCellDel=ret->getNumberOfTuples();
4782 _nodal_connec_index->reAlloc(nbOfCells-nCellDel+1);
4788 * This method remove null 1D cells from \a this. A 1D cell is considered null if start node is equal to end node.
4789 * Only connectivity is considered here.
4791 bool MEDCouplingUMesh::removeDegenerated1DCells()
4793 checkConnectivityFullyDefined();
4794 if(getMeshDimension()!=1)
4795 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::removeDegenerated1DCells works on umeshes with meshdim equals to 1 !");
4796 std::size_t nbCells(getNumberOfCells()),newSize(0),newSize2(0);
4797 const mcIdType *conn(getNodalConnectivity()->begin()),*conni(getNodalConnectivityIndex()->begin());
4799 for(std::size_t i=0;i<nbCells;i++)
4801 INTERP_KERNEL::NormalizedCellType ct((INTERP_KERNEL::NormalizedCellType)conn[conni[i]]);
4802 if(ct==INTERP_KERNEL::NORM_SEG2 || ct==INTERP_KERNEL::NORM_SEG3)
4804 if(conn[conni[i]+1]!=conn[conni[i]+2])
4807 newSize2+=conni[i+1]-conni[i];
4812 std::ostringstream oss; oss << "MEDCouplingUMesh::removeDegenerated1DCells : cell #" << i << " in this is not of type SEG2/SEG3 !";
4813 throw INTERP_KERNEL::Exception(oss.str());
4817 if(newSize==nbCells)//no cells has been removed -> do nothing
4819 MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()),newConnI(DataArrayIdType::New()); newConnI->alloc(newSize+1,1); newConn->alloc(newSize2,1);
4820 mcIdType *newConnPtr(newConn->getPointer()),*newConnIPtr(newConnI->getPointer()); newConnIPtr[0]=0;
4821 for(std::size_t i=0;i<nbCells;i++)
4823 if(conn[conni[i]+1]!=conn[conni[i]+2])
4825 newConnIPtr[1]=newConnIPtr[0]+conni[i+1]-conni[i];
4826 newConnPtr=std::copy(conn+conni[i],conn+conni[i+1],newConnPtr);
4830 setConnectivity(newConn,newConnI,true);
4835 * Finds incorrectly oriented cells of this 2D mesh in 3D space.
4836 * A cell is considered to be oriented correctly if an angle between its
4837 * normal vector and a given vector is less than \c PI / \c 2.
4838 * \param [in] vec - 3 components of the vector specifying the correct orientation of
4840 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
4842 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
4843 * is not cleared before filling in.
4844 * \throw If \a this->getMeshDimension() != 2.
4845 * \throw If \a this->getSpaceDimension() != 3.
4847 * \if ENABLE_EXAMPLES
4848 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
4849 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
4852 void MEDCouplingUMesh::are2DCellsNotCorrectlyOriented(const double *vec, bool polyOnly, std::vector<mcIdType>& cells) const
4854 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
4855 throw INTERP_KERNEL::Exception("Invalid mesh to apply are2DCellsNotCorrectlyOriented on it : must be meshDim==2 and spaceDim==3 !");
4856 mcIdType nbOfCells=getNumberOfCells();
4857 const mcIdType *conn=_nodal_connec->begin();
4858 const mcIdType *connI=_nodal_connec_index->begin();
4859 const double *coordsPtr=_coords->begin();
4860 for(mcIdType i=0;i<nbOfCells;i++)
4862 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4863 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
4865 bool isQuadratic=INTERP_KERNEL::CellModel::GetCellModel(type).isQuadratic();
4866 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4873 * Reverse connectivity of 2D cells whose orientation is not correct. A cell is
4874 * considered to be oriented correctly if an angle between its normal vector and a
4875 * given vector is less than \c PI / \c 2.
4876 * \param [in] vec - 3 components of the vector specifying the correct orientation of
4878 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
4880 * \throw If \a this->getMeshDimension() != 2.
4881 * \throw If \a this->getSpaceDimension() != 3.
4883 * \if ENABLE_EXAMPLES
4884 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
4885 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
4888 * \sa changeOrientationOfCells
4890 void MEDCouplingUMesh::orientCorrectly2DCells(const double *vec, bool polyOnly)
4892 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
4893 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectly2DCells on it : must be meshDim==2 and spaceDim==3 !");
4894 mcIdType nbOfCells=getNumberOfCells();
4895 mcIdType *conn(_nodal_connec->getPointer());
4896 const mcIdType *connI(_nodal_connec_index->begin());
4897 const double *coordsPtr(_coords->begin());
4898 bool isModified(false);
4899 for(mcIdType i=0;i<nbOfCells;i++)
4901 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4902 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
4904 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
4905 bool isQuadratic(cm.isQuadratic());
4906 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4909 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
4914 _nodal_connec->declareAsNew();
4919 * This method change the orientation of cells in \a this without any consideration of coordinates. Only connectivity is impacted.
4921 * \sa orientCorrectly2DCells
4923 void MEDCouplingUMesh::changeOrientationOfCells()
4925 int mdim(getMeshDimension());
4926 if(mdim!=2 && mdim!=1)
4927 throw INTERP_KERNEL::Exception("Invalid mesh to apply changeOrientationOfCells on it : must be meshDim==2 or meshDim==1 !");
4928 mcIdType nbOfCells=getNumberOfCells();
4929 mcIdType *conn(_nodal_connec->getPointer());
4930 const mcIdType *connI(_nodal_connec_index->begin());
4933 for(mcIdType i=0;i<nbOfCells;i++)
4935 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4936 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
4937 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
4942 for(mcIdType i=0;i<nbOfCells;i++)
4944 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4945 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
4946 cm.changeOrientationOf1D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
4952 * Finds incorrectly oriented polyhedral cells, i.e. polyhedrons having correctly
4953 * oriented facets. The normal vector of the facet should point out of the cell.
4954 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
4955 * is not cleared before filling in.
4956 * \throw If \a this->getMeshDimension() != 3.
4957 * \throw If \a this->getSpaceDimension() != 3.
4958 * \throw If the coordinates array is not set.
4959 * \throw If the nodal connectivity of cells is not defined.
4961 * \if ENABLE_EXAMPLES
4962 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
4963 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
4966 void MEDCouplingUMesh::arePolyhedronsNotCorrectlyOriented(std::vector<mcIdType>& cells) const
4968 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
4969 throw INTERP_KERNEL::Exception("Invalid mesh to apply arePolyhedronsNotCorrectlyOriented on it : must be meshDim==3 and spaceDim==3 !");
4970 mcIdType nbOfCells=getNumberOfCells();
4971 const mcIdType *conn=_nodal_connec->begin();
4972 const mcIdType *connI=_nodal_connec_index->begin();
4973 const double *coordsPtr=_coords->begin();
4974 for(mcIdType i=0;i<nbOfCells;i++)
4976 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4977 if(type==INTERP_KERNEL::NORM_POLYHED)
4979 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4986 * Tries to fix connectivity of polyhedra, so that normal vector of all facets to point
4988 * \throw If \a this->getMeshDimension() != 3.
4989 * \throw If \a this->getSpaceDimension() != 3.
4990 * \throw If the coordinates array is not set.
4991 * \throw If the nodal connectivity of cells is not defined.
4992 * \throw If the reparation fails.
4994 * \if ENABLE_EXAMPLES
4995 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
4996 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
4998 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
5000 void MEDCouplingUMesh::orientCorrectlyPolyhedrons()
5002 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
5003 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectlyPolyhedrons on it : must be meshDim==3 and spaceDim==3 !");
5004 mcIdType nbOfCells=getNumberOfCells();
5005 mcIdType *conn=_nodal_connec->getPointer();
5006 const mcIdType *connI=_nodal_connec_index->begin();
5007 const double *coordsPtr=_coords->begin();
5008 for(mcIdType i=0;i<nbOfCells;i++)
5010 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5011 if(type==INTERP_KERNEL::NORM_POLYHED)
5015 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5016 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
5018 catch(INTERP_KERNEL::Exception& e)
5020 std::ostringstream oss; oss << "Something wrong in polyhedron #" << i << " : " << e.what();
5021 throw INTERP_KERNEL::Exception(oss.str());
5029 * This method invert orientation of all cells in \a this.
5030 * After calling this method the absolute value of measure of cells in \a this are the same than before calling.
5031 * This method only operates on the connectivity so coordinates are not touched at all.
5033 void MEDCouplingUMesh::invertOrientationOfAllCells()
5035 checkConnectivityFullyDefined();
5036 std::set<INTERP_KERNEL::NormalizedCellType> gts(getAllGeoTypes());
5037 mcIdType *conn(_nodal_connec->getPointer());
5038 const mcIdType *conni(_nodal_connec_index->begin());
5039 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator gt=gts.begin();gt!=gts.end();gt++)
5041 INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::OrientationInverter> oi(INTERP_KERNEL::OrientationInverter::BuildInstanceFrom(*gt));
5042 MCAuto<DataArrayIdType> cwt(giveCellsWithType(*gt));
5043 for(const mcIdType *it=cwt->begin();it!=cwt->end();it++)
5044 oi->operate(conn+conni[*it]+1,conn+conni[*it+1]);
5050 * Finds and fixes incorrectly oriented linear extruded volumes (INTERP_KERNEL::NORM_HEXA8,
5051 * INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXGP12 etc) to respect the MED convention
5052 * according to which the first facet of the cell should be oriented to have the normal vector
5053 * pointing out of cell.
5054 * \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of fixed
5055 * cells. The caller is to delete this array using decrRef() as it is no more
5057 * \throw If \a this->getMeshDimension() != 3.
5058 * \throw If \a this->getSpaceDimension() != 3.
5059 * \throw If the coordinates array is not set.
5060 * \throw If the nodal connectivity of cells is not defined.
5062 * \if ENABLE_EXAMPLES
5063 * \ref cpp_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a C++ example".<br>
5064 * \ref py_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a Python example".
5066 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
5068 DataArrayIdType *MEDCouplingUMesh::findAndCorrectBadOriented3DExtrudedCells()
5070 const char msg[]="check3DCellsWellOriented detection works only for 3D cells !";
5071 if(getMeshDimension()!=3)
5072 throw INTERP_KERNEL::Exception(msg);
5073 int spaceDim=getSpaceDimension();
5075 throw INTERP_KERNEL::Exception(msg);
5077 mcIdType nbOfCells=getNumberOfCells();
5078 mcIdType *conn=_nodal_connec->getPointer();
5079 const mcIdType *connI=_nodal_connec_index->begin();
5080 const double *coo=getCoords()->begin();
5081 MCAuto<DataArrayIdType> cells(DataArrayIdType::New()); cells->alloc(0,1);
5082 for(mcIdType i=0;i<nbOfCells;i++)
5084 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5085 if(cm.isExtruded() && !cm.isDynamic() && !cm.isQuadratic())
5087 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coo))
5089 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
5090 cells->pushBackSilent(i);
5094 return cells.retn();
5098 * This method is a faster method to correct orientation of all 3D cells in \a this.
5099 * 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.
5100 * This method makes the hypothesis that \a this a coherent that is to say MEDCouplingUMesh::checkConsistency should throw no exception.
5102 * \return a newly allocated mcIdType array with one components containing cell ids renumbered to fit the convention of MED (MED file and MEDCoupling)
5103 * \sa MEDCouplingUMesh::orientCorrectlyPolyhedrons,
5105 DataArrayIdType *MEDCouplingUMesh::findAndCorrectBadOriented3DCells()
5107 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
5108 throw INTERP_KERNEL::Exception("Invalid mesh to apply findAndCorrectBadOriented3DCells on it : must be meshDim==3 and spaceDim==3 !");
5109 mcIdType nbOfCells=getNumberOfCells();
5110 mcIdType *conn=_nodal_connec->getPointer();
5111 const mcIdType *connI=_nodal_connec_index->begin();
5112 const double *coordsPtr=_coords->begin();
5113 MCAuto<DataArrayIdType> ret=DataArrayIdType::New(); ret->alloc(0,1);
5114 for(mcIdType i=0;i<nbOfCells;i++)
5116 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5119 case INTERP_KERNEL::NORM_TETRA4:
5121 if(!IsTetra4WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5123 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+3));
5124 ret->pushBackSilent(i);
5128 case INTERP_KERNEL::NORM_PYRA5:
5130 if(!IsPyra5WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5132 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+4));
5133 ret->pushBackSilent(i);
5137 case INTERP_KERNEL::NORM_PENTA6:
5138 case INTERP_KERNEL::NORM_HEXA8:
5139 case INTERP_KERNEL::NORM_HEXGP12:
5141 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5143 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
5144 ret->pushBackSilent(i);
5148 case INTERP_KERNEL::NORM_POLYHED:
5150 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5152 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
5153 ret->pushBackSilent(i);
5158 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 !");
5166 * This method has a sense for meshes with spaceDim==3 and meshDim==2.
5167 * If it is not the case an exception will be thrown.
5168 * This method is fast because the first cell of \a this is used to compute the plane.
5169 * \param vec output of size at least 3 used to store the normal vector (with norm equal to Area ) of searched plane.
5170 * \param pos output of size at least 3 used to store a point owned of searched plane.
5172 void MEDCouplingUMesh::getFastAveragePlaneOfThis(double *vec, double *pos) const
5174 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
5175 throw INTERP_KERNEL::Exception("Invalid mesh to apply getFastAveragePlaneOfThis on it : must be meshDim==2 and spaceDim==3 !");
5176 const mcIdType *conn=_nodal_connec->begin();
5177 const mcIdType *connI=_nodal_connec_index->begin();
5178 const double *coordsPtr=_coords->begin();
5179 INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(conn+1,connI[1]-connI[0]-1,coordsPtr,vec);
5180 std::copy(coordsPtr+3*conn[1],coordsPtr+3*conn[1]+3,pos);
5184 * Creates a new MEDCouplingFieldDouble holding Edge Ratio values of all
5185 * cells. Currently cells of the following types are treated:
5186 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5187 * For a cell of other type an exception is thrown.
5188 * Space dimension of a 2D mesh can be either 2 or 3.
5189 * The Edge Ratio of a cell \f$t\f$ is:
5190 * \f$\frac{|t|_\infty}{|t|_0}\f$,
5191 * where \f$|t|_\infty\f$ and \f$|t|_0\f$ respectively denote the greatest and
5192 * the smallest edge lengths of \f$t\f$.
5193 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5194 * cells and one time, lying on \a this mesh. The caller is to delete this
5195 * field using decrRef() as it is no more needed.
5196 * \throw If the coordinates array is not set.
5197 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5198 * \throw If the connectivity data array has more than one component.
5199 * \throw If the connectivity data array has a named component.
5200 * \throw If the connectivity index data array has more than one component.
5201 * \throw If the connectivity index data array has a named component.
5202 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
5203 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5204 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5206 MEDCouplingFieldDouble *MEDCouplingUMesh::getEdgeRatioField() const
5208 checkConsistencyLight();
5209 int spaceDim=getSpaceDimension();
5210 int meshDim=getMeshDimension();
5211 if(spaceDim!=2 && spaceDim!=3)
5212 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : SpaceDimension must be equal to 2 or 3 !");
5213 if(meshDim!=2 && meshDim!=3)
5214 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : MeshDimension must be equal to 2 or 3 !");
5215 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5217 mcIdType nbOfCells=getNumberOfCells();
5218 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5219 arr->alloc(nbOfCells,1);
5220 double *pt=arr->getPointer();
5221 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5222 const mcIdType *conn=_nodal_connec->begin();
5223 const mcIdType *connI=_nodal_connec_index->begin();
5224 const double *coo=_coords->begin();
5226 for(mcIdType i=0;i<nbOfCells;i++,pt++)
5228 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5231 case INTERP_KERNEL::NORM_TRI3:
5233 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5234 *pt=INTERP_KERNEL::triEdgeRatio(tmp);
5237 case INTERP_KERNEL::NORM_QUAD4:
5239 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5240 *pt=INTERP_KERNEL::quadEdgeRatio(tmp);
5243 case INTERP_KERNEL::NORM_TETRA4:
5245 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5246 *pt=INTERP_KERNEL::tetraEdgeRatio(tmp);
5250 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5252 conn+=connI[i+1]-connI[i];
5254 ret->setName("EdgeRatio");
5255 ret->synchronizeTimeWithSupport();
5260 * Creates a new MEDCouplingFieldDouble holding Aspect Ratio values of all
5261 * cells. Currently cells of the following types are treated:
5262 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5263 * For a cell of other type an exception is thrown.
5264 * Space dimension of a 2D mesh can be either 2 or 3.
5265 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5266 * cells and one time, lying on \a this mesh. The caller is to delete this
5267 * field using decrRef() as it is no more needed.
5268 * \throw If the coordinates array is not set.
5269 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5270 * \throw If the connectivity data array has more than one component.
5271 * \throw If the connectivity data array has a named component.
5272 * \throw If the connectivity index data array has more than one component.
5273 * \throw If the connectivity index data array has a named component.
5274 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
5275 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5276 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5278 MEDCouplingFieldDouble *MEDCouplingUMesh::getAspectRatioField() const
5280 checkConsistencyLight();
5281 int spaceDim=getSpaceDimension();
5282 int meshDim=getMeshDimension();
5283 if(spaceDim!=2 && spaceDim!=3)
5284 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : SpaceDimension must be equal to 2 or 3 !");
5285 if(meshDim!=2 && meshDim!=3)
5286 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : MeshDimension must be equal to 2 or 3 !");
5287 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5289 mcIdType nbOfCells=getNumberOfCells();
5290 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5291 arr->alloc(nbOfCells,1);
5292 double *pt=arr->getPointer();
5293 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5294 const mcIdType *conn=_nodal_connec->begin();
5295 const mcIdType *connI=_nodal_connec_index->begin();
5296 const double *coo=_coords->begin();
5298 for(mcIdType i=0;i<nbOfCells;i++,pt++)
5300 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5303 case INTERP_KERNEL::NORM_TRI3:
5305 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5306 *pt=INTERP_KERNEL::triAspectRatio(tmp);
5309 case INTERP_KERNEL::NORM_QUAD4:
5311 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5312 *pt=INTERP_KERNEL::quadAspectRatio(tmp);
5315 case INTERP_KERNEL::NORM_TETRA4:
5317 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5318 *pt=INTERP_KERNEL::tetraAspectRatio(tmp);
5322 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5324 conn+=connI[i+1]-connI[i];
5326 ret->setName("AspectRatio");
5327 ret->synchronizeTimeWithSupport();
5332 * Creates a new MEDCouplingFieldDouble holding Warping factor values of all
5333 * cells of \a this 2D mesh in 3D space. It is a measure of the "planarity" of 2D cell
5334 * in 3D space. Currently only cells of the following types are
5335 * treated: INTERP_KERNEL::NORM_QUAD4.
5336 * For a cell of other type an exception is thrown.
5337 * The warp field is computed as follows: let (a,b,c,d) be the points of the quad.
5339 * \f$t=\vec{da}\times\vec{ab}\f$,
5340 * \f$u=\vec{ab}\times\vec{bc}\f$
5341 * \f$v=\vec{bc}\times\vec{cd}\f$
5342 * \f$w=\vec{cd}\times\vec{da}\f$, the warp is defined as \f$W^3\f$ with
5344 * W=min(\frac{t}{|t|}\cdot\frac{v}{|v|}, \frac{u}{|u|}\cdot\frac{w}{|w|})
5346 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5347 * cells and one time, lying on \a this mesh. The caller is to delete this
5348 * field using decrRef() as it is no more needed.
5349 * \throw If the coordinates array is not set.
5350 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5351 * \throw If the connectivity data array has more than one component.
5352 * \throw If the connectivity data array has a named component.
5353 * \throw If the connectivity index data array has more than one component.
5354 * \throw If the connectivity index data array has a named component.
5355 * \throw If \a this->getMeshDimension() != 2.
5356 * \throw If \a this->getSpaceDimension() != 3.
5357 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5359 MEDCouplingFieldDouble *MEDCouplingUMesh::getWarpField() const
5361 checkConsistencyLight();
5362 int spaceDim=getSpaceDimension();
5363 int meshDim=getMeshDimension();
5365 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : SpaceDimension must be equal to 3 !");
5367 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : MeshDimension must be equal to 2 !");
5368 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5370 mcIdType nbOfCells=getNumberOfCells();
5371 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5372 arr->alloc(nbOfCells,1);
5373 double *pt=arr->getPointer();
5374 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5375 const mcIdType *conn=_nodal_connec->begin();
5376 const mcIdType *connI=_nodal_connec_index->begin();
5377 const double *coo=_coords->begin();
5379 for(mcIdType i=0;i<nbOfCells;i++,pt++)
5381 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5384 case INTERP_KERNEL::NORM_QUAD4:
5386 FillInCompact3DMode(3,4,conn+1,coo,tmp);
5387 *pt=INTERP_KERNEL::quadWarp(tmp);
5391 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : A cell with not manged type (NORM_QUAD4) has been detected !");
5393 conn+=connI[i+1]-connI[i];
5395 ret->setName("Warp");
5396 ret->synchronizeTimeWithSupport();
5402 * Creates a new MEDCouplingFieldDouble holding Skew factor values of all
5403 * cells of \a this 2D mesh in 3D space. Currently cells of the following types are
5404 * treated: INTERP_KERNEL::NORM_QUAD4.
5405 * The skew is computed as follow for a quad with points (a,b,c,d): let
5406 * \f$u=\vec{ab}+\vec{dc}\f$ and \f$v=\vec{ac}+\vec{bd}\f$
5407 * then the skew is computed as:
5409 * s=\frac{u}{|u|}\cdot\frac{v}{|v|}
5412 * For a cell of other type an exception is thrown.
5413 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5414 * cells and one time, lying on \a this mesh. The caller is to delete this
5415 * field using decrRef() as it is no more needed.
5416 * \throw If the coordinates array is not set.
5417 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5418 * \throw If the connectivity data array has more than one component.
5419 * \throw If the connectivity data array has a named component.
5420 * \throw If the connectivity index data array has more than one component.
5421 * \throw If the connectivity index data array has a named component.
5422 * \throw If \a this->getMeshDimension() != 2.
5423 * \throw If \a this->getSpaceDimension() != 3.
5424 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5426 MEDCouplingFieldDouble *MEDCouplingUMesh::getSkewField() const
5428 checkConsistencyLight();
5429 int spaceDim=getSpaceDimension();
5430 int meshDim=getMeshDimension();
5432 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : SpaceDimension must be equal to 3 !");
5434 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : MeshDimension must be equal to 2 !");
5435 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5437 mcIdType nbOfCells=getNumberOfCells();
5438 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5439 arr->alloc(nbOfCells,1);
5440 double *pt=arr->getPointer();
5441 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5442 const mcIdType *conn=_nodal_connec->begin();
5443 const mcIdType *connI=_nodal_connec_index->begin();
5444 const double *coo=_coords->begin();
5446 for(mcIdType i=0;i<nbOfCells;i++,pt++)
5448 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5451 case INTERP_KERNEL::NORM_QUAD4:
5453 FillInCompact3DMode(3,4,conn+1,coo,tmp);
5454 *pt=INTERP_KERNEL::quadSkew(tmp);
5458 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : A cell with not manged type (NORM_QUAD4) has been detected !");
5460 conn+=connI[i+1]-connI[i];
5462 ret->setName("Skew");
5463 ret->synchronizeTimeWithSupport();
5468 * 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.
5470 * \return a new instance of field containing the result. The returned instance has to be deallocated by the caller.
5472 * \sa getSkewField, getWarpField, getAspectRatioField, getEdgeRatioField
5474 MEDCouplingFieldDouble *MEDCouplingUMesh::computeDiameterField() const
5476 checkConsistencyLight();
5477 MCAuto<MEDCouplingFieldDouble> ret(MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME));
5479 std::set<INTERP_KERNEL::NormalizedCellType> types;
5480 ComputeAllTypesInternal(types,_nodal_connec,_nodal_connec_index);
5481 int spaceDim(getSpaceDimension());
5482 mcIdType nbCells(getNumberOfCells());
5483 MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
5484 arr->alloc(nbCells,1);
5485 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++)
5487 INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::DiameterCalculator> dc(INTERP_KERNEL::CellModel::GetCellModel(*it).buildInstanceOfDiameterCalulator(spaceDim));
5488 MCAuto<DataArrayIdType> cellIds(giveCellsWithType(*it));
5489 dc->computeForListOfCellIdsUMeshFrmt(cellIds->begin(),cellIds->end(),_nodal_connec_index->begin(),_nodal_connec->begin(),getCoords()->begin(),arr->getPointer());
5492 ret->setName("Diameter");
5497 * This method aggregate the bbox of each cell and put it into bbox parameter (xmin,xmax,ymin,ymax,zmin,zmax).
5499 * \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)
5500 * For all other cases this input parameter is ignored.
5501 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5503 * \throw If \a this is not fully set (coordinates and connectivity).
5504 * \throw If a cell in \a this has no valid nodeId.
5505 * \sa MEDCouplingUMesh::getBoundingBoxForBBTreeFast, MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5507 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree(double arcDetEps) const
5509 int mDim(getMeshDimension()),sDim(getSpaceDimension());
5510 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.
5511 return getBoundingBoxForBBTreeFast();
5512 if((mDim==2 && sDim==2) || (mDim==1 && sDim==2))
5514 bool presenceOfQuadratic(false);
5515 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=_types.begin();it!=_types.end();it++)
5517 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(*it));
5518 if(cm.isQuadratic())
5519 presenceOfQuadratic=true;
5521 if(!presenceOfQuadratic)
5522 return getBoundingBoxForBBTreeFast();
5523 if(mDim==2 && sDim==2)
5524 return getBoundingBoxForBBTree2DQuadratic(arcDetEps);
5526 return getBoundingBoxForBBTree1DQuadratic(arcDetEps);
5528 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) !");
5532 * This method aggregate the bbox of each cell only considering the nodes constituting each cell and put it into bbox parameter.
5533 * So meshes having quadratic cells the computed bounding boxes can be invalid !
5535 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5537 * \throw If \a this is not fully set (coordinates and connectivity).
5538 * \throw If a cell in \a this has no valid nodeId.
5540 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTreeFast() const
5542 checkFullyDefined();
5543 int spaceDim(getSpaceDimension());
5544 mcIdType nbOfCells(getNumberOfCells()), nbOfNodes(getNumberOfNodes());
5545 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5546 double *bbox(ret->getPointer());
5547 for(mcIdType i=0;i<nbOfCells*spaceDim;i++)
5549 bbox[2*i]=std::numeric_limits<double>::max();
5550 bbox[2*i+1]=-std::numeric_limits<double>::max();
5552 const double *coordsPtr(_coords->begin());
5553 const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5554 for(mcIdType i=0;i<nbOfCells;i++)
5556 mcIdType offset=connI[i]+1;
5557 mcIdType nbOfNodesForCell(connI[i+1]-offset),kk(0);
5558 for(mcIdType j=0;j<nbOfNodesForCell;j++)
5560 mcIdType nodeId=conn[offset+j];
5561 if(nodeId>=0 && nodeId<nbOfNodes)
5563 for(int k=0;k<spaceDim;k++)
5565 bbox[2*spaceDim*i+2*k]=std::min(bbox[2*spaceDim*i+2*k],coordsPtr[spaceDim*nodeId+k]);
5566 bbox[2*spaceDim*i+2*k+1]=std::max(bbox[2*spaceDim*i+2*k+1],coordsPtr[spaceDim*nodeId+k]);
5573 std::ostringstream oss; oss << "MEDCouplingUMesh::getBoundingBoxForBBTree : cell #" << i << " contains no valid nodeId !";
5574 throw INTERP_KERNEL::Exception(oss.str());
5581 * This method aggregates the bbox of each 2D cell in \a this considering the whole shape. This method is particularly
5582 * useful for 2D meshes having quadratic cells
5583 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5584 * the two extremities of the arc of circle).
5586 * \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)
5587 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5588 * \throw If \a this is not fully defined.
5589 * \throw If \a this is not a mesh with meshDimension equal to 2.
5590 * \throw If \a this is not a mesh with spaceDimension equal to 2.
5591 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic
5593 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic(double arcDetEps) const
5595 checkFullyDefined();
5596 INTERP_KERNEL::QuadraticPlanarPrecision arcPrec(arcDetEps);
5598 int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
5599 mcIdType nbOfCells=getNumberOfCells();
5600 if(spaceDim!=2 || mDim!=2)
5601 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!");
5602 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5603 double *bbox(ret->getPointer());
5604 const double *coords(_coords->begin());
5605 const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5606 for(mcIdType i=0;i<nbOfCells;i++,bbox+=4,connI++)
5608 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5609 mcIdType sz(connI[1]-connI[0]-1);
5610 std::vector<INTERP_KERNEL::Node *> nodes(sz);
5611 INTERP_KERNEL::QuadraticPolygon *pol(0);
5612 for(mcIdType j=0;j<sz;j++)
5614 mcIdType nodeId(conn[*connI+1+j]);
5615 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5617 if(!cm.isQuadratic())
5618 pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
5620 pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
5621 INTERP_KERNEL::Bounds b; b.prepareForAggregation(); pol->fillBounds(b); delete pol;
5622 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax();
5628 * This method aggregates the bbox of each 1D cell in \a this considering the whole shape. This method is particularly
5629 * useful for 2D meshes having quadratic cells
5630 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5631 * the two extremities of the arc of circle).
5633 * \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)
5634 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5635 * \throw If \a this is not fully defined.
5636 * \throw If \a this is not a mesh with meshDimension equal to 1.
5637 * \throw If \a this is not a mesh with spaceDimension equal to 2.
5638 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5640 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic(double arcDetEps) const
5642 checkFullyDefined();
5643 int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
5644 mcIdType nbOfCells=getNumberOfCells();
5645 if(spaceDim!=2 || mDim!=1)
5646 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!");
5647 INTERP_KERNEL::QuadraticPlanarPrecision arcPrec(arcDetEps);
5648 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5649 double *bbox(ret->getPointer());
5650 const double *coords(_coords->begin());
5651 const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5652 for(mcIdType i=0;i<nbOfCells;i++,bbox+=4,connI++)
5654 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5655 mcIdType sz(connI[1]-connI[0]-1);
5656 std::vector<INTERP_KERNEL::Node *> nodes(sz);
5657 INTERP_KERNEL::Edge *edge(0);
5658 for(mcIdType j=0;j<sz;j++)
5660 mcIdType nodeId(conn[*connI+1+j]);
5661 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5663 if(!cm.isQuadratic())
5664 edge=INTERP_KERNEL::QuadraticPolygon::BuildLinearEdge(nodes);
5666 edge=INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(nodes);
5667 const INTERP_KERNEL::Bounds& b(edge->getBounds());
5668 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax(); edge->decrRef();
5675 namespace MEDCouplingImpl
5680 ConnReader(const mcIdType *c, mcIdType val):_conn(c),_val(val) { }
5681 bool operator() (const mcIdType& pos) { return _conn[pos]!=_val; }
5683 const mcIdType *_conn;
5690 ConnReader2(const mcIdType *c, mcIdType val):_conn(c),_val(val) { }
5691 bool operator() (const mcIdType& pos) { return _conn[pos]==_val; }
5693 const mcIdType *_conn;
5701 * This method expects that \a this is sorted by types. If not an exception will be thrown.
5702 * This method returns in the same format as code (see MEDCouplingUMesh::checkTypeConsistencyAndContig or MEDCouplingUMesh::splitProfilePerType) how
5703 * \a this is composed in cell types.
5704 * The returned array is of size 3*n where n is the number of different types present in \a this.
5705 * For every k in [0,n] ret[3*k+2]==-1 because it has no sense here.
5706 * This parameter is kept only for compatibility with other method listed above.
5708 std::vector<mcIdType> MEDCouplingUMesh::getDistributionOfTypes() const
5710 checkConnectivityFullyDefined();
5711 const mcIdType *conn=_nodal_connec->begin();
5712 const mcIdType *connI=_nodal_connec_index->begin();
5713 const mcIdType *work=connI;
5714 mcIdType nbOfCells=getNumberOfCells();
5715 std::size_t n=getAllGeoTypes().size();
5716 std::vector<mcIdType> ret(3*n,-1); //ret[3*k+2]==-1 because it has no sense here
5717 std::set<INTERP_KERNEL::NormalizedCellType> types;
5718 for(std::size_t i=0;work!=connI+nbOfCells;i++)
5720 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn[*work];
5721 if(types.find(typ)!=types.end())
5723 std::ostringstream oss; oss << "MEDCouplingUMesh::getDistributionOfTypes : Type " << INTERP_KERNEL::CellModel::GetCellModel(typ).getRepr();
5724 oss << " is not contiguous !";
5725 throw INTERP_KERNEL::Exception(oss.str());
5729 const mcIdType *work2=std::find_if(work+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,typ));
5730 ret[3*i+1]=ToIdType(std::distance(work,work2));
5737 * This method is used to check that this has contiguous cell type in same order than described in \a code.
5738 * only for types cell, type node is not managed.
5739 * Format of \a code is the following. \a code should be of size 3*n and non empty. If not an exception is thrown.
5740 * foreach k in [0,n) on 3*k pos represent the geometric type and 3*k+1 number of elements of type 3*k.
5741 * 3*k+2 refers if different from -1 the pos in 'idsPerType' to get the corresponding array.
5742 * If 2 or more same geometric type is in \a code and exception is thrown too.
5744 * This method firstly checks
5745 * If it exists k so that 3*k geometric type is not in geometric types of this an exception will be thrown.
5746 * If it exists k so that 3*k geometric type exists but the number of consecutive cell types does not match,
5747 * an exception is thrown too.
5749 * If all geometric types in \a code are exactly those in \a this null pointer is returned.
5750 * If it exists a geometric type in \a this \b not in \a code \b no exception is thrown
5751 * and a DataArrayIdType instance is returned that the user has the responsibility to deallocate.
5753 DataArrayIdType *MEDCouplingUMesh::checkTypeConsistencyAndContig(const std::vector<mcIdType>& code, const std::vector<const DataArrayIdType *>& idsPerType) const
5756 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code is empty, should not !");
5757 std::size_t sz=code.size();
5760 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code size is NOT %3 !");
5761 std::vector<INTERP_KERNEL::NormalizedCellType> types;
5763 bool isNoPflUsed=true;
5764 for(std::size_t i=0;i<n;i++)
5765 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)code[3*i])==types.end())
5767 types.push_back((INTERP_KERNEL::NormalizedCellType)code[3*i]);
5769 if(_types.find((INTERP_KERNEL::NormalizedCellType)code[3*i])==_types.end())
5770 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : expected geo types not in this !");
5771 isNoPflUsed=isNoPflUsed && (code[3*i+2]==-1);
5774 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code contains duplication of types in unstructured mesh !");
5777 if(!checkConsecutiveCellTypesAndOrder(&types[0],&types[0]+types.size()))
5778 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : non contiguous type !");
5779 if(types.size()==_types.size())
5782 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
5784 mcIdType *retPtr=ret->getPointer();
5785 const mcIdType *connI=_nodal_connec_index->begin();
5786 const mcIdType *conn=_nodal_connec->begin();
5787 mcIdType nbOfCells=getNumberOfCells();
5788 const mcIdType *i=connI;
5790 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++,kk++)
5792 i=std::find_if(i,connI+nbOfCells,MEDCouplingImpl::ConnReader2(conn,ToIdType((*it))));
5793 mcIdType offset=ToIdType(std::distance(connI,i));
5794 const mcIdType *j=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType((*it))));
5795 mcIdType nbOfCellsOfCurType=ToIdType(std::distance(i,j));
5796 if(code[3*kk+2]==-1)
5797 for(mcIdType k=0;k<nbOfCellsOfCurType;k++)
5801 mcIdType idInIdsPerType=code[3*kk+2];
5802 if(idInIdsPerType>=0 && idInIdsPerType<ToIdType(idsPerType.size()))
5804 const DataArrayIdType *zePfl=idsPerType[idInIdsPerType];
5807 zePfl->checkAllocated();
5808 if(zePfl->getNumberOfComponents()==1)
5810 for(const mcIdType *k=zePfl->begin();k!=zePfl->end();k++,retPtr++)
5812 if(*k>=0 && *k<nbOfCellsOfCurType)
5813 *retPtr=(*k)+offset;
5816 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : the section " << kk << " points to the profile #" << idInIdsPerType;
5817 oss << ", and this profile contains a value " << *k << " should be in [0," << nbOfCellsOfCurType << ") !";
5818 throw INTERP_KERNEL::Exception(oss.str());
5823 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of a profile with nb of compo != 1 !");
5826 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of null profile !");
5830 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : at section " << kk << " of code it points to the array #" << idInIdsPerType;
5831 oss << " should be in [0," << idsPerType.size() << ") !";
5832 throw INTERP_KERNEL::Exception(oss.str());
5841 * This method makes the hypothesis that \a this is sorted by type. If not an exception will be thrown.
5842 * 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.
5843 * 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.
5844 * This method has 1 input \a profile and 3 outputs \a code \a idsInPflPerType and \a idsPerType.
5846 * \param [in] profile list of IDs constituing the profile
5847 * \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.
5848 * \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,
5849 * \a idsInPflPerType[i] stores the tuple ids in \a profile that correspond to the geometric type code[3*i+0]
5850 * \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.
5851 * This vector can be empty in case of all geometric type cells are fully covered in ascending in the given input \a profile.
5852 * \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
5854 void MEDCouplingUMesh::splitProfilePerType(const DataArrayIdType *profile, std::vector<mcIdType>& code, std::vector<DataArrayIdType *>& idsInPflPerType, std::vector<DataArrayIdType *>& idsPerType, bool smartPflKiller) const
5857 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile is NULL !");
5858 if(profile->getNumberOfComponents()!=1)
5859 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile should have exactly one component !");
5860 checkConnectivityFullyDefined();
5861 const mcIdType *conn=_nodal_connec->begin();
5862 const mcIdType *connI=_nodal_connec_index->begin();
5863 mcIdType nbOfCells=getNumberOfCells();
5864 std::vector<INTERP_KERNEL::NormalizedCellType> types;
5865 std::vector<mcIdType> typeRangeVals(1);
5866 for(const mcIdType *i=connI;i!=connI+nbOfCells;)
5868 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5869 if(std::find(types.begin(),types.end(),curType)!=types.end())
5871 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : current mesh is not sorted by type !");
5873 types.push_back(curType);
5874 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
5875 typeRangeVals.push_back(ToIdType(std::distance(connI,i)));
5878 DataArrayIdType *castArr=0,*rankInsideCast=0,*castsPresent=0;
5879 profile->splitByValueRange(&typeRangeVals[0],&typeRangeVals[0]+typeRangeVals.size(),castArr,rankInsideCast,castsPresent);
5880 MCAuto<DataArrayIdType> tmp0=castArr;
5881 MCAuto<DataArrayIdType> tmp1=rankInsideCast;
5882 MCAuto<DataArrayIdType> tmp2=castsPresent;
5884 mcIdType nbOfCastsFinal=castsPresent->getNumberOfTuples();
5885 code.resize(3*nbOfCastsFinal);
5886 std::vector< MCAuto<DataArrayIdType> > idsInPflPerType2;
5887 std::vector< MCAuto<DataArrayIdType> > idsPerType2;
5888 for(mcIdType i=0;i<nbOfCastsFinal;i++)
5890 mcIdType castId=castsPresent->getIJ(i,0);
5891 MCAuto<DataArrayIdType> tmp3=castArr->findIdsEqual(castId);
5892 idsInPflPerType2.push_back(tmp3);
5893 code[3*i]=ToIdType(types[castId]);
5894 code[3*i+1]=tmp3->getNumberOfTuples();
5895 MCAuto<DataArrayIdType> tmp4=rankInsideCast->selectByTupleId(tmp3->begin(),tmp3->begin()+tmp3->getNumberOfTuples());
5896 if(!smartPflKiller || !tmp4->isIota(typeRangeVals[castId+1]-typeRangeVals[castId]))
5898 tmp4->copyStringInfoFrom(*profile);
5899 idsPerType2.push_back(tmp4);
5900 code[3*i+2]=ToIdType(idsPerType2.size())-1;
5907 std::size_t sz2=idsInPflPerType2.size();
5908 idsInPflPerType.resize(sz2);
5909 for(std::size_t i=0;i<sz2;i++)
5911 DataArrayIdType *locDa=idsInPflPerType2[i];
5913 idsInPflPerType[i]=locDa;
5915 std::size_t sz=idsPerType2.size();
5916 idsPerType.resize(sz);
5917 for(std::size_t i=0;i<sz;i++)
5919 DataArrayIdType *locDa=idsPerType2[i];
5921 idsPerType[i]=locDa;
5926 * This method is here too emulate the MEDMEM behaviour on BDC (buildDescendingConnectivity). Hoping this method becomes deprecated very soon.
5927 * This method make the assumption that \a this and 'nM1LevMesh' mesh lyies on same coords (same pointer) as MED and MEDMEM does.
5928 * The following equality should be verified 'nM1LevMesh->getMeshDimension()==this->getMeshDimension()-1'
5929 * 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.
5931 MEDCouplingUMesh *MEDCouplingUMesh::emulateMEDMEMBDC(const MEDCouplingUMesh *nM1LevMesh, DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *&revDesc, DataArrayIdType *&revDescIndx, DataArrayIdType *& nM1LevMeshIds, DataArrayIdType *&meshnM1Old2New) const
5933 checkFullyDefined();
5934 nM1LevMesh->checkFullyDefined();
5935 if(getMeshDimension()-1!=nM1LevMesh->getMeshDimension())
5936 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : The mesh passed as first argument should have a meshDim equal to this->getMeshDimension()-1 !" );
5937 if(_coords!=nM1LevMesh->getCoords())
5938 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : 'this' and mesh in first argument should share the same coords : Use tryToShareSameCoords method !");
5939 MCAuto<DataArrayIdType> tmp0=DataArrayIdType::New();
5940 MCAuto<DataArrayIdType> tmp1=DataArrayIdType::New();
5941 MCAuto<MEDCouplingUMesh> ret1=buildDescendingConnectivity(desc,descIndx,tmp0,tmp1);
5942 MCAuto<DataArrayIdType> ret0=ret1->sortCellsInMEDFileFrmt();
5943 desc->transformWithIndArr(ret0->begin(),ret0->begin()+ret0->getNbOfElems());
5944 MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
5945 tmp->setConnectivity(tmp0,tmp1);
5946 tmp->renumberCells(ret0->begin(),false);
5947 revDesc=tmp->getNodalConnectivity();
5948 revDescIndx=tmp->getNodalConnectivityIndex();
5949 DataArrayIdType *ret=0;
5950 if(!ret1->areCellsIncludedIn(nM1LevMesh,2,ret))
5953 ret->getMaxValue(tmp2);
5955 std::ostringstream oss; oss << "MEDCouplingUMesh::emulateMEDMEMBDC : input N-1 mesh present a cell not in descending mesh ... Id of cell is " << tmp2 << " !";
5956 throw INTERP_KERNEL::Exception(oss.str());
5961 revDescIndx->incrRef();
5964 meshnM1Old2New=ret0;
5969 * Permutes the nodal connectivity arrays so that the cells are sorted by type, which is
5970 * necessary for writing the mesh to MED file. Additionally returns a permutation array
5971 * in "Old to New" mode.
5972 * \return DataArrayIdType * - a new instance of DataArrayIdType. The caller is to delete
5973 * this array using decrRef() as it is no more needed.
5974 * \throw If the nodal connectivity of cells is not defined.
5976 DataArrayIdType *MEDCouplingUMesh::sortCellsInMEDFileFrmt()
5978 checkConnectivityFullyDefined();
5979 MCAuto<DataArrayIdType> ret=getRenumArrForMEDFileFrmt();
5980 renumberCells(ret->begin(),false);
5985 * This methods checks that cells are sorted by their types.
5986 * This method makes asumption (no check) that connectivity is correctly set before calling.
5988 bool MEDCouplingUMesh::checkConsecutiveCellTypes() const
5990 checkFullyDefined();
5991 const mcIdType *conn=_nodal_connec->begin();
5992 const mcIdType *connI=_nodal_connec_index->begin();
5993 mcIdType nbOfCells=getNumberOfCells();
5994 std::set<INTERP_KERNEL::NormalizedCellType> types;
5995 for(const mcIdType *i=connI;i!=connI+nbOfCells;)
5997 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5998 if(types.find(curType)!=types.end())
6000 types.insert(curType);
6001 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6007 * This method is a specialization of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method that is called here.
6008 * The geometric type order is specified by MED file.
6010 * \sa MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder
6012 bool MEDCouplingUMesh::checkConsecutiveCellTypesForMEDFileFrmt() const
6014 return checkConsecutiveCellTypesAndOrder(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
6018 * This method performs the same job as checkConsecutiveCellTypes except that the order of types sequence is analyzed to check
6019 * that the order is specified in array defined by [ \a orderBg , \a orderEnd ).
6020 * If there is some geo types in \a this \b NOT in [ \a orderBg, \a orderEnd ) it is OK (return true) if contiguous.
6021 * If there is some geo types in [ \a orderBg, \a orderEnd ) \b NOT in \a this it is OK too (return true) if contiguous.
6023 bool MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
6025 checkFullyDefined();
6026 const mcIdType *conn=_nodal_connec->begin();
6027 const mcIdType *connI=_nodal_connec_index->begin();
6028 mcIdType nbOfCells=getNumberOfCells();
6031 mcIdType lastPos=-1;
6032 std::set<INTERP_KERNEL::NormalizedCellType> sg;
6033 for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6035 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6036 const INTERP_KERNEL::NormalizedCellType *isTypeExists=std::find(orderBg,orderEnd,curType);
6037 if(isTypeExists!=orderEnd)
6039 mcIdType pos=ToIdType(std::distance(orderBg,isTypeExists));
6043 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6047 if(sg.find(curType)==sg.end())
6049 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6060 * This method returns 2 newly allocated DataArrayIdType instances. The first is an array of size 'this->getNumberOfCells()' with one component,
6061 * 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
6062 * 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'.
6064 DataArrayIdType *MEDCouplingUMesh::getLevArrPerCellTypes(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd, DataArrayIdType *&nbPerType) const
6066 checkConnectivityFullyDefined();
6067 mcIdType nbOfCells=getNumberOfCells();
6068 const mcIdType *conn=_nodal_connec->begin();
6069 const mcIdType *connI=_nodal_connec_index->begin();
6070 MCAuto<DataArrayIdType> tmpa=DataArrayIdType::New();
6071 MCAuto<DataArrayIdType> tmpb=DataArrayIdType::New();
6072 tmpa->alloc(nbOfCells,1);
6073 tmpb->alloc(std::distance(orderBg,orderEnd),1);
6074 tmpb->fillWithZero();
6075 mcIdType *tmp=tmpa->getPointer();
6076 mcIdType *tmp2=tmpb->getPointer();
6077 for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6079 const INTERP_KERNEL::NormalizedCellType *where=std::find(orderBg,orderEnd,(INTERP_KERNEL::NormalizedCellType)conn[*i]);
6082 mcIdType pos=ToIdType(std::distance(orderBg,where));
6084 tmp[std::distance(connI,i)]=pos;
6088 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*i]);
6089 std::ostringstream oss; oss << "MEDCouplingUMesh::getLevArrPerCellTypes : Cell #" << std::distance(connI,i);
6090 oss << " has a type " << cm.getRepr() << " not in input array of type !";
6091 throw INTERP_KERNEL::Exception(oss.str());
6094 nbPerType=tmpb.retn();
6099 * This method behaves exactly as MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec but the order is those defined in MED file spec.
6101 * \return a new object containing the old to new correspondence.
6103 * \sa MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec, MEDCouplingUMesh::sortCellsInMEDFileFrmt.
6105 DataArrayIdType *MEDCouplingUMesh::getRenumArrForMEDFileFrmt() const
6107 return getRenumArrForConsecutiveCellTypesSpec(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
6111 * 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.
6112 * This method returns an array of size getNumberOfCells() that gives a renumber array old2New that can be used as input of MEDCouplingMesh::renumberCells.
6113 * The mesh after this call to MEDCouplingMesh::renumberCells will pass the test of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder with the same inputs.
6114 * The returned array minimizes the permutations that is to say the order of cells inside same geometric type remains the same.
6116 DataArrayIdType *MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
6118 DataArrayIdType *nbPerType=0;
6119 MCAuto<DataArrayIdType> tmpa=getLevArrPerCellTypes(orderBg,orderEnd,nbPerType);
6120 nbPerType->decrRef();
6121 return tmpa->buildPermArrPerLevel();
6125 * This method reorganize the cells of \a this so that the cells with same geometric types are put together.
6126 * The number of cells remains unchanged after the call of this method.
6127 * This method tries to minimizes the number of needed permutations. So, this method behaves not exactly as
6128 * MEDCouplingUMesh::sortCellsInMEDFileFrmt.
6130 * \return the array giving the correspondence old to new.
6132 DataArrayIdType *MEDCouplingUMesh::rearrange2ConsecutiveCellTypes()
6134 checkFullyDefined();
6136 const mcIdType *conn=_nodal_connec->begin();
6137 const mcIdType *connI=_nodal_connec_index->begin();
6138 mcIdType nbOfCells=getNumberOfCells();
6139 std::vector<INTERP_KERNEL::NormalizedCellType> types;
6140 for(const mcIdType *i=connI;i!=connI+nbOfCells && (types.size()!=_types.size());)
6141 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)conn[*i])==types.end())
6143 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6144 types.push_back(curType);
6145 for(i++;i!=connI+nbOfCells && (INTERP_KERNEL::NormalizedCellType)conn[*i]==curType;i++);
6147 DataArrayIdType *ret=DataArrayIdType::New();
6148 ret->alloc(nbOfCells,1);
6149 mcIdType *retPtr=ret->getPointer();
6150 std::fill(retPtr,retPtr+nbOfCells,-1);
6151 mcIdType newCellId=0;
6152 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
6154 for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6155 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
6156 retPtr[std::distance(connI,i)]=newCellId++;
6158 renumberCells(retPtr,false);
6163 * This method splits \a this into as mush as untructured meshes that consecutive set of same type cells.
6164 * So this method has typically a sense if MEDCouplingUMesh::checkConsecutiveCellTypes has a sense.
6165 * This method makes asumption that connectivity is correctly set before calling.
6167 std::vector<MEDCouplingUMesh *> MEDCouplingUMesh::splitByType() const
6169 checkConnectivityFullyDefined();
6170 const mcIdType *conn=_nodal_connec->begin();
6171 const mcIdType *connI=_nodal_connec_index->begin();
6172 mcIdType nbOfCells=getNumberOfCells();
6173 std::vector<MEDCouplingUMesh *> ret;
6174 for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6176 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6177 mcIdType beginCellId=ToIdType(std::distance(connI,i));
6178 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6179 mcIdType endCellId=ToIdType(std::distance(connI,i));
6180 mcIdType sz=endCellId-beginCellId;
6181 mcIdType *cells=new mcIdType[sz];
6182 for(mcIdType j=0;j<sz;j++)
6183 cells[j]=beginCellId+j;
6184 MEDCouplingUMesh *m=(MEDCouplingUMesh *)buildPartOfMySelf(cells,cells+sz,true);
6192 * This method performs the opposite operation than those in MEDCoupling1SGTUMesh::buildUnstructured.
6193 * If \a this is a single geometric type unstructured mesh, it will be converted into a more compact data structure,
6194 * MEDCoupling1GTUMesh instance. The returned instance will aggregate the same DataArrayDouble instance of coordinates than \a this.
6196 * \return a newly allocated instance, that the caller must manage.
6197 * \throw If \a this contains more than one geometric type.
6198 * \throw If the nodal connectivity of \a this is not fully defined.
6199 * \throw If the internal data is not coherent.
6201 MEDCoupling1GTUMesh *MEDCouplingUMesh::convertIntoSingleGeoTypeMesh() const
6203 checkConnectivityFullyDefined();
6204 if(_types.size()!=1)
6205 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6206 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6207 MCAuto<MEDCoupling1GTUMesh> ret=MEDCoupling1GTUMesh::New(getName(),typ);
6208 ret->setCoords(getCoords());
6209 MEDCoupling1SGTUMesh *retC=dynamic_cast<MEDCoupling1SGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6212 MCAuto<DataArrayIdType> c=convertNodalConnectivityToStaticGeoTypeMesh();
6213 retC->setNodalConnectivity(c);
6217 MEDCoupling1DGTUMesh *retD=dynamic_cast<MEDCoupling1DGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6219 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : Internal error !");
6220 DataArrayIdType *c=0,*ci=0;
6221 convertNodalConnectivityToDynamicGeoTypeMesh(c,ci);
6222 MCAuto<DataArrayIdType> cs(c),cis(ci);
6223 retD->setNodalConnectivity(cs,cis);
6228 DataArrayIdType *MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh() const
6230 checkConnectivityFullyDefined();
6231 if(_types.size()!=1)
6232 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6233 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6234 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6237 std::ostringstream oss; oss << "MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : this contains a single geo type (" << cm.getRepr() << ") but ";
6238 oss << "this type is dynamic ! Only static geometric type is possible for that type ! call convertNodalConnectivityToDynamicGeoTypeMesh instead !";
6239 throw INTERP_KERNEL::Exception(oss.str());
6241 mcIdType nbCells=getNumberOfCells();
6242 mcIdType typi=ToIdType(typ);
6243 mcIdType nbNodesPerCell=ToIdType(cm.getNumberOfNodes());
6244 MCAuto<DataArrayIdType> connOut=DataArrayIdType::New(); connOut->alloc(nbCells*nbNodesPerCell,1);
6245 mcIdType *outPtr=connOut->getPointer();
6246 const mcIdType *conn=_nodal_connec->begin();
6247 const mcIdType *connI=_nodal_connec_index->begin();
6249 for(mcIdType i=0;i<nbCells;i++,connI++)
6251 if(conn[connI[0]]==typi && connI[1]-connI[0]==nbNodesPerCell)
6252 outPtr=std::copy(conn+connI[0]+1,conn+connI[1],outPtr);
6255 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 << ") !";
6256 throw INTERP_KERNEL::Exception(oss.str());
6259 return connOut.retn();
6263 * Convert the nodal connectivity of the mesh so that all the cells are of dynamic types (polygon or quadratic
6264 * polygon). This returns the corresponding new nodal connectivity in \ref numbering-indirect format.
6265 * \param nodalConn nodal connectivity
6266 * \param nodalConnIndex nodal connectivity indices
6268 void MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh(DataArrayIdType *&nodalConn, DataArrayIdType *&nodalConnIndex) const
6270 static const char msg0[]="MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : nodal connectivity in this are invalid ! Call checkConsistency !";
6271 checkConnectivityFullyDefined();
6272 if(_types.size()!=1)
6273 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6274 mcIdType nbCells=getNumberOfCells(),
6275 lgth=_nodal_connec->getNumberOfTuples();
6277 throw INTERP_KERNEL::Exception(msg0);
6278 MCAuto<DataArrayIdType> c(DataArrayIdType::New()),ci(DataArrayIdType::New());
6279 c->alloc(lgth-nbCells,1); ci->alloc(nbCells+1,1);
6280 mcIdType *cp(c->getPointer()),*cip(ci->getPointer());
6281 const mcIdType *incp(_nodal_connec->begin()),*incip(_nodal_connec_index->begin());
6283 for(mcIdType i=0;i<nbCells;i++,cip++,incip++)
6285 mcIdType strt(incip[0]+1),stop(incip[1]);//+1 to skip geo type
6286 mcIdType delta(stop-strt);
6289 if((strt>=0 && strt<lgth) && (stop>=0 && stop<=lgth))
6290 cp=std::copy(incp+strt,incp+stop,cp);
6292 throw INTERP_KERNEL::Exception(msg0);
6295 throw INTERP_KERNEL::Exception(msg0);
6296 cip[1]=cip[0]+delta;
6298 nodalConn=c.retn(); nodalConnIndex=ci.retn();
6302 * This method takes in input a vector of MEDCouplingUMesh instances lying on the same coordinates with same mesh dimensions.
6303 * Each mesh in \b ms must be sorted by type with the same order (typically using MEDCouplingUMesh::sortCellsInMEDFileFrmt).
6304 * This method is particularly useful for MED file interaction. It allows to aggregate several meshes and keeping the type sorting
6305 * and the track of the permutation by chunk of same geotype cells to retrieve it. The traditional formats old2new and new2old
6306 * are not used here to avoid the build of big permutation array.
6308 * \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
6309 * those specified in MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6310 * \param [out] szOfCellGrpOfSameType is a newly allocated DataArrayIdType instance whose number of tuples is equal to the number of chunks of same geotype
6311 * in all meshes in \b ms. The accumulation of all values of this array is equal to the number of cells of returned mesh.
6312 * \param [out] idInMsOfCellGrpOfSameType is a newly allocated DataArrayIdType instance having the same size than \b szOfCellGrpOfSameType. This
6313 * output array gives for each chunck of same type the corresponding mesh id in \b ms.
6314 * \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
6315 * is sorted by type following the geo cell types order of MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6317 MEDCouplingUMesh *MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& ms,
6318 DataArrayIdType *&szOfCellGrpOfSameType,
6319 DataArrayIdType *&idInMsOfCellGrpOfSameType)
6321 std::vector<const MEDCouplingUMesh *> ms2;
6322 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms.begin();it!=ms.end();it++)
6325 (*it)->checkConnectivityFullyDefined();
6329 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : input vector is empty !");
6330 const DataArrayDouble *refCoo=ms2[0]->getCoords();
6331 int meshDim=ms2[0]->getMeshDimension();
6332 std::vector<const MEDCouplingUMesh *> m1ssm;
6333 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmAuto;
6335 std::vector<const MEDCouplingUMesh *> m1ssmSingle;
6336 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmSingleAuto;
6337 mcIdType fake=0,rk=0;
6338 MCAuto<DataArrayIdType> ret1(DataArrayIdType::New()),ret2(DataArrayIdType::New());
6339 ret1->alloc(0,1); ret2->alloc(0,1);
6340 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms2.begin();it!=ms2.end();it++,rk++)
6342 if(meshDim!=(*it)->getMeshDimension())
6343 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshdims mismatch !");
6344 if(refCoo!=(*it)->getCoords())
6345 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshes are not shared by a single coordinates coords !");
6346 std::vector<MEDCouplingUMesh *> sp=(*it)->splitByType();
6347 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<const MEDCouplingUMesh *> >(m1ssm));
6348 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<MCAuto<MEDCouplingUMesh> > >(m1ssmAuto));
6349 for(std::vector<MEDCouplingUMesh *>::const_iterator it2=sp.begin();it2!=sp.end();it2++)
6351 MEDCouplingUMesh *singleCell=static_cast<MEDCouplingUMesh *>((*it2)->buildPartOfMySelf(&fake,&fake+1,true));
6352 m1ssmSingleAuto.push_back(singleCell);
6353 m1ssmSingle.push_back(singleCell);
6354 ret1->pushBackSilent((*it2)->getNumberOfCells()); ret2->pushBackSilent(rk);
6357 MCAuto<MEDCouplingUMesh> m1ssmSingle2=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmSingle);
6358 MCAuto<DataArrayIdType> renum=m1ssmSingle2->sortCellsInMEDFileFrmt();
6359 std::vector<const MEDCouplingUMesh *> m1ssmfinal(m1ssm.size());
6360 for(mcIdType i=0;i<ToIdType(m1ssm.size());i++)
6361 m1ssmfinal[renum->getIJ(i,0)]=m1ssm[i];
6362 MCAuto<MEDCouplingUMesh> ret0=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmfinal);
6363 szOfCellGrpOfSameType=ret1->renumber(renum->begin());
6364 idInMsOfCellGrpOfSameType=ret2->renumber(renum->begin());
6369 * This method returns a newly created DataArrayIdType instance.
6370 * This method retrieves cell ids in [ \a begin, \a end ) that have the type \a type.
6372 DataArrayIdType *MEDCouplingUMesh::keepCellIdsByType(INTERP_KERNEL::NormalizedCellType type, const mcIdType *begin, const mcIdType *end) const
6374 checkFullyDefined();
6375 const mcIdType *conn=_nodal_connec->begin();
6376 const mcIdType *connIndex=_nodal_connec_index->begin();
6377 MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(0,1);
6378 for(const mcIdType *w=begin;w!=end;w++)
6379 if((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]==type)
6380 ret->pushBackSilent(*w);
6385 * This method makes the assumption that da->getNumberOfTuples()<this->getNumberOfCells(). This method makes the assumption that ids contained in 'da'
6386 * are in [0:getNumberOfCells())
6388 DataArrayIdType *MEDCouplingUMesh::convertCellArrayPerGeoType(const DataArrayIdType *da) const
6390 checkFullyDefined();
6391 const mcIdType *conn=_nodal_connec->begin();
6392 const mcIdType *connI=_nodal_connec_index->begin();
6393 mcIdType nbOfCells=getNumberOfCells();
6394 std::set<INTERP_KERNEL::NormalizedCellType> types(getAllGeoTypes());
6395 mcIdType *tmp=new mcIdType[nbOfCells];
6396 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
6399 for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6400 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
6401 tmp[std::distance(connI,i)]=j++;
6403 DataArrayIdType *ret=DataArrayIdType::New();
6404 ret->alloc(da->getNumberOfTuples(),da->getNumberOfComponents());
6405 ret->copyStringInfoFrom(*da);
6406 mcIdType *retPtr=ret->getPointer();
6407 const mcIdType *daPtr=da->begin();
6408 mcIdType nbOfElems=da->getNbOfElems();
6409 for(mcIdType k=0;k<nbOfElems;k++)
6410 retPtr[k]=tmp[daPtr[k]];
6416 * This method reduced number of cells of this by keeping cells whose type is different from 'type' and if type=='type'
6417 * This method \b works \b for mesh sorted by type.
6418 * cells whose ids is in 'idsPerGeoType' array.
6419 * This method conserves coords and name of mesh.
6421 MEDCouplingUMesh *MEDCouplingUMesh::keepSpecifiedCells(INTERP_KERNEL::NormalizedCellType type, const mcIdType *idsPerGeoTypeBg, const mcIdType *idsPerGeoTypeEnd) const
6423 std::vector<mcIdType> code=getDistributionOfTypes();
6424 std::size_t nOfTypesInThis=code.size()/3;
6425 mcIdType sz=0,szOfType=0;
6426 for(std::size_t i=0;i<nOfTypesInThis;i++)
6431 szOfType=code[3*i+1];
6433 for(const mcIdType *work=idsPerGeoTypeBg;work!=idsPerGeoTypeEnd;work++)
6434 if(*work<0 || *work>=szOfType)
6436 std::ostringstream oss; oss << "MEDCouplingUMesh::keepSpecifiedCells : Request on type " << type << " at place #" << std::distance(idsPerGeoTypeBg,work) << " value " << *work;
6437 oss << ". It should be in [0," << szOfType << ") !";
6438 throw INTERP_KERNEL::Exception(oss.str());
6440 MCAuto<DataArrayIdType> idsTokeep=DataArrayIdType::New(); idsTokeep->alloc(sz+std::distance(idsPerGeoTypeBg,idsPerGeoTypeEnd),1);
6441 mcIdType *idsPtr=idsTokeep->getPointer();
6443 for(std::size_t i=0;i<nOfTypesInThis;i++)
6446 for(mcIdType j=0;j<code[3*i+1];j++)
6449 idsPtr=std::transform(idsPerGeoTypeBg,idsPerGeoTypeEnd,idsPtr,std::bind(std::plus<mcIdType>(),std::placeholders::_1,offset));
6450 offset+=code[3*i+1];
6452 MCAuto<MEDCouplingUMesh> ret=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(idsTokeep->begin(),idsTokeep->end(),true));
6453 ret->copyTinyInfoFrom(this);
6458 * This method returns a vector of size 'this->getNumberOfCells()'.
6459 * This method retrieves for each cell in \a this if it is linear (false) or quadratic(true).
6461 std::vector<bool> MEDCouplingUMesh::getQuadraticStatus() const
6463 mcIdType ncell=getNumberOfCells();
6464 std::vector<bool> ret(ncell);
6465 const mcIdType *cI=getNodalConnectivityIndex()->begin();
6466 const mcIdType *c=getNodalConnectivity()->begin();
6467 for(mcIdType i=0;i<ncell;i++)
6469 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[i]];
6470 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6471 ret[i]=cm.isQuadratic();
6477 * Returns a newly created mesh (with ref count ==1) that contains merge of \a this and \a other.
6479 MEDCouplingMesh *MEDCouplingUMesh::mergeMyselfWith(const MEDCouplingMesh *other) const
6481 if(other->getType()!=UNSTRUCTURED)
6482 throw INTERP_KERNEL::Exception("Merge of umesh only available with umesh each other !");
6483 const MEDCouplingUMesh *otherC=static_cast<const MEDCouplingUMesh *>(other);
6484 return MergeUMeshes(this,otherC);
6488 * Returns a new DataArrayDouble holding barycenters of all cells. The barycenter is
6489 * computed by averaging coordinates of cell nodes, so this method is not a right
6490 * choice for degenerated meshes (not well oriented, cells with measure close to zero).
6491 * Beware also that for quadratic meshes, degenerated arc of circles are turned into linear edges for the computation.
6492 * This happens with a default detection precision of eps=1.0e-14. If you need control over this use computeCellCenterOfMassWithPrecision().
6493 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
6494 * this->getNumberOfCells() tuples per \a this->getSpaceDimension()
6495 * components. The caller is to delete this array using decrRef() as it is
6497 * \throw If the coordinates array is not set.
6498 * \throw If the nodal connectivity of cells is not defined.
6499 * \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
6500 * \sa MEDCouplingUMesh::computeCellCenterOfMassWithPrecision
6502 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMass() const
6504 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6505 int spaceDim=getSpaceDimension();
6506 mcIdType nbOfCells=getNumberOfCells();
6507 ret->alloc(nbOfCells,spaceDim);
6508 ret->copyStringInfoFrom(*getCoords());
6509 double *ptToFill=ret->getPointer();
6510 const mcIdType *nodal=_nodal_connec->begin();
6511 const mcIdType *nodalI=_nodal_connec_index->begin();
6512 const double *coor=_coords->begin();
6513 for(mcIdType i=0;i<nbOfCells;i++)
6515 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6516 INTERP_KERNEL::computeBarycenter2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[i]+1,nodalI[i+1]-nodalI[i]-1,coor,spaceDim,ptToFill);
6524 * See computeCellCenterOfMass().
6525 * \param eps a precision for the detection of degenerated arc of circles.
6526 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
6527 * this->getNumberOfCells() tuples per \a this->getSpaceDimension()
6528 * components. The caller is to delete this array using decrRef() as it is
6530 * \throw If the coordinates array is not set.
6531 * \throw If the nodal connectivity of cells is not defined.
6532 * \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
6533 * \sa MEDCouplingUMesh::computeCellCenterOfMassWithPrecision
6535 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMassWithPrecision(double eps) const
6537 INTERP_KERNEL::QuadraticPlanarPrecision prec(eps);
6538 MCAuto<DataArrayDouble> ret = computeCellCenterOfMass();
6544 * This method computes for each cell in \a this, the location of the iso barycenter of nodes constituting
6545 * the cell. Contrary to badly named MEDCouplingUMesh::computeCellCenterOfMass method that returns the center of inertia of the
6547 * \return a newly allocated DataArrayDouble instance that the caller has to deal with. The returned
6548 * DataArrayDouble instance will have \c this->getNumberOfCells() tuples and \c this->getSpaceDimension() components.
6550 * \sa MEDCouplingUMesh::computeCellCenterOfMass
6551 * \throw If \a this is not fully defined (coordinates and connectivity)
6552 * \throw If there is presence in nodal connectivity in \a this of node ids not in [0, \c this->getNumberOfNodes() )
6554 DataArrayDouble *MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell() const
6556 checkFullyDefined();
6557 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6558 int spaceDim=getSpaceDimension();
6559 mcIdType nbOfCells=getNumberOfCells();
6560 mcIdType nbOfNodes=getNumberOfNodes();
6561 ret->alloc(nbOfCells,spaceDim);
6562 double *ptToFill=ret->getPointer();
6563 const mcIdType *nodal=_nodal_connec->begin();
6564 const mcIdType *nodalI=_nodal_connec_index->begin();
6565 const double *coor=_coords->begin();
6566 for(mcIdType i=0;i<nbOfCells;i++,ptToFill+=spaceDim)
6568 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6569 std::fill(ptToFill,ptToFill+spaceDim,0.);
6570 if(type!=INTERP_KERNEL::NORM_POLYHED)
6572 for(const mcIdType *conn=nodal+nodalI[i]+1;conn!=nodal+nodalI[i+1];conn++)
6574 if(*conn>=0 && *conn<nbOfNodes)
6575 std::transform(coor+spaceDim*conn[0],coor+spaceDim*(conn[0]+1),ptToFill,ptToFill,std::plus<double>());
6578 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of nodeId #" << *conn << " should be in [0," << nbOfNodes << ") !";
6579 throw INTERP_KERNEL::Exception(oss.str());
6582 mcIdType nbOfNodesInCell=nodalI[i+1]-nodalI[i]-1;
6583 if(nbOfNodesInCell>0)
6584 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind(std::multiplies<double>(),std::placeholders::_1,1./(double)nbOfNodesInCell));
6587 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of cell with no nodes !";
6588 throw INTERP_KERNEL::Exception(oss.str());
6593 std::set<mcIdType> s(nodal+nodalI[i]+1,nodal+nodalI[i+1]);
6595 for(std::set<mcIdType>::const_iterator it=s.begin();it!=s.end();it++)
6597 if(*it>=0 && *it<nbOfNodes)
6598 std::transform(coor+spaceDim*(*it),coor+spaceDim*((*it)+1),ptToFill,ptToFill,std::plus<double>());
6601 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell polyhedron cell #" << i << " presence of nodeId #" << *it << " should be in [0," << nbOfNodes << ") !";
6602 throw INTERP_KERNEL::Exception(oss.str());
6606 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind(std::multiplies<double>(),std::placeholders::_1,1./(double)s.size()));
6609 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on polyhedron cell #" << i << " there are no nodes !";
6610 throw INTERP_KERNEL::Exception(oss.str());
6618 * Returns a new DataArrayDouble holding barycenters of specified cells. The
6619 * barycenter is computed by averaging coordinates of cell nodes. The cells to treat
6620 * are specified via an array of cell ids.
6621 * \warning Validity of the specified cell ids is not checked!
6622 * Valid range is [ 0, \a this->getNumberOfCells() ).
6623 * \param [in] begin - an array of cell ids of interest.
6624 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
6625 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size ( \a
6626 * end - \a begin ) tuples per \a this->getSpaceDimension() components. The
6627 * caller is to delete this array using decrRef() as it is no more needed.
6628 * \throw If the coordinates array is not set.
6629 * \throw If the nodal connectivity of cells is not defined.
6631 * \if ENABLE_EXAMPLES
6632 * \ref cpp_mcumesh_getPartBarycenterAndOwner "Here is a C++ example".<br>
6633 * \ref py_mcumesh_getPartBarycenterAndOwner "Here is a Python example".
6636 DataArrayDouble *MEDCouplingUMesh::getPartBarycenterAndOwner(const mcIdType *begin, const mcIdType *end) const
6638 DataArrayDouble *ret=DataArrayDouble::New();
6639 int spaceDim=getSpaceDimension();
6640 std::size_t nbOfTuple=std::distance(begin,end);
6641 ret->alloc(nbOfTuple,spaceDim);
6642 double *ptToFill=ret->getPointer();
6643 double *tmp=new double[spaceDim];
6644 const mcIdType *nodal=_nodal_connec->begin();
6645 const mcIdType *nodalI=_nodal_connec_index->begin();
6646 const double *coor=_coords->begin();
6647 for(const mcIdType *w=begin;w!=end;w++)
6649 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[*w]];
6650 INTERP_KERNEL::computeBarycenter2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[*w]+1,nodalI[*w+1]-nodalI[*w]-1,coor,spaceDim,ptToFill);
6658 * 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".
6659 * So the returned instance will have 4 components and \c this->getNumberOfCells() tuples.
6660 * So this method expects that \a this has a spaceDimension equal to 3 and meshDimension equal to 2.
6661 * The computation of the plane equation is done using each time the 3 first nodes of 2D cells.
6662 * This method is useful to detect 2D cells in 3D space that are not coplanar.
6664 * \return DataArrayDouble * - a new instance of DataArrayDouble having 4 components and a number of tuples equal to number of cells in \a this.
6665 * \throw If spaceDim!=3 or meshDim!=2.
6666 * \throw If connectivity of \a this is invalid.
6667 * \throw If connectivity of a cell in \a this points to an invalid node.
6669 DataArrayDouble *MEDCouplingUMesh::computePlaneEquationOf3DFaces() const
6671 MCAuto<DataArrayDouble> ret(DataArrayDouble::New());
6672 mcIdType nbOfCells=getNumberOfCells();
6673 mcIdType nbOfNodes(getNumberOfNodes());
6674 if(getSpaceDimension()!=3 || getMeshDimension()!=2)
6675 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computePlaneEquationOf3DFaces : This method must be applied on a mesh having meshDimension equal 2 and a spaceDimension equal to 3 !");
6676 ret->alloc(nbOfCells,4);
6677 double *retPtr(ret->getPointer());
6678 const mcIdType *nodal(_nodal_connec->begin()),*nodalI(_nodal_connec_index->begin());
6679 const double *coor(_coords->begin());
6680 for(mcIdType i=0;i<nbOfCells;i++,nodalI++,retPtr+=4)
6682 double matrix[16]={0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,0},matrix2[16];
6683 if(nodalI[1]-nodalI[0]>=4)
6685 double aa[3]={coor[nodal[nodalI[0]+1+1]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6686 coor[nodal[nodalI[0]+1+1]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6687 coor[nodal[nodalI[0]+1+1]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]}
6688 ,bb[3]={coor[nodal[nodalI[0]+1+2]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6689 coor[nodal[nodalI[0]+1+2]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6690 coor[nodal[nodalI[0]+1+2]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]};
6691 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]};
6692 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]));
6693 for(int j=0;j<3;j++)
6695 mcIdType nodeId(nodal[nodalI[0]+1+j]);
6696 if(nodeId>=0 && nodeId<nbOfNodes)
6697 std::copy(coor+nodeId*3,coor+(nodeId+1)*3,matrix+4*j);
6700 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! This cell points to an invalid nodeId : " << nodeId << " !";
6701 throw INTERP_KERNEL::Exception(oss.str());
6704 if(sqrt(cc[0]*cc[0]+cc[1]*cc[1]+cc[2]*cc[2])>(1e-3*aa_norm*bb_norm))
6706 INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6707 retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6711 if(nodalI[1]-nodalI[0]==4)
6713 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : cell" << i << " : Presence of The 3 colinear points !";
6714 throw INTERP_KERNEL::Exception(oss.str());
6717 double dd[3]={0.,0.,0.};
6718 for(mcIdType offset=nodalI[0]+1;offset<nodalI[1];offset++)
6719 std::transform(coor+3*nodal[offset],coor+3*(nodal[offset]+1),dd,dd,std::plus<double>());
6720 mcIdType nbOfNodesInCell(nodalI[1]-nodalI[0]-1);
6721 std::transform(dd,dd+3,dd,std::bind(std::multiplies<double>(),std::placeholders::_1,1./(double)nbOfNodesInCell));
6722 std::copy(dd,dd+3,matrix+4*2);
6723 INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6724 retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6729 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! Must be constitued by more than 3 nodes !";
6730 throw INTERP_KERNEL::Exception(oss.str());
6737 * This method expects as input a DataArrayDouble non nul instance 'da' that should be allocated. If not an exception is thrown.
6740 MEDCouplingUMesh *MEDCouplingUMesh::Build0DMeshFromCoords(DataArrayDouble *da)
6743 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build0DMeshFromCoords : instance of DataArrayDouble must be not null !");
6744 da->checkAllocated();
6745 std::string name(da->getName());
6746 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New(name,0));
6748 ret->setName("Mesh");
6750 mcIdType nbOfTuples(da->getNumberOfTuples());
6751 MCAuto<DataArrayIdType> c(DataArrayIdType::New()),cI(DataArrayIdType::New());
6752 c->alloc(2*nbOfTuples,1);
6753 cI->alloc(nbOfTuples+1,1);
6754 mcIdType *cp(c->getPointer()),*cip(cI->getPointer());
6756 for(mcIdType i=0;i<nbOfTuples;i++)
6758 *cp++=INTERP_KERNEL::NORM_POINT1;
6762 ret->setConnectivity(c,cI,true);
6766 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::Build1DMeshFromCoords(DataArrayDouble *da)
6769 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build01MeshFromCoords : instance of DataArrayDouble must be not null !");
6770 da->checkAllocated();
6771 std::string name(da->getName());
6772 MCAuto<MEDCouplingUMesh> ret;
6774 MCAuto<MEDCouplingCMesh> tmp(MEDCouplingCMesh::New());
6775 MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
6776 arr->alloc(da->getNumberOfTuples());
6777 tmp->setCoordsAt(0,arr);
6778 ret=tmp->buildUnstructured();
6782 ret->setName("Mesh");
6789 * Creates a new MEDCouplingUMesh by concatenating two given meshes of the same dimension.
6790 * Cells and nodes of
6791 * the first mesh precede cells and nodes of the second mesh within the result mesh.
6792 * \param [in] mesh1 - the first mesh.
6793 * \param [in] mesh2 - the second mesh.
6794 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6795 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6796 * is no more needed.
6797 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
6798 * \throw If the coordinates array is not set in none of the meshes.
6799 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
6800 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
6802 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
6804 std::vector<const MEDCouplingUMesh *> tmp(2);
6805 tmp[0]=const_cast<MEDCouplingUMesh *>(mesh1); tmp[1]=const_cast<MEDCouplingUMesh *>(mesh2);
6806 return MergeUMeshes(tmp);
6810 * Creates a new MEDCouplingUMesh by concatenating all given meshes of the same dimension.
6811 * Cells and nodes of
6812 * the *i*-th mesh precede cells and nodes of the (*i*+1)-th mesh within the result mesh.
6813 * \param [in] a - a vector of meshes (MEDCouplingUMesh) to concatenate.
6814 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6815 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6816 * is no more needed.
6817 * \throw If \a a.size() == 0.
6818 * \throw If \a a[ *i* ] == NULL.
6819 * \throw If the coordinates array is not set in none of the meshes.
6820 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
6821 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
6823 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const std::vector<const MEDCouplingUMesh *>& a)
6825 std::size_t sz=a.size();
6827 return MergeUMeshesLL(a);
6828 for(std::size_t ii=0;ii<sz;ii++)
6831 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshes : item #" << ii << " in input array of size "<< sz << " is empty !";
6832 throw INTERP_KERNEL::Exception(oss.str());
6834 std::vector< MCAuto<MEDCouplingUMesh> > bb(sz);
6835 std::vector< const MEDCouplingUMesh * > aa(sz);
6837 for(std::size_t i=0;i<sz && spaceDim==-3;i++)
6839 const MEDCouplingUMesh *cur=a[i];
6840 const DataArrayDouble *coo=cur->getCoords();
6842 spaceDim=int(coo->getNumberOfComponents());
6845 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : no spaceDim specified ! unable to perform merge !");
6846 for(std::size_t i=0;i<sz;i++)
6848 bb[i]=a[i]->buildSetInstanceFromThis(spaceDim);
6851 return MergeUMeshesLL(aa);
6855 * Creates a new MEDCouplingUMesh by concatenating cells of two given meshes of same
6856 * dimension and sharing the node coordinates array.
6857 * All cells of the first mesh precede all cells of the second mesh
6858 * within the result mesh.
6859 * \param [in] mesh1 - the first mesh.
6860 * \param [in] mesh2 - the second mesh.
6861 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6862 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6863 * is no more needed.
6864 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
6865 * \throw If the meshes do not share the node coordinates array.
6866 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
6867 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
6869 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
6871 std::vector<const MEDCouplingUMesh *> tmp(2);
6872 tmp[0]=mesh1; tmp[1]=mesh2;
6873 return MergeUMeshesOnSameCoords(tmp);
6877 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
6878 * dimension and sharing the node coordinates array.
6879 * All cells of the *i*-th mesh precede all cells of the
6880 * (*i*+1)-th mesh within the result mesh.
6881 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
6882 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6883 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6884 * is no more needed.
6885 * \throw If \a a.size() == 0.
6886 * \throw If \a a[ *i* ] == NULL.
6887 * \throw If the meshes do not share the node coordinates array.
6888 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
6889 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
6891 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes)
6894 throw INTERP_KERNEL::Exception("meshes input parameter is expected to be non empty.");
6895 for(std::size_t ii=0;ii<meshes.size();ii++)
6898 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshesOnSameCoords : item #" << ii << " in input array of size "<< meshes.size() << " is empty !";
6899 throw INTERP_KERNEL::Exception(oss.str());
6901 const DataArrayDouble *coords=meshes.front()->getCoords();
6902 int meshDim=meshes.front()->getMeshDimension();
6903 std::vector<const MEDCouplingUMesh *>::const_iterator iter=meshes.begin();
6904 mcIdType meshLgth=0;
6905 mcIdType meshIndexLgth=0;
6906 for(;iter!=meshes.end();iter++)
6908 if(coords!=(*iter)->getCoords())
6909 throw INTERP_KERNEL::Exception("meshes does not share the same coords ! Try using tryToShareSameCoords method !");
6910 if(meshDim!=(*iter)->getMeshDimension())
6911 throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, FuseUMeshesOnSameCoords impossible !");
6912 meshLgth+=(*iter)->getNodalConnectivityArrayLen();
6913 meshIndexLgth+=(*iter)->getNumberOfCells();
6915 MCAuto<DataArrayIdType> nodal=DataArrayIdType::New();
6916 nodal->alloc(meshLgth,1);
6917 mcIdType *nodalPtr=nodal->getPointer();
6918 MCAuto<DataArrayIdType> nodalIndex=DataArrayIdType::New();
6919 nodalIndex->alloc(meshIndexLgth+1,1);
6920 mcIdType *nodalIndexPtr=nodalIndex->getPointer();
6922 for(iter=meshes.begin();iter!=meshes.end();iter++)
6924 const mcIdType *nod=(*iter)->getNodalConnectivity()->begin();
6925 const mcIdType *index=(*iter)->getNodalConnectivityIndex()->begin();
6926 mcIdType nbOfCells=(*iter)->getNumberOfCells();
6927 mcIdType meshLgth2=(*iter)->getNodalConnectivityArrayLen();
6928 nodalPtr=std::copy(nod,nod+meshLgth2,nodalPtr);
6929 if(iter!=meshes.begin())
6930 nodalIndexPtr=std::transform(index+1,index+nbOfCells+1,nodalIndexPtr,std::bind(std::plus<mcIdType>(),std::placeholders::_1,offset));
6932 nodalIndexPtr=std::copy(index,index+nbOfCells+1,nodalIndexPtr);
6935 MEDCouplingUMesh *ret=MEDCouplingUMesh::New();
6936 ret->setName("merge");
6937 ret->setMeshDimension(meshDim);
6938 ret->setConnectivity(nodal,nodalIndex,true);
6939 ret->setCoords(coords);
6944 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
6945 * dimension and sharing the node coordinates array. Cells of the *i*-th mesh precede
6946 * cells of the (*i*+1)-th mesh within the result mesh. Duplicates of cells are
6947 * removed from \a this mesh and arrays mapping between new and old cell ids in "Old to
6948 * New" mode are returned for each input mesh.
6949 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
6950 * \param [in] compType - specifies a cell comparison technique. For meaning of its
6951 * valid values [0,1,2], see zipConnectivityTraducer().
6952 * \param [in,out] corr - an array of DataArrayIdType, of the same size as \a
6953 * meshes. The *i*-th array describes cell ids mapping for \a meshes[ *i* ]
6954 * mesh. The caller is to delete each of the arrays using decrRef() as it is
6956 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6957 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6958 * is no more needed.
6959 * \throw If \a meshes.size() == 0.
6960 * \throw If \a meshes[ *i* ] == NULL.
6961 * \throw If the meshes do not share the node coordinates array.
6962 * \throw If \a meshes[ *i* ]->getMeshDimension() < 0.
6963 * \throw If the \a meshes are of different dimension (getMeshDimension()).
6964 * \throw If the nodal connectivity of cells of any of \a meshes is not defined.
6965 * \throw If the nodal connectivity any of \a meshes includes an invalid id.
6967 MEDCouplingUMesh *MEDCouplingUMesh::FuseUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes, int compType, std::vector<DataArrayIdType *>& corr)
6969 //All checks are delegated to MergeUMeshesOnSameCoords
6970 MCAuto<MEDCouplingUMesh> ret=MergeUMeshesOnSameCoords(meshes);
6971 MCAuto<DataArrayIdType> o2n=ret->zipConnectivityTraducer(compType);
6972 corr.resize(meshes.size());
6973 std::size_t nbOfMeshes=meshes.size();
6975 const mcIdType *o2nPtr=o2n->begin();
6976 for(std::size_t i=0;i<nbOfMeshes;i++)
6978 DataArrayIdType *tmp=DataArrayIdType::New();
6979 mcIdType curNbOfCells=meshes[i]->getNumberOfCells();
6980 tmp->alloc(curNbOfCells,1);
6981 std::copy(o2nPtr+offset,o2nPtr+offset+curNbOfCells,tmp->getPointer());
6982 offset+=curNbOfCells;
6983 tmp->setName(meshes[i]->getName());
6990 * Makes all given meshes share the nodal connectivity array. The common connectivity
6991 * array is created by concatenating the connectivity arrays of all given meshes. All
6992 * the given meshes must be of the same space dimension but dimension of cells **can
6993 * differ**. This method is particularly useful in MEDLoader context to build a \ref
6994 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
6995 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
6996 * \param [in,out] meshes - a vector of meshes to update.
6997 * \throw If any of \a meshes is NULL.
6998 * \throw If the coordinates array is not set in any of \a meshes.
6999 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
7000 * \throw If \a meshes are of different space dimension.
7002 void MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords(const std::vector<MEDCouplingUMesh *>& meshes)
7004 std::size_t sz=meshes.size();
7007 std::vector< const DataArrayDouble * > coords(meshes.size());
7008 std::vector< const DataArrayDouble * >::iterator it2=coords.begin();
7009 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++,it2++)
7013 (*it)->checkConnectivityFullyDefined();
7014 const DataArrayDouble *coo=(*it)->getCoords();
7019 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
7020 oss << " has no coordinate array defined !";
7021 throw INTERP_KERNEL::Exception(oss.str());
7026 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
7027 oss << " is null !";
7028 throw INTERP_KERNEL::Exception(oss.str());
7031 MCAuto<DataArrayDouble> res=DataArrayDouble::Aggregate(coords);
7032 std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();
7033 mcIdType offset=(*it)->getNumberOfNodes();
7034 (*it++)->setCoords(res);
7035 for(;it!=meshes.end();it++)
7037 mcIdType oldNumberOfNodes=(*it)->getNumberOfNodes();
7038 (*it)->setCoords(res);
7039 (*it)->shiftNodeNumbersInConn(offset);
7040 offset+=oldNumberOfNodes;
7045 * Merges nodes coincident with a given precision within all given meshes that share
7046 * the nodal connectivity array. The given meshes **can be of different** mesh
7047 * dimension. This method is particularly useful in MEDLoader context to build a \ref
7048 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
7049 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
7050 * \param [in,out] meshes - a vector of meshes to update.
7051 * \param [in] eps - the precision used to detect coincident nodes (infinite norm).
7052 * \throw If any of \a meshes is NULL.
7053 * \throw If the \a meshes do not share the same node coordinates array.
7054 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
7056 void MEDCouplingUMesh::MergeNodesOnUMeshesSharingSameCoords(const std::vector<MEDCouplingUMesh *>& meshes, double eps)
7060 std::set<const DataArrayDouble *> s;
7061 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
7064 s.insert((*it)->getCoords());
7067 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 !";
7068 throw INTERP_KERNEL::Exception(oss.str());
7073 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 !";
7074 throw INTERP_KERNEL::Exception(oss.str());
7076 const DataArrayDouble *coo=*(s.begin());
7080 DataArrayIdType *comm,*commI;
7081 coo->findCommonTuples(eps,-1,comm,commI);
7082 MCAuto<DataArrayIdType> tmp1(comm),tmp2(commI);
7083 mcIdType oldNbOfNodes=coo->getNumberOfTuples();
7084 mcIdType newNbOfNodes;
7085 MCAuto<DataArrayIdType> o2n=DataArrayIdType::ConvertIndexArrayToO2N(oldNbOfNodes,comm->begin(),commI->begin(),commI->end(),newNbOfNodes);
7086 if(oldNbOfNodes==newNbOfNodes)
7088 MCAuto<DataArrayDouble> newCoords=coo->renumberAndReduce(o2n->begin(),newNbOfNodes);
7089 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
7091 (*it)->renumberNodesInConn(o2n->begin());
7092 (*it)->setCoords(newCoords);
7098 * This static operates only for coords in 3D. The polygon is specified by its connectivity nodes in [ \a begin , \a end ).
7100 bool MEDCouplingUMesh::IsPolygonWellOriented(bool isQuadratic, const double *vec, const mcIdType *begin, const mcIdType *end, const double *coords)
7103 double v[3]={0.,0.,0.};
7104 std::size_t sz=std::distance(begin,end);
7108 // Algorithm: sum in v the cross products of (e1, e2) where e_i it the vector between (0,0,0) and point i
7109 // and e2 is linear point directly following e1 in the connectivity. All points are used.
7110 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];
7111 v[1]+=coords[3*begin[i]+2]*coords[3*begin[(i+1)%sz]]-coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+2];
7112 v[2]+=coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+1]-coords[3*begin[i]+1]*coords[3*begin[(i+1)%sz]];
7116 // Same algorithm as above but also using intermediate quadratic points.
7117 // (taking only linear points might lead to issues if the linearized version of the
7118 // polygon is not convex or self-intersecting ... see testCellOrientation4)
7119 std::size_t hsz = sz/2;
7120 for(std::size_t j=0;j<sz;j++)
7122 if (j%2) // current point i is quadratic, next point i+1 is standard
7125 ip1 = ((j-1)/2 + 1)%hsz; // ip1 means "i+1", i.e. next point
7127 else // current point i is standard, next point i+1 is quadratic
7132 v[0]+=coords[3*begin[i]+1]*coords[3*begin[ip1]+2]-coords[3*begin[i]+2]*coords[3*begin[ip1]+1];
7133 v[1]+=coords[3*begin[i]+2]*coords[3*begin[ip1]]-coords[3*begin[i]]*coords[3*begin[ip1]+2];
7134 v[2]+=coords[3*begin[i]]*coords[3*begin[ip1]+1]-coords[3*begin[i]+1]*coords[3*begin[ip1]];
7137 double ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
7142 * The polyhedron is specified by its connectivity nodes in [ \a begin , \a end ).
7144 bool MEDCouplingUMesh::IsPolyhedronWellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7146 std::vector<std::pair<mcIdType,mcIdType> > edges;
7147 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
7148 const mcIdType *bgFace=begin;
7149 for(std::size_t i=0;i<nbOfFaces;i++)
7151 const mcIdType *endFace=std::find(bgFace+1,end,-1);
7152 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
7153 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7155 std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7156 if(std::find(edges.begin(),edges.end(),p1)!=edges.end())
7158 edges.push_back(p1);
7162 return INTERP_KERNEL::calculateVolumeForPolyh2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,ToIdType(std::distance(begin,end)),coords)>-EPS_FOR_POLYH_ORIENTATION;
7166 * The 3D extruded static cell (PENTA6,HEXA8,HEXAGP12...) its connectivity nodes in [ \a begin , \a end ).
7168 bool MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7170 double vec0[3],vec1[3];
7171 std::size_t sz=std::distance(begin,end);
7173 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented : the length of nodal connectivity of extruded cell is not even !");
7174 mcIdType nbOfNodes=ToIdType(sz/2);
7175 INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,nbOfNodes,coords,vec0);
7176 const double *pt0=coords+3*begin[0];
7177 const double *pt1=coords+3*begin[nbOfNodes];
7178 vec1[0]=pt1[0]-pt0[0]; vec1[1]=pt1[1]-pt0[1]; vec1[2]=pt1[2]-pt0[2];
7179 return (vec0[0]*vec1[0]+vec0[1]*vec1[1]+vec0[2]*vec1[2])<0.;
7182 void MEDCouplingUMesh::CorrectExtrudedStaticCell(mcIdType *begin, mcIdType *end)
7184 std::size_t sz=std::distance(begin,end);
7185 INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz];
7186 std::size_t nbOfNodes(sz/2);
7187 std::copy(begin,end,(mcIdType *)tmp);
7188 for(std::size_t j=1;j<nbOfNodes;j++)
7190 begin[j]=tmp[nbOfNodes-j];
7191 begin[j+nbOfNodes]=tmp[nbOfNodes+nbOfNodes-j];
7195 bool MEDCouplingUMesh::IsTetra4WellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7197 std::size_t sz=std::distance(begin,end);
7199 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsTetra4WellOriented : Tetra4 cell with not 4 nodes ! Call checkConsistency !");
7200 double vec0[3],vec1[3];
7201 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[1],*pt2=coords+3*begin[2],*pt3=coords+3*begin[3];
7202 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];
7203 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;
7206 bool MEDCouplingUMesh::IsPyra5WellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7208 std::size_t sz=std::distance(begin,end);
7210 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsPyra5WellOriented : Pyra5 cell with not 5 nodes ! Call checkConsistency !");
7212 INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,4,coords,vec0);
7213 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[4];
7214 return (vec0[0]*(pt1[0]-pt0[0])+vec0[1]*(pt1[1]-pt0[1])+vec0[2]*(pt1[2]-pt0[2]))<0.;
7218 * 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 )
7219 * 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
7222 * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not.
7223 * \param [in] coords the coordinates with nb of components exactly equal to 3
7224 * \param [in] index begin of the nodal connectivity (geometric type included) of a single polyhedron cell
7225 * \param [out] res the result is put at the end of the vector without any alteration of the data.
7227 void MEDCouplingUMesh::SimplifyPolyhedronCell(double eps, const DataArrayDouble *coords, mcIdType index, DataArrayIdType *res, MEDCouplingUMesh *faces,
7228 DataArrayIdType *E_Fi, DataArrayIdType *E_F, DataArrayIdType *F_Ei, DataArrayIdType *F_E)
7230 mcIdType nbFaces = E_Fi->getIJ(index + 1, 0) - E_Fi->getIJ(index, 0);
7231 MCAuto<DataArrayDouble> v=DataArrayDouble::New(); v->alloc(nbFaces,3);
7232 double *vPtr=v->getPointer();
7233 MCAuto<DataArrayDouble> p=DataArrayDouble::New(); p->alloc(nbFaces,2);
7234 double *pPtr=p->getPointer();
7235 mcIdType *e_fi = E_Fi->getPointer(), *e_f = E_F->getPointer(), *f_ei = F_Ei->getPointer(), *f_e = F_E->getPointer();
7236 const mcIdType *f_idx = faces->getNodalConnectivityIndex()->getPointer(), *f_cnn = faces->getNodalConnectivity()->getPointer();
7237 for(mcIdType i=0;i<nbFaces;i++,vPtr+=3,pPtr++)
7239 mcIdType face = e_f[e_fi[index] + i];
7240 ComputeVecAndPtOfFace(eps, coords->begin(), f_cnn + f_idx[face] + 1, f_cnn + f_idx[face + 1], vPtr, pPtr);
7241 // to differentiate faces going to different cells:
7243 for (mcIdType j = f_ei[face]; j < f_ei[face + 1]; j++)
7244 *pPtr += FromIdType<double>(f_e[j]);
7246 pPtr=p->getPointer(); vPtr=v->getPointer();
7247 DataArrayIdType *comm1=0,*commI1=0;
7248 v->findCommonTuples(eps,-1,comm1,commI1);
7249 for (mcIdType i = 0; i < nbFaces; i++)
7250 if (comm1->findIdFirstEqual(i) < 0)
7252 comm1->pushBackSilent(i);
7253 commI1->pushBackSilent(comm1->getNumberOfTuples());
7255 MCAuto<DataArrayIdType> comm1Auto(comm1),commI1Auto(commI1);
7256 const mcIdType *comm1Ptr=comm1->begin();
7257 const mcIdType *commI1Ptr=commI1->begin();
7258 mcIdType nbOfGrps1=commI1Auto->getNumberOfTuples()-1;
7259 res->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYHED));
7261 for(mcIdType i=0;i<nbOfGrps1;i++)
7263 mcIdType vecId=comm1Ptr[commI1Ptr[i]];
7264 MCAuto<DataArrayDouble> tmpgrp2=p->selectByTupleId(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7265 DataArrayIdType *comm2=0,*commI2=0;
7266 tmpgrp2->findCommonTuples(eps,-1,comm2,commI2);
7267 for (mcIdType j = 0; j < commI1Ptr[i+1] - commI1Ptr[i]; j++)
7268 if (comm2->findIdFirstEqual(j) < 0)
7270 comm2->pushBackSilent(j);
7271 commI2->pushBackSilent(comm2->getNumberOfTuples());
7273 MCAuto<DataArrayIdType> comm2Auto(comm2),commI2Auto(commI2);
7274 const mcIdType *comm2Ptr=comm2->begin();
7275 const mcIdType *commI2Ptr=commI2->begin();
7276 mcIdType nbOfGrps2=commI2Auto->getNumberOfTuples()-1;
7277 for(mcIdType j=0;j<nbOfGrps2;j++)
7279 if(commI2Ptr[j+1] == commI2Ptr[j] + 1)
7281 mcIdType face = e_f[e_fi[index] + comm1Ptr[commI1Ptr[i] + comm2Ptr[commI2Ptr[j]]]]; //hmmm
7282 res->insertAtTheEnd(f_cnn + f_idx[face] + 1, f_cnn + f_idx[face + 1]);
7283 res->pushBackSilent(-1);
7287 mcIdType pointId=comm1Ptr[commI1Ptr[i]+comm2Ptr[commI2Ptr[j]]];
7288 MCAuto<DataArrayIdType> ids2=comm2->selectByTupleIdSafeSlice(commI2Ptr[j],commI2Ptr[j+1],1);
7289 ids2->transformWithIndArr(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7290 ids2->transformWithIndArr(e_f + e_fi[index], e_f + e_fi[index + 1]);
7291 MCAuto<MEDCouplingUMesh> mm3=static_cast<MEDCouplingUMesh *>(faces->buildPartOfMySelf(ids2->begin(),ids2->end(),true));
7292 MCAuto<DataArrayIdType> idsNodeTmp=mm3->zipCoordsTraducer();
7293 MCAuto<DataArrayIdType> idsNode=idsNodeTmp->invertArrayO2N2N2O(mm3->getNumberOfNodes());
7294 const mcIdType *idsNodePtr=idsNode->begin();
7295 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];
7296 double vec[3]; vec[0]=vPtr[3*vecId+1]; vec[1]=-vPtr[3*vecId]; vec[2]=0.;
7297 double norm=vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2];
7298 if(std::abs(norm)>eps)
7300 double angle=INTERP_KERNEL::EdgeArcCircle::SafeAsin(norm);
7301 mm3->rotate(center,vec,angle);
7303 mm3->changeSpaceDimension(2);
7304 MCAuto<MEDCouplingUMesh> mm4=mm3->buildSpreadZonesWithPoly();
7305 const mcIdType *conn4=mm4->getNodalConnectivity()->begin();
7306 const mcIdType *connI4=mm4->getNodalConnectivityIndex()->begin();
7307 mcIdType nbOfCells=mm4->getNumberOfCells();
7308 for(mcIdType k=0;k<nbOfCells;k++)
7311 for(const mcIdType *work=conn4+connI4[k]+1;work!=conn4+connI4[k+1];work++,l++)
7312 res->pushBackSilent(idsNodePtr[*work]);
7313 res->pushBackSilent(-1);
7318 res->popBackSilent();
7322 * 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
7323 * through origin. The plane is defined by its nodal connectivity [ \b begin, \b end ).
7325 * \param [in] eps below that value the dot product of 2 vectors is considered as colinears
7326 * \param [in] coords coordinates expected to have 3 components.
7327 * \param [in] begin start of the nodal connectivity of the face.
7328 * \param [in] end end of the nodal connectivity (excluded) of the face.
7329 * \param [out] v the normalized vector of size 3
7330 * \param [out] p the pos of plane
7332 void MEDCouplingUMesh::ComputeVecAndPtOfFace(double eps, const double *coords, const mcIdType *begin, const mcIdType *end, double *v, double *p)
7334 std::size_t nbPoints=std::distance(begin,end);
7336 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeVecAndPtOfFace : < of 3 points in face ! not able to find a plane on that face !");
7337 double vec[3]={0.,0.,0.};
7339 bool refFound=false;
7340 for(;j<nbPoints-1 && !refFound;j++)
7342 vec[0]=coords[3*begin[j+1]]-coords[3*begin[j]];
7343 vec[1]=coords[3*begin[j+1]+1]-coords[3*begin[j]+1];
7344 vec[2]=coords[3*begin[j+1]+2]-coords[3*begin[j]+2];
7345 double norm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
7349 vec[0]/=norm; vec[1]/=norm; vec[2]/=norm;
7352 for(std::size_t i=j;i<nbPoints-1;i++)
7355 curVec[0]=coords[3*begin[i+1]]-coords[3*begin[i]];
7356 curVec[1]=coords[3*begin[i+1]+1]-coords[3*begin[i]+1];
7357 curVec[2]=coords[3*begin[i+1]+2]-coords[3*begin[i]+2];
7358 double norm=sqrt(curVec[0]*curVec[0]+curVec[1]*curVec[1]+curVec[2]*curVec[2]);
7361 curVec[0]/=norm; curVec[1]/=norm; curVec[2]/=norm;
7362 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];
7363 norm=sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
7366 v[0]/=norm; v[1]/=norm; v[2]/=norm;
7367 *p=v[0]*coords[3*begin[i]]+v[1]*coords[3*begin[i]+1]+v[2]*coords[3*begin[i]+2];
7371 throw INTERP_KERNEL::Exception("Not able to find a normal vector of that 3D face !");
7375 * This method tries to obtain a well oriented polyhedron.
7376 * If the algorithm fails, an exception will be thrown.
7378 void MEDCouplingUMesh::TryToCorrectPolyhedronOrientation(mcIdType *begin, mcIdType *end, const double *coords)
7380 std::list< std::pair<mcIdType,mcIdType> > edgesOK,edgesFinished;
7381 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
7382 std::vector<bool> isPerm(nbOfFaces,false);//field on faces False: I don't know, True : oriented
7384 mcIdType *bgFace=begin,*endFace=std::find(begin+1,end,-1);
7385 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
7386 for(std::size_t l=0;l<nbOfEdgesInFace;l++) { std::pair<mcIdType,mcIdType> p1(bgFace[l],bgFace[(l+1)%nbOfEdgesInFace]); edgesOK.push_back(p1); }
7388 while(std::find(isPerm.begin(),isPerm.end(),false)!=isPerm.end())
7391 std::size_t smthChanged=0;
7392 for(std::size_t i=0;i<nbOfFaces;i++)
7394 endFace=std::find(bgFace+1,end,-1);
7395 nbOfEdgesInFace=std::distance(bgFace,endFace);
7399 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7401 std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7402 std::pair<mcIdType,mcIdType> p2(p1.second,p1.first);
7403 bool b1=std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end();
7404 bool b2=std::find(edgesOK.begin(),edgesOK.end(),p2)!=edgesOK.end();
7405 if(b1 || b2) { b=b2; isPerm[i]=true; smthChanged++; break; }
7410 std::reverse(bgFace+1,endFace);
7411 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7413 std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7414 std::pair<mcIdType,mcIdType> p2(p1.second,p1.first);
7415 if(std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end())
7416 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7417 if(std::find(edgesFinished.begin(),edgesFinished.end(),p1)!=edgesFinished.end() || std::find(edgesFinished.begin(),edgesFinished.end(),p2)!=edgesFinished.end())
7418 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7419 std::list< std::pair<mcIdType,mcIdType> >::iterator it=std::find(edgesOK.begin(),edgesOK.end(),p2);
7420 if(it!=edgesOK.end())
7423 edgesFinished.push_back(p1);
7426 edgesOK.push_back(p1);
7433 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired !"); }
7435 if(!edgesOK.empty())
7436 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired : Some edges are shared only once !"); }
7437 if(INTERP_KERNEL::calculateVolumeForPolyh2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,ToIdType(std::distance(begin,end)),coords)<-EPS_FOR_POLYH_ORIENTATION)
7438 {//not lucky ! The first face was not correctly oriented : reorient all faces...
7440 for(std::size_t i=0;i<nbOfFaces;i++)
7442 endFace=std::find(bgFace+1,end,-1);
7443 std::reverse(bgFace+1,endFace);
7451 * This method makes the assumption spacedimension == meshdimension == 2.
7452 * This method works only for linear cells.
7454 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYGON in pos#0)
7456 DataArrayIdType *MEDCouplingUMesh::buildUnionOf2DMesh() const
7458 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
7459 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : meshdimension, spacedimension must be equal to 2 !");
7460 MCAuto<MEDCouplingUMesh> skin(computeSkin());
7461 mcIdType oldNbOfNodes(skin->getNumberOfNodes());
7462 MCAuto<DataArrayIdType> o2n(skin->zipCoordsTraducer());
7463 mcIdType nbOfNodesExpected(skin->getNumberOfNodes());
7464 MCAuto<DataArrayIdType> n2o(o2n->invertArrayO2N2N2O(oldNbOfNodes));
7465 mcIdType nbCells=skin->getNumberOfCells();
7466 if(nbCells==nbOfNodesExpected)
7467 return buildUnionOf2DMeshLinear(skin,n2o);
7468 else if(2*nbCells==nbOfNodesExpected)
7469 return buildUnionOf2DMeshQuadratic(skin,n2o);
7471 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : the mesh 2D in input appears to be not in a single part of a 2D mesh !");
7475 * This method makes the assumption spacedimension == meshdimension == 3.
7476 * This method works only for linear cells.
7478 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYHED in pos#0)
7480 DataArrayIdType *MEDCouplingUMesh::buildUnionOf3DMesh() const
7482 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
7483 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf3DMesh : meshdimension, spacedimension must be equal to 2 !");
7484 MCAuto<MEDCouplingUMesh> m=computeSkin();
7485 const mcIdType *conn=m->getNodalConnectivity()->begin();
7486 const mcIdType *connI=m->getNodalConnectivityIndex()->begin();
7487 mcIdType nbOfCells=m->getNumberOfCells();
7488 MCAuto<DataArrayIdType> ret=DataArrayIdType::New(); ret->alloc(m->getNodalConnectivity()->getNumberOfTuples(),1);
7489 mcIdType *work=ret->getPointer(); *work++=INTERP_KERNEL::NORM_POLYHED;
7492 work=std::copy(conn+connI[0]+1,conn+connI[1],work);
7493 for(mcIdType i=1;i<nbOfCells;i++)
7496 work=std::copy(conn+connI[i]+1,conn+connI[i+1],work);
7502 * \brief Creates a graph of cell neighbors
7503 * \return MEDCouplingSkyLineArray * - an sky line array the user should delete.
7504 * In the sky line array, graph arcs are stored in terms of (index,value) notation.
7506 * - index: 0 3 5 6 6
7507 * - value: 1 2 3 2 3 3
7508 * means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7509 * Arcs are not doubled but reflexive (1,1) arcs are present for each cell
7511 MEDCouplingSkyLineArray* MEDCouplingUMesh::generateGraph() const
7513 checkConnectivityFullyDefined();
7515 int meshDim = this->getMeshDimension();
7516 MEDCoupling::DataArrayIdType* indexr=MEDCoupling::DataArrayIdType::New();
7517 MEDCoupling::DataArrayIdType* revConn=MEDCoupling::DataArrayIdType::New();
7518 this->getReverseNodalConnectivity(revConn,indexr);
7519 const mcIdType* indexr_ptr=indexr->begin();
7520 const mcIdType* revConn_ptr=revConn->begin();
7522 const MEDCoupling::DataArrayIdType* index;
7523 const MEDCoupling::DataArrayIdType* conn;
7524 conn=this->getNodalConnectivity(); // it includes a type as the 1st element!!!
7525 index=this->getNodalConnectivityIndex();
7526 mcIdType nbCells=this->getNumberOfCells();
7527 const mcIdType* index_ptr=index->begin();
7528 const mcIdType* conn_ptr=conn->begin();
7530 //creating graph arcs (cell to cell relations)
7531 //arcs are stored in terms of (index,value) notation
7534 // means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7535 // in present version arcs are not doubled but reflexive (1,1) arcs are present for each cell
7537 //warning here one node have less than or equal effective number of cell with it
7538 //but cell could have more than effective nodes
7539 //because other equals nodes in other domain (with other global inode)
7540 std::vector <mcIdType> cell2cell_index(nbCells+1,0);
7541 std::vector <mcIdType> cell2cell;
7542 cell2cell.reserve(3*nbCells);
7544 for (mcIdType icell=0; icell<nbCells;icell++)
7546 std::map<mcIdType,mcIdType > counter;
7547 for (mcIdType iconn=index_ptr[icell]+1; iconn<index_ptr[icell+1];iconn++)
7549 mcIdType inode=conn_ptr[iconn];
7550 for (mcIdType iconnr=indexr_ptr[inode]; iconnr<indexr_ptr[inode+1];iconnr++)
7552 mcIdType icell2=revConn_ptr[iconnr];
7553 std::map<mcIdType,mcIdType>::iterator iter=counter.find(icell2);
7554 if (iter!=counter.end()) (iter->second)++;
7555 else counter.insert(std::make_pair(icell2,1));
7558 for (std::map<mcIdType,mcIdType>::const_iterator iter=counter.begin();
7559 iter!=counter.end(); iter++)
7560 if (iter->second >= meshDim)
7562 cell2cell_index[icell+1]++;
7563 cell2cell.push_back(iter->first);
7568 cell2cell_index[0]=0;
7569 for (mcIdType icell=0; icell<nbCells;icell++)
7570 cell2cell_index[icell+1]=cell2cell_index[icell]+cell2cell_index[icell+1];
7572 //filling up index and value to create skylinearray structure
7573 MEDCouplingSkyLineArray * array(MEDCouplingSkyLineArray::New(cell2cell_index,cell2cell));
7578 void MEDCouplingUMesh::writeVTKLL(std::ostream& ofs, const std::string& cellData, const std::string& pointData, DataArrayByte *byteData) const
7580 mcIdType nbOfCells=getNumberOfCells();
7582 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::writeVTK : the unstructured mesh has no cells !");
7583 ofs << " <" << getVTKDataSetType() << ">\n";
7584 ofs << " <Piece NumberOfPoints=\"" << getNumberOfNodes() << "\" NumberOfCells=\"" << nbOfCells << "\">\n";
7585 ofs << " <PointData>\n" << pointData << std::endl;
7586 ofs << " </PointData>\n";
7587 ofs << " <CellData>\n" << cellData << std::endl;
7588 ofs << " </CellData>\n";
7589 ofs << " <Points>\n";
7590 if(getSpaceDimension()==3)
7591 _coords->writeVTK(ofs,8,"Points",byteData);
7594 MCAuto<DataArrayDouble> coo=_coords->changeNbOfComponents(3,0.);
7595 coo->writeVTK(ofs,8,"Points",byteData);
7597 ofs << " </Points>\n";
7598 ofs << " <Cells>\n";
7599 const mcIdType *cPtr=_nodal_connec->begin();
7600 const mcIdType *cIPtr=_nodal_connec_index->begin();
7601 MCAuto<DataArrayIdType> faceoffsets=DataArrayIdType::New(); faceoffsets->alloc(nbOfCells,1);
7602 MCAuto<DataArrayIdType> types=DataArrayIdType::New(); types->alloc(nbOfCells,1);
7603 MCAuto<DataArrayIdType> offsets=DataArrayIdType::New(); offsets->alloc(nbOfCells,1);
7604 MCAuto<DataArrayIdType> connectivity=DataArrayIdType::New(); connectivity->alloc(_nodal_connec->getNumberOfTuples()-nbOfCells,1);
7605 mcIdType *w1=faceoffsets->getPointer(),*w2=types->getPointer(),*w3=offsets->getPointer(),*w4=connectivity->getPointer();
7606 mcIdType szFaceOffsets=0,szConn=0;
7607 for(mcIdType i=0;i<nbOfCells;i++,w1++,w2++,w3++)
7610 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]!=INTERP_KERNEL::NORM_POLYHED)
7613 *w3=szConn+cIPtr[i+1]-cIPtr[i]-1; szConn+=cIPtr[i+1]-cIPtr[i]-1;
7614 w4=std::copy(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],w4);
7618 mcIdType deltaFaceOffset=cIPtr[i+1]-cIPtr[i]+1;
7619 *w1=szFaceOffsets+deltaFaceOffset; szFaceOffsets+=deltaFaceOffset;
7620 std::set<mcIdType> c(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1]); c.erase(-1);
7621 *w3=szConn+ToIdType(c.size()); szConn+=ToIdType(c.size());
7622 w4=std::copy(c.begin(),c.end(),w4);
7625 std::unique_ptr<mcIdType[]> medcoupling2vtkTypeTraducer_mcIdType(new mcIdType[MEDCOUPLING2VTKTYPETRADUCER_LGTH]);
7626 for(auto ii = 0; ii<MEDCOUPLING2VTKTYPETRADUCER_LGTH ; ++ii)
7627 medcoupling2vtkTypeTraducer_mcIdType[ii] = MEDCOUPLING2VTKTYPETRADUCER[ii]!=MEDCOUPLING2VTKTYPETRADUCER_NONE?MEDCOUPLING2VTKTYPETRADUCER[ii] : -1;
7628 types->transformWithIndArr(medcoupling2vtkTypeTraducer_mcIdType.get(),medcoupling2vtkTypeTraducer_mcIdType.get()+MEDCOUPLING2VTKTYPETRADUCER_LGTH);
7629 types->writeVTK(ofs,8,"UInt8","types",byteData);
7630 std::string vtkTypeName = Traits<mcIdType>::VTKReprStr;
7631 offsets->writeVTK(ofs,8,vtkTypeName,"offsets",byteData);
7632 if(szFaceOffsets!=0)
7633 {//presence of Polyhedra
7634 connectivity->reAlloc(szConn);
7635 faceoffsets->writeVTK(ofs,8,vtkTypeName,"faceoffsets",byteData);
7636 MCAuto<DataArrayIdType> faces=DataArrayIdType::New(); faces->alloc(szFaceOffsets,1);
7637 w1=faces->getPointer();
7638 for(mcIdType i=0;i<nbOfCells;i++)
7639 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]==INTERP_KERNEL::NORM_POLYHED)
7641 mcIdType nbFaces=ToIdType(std::count(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],-1))+1;
7643 const mcIdType *w6=cPtr+cIPtr[i]+1,*w5=0;
7644 for(mcIdType j=0;j<nbFaces;j++)
7646 w5=std::find(w6,cPtr+cIPtr[i+1],-1);
7647 *w1++=ToIdType(std::distance(w6,w5));
7648 w1=std::copy(w6,w5,w1);
7652 faces->writeVTK(ofs,8,vtkTypeName,"faces",byteData);
7654 connectivity->writeVTK(ofs,8,vtkTypeName,"connectivity",byteData);
7655 ofs << " </Cells>\n";
7656 ofs << " </Piece>\n";
7657 ofs << " </" << getVTKDataSetType() << ">\n";
7660 void MEDCouplingUMesh::reprQuickOverview(std::ostream& stream) const
7662 stream << "MEDCouplingUMesh C++ instance at " << this << ". Name : \"" << getName() << "\".";
7664 { stream << " Not set !"; return ; }
7665 stream << " Mesh dimension : " << _mesh_dim << ".";
7669 { stream << " No coordinates set !"; return ; }
7670 if(!_coords->isAllocated())
7671 { stream << " Coordinates set but not allocated !"; return ; }
7672 stream << " Space dimension : " << _coords->getNumberOfComponents() << "." << std::endl;
7673 stream << "Number of nodes : " << _coords->getNumberOfTuples() << ".";
7674 if(!_nodal_connec_index)
7675 { stream << std::endl << "Nodal connectivity NOT set !"; return ; }
7676 if(!_nodal_connec_index->isAllocated())
7677 { stream << std::endl << "Nodal connectivity set but not allocated !"; return ; }
7678 mcIdType lgth=_nodal_connec_index->getNumberOfTuples();
7679 std::size_t cpt=_nodal_connec_index->getNumberOfComponents();
7680 if(cpt!=1 || lgth<1)
7682 stream << std::endl << "Number of cells : " << lgth-1 << ".";
7685 std::string MEDCouplingUMesh::getVTKDataSetType() const
7687 return std::string("UnstructuredGrid");
7690 std::string MEDCouplingUMesh::getVTKFileExtension() const
7692 return std::string("vtu");
7698 * Provides a renumbering of the cells of this (which has to be a piecewise connected 1D line), so that
7699 * the segments of the line are indexed in consecutive order (i.e. cells \a i and \a i+1 are neighbors).
7700 * This doesn't modify the mesh. This method only works using nodal connectivity consideration. Coordinates of nodes are ignored here.
7701 * The caller is to deal with the resulting DataArrayIdType.
7702 * \throw If the coordinate array is not set.
7703 * \throw If the nodal connectivity of the cells is not defined.
7704 * \throw If m1 is not a mesh of dimension 2, or m1 is not a mesh of dimension 1
7705 * \throw If m2 is not a (piecewise) line (i.e. if a point has more than 2 adjacent segments)
7707 * \sa DataArrayIdType::sortEachPairToMakeALinkedList
7709 DataArrayIdType *MEDCouplingUMesh::orderConsecutiveCells1D() const
7711 checkFullyDefined();
7712 if(getMeshDimension()!=1)
7713 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D works on unstructured mesh with meshdim = 1 !");
7715 // Check that this is a line (and not a more complex 1D mesh) - each point is used at most by 2 segments:
7716 MCAuto<DataArrayIdType> _d(DataArrayIdType::New()),_dI(DataArrayIdType::New());
7717 MCAuto<DataArrayIdType> _rD(DataArrayIdType::New()),_rDI(DataArrayIdType::New());
7718 MCAuto<MEDCouplingUMesh> m_points(buildDescendingConnectivity(_d, _dI, _rD, _rDI));
7719 const mcIdType *d(_d->begin()), *dI(_dI->begin());
7720 const mcIdType *rD(_rD->begin()), *rDI(_rDI->begin());
7721 MCAuto<DataArrayIdType> _dsi(_rDI->deltaShiftIndex());
7722 const mcIdType * dsi(_dsi->begin());
7723 MCAuto<DataArrayIdType> dsii = _dsi->findIdsNotInRange(0,3);
7725 if (dsii->getNumberOfTuples())
7726 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D only work with a mesh being a (piecewise) connected line!");
7728 mcIdType nc=getNumberOfCells();
7729 MCAuto<DataArrayIdType> result(DataArrayIdType::New());
7730 result->alloc(nc,1);
7732 // set of edges not used so far
7733 std::set<mcIdType> edgeSet;
7734 for (mcIdType i=0; i<nc; edgeSet.insert(i), i++);
7736 mcIdType startSeg=0;
7738 // while we have points with only one neighbor segments
7741 std::list<mcIdType> linePiece;
7742 // fills a list of consecutive segment linked to startSeg. This can go forward or backward.
7743 for (int direction=0;direction<2;direction++) // direction=0 --> forward, direction=1 --> backward
7745 // Fill the list forward (resp. backward) from the start segment:
7746 mcIdType activeSeg = startSeg;
7747 mcIdType prevPointId = -20;
7749 while (!edgeSet.empty())
7751 if (!(direction == 1 && prevPointId==-20)) // prevent adding twice startSeg
7754 linePiece.push_back(activeSeg);
7756 linePiece.push_front(activeSeg);
7757 edgeSet.erase(activeSeg);
7760 mcIdType ptId1 = d[dI[activeSeg]], ptId2 = d[dI[activeSeg]+1];
7761 ptId = direction ? (ptId1 == prevPointId ? ptId2 : ptId1) : (ptId2 == prevPointId ? ptId1 : ptId2);
7762 if (dsi[ptId] == 1) // hitting the end of the line
7765 mcIdType seg1 = rD[rDI[ptId]], seg2 = rD[rDI[ptId]+1];
7766 activeSeg = (seg1 == activeSeg) ? seg2 : seg1;
7769 // Done, save final piece into DA:
7770 std::copy(linePiece.begin(), linePiece.end(), result->getPointer()+newIdx);
7771 newIdx += ToIdType(linePiece.size());
7773 // identify next valid start segment (one which is not consumed)
7774 if(!edgeSet.empty())
7775 startSeg = *(edgeSet.begin());
7777 while (!edgeSet.empty());
7778 return result.retn();
7782 * This method split some of edges of 2D cells in \a this. The edges to be split are specified in \a subNodesInSeg
7783 * and in \a subNodesInSegI using \ref numbering-indirect storage mode.
7784 * To do the work this method can optionally needs information about middle of subedges for quadratic cases if
7785 * a minimal creation of new nodes is wanted.
7786 * So this method try to reduce at most the number of new nodes. The only case that can lead this method to add
7787 * nodes if a SEG3 is split without information of middle.
7788 * \b WARNING : is returned value is different from 0 a call to MEDCouplingUMesh::mergeNodes is necessary to
7789 * avoid to have a non conform mesh.
7791 * \return mcIdType - the number of new nodes created (in most of cases 0).
7793 * \throw If \a this is not coherent.
7794 * \throw If \a this has not spaceDim equal to 2.
7795 * \throw If \a this has not meshDim equal to 2.
7796 * \throw If some subcells needed to be split are orphan.
7797 * \sa MEDCouplingUMesh::conformize2D
7799 mcIdType MEDCouplingUMesh::split2DCells(const DataArrayIdType *desc, const DataArrayIdType *descI, const DataArrayIdType *subNodesInSeg, const DataArrayIdType *subNodesInSegI, const DataArrayIdType *midOpt, const DataArrayIdType *midOptI)
7801 if(!desc || !descI || !subNodesInSeg || !subNodesInSegI)
7802 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : the 4 first arrays must be not null !");
7803 desc->checkAllocated(); descI->checkAllocated(); subNodesInSeg->checkAllocated(); subNodesInSegI->checkAllocated();
7804 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
7805 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : This method only works for meshes with spaceDim=2 and meshDim=2 !");
7806 if(midOpt==0 && midOptI==0)
7808 split2DCellsLinear(desc,descI,subNodesInSeg,subNodesInSegI);
7811 else if(midOpt!=0 && midOptI!=0)
7812 return split2DCellsQuadratic(desc,descI,subNodesInSeg,subNodesInSegI,midOpt,midOptI);
7814 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : middle parameters must be set to null for all or not null for all.");
7818 * 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
7819 * 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
7820 * the geometric cell type set to INTERP_KERNEL::NORM_POLYGON.
7821 * 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
7822 * 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.
7824 * \return false if the input connectivity represents already the convex hull, true if the input cell needs to be reordered.
7826 bool MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis(const double *coords, const mcIdType *nodalConnBg, const mcIdType *nodalConnEnd, DataArrayIdType *nodalConnecOut)
7828 std::size_t sz=std::distance(nodalConnBg,nodalConnEnd);
7831 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)*nodalConnBg);
7832 if(cm.getDimension()==2)
7834 const mcIdType *node=nodalConnBg+1;
7835 mcIdType startNode=*node++;
7836 double refX=coords[2*startNode];
7837 for(;node!=nodalConnEnd;node++)
7839 if(coords[2*(*node)]<refX)
7842 refX=coords[2*startNode];
7845 std::vector<mcIdType> tmpOut; tmpOut.reserve(sz); tmpOut.push_back(startNode);
7849 double angle0=-M_PI/2;
7851 mcIdType nextNode=-1;
7852 mcIdType prevNode=-1;
7854 double angleNext=0.;
7855 while(nextNode!=startNode)
7859 for(node=nodalConnBg+1;node!=nodalConnEnd;node++)
7861 if(*node!=tmpOut.back() && *node!=prevNode)
7863 tmp2[0]=coords[2*(*node)]-coords[2*tmpOut.back()]; tmp2[1]=coords[2*(*node)+1]-coords[2*tmpOut.back()+1];
7864 double angleM=INTERP_KERNEL::EdgeArcCircle::GetAbsoluteAngle(tmp2,tmp1);
7869 res=angle0-angleM+2.*M_PI;
7878 if(nextNode!=startNode)
7880 angle0=angleNext-M_PI;
7883 prevNode=tmpOut.back();
7884 tmpOut.push_back(nextNode);
7887 std::vector<mcIdType> tmp3(2*(sz-1));
7888 std::vector<mcIdType>::iterator it=std::copy(nodalConnBg+1,nodalConnEnd,tmp3.begin());
7889 std::copy(nodalConnBg+1,nodalConnEnd,it);
7890 if(std::search(tmp3.begin(),tmp3.end(),tmpOut.begin(),tmpOut.end())!=tmp3.end())
7892 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
7895 if(std::search(tmp3.rbegin(),tmp3.rend(),tmpOut.begin(),tmpOut.end())!=tmp3.rend())
7897 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
7902 nodalConnecOut->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYGON));
7903 nodalConnecOut->insertAtTheEnd(tmpOut.begin(),tmpOut.end());
7908 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
7911 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
7915 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
7916 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
7917 * 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]].
7918 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
7919 * A negative value in \b arrIn means that it is ignored.
7920 * 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.
7922 * \param [in] arrIn arr origin array from which the extraction will be done.
7923 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7924 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
7925 * \sa MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed, MEDCouplingUMesh::partitionBySpreadZone
7927 DataArrayIdType *MEDCouplingUMesh::ComputeSpreadZoneGradually(const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn)
7929 mcIdType seed=0,nbOfDepthPeelingPerformed=0;
7930 return ComputeSpreadZoneGraduallyFromSeed(&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfDepthPeelingPerformed);
7934 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
7935 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
7936 * 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]].
7937 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
7938 * A negative value in \b arrIn means that it is ignored.
7939 * 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.
7940 * \param [in] seedBg the begin pointer (included) of an array containing the seed of the search zone
7941 * \param [in] seedEnd the end pointer (not included) of an array containing the seed of the search zone
7942 * \param [in] arrIn arr origin array from which the extraction will be done.
7943 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7944 * \param [in] nbOfDepthPeeling the max number of peels requested in search. By default -1, that is to say, no limit.
7945 * \param [out] nbOfDepthPeelingPerformed the number of peels effectively performed. May be different from \a nbOfDepthPeeling
7946 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
7947 * \sa MEDCouplingUMesh::partitionBySpreadZone
7949 DataArrayIdType *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(const mcIdType *seedBg, const mcIdType *seedEnd, const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn, mcIdType nbOfDepthPeeling, mcIdType& nbOfDepthPeelingPerformed)
7951 nbOfDepthPeelingPerformed=0;
7953 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed : arrIndxIn input pointer is NULL !");
7954 mcIdType nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
7957 DataArrayIdType *ret=DataArrayIdType::New(); ret->alloc(0,1);
7961 std::vector<bool> fetched(nbOfTuples,false);
7962 return ComputeSpreadZoneGraduallyFromSeedAlg(fetched,seedBg,seedEnd,arrIn,arrIndxIn,nbOfDepthPeeling,nbOfDepthPeelingPerformed);
7968 * \b this is expected to be a mesh fully defined whose spaceDim==meshDim.
7969 * It returns a new allocated mesh having the same mesh dimension and lying on same coordinates.
7970 * The returned mesh contains as poly cells as number of contiguous zone (regarding connectivity).
7971 * A spread contiguous zone is built using poly cells (polyhedra in 3D, polygons in 2D and polyline in 1D).
7972 * The sum of measure field of returned mesh is equal to the sum of measure field of this.
7974 * \return a newly allocated mesh lying on the same coords than \b this with same meshdimension than \b this.
7976 MEDCouplingUMesh *MEDCouplingUMesh::buildSpreadZonesWithPoly() const
7978 checkFullyDefined();
7979 int mdim=getMeshDimension();
7980 int spaceDim=getSpaceDimension();
7982 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension and spacedimension do not match !");
7983 std::vector<DataArrayIdType *> partition=partitionBySpreadZone();
7984 std::vector< MCAuto<DataArrayIdType> > partitionAuto; partitionAuto.reserve(partition.size());
7985 std::copy(partition.begin(),partition.end(),std::back_insert_iterator<std::vector< MCAuto<DataArrayIdType> > >(partitionAuto));
7986 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
7987 ret->setCoords(getCoords());
7988 ret->allocateCells(ToIdType(partition.size()));
7990 for(std::vector<DataArrayIdType *>::const_iterator it=partition.begin();it!=partition.end();it++)
7992 MCAuto<MEDCouplingUMesh> tmp=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf((*it)->begin(),(*it)->end(),true));
7993 MCAuto<DataArrayIdType> cell;
7997 cell=tmp->buildUnionOf2DMesh();
8000 cell=tmp->buildUnionOf3DMesh();
8003 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension supported are [2,3] ! Not implemented yet for others !");
8006 ret->insertNextCell((INTERP_KERNEL::NormalizedCellType)cell->getIJSafe(0,0),cell->getNumberOfTuples()-1,cell->begin()+1);
8009 ret->finishInsertingCells();
8014 * This method partitions \b this into contiguous zone.
8015 * This method only needs a well defined connectivity. Coordinates are not considered here.
8016 * This method returns a vector of \b newly allocated arrays that the caller has to deal with.
8018 std::vector<DataArrayIdType *> MEDCouplingUMesh::partitionBySpreadZone() const
8020 DataArrayIdType *neigh=0,*neighI=0;
8021 computeNeighborsOfCells(neigh,neighI);
8022 MCAuto<DataArrayIdType> neighAuto(neigh),neighIAuto(neighI);
8023 return PartitionBySpreadZone(neighAuto,neighIAuto);
8026 std::vector<DataArrayIdType *> MEDCouplingUMesh::PartitionBySpreadZone(const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn)
8028 if(!arrIn || !arrIndxIn)
8029 throw INTERP_KERNEL::Exception("PartitionBySpreadZone : null input pointers !");
8030 arrIn->checkAllocated(); arrIndxIn->checkAllocated();
8031 mcIdType nbOfTuples(arrIndxIn->getNumberOfTuples());
8032 if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1 || nbOfTuples<1)
8033 throw INTERP_KERNEL::Exception("PartitionBySpreadZone : invalid arrays in input !");
8034 mcIdType nbOfCellsCur(nbOfTuples-1);
8035 std::vector<DataArrayIdType *> ret;
8038 std::vector<bool> fetchedCells(nbOfCellsCur,false);
8039 std::vector< MCAuto<DataArrayIdType> > ret2;
8041 while(seed<nbOfCellsCur)
8043 mcIdType nbOfPeelPerformed=0;
8044 ret2.push_back(ComputeSpreadZoneGraduallyFromSeedAlg(fetchedCells,&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfPeelPerformed));
8045 seed=ToIdType(std::distance(fetchedCells.begin(),std::find(fetchedCells.begin()+seed,fetchedCells.end(),false)));
8047 for(std::vector< MCAuto<DataArrayIdType> >::iterator it=ret2.begin();it!=ret2.end();it++)
8048 ret.push_back((*it).retn());
8053 * This method returns given a distribution of cell type (returned for example by MEDCouplingUMesh::getDistributionOfTypes method and customized after) a
8054 * newly allocated DataArrayIdType instance with 2 components ready to be interpreted as input of DataArrayIdType::findRangeIdForEachTuple method.
8056 * \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.
8057 * \return a newly allocated DataArrayIdType to be managed by the caller.
8058 * \throw In case of \a code has not the right format (typically of size 3*n)
8060 DataArrayIdType *MEDCouplingUMesh::ComputeRangesFromTypeDistribution(const std::vector<mcIdType>& code)
8062 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
8063 std::size_t nb=code.size()/3;
8064 if(code.size()%3!=0)
8065 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeRangesFromTypeDistribution : invalid input code !");
8067 mcIdType *retPtr=ret->getPointer();
8068 for(std::size_t i=0;i<nb;i++,retPtr+=2)
8070 retPtr[0]=code[3*i+2];
8071 retPtr[1]=code[3*i+2]+code[3*i+1];
8077 * This method expects that \a this a 3D mesh (spaceDim=3 and meshDim=3) with all coordinates and connectivities set.
8078 * All cells in \a this are expected to be linear 3D cells.
8079 * This method will split **all** 3D cells in \a this into INTERP_KERNEL::NORM_TETRA4 cells and put them in the returned mesh.
8080 * It leads to an increase to number of cells.
8081 * This method contrary to MEDCouplingUMesh::simplexize can append coordinates in \a this to perform its work.
8082 * The \a nbOfAdditionalPoints returned value informs about it. If > 0, the coordinates array in returned mesh will have \a nbOfAdditionalPoints
8083 * more tuples (nodes) than in \a this. Anyway, all the nodes in \a this (with the same order) will be in the returned mesh.
8085 * \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.
8086 * For all other cells, the splitting policy will be ignored. See INTERP_KERNEL::SplittingPolicy for the images.
8087 * \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.
8088 * \param [out] n2oCells - A new instance of DataArrayIdType holding, for each new cell,
8089 * an id of old cell producing it. The caller is to delete this array using
8090 * decrRef() as it is no more needed.
8091 * \return MEDCoupling1SGTUMesh * - the mesh containing only INTERP_KERNEL::NORM_TETRA4 cells.
8093 * \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
8094 * the policy PLANAR_FACE_6 should be used on a mesh sorted with MEDCoupling1SGTUMesh::sortHexa8EachOther.
8096 * \throw If \a this is not a 3D mesh (spaceDim==3 and meshDim==3).
8097 * \throw If \a this is not fully constituted with linear 3D cells.
8098 * \sa MEDCouplingUMesh::simplexize, MEDCoupling1SGTUMesh::sortHexa8EachOther
8100 MEDCoupling1SGTUMesh *MEDCouplingUMesh::tetrahedrize(int policy, DataArrayIdType *& n2oCells, mcIdType& nbOfAdditionalPoints) const
8102 INTERP_KERNEL::SplittingPolicy pol((INTERP_KERNEL::SplittingPolicy)policy);
8103 checkConnectivityFullyDefined();
8104 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
8105 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tetrahedrize : only available for mesh with meshdim == 3 and spacedim == 3 !");
8106 mcIdType nbOfCells=getNumberOfCells();
8107 mcIdType nbNodes(getNumberOfNodes());
8108 MCAuto<MEDCoupling1SGTUMesh> ret0(MEDCoupling1SGTUMesh::New(getName(),INTERP_KERNEL::NORM_TETRA4));
8109 MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(nbOfCells,1);
8110 mcIdType *retPt(ret->getPointer());
8111 MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()); newConn->alloc(0,1);
8112 MCAuto<DataArrayDouble> addPts(DataArrayDouble::New()); addPts->alloc(0,1);
8113 const mcIdType *oldc(_nodal_connec->begin());
8114 const mcIdType *oldci(_nodal_connec_index->begin());
8115 const double *coords(_coords->begin());
8116 for(mcIdType i=0;i<nbOfCells;i++,oldci++,retPt++)
8118 std::vector<mcIdType> a; std::vector<double> b;
8119 INTERP_KERNEL::SplitIntoTetras(pol,(INTERP_KERNEL::NormalizedCellType)oldc[oldci[0]],oldc+oldci[0]+1,oldc+oldci[1],coords,a,b);
8120 std::size_t nbOfTet(a.size()/4); *retPt=ToIdType(nbOfTet);
8121 const mcIdType *aa(&a[0]);
8124 for(std::vector<mcIdType>::iterator it=a.begin();it!=a.end();it++)
8126 *it=(-(*(it))-1+nbNodes);
8127 addPts->insertAtTheEnd(b.begin(),b.end());
8128 nbNodes+=ToIdType(b.size()/3);
8130 for(std::size_t j=0;j<nbOfTet;j++,aa+=4)
8131 newConn->insertAtTheEnd(aa,aa+4);
8133 if(!addPts->empty())
8135 addPts->rearrange(3);
8136 nbOfAdditionalPoints=addPts->getNumberOfTuples();
8137 addPts=DataArrayDouble::Aggregate(getCoords(),addPts);
8138 ret0->setCoords(addPts);
8142 nbOfAdditionalPoints=0;
8143 ret0->setCoords(getCoords());
8145 ret0->setNodalConnectivity(newConn);
8147 ret->computeOffsetsFull();
8148 n2oCells=ret->buildExplicitArrOfSliceOnScaledArr(0,nbOfCells,1);
8152 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),
8153 _own_cell(true),_cell_id(-1),_nb_cell(0)
8158 _nb_cell=mesh->getNumberOfCells();
8162 MEDCouplingUMeshCellIterator::~MEDCouplingUMeshCellIterator()
8170 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh, MEDCouplingUMeshCell *itc, mcIdType bg, mcIdType end):_mesh(mesh),_cell(itc),
8171 _own_cell(false),_cell_id(bg-1),
8178 MEDCouplingUMeshCell *MEDCouplingUMeshCellIterator::nextt()
8181 if(_cell_id<_nb_cell)
8190 MEDCouplingUMeshCellByTypeEntry::MEDCouplingUMeshCellByTypeEntry(MEDCouplingUMesh *mesh):_mesh(mesh)
8196 MEDCouplingUMeshCellByTypeIterator *MEDCouplingUMeshCellByTypeEntry::iterator()
8198 return new MEDCouplingUMeshCellByTypeIterator(_mesh);
8201 MEDCouplingUMeshCellByTypeEntry::~MEDCouplingUMeshCellByTypeEntry()
8207 MEDCouplingUMeshCellEntry::MEDCouplingUMeshCellEntry(MEDCouplingUMesh *mesh, INTERP_KERNEL::NormalizedCellType type, MEDCouplingUMeshCell *itc, mcIdType bg, mcIdType end):_mesh(mesh),_type(type),
8215 MEDCouplingUMeshCellEntry::~MEDCouplingUMeshCellEntry()
8221 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCellEntry::getType() const
8226 mcIdType MEDCouplingUMeshCellEntry::getNumberOfElems() const
8231 MEDCouplingUMeshCellIterator *MEDCouplingUMeshCellEntry::iterator()
8233 return new MEDCouplingUMeshCellIterator(_mesh,_itc,_bg,_end);
8236 MEDCouplingUMeshCellByTypeIterator::MEDCouplingUMeshCellByTypeIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),_cell_id(0),_nb_cell(0)
8241 _nb_cell=mesh->getNumberOfCells();
8245 MEDCouplingUMeshCellByTypeIterator::~MEDCouplingUMeshCellByTypeIterator()
8252 MEDCouplingUMeshCellEntry *MEDCouplingUMeshCellByTypeIterator::nextt()
8254 const mcIdType *c=_mesh->getNodalConnectivity()->begin();
8255 const mcIdType *ci=_mesh->getNodalConnectivityIndex()->begin();
8256 if(_cell_id<_nb_cell)
8258 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[_cell_id]];
8259 mcIdType nbOfElems=ToIdType(std::distance(ci+_cell_id,std::find_if(ci+_cell_id,ci+_nb_cell,MEDCouplingImpl::ConnReader(c,type))));
8260 mcIdType startId=_cell_id;
8261 _cell_id+=nbOfElems;
8262 return new MEDCouplingUMeshCellEntry(_mesh,type,_cell,startId,_cell_id);
8268 MEDCouplingUMeshCell::MEDCouplingUMeshCell(MEDCouplingUMesh *mesh):_conn(0),_conn_indx(0),_conn_lgth(NOTICABLE_FIRST_VAL)
8272 _conn=mesh->getNodalConnectivity()->getPointer();
8273 _conn_indx=mesh->getNodalConnectivityIndex()->getPointer();
8277 void MEDCouplingUMeshCell::next()
8279 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8284 _conn_lgth=_conn_indx[1]-_conn_indx[0];
8287 std::string MEDCouplingUMeshCell::repr() const
8289 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8291 std::ostringstream oss; oss << "Cell Type " << INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)_conn[0]).getRepr();
8293 std::copy(_conn+1,_conn+_conn_lgth,std::ostream_iterator<mcIdType>(oss," "));
8297 return std::string("MEDCouplingUMeshCell::repr : Invalid pos");
8300 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCell::getType() const
8302 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8303 return (INTERP_KERNEL::NormalizedCellType)_conn[0];
8305 return INTERP_KERNEL::NORM_ERROR;
8308 const mcIdType *MEDCouplingUMeshCell::getAllConn(mcIdType& lgth) const
8311 if(_conn_lgth!=NOTICABLE_FIRST_VAL)