1 // Copyright (C) 2007-2019 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"
54 using namespace MEDCoupling;
56 double MEDCouplingUMesh::EPS_FOR_POLYH_ORIENTATION=1.e-14;
59 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 };
60 const mcIdType MEDCouplingUMesh::MEDCOUPLING2VTKTYPETRADUCER[INTERP_KERNEL::NORM_MAXTYPE+1]={1,3,21,5,9,7,22,34,23,28,-1,-1,-1,-1,10,14,13,-1,12,-1,24,-1,16,27,-1,26,-1,29,32,-1,25,42,36,4};
63 MEDCouplingUMesh *MEDCouplingUMesh::New()
65 return new MEDCouplingUMesh;
68 MEDCouplingUMesh *MEDCouplingUMesh::New(const std::string& meshName, int meshDim)
70 MEDCouplingUMesh *ret=new MEDCouplingUMesh;
71 ret->setName(meshName);
72 ret->setMeshDimension(meshDim);
77 * Returns a new MEDCouplingUMesh which is a full copy of \a this one. No data is shared
78 * between \a this and the new mesh.
79 * \return MEDCouplingUMesh * - a new instance of MEDCouplingMesh. The caller is to
80 * delete this mesh using decrRef() as it is no more needed.
82 MEDCouplingUMesh *MEDCouplingUMesh::deepCopy() const
89 * Returns a new MEDCouplingUMesh which is a copy of \a this one.
90 * \param [in] recDeepCpy - if \a true, the copy is deep, else all data arrays of \a
91 * this mesh are shared by the new mesh.
92 * \return MEDCouplingUMesh * - a new instance of MEDCouplingMesh. The caller is to
93 * delete this mesh using decrRef() as it is no more needed.
95 MEDCouplingUMesh *MEDCouplingUMesh::clone(bool recDeepCpy) const
97 return new MEDCouplingUMesh(*this,recDeepCpy);
101 * This method behaves mostly like MEDCouplingUMesh::deepCopy method, except that only nodal connectivity arrays are deeply copied.
102 * The coordinates are shared between \a this and the returned instance.
104 * \return MEDCouplingUMesh * - A new object instance holding the copy of \a this (deep for connectivity, shallow for coordiantes)
105 * \sa MEDCouplingUMesh::deepCopy
107 MEDCouplingUMesh *MEDCouplingUMesh::deepCopyConnectivityOnly() const
109 checkConnectivityFullyDefined();
110 MCAuto<MEDCouplingUMesh> ret=clone(false);
111 MCAuto<DataArrayIdType> c(getNodalConnectivity()->deepCopy()),ci(getNodalConnectivityIndex()->deepCopy());
112 ret->setConnectivity(c,ci);
116 void MEDCouplingUMesh::shallowCopyConnectivityFrom(const MEDCouplingPointSet *other)
119 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is null !");
120 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
122 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is not an MEDCouplingUMesh instance !");
123 MEDCouplingUMesh *otherC2=const_cast<MEDCouplingUMesh *>(otherC);//sorry :(
124 setConnectivity(otherC2->getNodalConnectivity(),otherC2->getNodalConnectivityIndex(),true);
127 std::size_t MEDCouplingUMesh::getHeapMemorySizeWithoutChildren() const
129 std::size_t ret(MEDCouplingPointSet::getHeapMemorySizeWithoutChildren());
133 std::vector<const BigMemoryObject *> MEDCouplingUMesh::getDirectChildrenWithNull() const
135 std::vector<const BigMemoryObject *> ret(MEDCouplingPointSet::getDirectChildrenWithNull());
136 ret.push_back(_nodal_connec);
137 ret.push_back(_nodal_connec_index);
141 void MEDCouplingUMesh::updateTime() const
143 MEDCouplingPointSet::updateTime();
146 updateTimeWith(*_nodal_connec);
148 if(_nodal_connec_index)
150 updateTimeWith(*_nodal_connec_index);
154 MEDCouplingUMesh::MEDCouplingUMesh():_mesh_dim(-2),_nodal_connec(0),_nodal_connec_index(0)
159 * Checks if \a this mesh is well defined. If no exception is thrown by this method,
160 * then \a this mesh is most probably is writable, exchangeable and available for most
161 * of algorithms. When a mesh is constructed from scratch, it is a good habit to call
162 * this method to check that all is in order with \a this mesh.
163 * \throw If the mesh dimension is not set.
164 * \throw If the coordinates array is not set (if mesh dimension != -1 ).
165 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
166 * \throw If the connectivity data array has more than one component.
167 * \throw If the connectivity data array has a named component.
168 * \throw If the connectivity index data array has more than one component.
169 * \throw If the connectivity index data array has a named component.
171 void MEDCouplingUMesh::checkConsistencyLight() const
174 throw INTERP_KERNEL::Exception("No mesh dimension specified !");
176 MEDCouplingPointSet::checkConsistencyLight();
177 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
179 if(ToIdType(INTERP_KERNEL::CellModel::GetCellModel(*iter).getDimension())!=_mesh_dim)
181 std::ostringstream message;
182 message << "Mesh invalid because dimension is " << _mesh_dim << " and there is presence of cell(s) with type " << (*iter);
183 throw INTERP_KERNEL::Exception(message.str().c_str());
188 if(_nodal_connec->getNumberOfComponents()!=1)
189 throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to be with number of components set to one !");
190 if(_nodal_connec->getInfoOnComponent(0)!="")
191 throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to have no info on its single component !");
195 throw INTERP_KERNEL::Exception("Nodal connectivity array is not defined !");
196 if(_nodal_connec_index)
198 if(_nodal_connec_index->getNumberOfComponents()!=1)
199 throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to be with number of components set to one !");
200 if(_nodal_connec_index->getInfoOnComponent(0)!="")
201 throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to have no info on its single component !");
205 throw INTERP_KERNEL::Exception("Nodal connectivity index array is not defined !");
209 * Checks if \a this mesh is well defined. If no exception is thrown by this method,
210 * then \a this mesh is most probably is writable, exchangeable and available for all
211 * algorithms. <br> In addition to the checks performed by checkConsistencyLight(), this
212 * method thoroughly checks the nodal connectivity.
213 * \param [in] eps - a not used parameter.
214 * \throw If the mesh dimension is not set.
215 * \throw If the coordinates array is not set (if mesh dimension != -1 ).
216 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
217 * \throw If the connectivity data array has more than one component.
218 * \throw If the connectivity data array has a named component.
219 * \throw If the connectivity index data array has more than one component.
220 * \throw If the connectivity index data array has a named component.
221 * \throw If number of nodes defining an element does not correspond to the type of element.
222 * \throw If the nodal connectivity includes an invalid node id.
224 void MEDCouplingUMesh::checkConsistency(double eps) const
226 checkConsistencyLight();
229 int meshDim=getMeshDimension();
230 mcIdType nbOfNodes=getNumberOfNodes();
231 mcIdType nbOfCells=getNumberOfCells();
232 const mcIdType *ptr=_nodal_connec->getConstPointer();
233 const mcIdType *ptrI=_nodal_connec_index->getConstPointer();
234 for(mcIdType i=0;i<nbOfCells;i++)
236 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)ptr[ptrI[i]]);
237 if(ToIdType(cm.getDimension())!=meshDim)
239 std::ostringstream oss;
240 oss << "MEDCouplingUMesh::checkConsistency : cell << #" << i<< " with type Type " << cm.getRepr() << " in 'this' whereas meshdim == " << meshDim << " !";
241 throw INTERP_KERNEL::Exception(oss.str());
243 mcIdType nbOfNodesInCell=ptrI[i+1]-ptrI[i]-1;
245 if(nbOfNodesInCell!=ToIdType(cm.getNumberOfNodes()))
247 std::ostringstream oss;
248 oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with static Type '" << cm.getRepr() << "' has " << cm.getNumberOfNodes();
249 oss << " nodes whereas in connectivity there is " << nbOfNodesInCell << " nodes ! Looks very bad !";
250 throw INTERP_KERNEL::Exception(oss.str());
252 if(cm.isQuadratic() && cm.isDynamic() && meshDim == 2)
253 if (nbOfNodesInCell % 2 || nbOfNodesInCell < 4)
255 std::ostringstream oss;
256 oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with quadratic type '" << cm.getRepr() << "' has " << nbOfNodesInCell;
257 oss << " nodes. This should be even, and greater or equal than 4!! Looks very bad!";
258 throw INTERP_KERNEL::Exception(oss.str());
260 for(const mcIdType *w=ptr+ptrI[i]+1;w!=ptr+ptrI[i+1];w++)
265 if(nodeId>=nbOfNodes)
267 std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " whereas there are only " << nbOfNodes << " nodes in the mesh !";
268 throw INTERP_KERNEL::Exception(oss.str());
273 std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " in connectivity ! sounds bad !";
274 throw INTERP_KERNEL::Exception(oss.str());
278 if((INTERP_KERNEL::NormalizedCellType)(ptr[ptrI[i]])!=INTERP_KERNEL::NORM_POLYHED)
280 std::ostringstream oss; oss << "Cell #" << i << " is built with node #-1 in connectivity ! sounds bad !";
281 throw INTERP_KERNEL::Exception(oss.str());
289 * Sets dimension of \a this mesh. The mesh dimension in general depends on types of
290 * elements contained in the mesh. For more info on the mesh dimension see
291 * \ref MEDCouplingUMeshPage.
292 * \param [in] meshDim - a new mesh dimension.
293 * \throw If \a meshDim is invalid. A valid range is <em> -1 <= meshDim <= 3</em>.
295 void MEDCouplingUMesh::setMeshDimension(int meshDim)
297 if(meshDim<-1 || meshDim>3)
298 throw INTERP_KERNEL::Exception("Invalid meshDim specified ! Must be greater or equal to -1 and lower or equal to 3 !");
304 * Allocates memory to store an estimation of the given number of cells.
305 * The closer the estimation to the number of cells effectively inserted, the less need the library requires
306 * to reallocate memory. If the number of cells to be inserted is not known simply assign 0 to this parameter.
307 * If a nodal connectivity previously existed before the call of this method, it will be reset.
309 * \param [in] nbOfCells - estimation of the number of cell \a this mesh will contain.
311 * \if ENABLE_EXAMPLES
312 * \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
313 * \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
316 void MEDCouplingUMesh::allocateCells(mcIdType nbOfCells)
319 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::allocateCells : the input number of cells should be >= 0 !");
320 if(_nodal_connec_index)
322 _nodal_connec_index->decrRef();
326 _nodal_connec->decrRef();
328 _nodal_connec_index=DataArrayIdType::New();
329 _nodal_connec_index->reserve(nbOfCells+1);
330 _nodal_connec_index->pushBackSilent(0);
331 _nodal_connec=DataArrayIdType::New();
332 _nodal_connec->reserve(2*nbOfCells);
338 * Appends a cell to the connectivity array. For deeper understanding what is
339 * happening see \ref MEDCouplingUMeshNodalConnectivity.
340 * \param [in] type - type of cell to add.
341 * \param [in] size - number of nodes constituting this cell.
342 * \param [in] nodalConnOfCell - the connectivity of the cell to add.
344 * \if ENABLE_EXAMPLES
345 * \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
346 * \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
349 void MEDCouplingUMesh::insertNextCell(INTERP_KERNEL::NormalizedCellType type, mcIdType size, const mcIdType *nodalConnOfCell)
351 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
352 if(_nodal_connec_index==0)
353 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::insertNextCell : nodal connectivity not set ! invoke allocateCells before calling insertNextCell !");
354 if(ToIdType(cm.getDimension())==_mesh_dim)
357 if(size!=ToIdType(cm.getNumberOfNodes()))
359 std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : Trying to push a " << cm.getRepr() << " cell with a size of " << size;
360 oss << " ! Expecting " << cm.getNumberOfNodes() << " !";
361 throw INTERP_KERNEL::Exception(oss.str());
363 mcIdType idx=_nodal_connec_index->back();
364 mcIdType val=idx+size+1;
365 _nodal_connec_index->pushBackSilent(val);
366 _nodal_connec->writeOnPlace(idx,type,nodalConnOfCell,size);
371 std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : cell type " << cm.getRepr() << " has a dimension " << cm.getDimension();
372 oss << " whereas Mesh Dimension of current UMesh instance is set to " << _mesh_dim << " ! Please invoke \"setMeshDimension\" method before or invoke ";
373 oss << "\"MEDCouplingUMesh::New\" static method with 2 parameters name and meshDimension !";
374 throw INTERP_KERNEL::Exception(oss.str());
379 * Compacts data arrays to release unused memory. This method is to be called after
380 * finishing cell insertion using \a this->insertNextCell().
382 * \if ENABLE_EXAMPLES
383 * \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
384 * \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
387 void MEDCouplingUMesh::finishInsertingCells()
389 _nodal_connec->pack();
390 _nodal_connec_index->pack();
391 _nodal_connec->declareAsNew();
392 _nodal_connec_index->declareAsNew();
397 * Entry point for iteration over cells of this. Warning the returned cell iterator should be deallocated.
398 * Useful for python users.
400 MEDCouplingUMeshCellIterator *MEDCouplingUMesh::cellIterator()
402 return new MEDCouplingUMeshCellIterator(this);
406 * Entry point for iteration over cells groups geo types per geotypes. Warning the returned cell iterator should be deallocated.
407 * If \a this is not so that the cells are grouped by geo types, this method will throw an exception.
408 * In this case MEDCouplingUMesh::sortCellsInMEDFileFrmt or MEDCouplingUMesh::rearrange2ConsecutiveCellTypes methods for example can be called before invoking this method.
409 * Useful for python users.
411 MEDCouplingUMeshCellByTypeEntry *MEDCouplingUMesh::cellsByType()
413 if(!checkConsecutiveCellTypes())
414 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::cellsByType : this mesh is not sorted by type !");
415 return new MEDCouplingUMeshCellByTypeEntry(this);
419 * Returns a set of all cell types available in \a this mesh.
420 * \return std::set<INTERP_KERNEL::NormalizedCellType> - the set of cell types.
421 * \warning this method does not throw any exception even if \a this is not defined.
422 * \sa MEDCouplingUMesh::getAllGeoTypesSorted
424 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypes() const
430 * This method returns the sorted list of geometric types in \a this.
431 * 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
432 * having the same geometric type. So a same geometric type can appear more than once if the cells are not sorted per geometric type.
434 * \throw if connectivity in \a this is not correctly defined.
436 * \sa MEDCouplingMesh::getAllGeoTypes
438 std::vector<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypesSorted() const
440 std::vector<INTERP_KERNEL::NormalizedCellType> ret;
441 checkConnectivityFullyDefined();
442 mcIdType nbOfCells=getNumberOfCells();
445 if(getNodalConnectivityArrayLen()<1)
446 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAllGeoTypesSorted : the connectivity in this seems invalid !");
447 const mcIdType *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin());
448 ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci++]);
449 for(mcIdType i=1;i<nbOfCells;i++,ci++)
450 if(ret.back()!=((INTERP_KERNEL::NormalizedCellType)c[*ci]))
451 ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci]);
456 * This method is a method that compares \a this and \a other.
457 * This method compares \b all attributes, even names and component names.
459 bool MEDCouplingUMesh::isEqualIfNotWhy(const MEDCouplingMesh *other, double prec, std::string& reason) const
462 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isEqualIfNotWhy : input other pointer is null !");
463 std::ostringstream oss; oss.precision(15);
464 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
467 reason="mesh given in input is not castable in MEDCouplingUMesh !";
470 if(!MEDCouplingPointSet::isEqualIfNotWhy(other,prec,reason))
472 if(_mesh_dim!=otherC->_mesh_dim)
474 oss << "umesh dimension mismatch : this mesh dimension=" << _mesh_dim << " other mesh dimension=" << otherC->_mesh_dim;
478 if(_types!=otherC->_types)
480 oss << "umesh geometric type mismatch :\nThis geometric types are :";
481 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
482 { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
483 oss << "\nOther geometric types are :";
484 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=otherC->_types.begin();iter!=otherC->_types.end();iter++)
485 { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
489 if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
490 if(_nodal_connec==0 || otherC->_nodal_connec==0)
492 reason="Only one UMesh between the two this and other has its nodal connectivity DataArrayInt defined !";
495 if(_nodal_connec!=otherC->_nodal_connec)
496 if(!_nodal_connec->isEqualIfNotWhy(*otherC->_nodal_connec,reason))
498 reason.insert(0,"Nodal connectivity DataArrayInt differ : ");
501 if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
502 if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
504 reason="Only one UMesh between the two this and other has its nodal connectivity index DataArrayInt defined !";
507 if(_nodal_connec_index!=otherC->_nodal_connec_index)
508 if(!_nodal_connec_index->isEqualIfNotWhy(*otherC->_nodal_connec_index,reason))
510 reason.insert(0,"Nodal connectivity index DataArrayInt differ : ");
517 * Checks if data arrays of this mesh (node coordinates, nodal
518 * connectivity of cells, etc) of two meshes are same. Textual data like name etc. are
520 * \param [in] other - the mesh to compare with.
521 * \param [in] prec - precision value used to compare node coordinates.
522 * \return bool - \a true if the two meshes are same.
524 bool MEDCouplingUMesh::isEqualWithoutConsideringStr(const MEDCouplingMesh *other, double prec) const
526 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
529 if(!MEDCouplingPointSet::isEqualWithoutConsideringStr(other,prec))
531 if(_mesh_dim!=otherC->_mesh_dim)
533 if(_types!=otherC->_types)
535 if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
536 if(_nodal_connec==0 || otherC->_nodal_connec==0)
538 if(_nodal_connec!=otherC->_nodal_connec)
539 if(!_nodal_connec->isEqualWithoutConsideringStr(*otherC->_nodal_connec))
541 if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
542 if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
544 if(_nodal_connec_index!=otherC->_nodal_connec_index)
545 if(!_nodal_connec_index->isEqualWithoutConsideringStr(*otherC->_nodal_connec_index))
551 * Checks if \a this and \a other meshes are geometrically equivalent with high
552 * probability, else an exception is thrown. The meshes are considered equivalent if
553 * (1) meshes contain the same number of nodes and the same number of elements of the
554 * same types (2) three cells of the two meshes (first, last and middle) are based
555 * on coincident nodes (with a specified precision).
556 * \param [in] other - the mesh to compare with.
557 * \param [in] prec - the precision used to compare nodes of the two meshes.
558 * \throw If the two meshes do not match.
560 void MEDCouplingUMesh::checkFastEquivalWith(const MEDCouplingMesh *other, double prec) const
562 MEDCouplingPointSet::checkFastEquivalWith(other,prec);
563 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
565 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkFastEquivalWith : Two meshes are not not unstructured !");
569 * Returns the reverse nodal connectivity. The reverse nodal connectivity enumerates
570 * cells each node belongs to.
571 * \warning For speed reasons, this method does not check if node ids in the nodal
572 * connectivity correspond to the size of node coordinates array.
573 * \param [in,out] revNodal - an array holding ids of cells sharing each node.
574 * \param [in,out] revNodalIndx - an array, of length \a this->getNumberOfNodes() + 1,
575 * dividing cell ids in \a revNodal into groups each referring to one
576 * node. Its every element (except the last one) is an index pointing to the
577 * first id of a group of cells. For example cells sharing the node #1 are
578 * described by following range of indices:
579 * [ \a revNodalIndx[1], \a revNodalIndx[2] ) and the cell ids are
580 * \a revNodal[ \a revNodalIndx[1] ], \a revNodal[ \a revNodalIndx[1] + 1], ...
581 * Number of cells sharing the *i*-th node is
582 * \a revNodalIndx[ *i*+1 ] - \a revNodalIndx[ *i* ].
583 * \throw If the coordinates array is not set.
584 * \throw If the nodal connectivity of cells is not defined.
586 * \if ENABLE_EXAMPLES
587 * \ref cpp_mcumesh_getReverseNodalConnectivity "Here is a C++ example".<br>
588 * \ref py_mcumesh_getReverseNodalConnectivity "Here is a Python example".
591 void MEDCouplingUMesh::getReverseNodalConnectivity(DataArrayIdType *revNodal, DataArrayIdType *revNodalIndx) const
594 mcIdType nbOfNodes(getNumberOfNodes());
595 mcIdType *revNodalIndxPtr=(mcIdType *)malloc((nbOfNodes+1)*sizeof(mcIdType));
596 revNodalIndx->useArray(revNodalIndxPtr,true,DeallocType::C_DEALLOC,nbOfNodes+1,1);
597 std::fill(revNodalIndxPtr,revNodalIndxPtr+nbOfNodes+1,0);
598 const mcIdType *conn(_nodal_connec->begin()),*connIndex(_nodal_connec_index->begin());
599 mcIdType nbOfCells(getNumberOfCells()),nbOfEltsInRevNodal(0);
600 for(mcIdType eltId=0;eltId<nbOfCells;eltId++)
602 const mcIdType *strtNdlConnOfCurCell(conn+connIndex[eltId]+1),*endNdlConnOfCurCell(conn+connIndex[eltId+1]);
603 for(const mcIdType *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
604 if(*iter>=0)//for polyhedrons
606 nbOfEltsInRevNodal++;
607 revNodalIndxPtr[(*iter)+1]++;
610 std::transform(revNodalIndxPtr+1,revNodalIndxPtr+nbOfNodes+1,revNodalIndxPtr,revNodalIndxPtr+1,std::plus<mcIdType>());
611 mcIdType *revNodalPtr=(mcIdType *)malloc(nbOfEltsInRevNodal*sizeof(mcIdType));
612 revNodal->useArray(revNodalPtr,true,DeallocType::C_DEALLOC,nbOfEltsInRevNodal,1);
613 std::fill(revNodalPtr,revNodalPtr+nbOfEltsInRevNodal,-1);
614 for(mcIdType eltId=0;eltId<nbOfCells;eltId++)
616 const mcIdType *strtNdlConnOfCurCell=conn+connIndex[eltId]+1;
617 const mcIdType *endNdlConnOfCurCell=conn+connIndex[eltId+1];
618 for(const mcIdType *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
619 if(*iter>=0)//for polyhedrons
620 *std::find_if(revNodalPtr+revNodalIndxPtr[*iter],revNodalPtr+revNodalIndxPtr[*iter+1],std::bind2nd(std::equal_to<mcIdType>(),-1))=eltId;
625 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
626 * this->getMeshDimension(), that bound cells of \a this mesh. In addition arrays
627 * describing correspondence between cells of \a this and the result meshes are
628 * returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending connectivity,
629 * i.e. enumerate cells of the result mesh bounding each cell of \a this mesh. The
630 * arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
631 * i.e. enumerate cells of \a this mesh bounded by each cell of the result mesh.
632 * \warning For speed reasons, this method does not check if node ids in the nodal
633 * connectivity correspond to the size of node coordinates array.
634 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
635 * to write this mesh to the MED file, its cells must be sorted using
636 * sortCellsInMEDFileFrmt().
637 * \param [in,out] desc - the array containing cell ids of the result mesh bounding
638 * each cell of \a this mesh.
639 * \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
640 * dividing cell ids in \a desc into groups each referring to one
641 * cell of \a this mesh. Its every element (except the last one) is an index
642 * pointing to the first id of a group of cells. For example cells of the
643 * result mesh bounding the cell #1 of \a this mesh are described by following
645 * [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
646 * \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
647 * Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
648 * \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
649 * \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
650 * by each cell of the result mesh.
651 * \param [in,out] revDescIndx - the array, of length one more than number of cells
652 * in the result mesh,
653 * dividing cell ids in \a revDesc into groups each referring to one
654 * cell of the result mesh the same way as \a descIndx divides \a desc.
655 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is to
656 * delete this mesh using decrRef() as it is no more needed.
657 * \throw If the coordinates array is not set.
658 * \throw If the nodal connectivity of cells is node defined.
659 * \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
660 * revDescIndx == NULL.
662 * \if ENABLE_EXAMPLES
663 * \ref cpp_mcumesh_buildDescendingConnectivity "Here is a C++ example".<br>
664 * \ref py_mcumesh_buildDescendingConnectivity "Here is a Python example".
666 * \sa buildDescendingConnectivity2()
668 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
670 return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
674 * \a this has to have a mesh dimension equal to 3. If it is not the case an INTERP_KERNEL::Exception will be thrown.
675 * This behaves exactly as MEDCouplingUMesh::buildDescendingConnectivity does except that this method compute directly the transition from mesh dimension 3 to sub edges (dimension 1)
676 * in one shot. That is to say that this method is equivalent to 2 successive calls to MEDCouplingUMesh::buildDescendingConnectivity.
677 * This method returns 4 arrays and a mesh as MEDCouplingUMesh::buildDescendingConnectivity does.
678 * \sa MEDCouplingUMesh::buildDescendingConnectivity
680 MEDCouplingUMesh *MEDCouplingUMesh::explode3DMeshTo1D(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
683 if(getMeshDimension()!=3)
684 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explode3DMeshTo1D : This has to have a mesh dimension to 3 !");
685 return buildDescendingConnectivityGen<MinusTwoSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
689 * 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.
690 * This method works for both meshes with mesh dimension equal to 2 or 3. Dynamical cells are not supported (polygons, polyhedrons...)
692 * \sa explode3DMeshTo1D, buildDescendingConnectiviy
694 MEDCouplingUMesh *MEDCouplingUMesh::explodeMeshIntoMicroEdges(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
697 switch(getMeshDimension())
700 return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
702 return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
704 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explodeMeshIntoMicroEdges : Only 2D and 3D supported !");
709 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
710 * this->getMeshDimension(), that bound cells of \a this mesh. In
711 * addition arrays describing correspondence between cells of \a this and the result
712 * meshes are returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending
713 * connectivity, i.e. enumerate cells of the result mesh bounding each cell of \a this
714 * mesh. This method differs from buildDescendingConnectivity() in that apart
715 * from cell ids, \a desc returns mutual orientation of cells in \a this and the
716 * result meshes. So a positive id means that order of nodes in corresponding cells
717 * of two meshes is same, and a negative id means a reverse order of nodes. Since a
718 * cell with id #0 can't be negative, the array \a desc returns ids in FORTRAN mode,
719 * i.e. cell ids are one-based.
720 * Arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
721 * i.e. enumerate cells of \a this mesh bounded by each cell of the result mesh.
722 * \warning For speed reasons, this method does not check if node ids in the nodal
723 * connectivity correspond to the size of node coordinates array.
724 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
725 * to write this mesh to the MED file, its cells must be sorted using
726 * sortCellsInMEDFileFrmt().
727 * \param [in,out] desc - the array containing cell ids of the result mesh bounding
728 * each cell of \a this mesh.
729 * \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
730 * dividing cell ids in \a desc into groups each referring to one
731 * cell of \a this mesh. Its every element (except the last one) is an index
732 * pointing to the first id of a group of cells. For example cells of the
733 * result mesh bounding the cell #1 of \a this mesh are described by following
735 * [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
736 * \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
737 * Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
738 * \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
739 * \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
740 * by each cell of the result mesh.
741 * \param [in,out] revDescIndx - the array, of length one more than number of cells
742 * in the result mesh,
743 * dividing cell ids in \a revDesc into groups each referring to one
744 * cell of the result mesh the same way as \a descIndx divides \a desc.
745 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This result mesh
746 * shares the node coordinates array with \a this mesh. The caller is to
747 * delete this mesh using decrRef() as it is no more needed.
748 * \throw If the coordinates array is not set.
749 * \throw If the nodal connectivity of cells is node defined.
750 * \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
751 * revDescIndx == NULL.
753 * \if ENABLE_EXAMPLES
754 * \ref cpp_mcumesh_buildDescendingConnectivity2 "Here is a C++ example".<br>
755 * \ref py_mcumesh_buildDescendingConnectivity2 "Here is a Python example".
757 * \sa buildDescendingConnectivity()
759 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity2(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
761 return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingOrientationSensitiveNbrer);
765 * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
766 * For speed reasons no check of this will be done. This method calls
767 * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
768 * This method lists cell by cell in \b this which are its neighbors. To compute the result
769 * only connectivities are considered.
770 * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
771 * The format of return is hence \ref numbering-indirect.
773 * \param [out] neighbors is an array storing all the neighbors of all cells in \b this. This array is newly
774 * allocated and should be dealt by the caller. \b neighborsIndx 2nd output
775 * parameter allows to select the right part in this array (\ref numbering-indirect). The number of tuples
776 * is equal to the last values in \b neighborsIndx.
777 * \param [out] neighborsIndx is an array of size this->getNumberOfCells()+1 newly allocated and should be
778 * dealt by the caller. This arrays allow to use the first output parameter \b neighbors (\ref numbering-indirect).
780 void MEDCouplingUMesh::computeNeighborsOfCells(DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIndx) const
782 MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
783 MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
784 MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
785 MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
786 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
788 ComputeNeighborsOfCellsAdv(desc,descIndx,revDesc,revDescIndx,neighbors,neighborsIndx);
791 void MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne(const DataArrayIdType *nodeNeigh, const DataArrayIdType *nodeNeighI, MCAuto<DataArrayIdType>& cellNeigh, MCAuto<DataArrayIdType>& cellNeighIndex) const
793 if(!nodeNeigh || !nodeNeighI)
794 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : null pointer !");
795 checkConsistencyLight();
796 nodeNeigh->checkAllocated(); nodeNeighI->checkAllocated();
797 nodeNeigh->checkNbOfComps(1,"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : node neigh");
798 nodeNeighI->checkNbOfComps(1,"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : node neigh index");
799 nodeNeighI->checkNbOfTuples(1+getNumberOfNodes(),"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : invalid length");
800 mcIdType nbCells=getNumberOfCells();
801 const mcIdType *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin()),*ne(nodeNeigh->begin()),*nei(nodeNeighI->begin());
802 cellNeigh=DataArrayIdType::New(); cellNeigh->alloc(0,1); cellNeighIndex=DataArrayIdType::New(); cellNeighIndex->alloc(1,1); cellNeighIndex->setIJ(0,0,0);
803 for(mcIdType i=0;i<nbCells;i++)
805 std::set<mcIdType> s;
806 for(const mcIdType *it=c+ci[i]+1;it!=c+ci[i+1];it++)
808 s.insert(ne+nei[*it],ne+nei[*it+1]);
810 cellNeigh->insertAtTheEnd(s.begin(),s.end());
811 cellNeighIndex->pushBackSilent(cellNeigh->getNumberOfTuples());
816 * This method is called by MEDCouplingUMesh::computeNeighborsOfCells. This methods performs the algorithm
817 * of MEDCouplingUMesh::computeNeighborsOfCells.
818 * This method is useful for users that want to reduce along a criterion the set of neighbours cell. This is
819 * typically the case to extract a set a neighbours,
820 * excluding a set of meshdim-1 cells in input descending connectivity.
821 * Typically \b desc, \b descIndx, \b revDesc and \b revDescIndx (\ref numbering-indirect) input params are
822 * the result of MEDCouplingUMesh::buildDescendingConnectivity.
823 * This method lists cell by cell in \b this which are its neighbors. To compute the result only connectivities
825 * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
827 * \param [in] desc descending connectivity array.
828 * \param [in] descIndx descending connectivity index array used to walk through \b desc (\ref numbering-indirect).
829 * \param [in] revDesc reverse descending connectivity array.
830 * \param [in] revDescIndx reverse descending connectivity index array used to walk through \b revDesc (\ref numbering-indirect).
831 * \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
832 * parameter allows to select the right part in this array. The number of tuples is equal to the last values in \b neighborsIndx.
833 * \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.
835 void MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(const DataArrayIdType *desc, const DataArrayIdType *descIndx, const DataArrayIdType *revDesc, const DataArrayIdType *revDescIndx,
836 DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIndx)
838 if(!desc || !descIndx || !revDesc || !revDescIndx)
839 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeNeighborsOfCellsAdv some input array is empty !");
840 const mcIdType *descPtr=desc->begin();
841 const mcIdType *descIPtr=descIndx->begin();
842 const mcIdType *revDescPtr=revDesc->begin();
843 const mcIdType *revDescIPtr=revDescIndx->begin();
845 mcIdType nbCells=descIndx->getNumberOfTuples()-1;
846 MCAuto<DataArrayIdType> out0=DataArrayIdType::New();
847 MCAuto<DataArrayIdType> out1=DataArrayIdType::New(); out1->alloc(nbCells+1,1);
848 mcIdType *out1Ptr=out1->getPointer();
850 out0->reserve(desc->getNumberOfTuples());
851 for(mcIdType i=0;i<nbCells;i++,descIPtr++,out1Ptr++)
853 for(const mcIdType *w1=descPtr+descIPtr[0];w1!=descPtr+descIPtr[1];w1++)
855 std::set<mcIdType> s(revDescPtr+revDescIPtr[*w1],revDescPtr+revDescIPtr[(*w1)+1]);
857 out0->insertAtTheEnd(s.begin(),s.end());
859 *out1Ptr=out0->getNumberOfTuples();
861 neighbors=out0.retn();
862 neighborsIndx=out1.retn();
866 * Explodes \a this into edges whatever its dimension.
868 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::explodeIntoEdges(MCAuto<DataArrayIdType>& desc, MCAuto<DataArrayIdType>& descIndex, MCAuto<DataArrayIdType>& revDesc, MCAuto<DataArrayIdType>& revDescIndx) const
871 int mdim(getMeshDimension());
872 desc=DataArrayIdType::New(); descIndex=DataArrayIdType::New(); revDesc=DataArrayIdType::New(); revDescIndx=DataArrayIdType::New();
873 MCAuto<MEDCouplingUMesh> mesh1D;
878 mesh1D=explode3DMeshTo1D(desc,descIndex,revDesc,revDescIndx);
883 mesh1D=buildDescendingConnectivity(desc,descIndex,revDesc,revDescIndx);
888 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2] !");
895 * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
896 * For speed reasons no check of this will be done. This method calls
897 * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
898 * This method lists node by node in \b this which are its neighbors. To compute the result
899 * only connectivities are considered.
900 * The neighbor nodes of node having id 'nodeId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
902 * \param [out] neighbors is an array storing all the neighbors of all nodes in \b this. This array
903 * is newly allocated and should be dealt by the caller. \b neighborsIndx 2nd output
904 * parameter allows to select the right part in this array (\ref numbering-indirect).
905 * The number of tuples is equal to the last values in \b neighborsIndx.
906 * \param [out] neighborsIdx is an array of size this->getNumberOfCells()+1 newly allocated and should
907 * be dealt by the caller. This arrays allow to use the first output parameter \b neighbors.
909 * \sa MEDCouplingUMesh::computeEnlargedNeighborsOfNodes
911 void MEDCouplingUMesh::computeNeighborsOfNodes(DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIdx) const
914 mcIdType mdim(getMeshDimension()),nbNodes(getNumberOfNodes());
915 MCAuto<DataArrayIdType> desc(DataArrayIdType::New()),descIndx(DataArrayIdType::New()),revDesc(DataArrayIdType::New()),revDescIndx(DataArrayIdType::New());
916 MCConstAuto<MEDCouplingUMesh> mesh1D;
921 mesh1D=explode3DMeshTo1D(desc,descIndx,revDesc,revDescIndx);
926 mesh1D=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
931 mesh1D.takeRef(this);
936 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2,1] !");
939 desc=DataArrayIdType::New(); descIndx=DataArrayIdType::New(); revDesc=0; revDescIndx=0;
940 mesh1D->getReverseNodalConnectivity(desc,descIndx);
941 MCAuto<DataArrayIdType> ret0(DataArrayIdType::New());
942 ret0->alloc(desc->getNumberOfTuples(),1);
943 mcIdType *r0Pt(ret0->getPointer());
944 const mcIdType *c1DPtr(mesh1D->getNodalConnectivity()->begin()),*rn(desc->begin()),*rni(descIndx->begin());
945 for(mcIdType i=0;i<nbNodes;i++,rni++)
947 for(const mcIdType *oneDCellIt=rn+rni[0];oneDCellIt!=rn+rni[1];oneDCellIt++)
948 *r0Pt++=c1DPtr[3*(*oneDCellIt)+1]==i?c1DPtr[3*(*oneDCellIt)+2]:c1DPtr[3*(*oneDCellIt)+1];
950 neighbors=ret0.retn();
951 neighborsIdx=descIndx.retn();
955 * 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.
956 * 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.
957 * This method is useful to find ghost cells of a part of a mesh with a code based on fields on nodes.
959 * \sa MEDCouplingUMesh::computeNeighborsOfNodes
961 void MEDCouplingUMesh::computeEnlargedNeighborsOfNodes(MCAuto<DataArrayIdType> &neighbors, MCAuto<DataArrayIdType>& neighborsIdx) const
964 mcIdType nbOfNodes(getNumberOfNodes());
965 const mcIdType *conn(_nodal_connec->begin()),*connIndex(_nodal_connec_index->begin());
966 mcIdType nbOfCells=getNumberOfCells();
967 std::vector< std::set<mcIdType> > st0(nbOfNodes);
968 for(mcIdType eltId=0;eltId<nbOfCells;eltId++)
970 const mcIdType *strtNdlConnOfCurCell(conn+connIndex[eltId]+1),*endNdlConnOfCurCell(conn+connIndex[eltId+1]);
971 std::set<mcIdType> s(strtNdlConnOfCurCell,endNdlConnOfCurCell); s.erase(-1); //for polyhedrons
972 for(std::set<mcIdType>::const_iterator iter2=s.begin();iter2!=s.end();iter2++)
973 st0[*iter2].insert(s.begin(),s.end());
975 neighborsIdx=DataArrayIdType::New(); neighborsIdx->alloc(nbOfNodes+1,1); neighborsIdx->setIJ(0,0,0);
977 mcIdType *neighIdx(neighborsIdx->getPointer());
978 for(std::vector< std::set<mcIdType> >::const_iterator it=st0.begin();it!=st0.end();it++,neighIdx++)
981 neighIdx[1]=neighIdx[0];
983 neighIdx[1]=neighIdx[0]+ToIdType((*it).size())-1;
986 neighbors=DataArrayIdType::New(); neighbors->alloc(neighborsIdx->back(),1);
988 const mcIdType *neighIdx(neighborsIdx->begin());
989 mcIdType *neigh(neighbors->getPointer()),nodeId(0);
990 for(std::vector< std::set<mcIdType> >::const_iterator it=st0.begin();it!=st0.end();it++,neighIdx++,nodeId++)
992 std::set<mcIdType> s(*it); s.erase(nodeId);
993 std::copy(s.begin(),s.end(),neigh+*neighIdx);
999 * Converts specified cells to either polygons (if \a this is a 2D mesh) or
1000 * polyhedrons (if \a this is a 3D mesh). The cells to convert are specified by an
1001 * array of cell ids. Pay attention that after conversion all algorithms work slower
1002 * with \a this mesh than before conversion. <br> If an exception is thrown during the
1003 * conversion due presence of invalid ids in the array of cells to convert, as a
1004 * result \a this mesh contains some already converted elements. In this case the 2D
1005 * mesh remains valid but 3D mesh becomes \b inconsistent!
1006 * \warning This method can significantly modify the order of geometric types in \a this,
1007 * hence, to write this mesh to the MED file, its cells must be sorted using
1008 * sortCellsInMEDFileFrmt().
1009 * \param [in] cellIdsToConvertBg - the array holding ids of cells to convert.
1010 * \param [in] cellIdsToConvertEnd - a pointer to the last-plus-one-th element of \a
1011 * cellIdsToConvertBg.
1012 * \throw If the coordinates array is not set.
1013 * \throw If the nodal connectivity of cells is node defined.
1014 * \throw If dimension of \a this mesh is not either 2 or 3.
1016 * \if ENABLE_EXAMPLES
1017 * \ref cpp_mcumesh_convertToPolyTypes "Here is a C++ example".<br>
1018 * \ref py_mcumesh_convertToPolyTypes "Here is a Python example".
1021 void MEDCouplingUMesh::convertToPolyTypes(const mcIdType *cellIdsToConvertBg, const mcIdType *cellIdsToConvertEnd)
1023 checkFullyDefined();
1024 int dim=getMeshDimension();
1026 throw INTERP_KERNEL::Exception("Invalid mesh dimension : must be 2 or 3 !");
1027 mcIdType nbOfCells=getNumberOfCells();
1030 const mcIdType *connIndex=_nodal_connec_index->begin();
1031 mcIdType *conn=_nodal_connec->getPointer();
1032 for(const mcIdType *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1034 if(*iter>=0 && *iter<nbOfCells)
1036 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*iter]]);
1037 if(!cm.isQuadratic())
1038 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_POLYGON;
1040 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_QPOLYG;
1044 std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1045 oss << " in range [0," << nbOfCells << ") !";
1046 throw INTERP_KERNEL::Exception(oss.str());
1052 mcIdType *connIndex(_nodal_connec_index->getPointer());
1053 const mcIdType *connOld(_nodal_connec->getConstPointer());
1054 MCAuto<DataArrayIdType> connNew(DataArrayIdType::New()),connNewI(DataArrayIdType::New()); connNew->alloc(0,1); connNewI->alloc(1,1); connNewI->setIJ(0,0,0);
1055 std::vector<bool> toBeDone(nbOfCells,false);
1056 for(const mcIdType *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1058 if(*iter>=0 && *iter<nbOfCells)
1059 toBeDone[*iter]=true;
1062 std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1063 oss << " in range [0," << nbOfCells << ") !";
1064 throw INTERP_KERNEL::Exception(oss.str());
1067 for(mcIdType cellId=0;cellId<nbOfCells;cellId++)
1069 mcIdType pos(connIndex[cellId]),posP1(connIndex[cellId+1]);
1070 mcIdType lgthOld(posP1-pos-1);
1071 if(toBeDone[cellId])
1073 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connOld[pos]);
1074 unsigned nbOfFaces(cm.getNumberOfSons2(connOld+pos+1,lgthOld));
1075 mcIdType *tmp(new mcIdType[nbOfFaces*lgthOld+1]);
1076 mcIdType *work=tmp; *work++=INTERP_KERNEL::NORM_POLYHED;
1077 for(unsigned j=0;j<nbOfFaces;j++)
1079 INTERP_KERNEL::NormalizedCellType type;
1080 unsigned offset=cm.fillSonCellNodalConnectivity2(j,connOld+pos+1,lgthOld,work,type);
1084 std::size_t newLgth(std::distance(tmp,work)-1);//-1 for last -1
1085 connNew->pushBackValsSilent(tmp,tmp+newLgth);
1086 connNewI->pushBackSilent(connNewI->back()+ToIdType(newLgth));
1091 connNew->pushBackValsSilent(connOld+pos,connOld+posP1);
1092 connNewI->pushBackSilent(connNewI->back()+posP1-pos);
1095 setConnectivity(connNew,connNewI,false);//false because computeTypes called just behind.
1101 * Converts all cells to either polygons (if \a this is a 2D mesh) or
1102 * polyhedrons (if \a this is a 3D mesh).
1103 * \warning As this method is purely for user-friendliness and no optimization is
1104 * done to avoid construction of a useless vector, this method can be costly
1106 * \throw If the coordinates array is not set.
1107 * \throw If the nodal connectivity of cells is node defined.
1108 * \throw If dimension of \a this mesh is not either 2 or 3.
1110 void MEDCouplingUMesh::convertAllToPoly()
1112 mcIdType nbOfCells=getNumberOfCells();
1113 std::vector<mcIdType> cellIds(nbOfCells);
1114 for(mcIdType i=0;i<nbOfCells;i++)
1116 convertToPolyTypes(&cellIds[0],&cellIds[0]+ToIdType(cellIds.size()));
1120 * Fixes nodal connectivity of invalid cells of type NORM_POLYHED. This method
1121 * expects that all NORM_POLYHED cells have connectivity similar to that of prismatic
1122 * volumes like NORM_HEXA8, NORM_PENTA6 etc., i.e. the first half of nodes describes a
1123 * base facet of the volume and the second half of nodes describes an opposite facet
1124 * having the same number of nodes as the base one. This method converts such
1125 * connectivity to a valid polyhedral format where connectivity of each facet is
1126 * explicitly described and connectivity of facets are separated by -1. If \a this mesh
1127 * contains a NORM_POLYHED cell with a valid connectivity, or an invalid connectivity is
1128 * not as expected, an exception is thrown and the mesh remains unchanged. Care of
1129 * a correct orientation of the first facet of a polyhedron, else orientation of a
1130 * corrected cell is reverse.<br>
1131 * This method is useful to build an extruded unstructured mesh with polyhedrons as
1132 * it releases the user from boring description of polyhedra connectivity in the valid
1134 * \throw If \a this->getMeshDimension() != 3.
1135 * \throw If \a this->getSpaceDimension() != 3.
1136 * \throw If the nodal connectivity of cells is not defined.
1137 * \throw If the coordinates array is not set.
1138 * \throw If \a this mesh contains polyhedrons with the valid connectivity.
1139 * \throw If \a this mesh contains polyhedrons with odd number of nodes.
1141 * \if ENABLE_EXAMPLES
1142 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
1143 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
1146 void MEDCouplingUMesh::convertExtrudedPolyhedra()
1148 checkFullyDefined();
1149 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1150 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertExtrudedPolyhedra works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
1151 mcIdType nbOfCells=getNumberOfCells();
1152 MCAuto<DataArrayIdType> newCi=DataArrayIdType::New();
1153 newCi->alloc(nbOfCells+1,1);
1154 mcIdType *newci=newCi->getPointer();
1155 const mcIdType *ci=_nodal_connec_index->getConstPointer();
1156 const mcIdType *c=_nodal_connec->getConstPointer();
1158 for(mcIdType i=0;i<nbOfCells;i++)
1160 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1161 if(type==INTERP_KERNEL::NORM_POLYHED)
1163 if(std::count(c+ci[i]+1,c+ci[i+1],-1)!=0)
1165 std::ostringstream oss; oss << "MEDCouplingUMesh::convertExtrudedPolyhedra : cell # " << i << " is a polhedron BUT it has NOT exactly 1 face !";
1166 throw INTERP_KERNEL::Exception(oss.str());
1168 std::size_t n2=std::distance(c+ci[i]+1,c+ci[i+1]);
1171 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 !";
1172 throw INTERP_KERNEL::Exception(oss.str());
1174 mcIdType n1=ToIdType(n2/2);
1175 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)
1178 newci[i+1]=(ci[i+1]-ci[i])+newci[i];
1180 MCAuto<DataArrayIdType> newC=DataArrayIdType::New();
1181 newC->alloc(newci[nbOfCells],1);
1182 mcIdType *newc=newC->getPointer();
1183 for(mcIdType i=0;i<nbOfCells;i++)
1185 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1186 if(type==INTERP_KERNEL::NORM_POLYHED)
1188 std::size_t n1=std::distance(c+ci[i]+1,c+ci[i+1])/2;
1189 newc=std::copy(c+ci[i],c+ci[i]+n1+1,newc);
1191 for(std::size_t j=0;j<n1;j++)
1193 newc[j]=c[ci[i]+1+n1+(n1-j)%n1];
1195 newc[n1+5*j+1]=c[ci[i]+1+j];
1196 newc[n1+5*j+2]=c[ci[i]+1+j+n1];
1197 newc[n1+5*j+3]=c[ci[i]+1+(j+1)%n1+n1];
1198 newc[n1+5*j+4]=c[ci[i]+1+(j+1)%n1];
1203 newc=std::copy(c+ci[i],c+ci[i+1],newc);
1205 _nodal_connec_index->decrRef(); _nodal_connec_index=newCi.retn();
1206 _nodal_connec->decrRef(); _nodal_connec=newC.retn();
1211 * Converts all polygons (if \a this is a 2D mesh) or polyhedrons (if \a this is a 3D
1212 * mesh) to cells of classical types. This method is opposite to convertToPolyTypes().
1213 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
1214 * to write this mesh to the MED file, its cells must be sorted using
1215 * sortCellsInMEDFileFrmt().
1216 * \warning Cells (and most notably polyhedrons) must be correctly oriented for this to work
1217 * properly. See orientCorrectlyPolyhedrons() and arePolyhedronsNotCorrectlyOriented().
1218 * \return \c true if at least one cell has been converted, \c false else. In the
1219 * last case the nodal connectivity remains unchanged.
1220 * \throw If the coordinates array is not set.
1221 * \throw If the nodal connectivity of cells is not defined.
1222 * \throw If \a this->getMeshDimension() < 0.
1224 bool MEDCouplingUMesh::unPolyze()
1226 checkFullyDefined();
1227 int mdim=getMeshDimension();
1229 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::unPolyze works on umeshes with meshdim equals to 0, 1 2 or 3 !");
1232 mcIdType nbOfCells=getNumberOfCells();
1235 mcIdType initMeshLgth=getNodalConnectivityArrayLen();
1236 mcIdType *conn=_nodal_connec->getPointer();
1237 mcIdType *index=_nodal_connec_index->getPointer();
1238 mcIdType posOfCurCell=0;
1240 mcIdType lgthOfCurCell;
1242 for(mcIdType i=0;i<nbOfCells;i++)
1244 lgthOfCurCell=index[i+1]-posOfCurCell;
1245 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
1246 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
1247 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::NORM_ERROR;
1251 switch(cm.getDimension())
1255 INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[lgthOfCurCell-1];
1256 std::copy(conn+posOfCurCell+1,conn+posOfCurCell+lgthOfCurCell,(mcIdType *)tmp);
1257 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly2D(cm.isQuadratic(),tmp,lgthOfCurCell-1,conn+newPos+1,newLgth);
1262 mcIdType nbOfFaces,lgthOfPolyhConn;
1263 INTERP_KERNEL::AutoPtr<mcIdType> zipFullReprOfPolyh=INTERP_KERNEL::CellSimplify::getFullPolyh3DCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,nbOfFaces,lgthOfPolyhConn);
1264 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly3D(zipFullReprOfPolyh,nbOfFaces,lgthOfPolyhConn,conn+newPos+1,newLgth);
1269 newType=(lgthOfCurCell==3)?INTERP_KERNEL::NORM_SEG2:INTERP_KERNEL::NORM_POLYL;
1273 ret=ret || (newType!=type);
1274 conn[newPos]=newType;
1276 posOfCurCell=index[i+1];
1281 std::copy(conn+posOfCurCell,conn+posOfCurCell+lgthOfCurCell,conn+newPos);
1282 newPos+=lgthOfCurCell;
1283 posOfCurCell+=lgthOfCurCell;
1287 if(newPos!=initMeshLgth)
1288 _nodal_connec->reAlloc(newPos);
1295 * This method expects that spaceDimension is equal to 3 and meshDimension equal to 3.
1296 * This method performs operation only on polyhedrons in \b this. If no polyhedrons exists in \b this, \b this remains unchanged.
1297 * This method allows to merge if any coplanar 3DSurf cells that may appear in some polyhedrons cells.
1299 * \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
1302 void MEDCouplingUMesh::simplifyPolyhedra(double eps)
1304 checkFullyDefined();
1305 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1306 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplifyPolyhedra : works on meshdimension 3 and spaceDimension 3 !");
1307 MCAuto<DataArrayDouble> coords=getCoords()->deepCopy();
1308 coords->recenterForMaxPrecision(eps);
1310 mcIdType nbOfCells=getNumberOfCells();
1311 const mcIdType *conn=_nodal_connec->getConstPointer();
1312 const mcIdType *index=_nodal_connec_index->getConstPointer();
1313 MCAuto<DataArrayIdType> connINew=DataArrayIdType::New();
1314 connINew->alloc(nbOfCells+1,1);
1315 mcIdType *connINewPtr=connINew->getPointer(); *connINewPtr++=0;
1316 MCAuto<DataArrayIdType> connNew=DataArrayIdType::New(); connNew->alloc(0,1);
1317 MCAuto<DataArrayIdType> E_Fi(DataArrayIdType::New()), E_F(DataArrayIdType::New()), F_Ei(DataArrayIdType::New()), F_E(DataArrayIdType::New());
1318 MCAuto<MEDCouplingUMesh> m_faces(buildDescendingConnectivity(E_F, E_Fi, F_E, F_Ei));
1320 for(mcIdType i=0;i<nbOfCells;i++,connINewPtr++)
1322 if(conn[index[i]]==ToIdType(INTERP_KERNEL::NORM_POLYHED))
1324 SimplifyPolyhedronCell(eps,coords, i,connNew, m_faces, E_Fi, E_F, F_Ei, F_E);
1328 connNew->insertAtTheEnd(conn+index[i],conn+index[i+1]);
1329 *connINewPtr=connNew->getNumberOfTuples();
1332 setConnectivity(connNew,connINew,false);
1336 * This method returns all node ids used in the connectivity of \b this. The data array returned has to be dealt by the caller.
1337 * The returned node ids are sorted ascendingly. This method is close to MEDCouplingUMesh::getNodeIdsInUse except
1338 * the format of the returned DataArrayIdType instance.
1340 * \return a newly allocated DataArrayIdType sorted ascendingly of fetched node ids.
1341 * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1343 DataArrayIdType *MEDCouplingUMesh::computeFetchedNodeIds() const
1345 checkConnectivityFullyDefined();
1346 const mcIdType *maxEltPt(std::max_element(_nodal_connec->begin(),_nodal_connec->end()));
1347 mcIdType maxElt(maxEltPt==_nodal_connec->end()?0:std::abs(*maxEltPt)+1);
1348 std::vector<bool> retS(maxElt,false);
1349 computeNodeIdsAlg(retS);
1350 return DataArrayIdType::BuildListOfSwitchedOn(retS);
1354 * \param [in,out] nodeIdsInUse an array of size typically equal to nbOfNodes.
1355 * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1357 void MEDCouplingUMesh::computeNodeIdsAlg(std::vector<bool>& nodeIdsInUse) const
1359 mcIdType nbOfNodes=ToIdType(nodeIdsInUse.size()),
1360 nbOfCells=getNumberOfCells();
1361 const mcIdType *connIndex(_nodal_connec_index->getConstPointer()),*conn(_nodal_connec->getConstPointer());
1362 for(mcIdType i=0;i<nbOfCells;i++)
1363 for(mcIdType j=connIndex[i]+1;j<connIndex[i+1];j++)
1366 if(conn[j]<nbOfNodes)
1367 nodeIdsInUse[conn[j]]=true;
1370 std::ostringstream oss; oss << "MEDCouplingUMesh::computeNodeIdsAlg : In cell #" << i << " presence of node id " << conn[j] << " not in [0," << nbOfNodes << ") !";
1371 throw INTERP_KERNEL::Exception(oss.str());
1378 struct MEDCouplingAccVisit
1380 MEDCouplingAccVisit():_new_nb_of_nodes(0) { }
1381 mcIdType operator()(mcIdType val) { if(val!=-1) return _new_nb_of_nodes++; else return -1; }
1382 mcIdType _new_nb_of_nodes;
1388 * Finds nodes not used in any cell and returns an array giving a new id to every node
1389 * by excluding the unused nodes, for which the array holds -1. The result array is
1390 * a mapping in "Old to New" mode.
1391 * \param [out] nbrOfNodesInUse - number of node ids present in the nodal connectivity.
1392 * \return DataArrayIdType * - a new instance of DataArrayIdType. Its length is \a
1393 * this->getNumberOfNodes(). It holds for each node of \a this mesh either -1
1394 * if the node is unused or a new id else. The caller is to delete this
1395 * array using decrRef() as it is no more needed.
1396 * \throw If the coordinates array is not set.
1397 * \throw If the nodal connectivity of cells is not defined.
1398 * \throw If the nodal connectivity includes an invalid id.
1400 * \if ENABLE_EXAMPLES
1401 * \ref cpp_mcumesh_getNodeIdsInUse "Here is a C++ example".<br>
1402 * \ref py_mcumesh_getNodeIdsInUse "Here is a Python example".
1404 * \sa computeFetchedNodeIds, computeNodeIdsAlg()
1406 DataArrayIdType *MEDCouplingUMesh::getNodeIdsInUse(mcIdType& nbrOfNodesInUse) const
1409 mcIdType nbOfNodes(getNumberOfNodes());
1410 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1411 ret->alloc(nbOfNodes,1);
1412 mcIdType *traducer=ret->getPointer();
1413 std::fill(traducer,traducer+nbOfNodes,-1);
1414 mcIdType nbOfCells=getNumberOfCells();
1415 const mcIdType *connIndex=_nodal_connec_index->getConstPointer();
1416 const mcIdType *conn=_nodal_connec->getConstPointer();
1417 for(mcIdType i=0;i<nbOfCells;i++)
1418 for(mcIdType j=connIndex[i]+1;j<connIndex[i+1];j++)
1421 if(conn[j]<nbOfNodes)
1422 traducer[conn[j]]=1;
1425 std::ostringstream oss; oss << "MEDCouplingUMesh::getNodeIdsInUse : In cell #" << i << " presence of node id " << conn[j] << " not in [0," << nbOfNodes << ") !";
1426 throw INTERP_KERNEL::Exception(oss.str());
1429 nbrOfNodesInUse=ToIdType(std::count(traducer,traducer+nbOfNodes,1));
1430 std::transform(traducer,traducer+nbOfNodes,traducer,MEDCouplingAccVisit());
1435 * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1436 * For each cell in \b this the number of nodes constituting cell is computed.
1437 * For each polyhedron cell, the sum of the number of nodes of each face constituting polyhedron cell is returned.
1438 * So for pohyhedrons some nodes can be counted several times in the returned result.
1440 * \return a newly allocated array
1441 * \sa MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell
1443 DataArrayIdType *MEDCouplingUMesh::computeNbOfNodesPerCell() const
1445 checkConnectivityFullyDefined();
1446 mcIdType nbOfCells=getNumberOfCells();
1447 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1448 ret->alloc(nbOfCells,1);
1449 mcIdType *retPtr=ret->getPointer();
1450 const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1451 const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1452 for(mcIdType i=0;i<nbOfCells;i++,retPtr++)
1454 if(conn[connI[i]]!=ToIdType(INTERP_KERNEL::NORM_POLYHED))
1455 *retPtr=connI[i+1]-connI[i]-1;
1457 *retPtr=connI[i+1]-connI[i]-1-ToIdType(std::count(conn+connI[i]+1,conn+connI[i+1],-1));
1463 * This method computes effective number of nodes per cell. That is to say nodes appearing several times in nodal connectivity of a cell,
1464 * will be counted only once here whereas it will be counted several times in MEDCouplingUMesh::computeNbOfNodesPerCell method.
1466 * \return DataArrayIdType * - new object to be deallocated by the caller.
1467 * \sa MEDCouplingUMesh::computeNbOfNodesPerCell
1469 DataArrayIdType *MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell() const
1471 checkConnectivityFullyDefined();
1472 mcIdType nbOfCells=getNumberOfCells();
1473 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1474 ret->alloc(nbOfCells,1);
1475 mcIdType *retPtr=ret->getPointer();
1476 const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1477 const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1478 for(mcIdType i=0;i<nbOfCells;i++,retPtr++)
1480 std::set<mcIdType> s(conn+connI[i]+1,conn+connI[i+1]);
1481 if(conn[connI[i]]!=ToIdType(INTERP_KERNEL::NORM_POLYHED))
1482 *retPtr=ToIdType(s.size());
1486 *retPtr=ToIdType(s.size());
1493 * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1494 * For each cell in \b this the number of faces constituting (entity of dimension this->getMeshDimension()-1) cell is computed.
1496 * \return a newly allocated array
1498 DataArrayIdType *MEDCouplingUMesh::computeNbOfFacesPerCell() const
1500 checkConnectivityFullyDefined();
1501 mcIdType nbOfCells=getNumberOfCells();
1502 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1503 ret->alloc(nbOfCells,1);
1504 mcIdType *retPtr=ret->getPointer();
1505 const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1506 const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1507 for(mcIdType i=0;i<nbOfCells;i++,retPtr++,connI++)
1509 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]);
1510 *retPtr=cm.getNumberOfSons2(conn+connI[0]+1,connI[1]-connI[0]-1);
1516 * Removes unused nodes (the node coordinates array is shorten) and returns an array
1517 * mapping between new and old node ids in "Old to New" mode. -1 values in the returned
1518 * array mean that the corresponding old node is no more used.
1519 * \return DataArrayIdType * - a new instance of DataArrayIdType of length \a
1520 * this->getNumberOfNodes() before call of this method. The caller is to
1521 * delete this array using decrRef() as it is no more needed.
1522 * \throw If the coordinates array is not set.
1523 * \throw If the nodal connectivity of cells is not defined.
1524 * \throw If the nodal connectivity includes an invalid id.
1525 * \sa areAllNodesFetched
1527 * \if ENABLE_EXAMPLES
1528 * \ref cpp_mcumesh_zipCoordsTraducer "Here is a C++ example".<br>
1529 * \ref py_mcumesh_zipCoordsTraducer "Here is a Python example".
1532 DataArrayIdType *MEDCouplingUMesh::zipCoordsTraducer()
1534 return MEDCouplingPointSet::zipCoordsTraducer();
1538 * This method stands if 'cell1' and 'cell2' are equals regarding 'compType' policy.
1539 * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1541 int MEDCouplingUMesh::AreCellsEqual(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2, int compType)
1546 return AreCellsEqualPolicy0(conn,connI,cell1,cell2);
1548 return AreCellsEqualPolicy1(conn,connI,cell1,cell2);
1550 return AreCellsEqualPolicy2(conn,connI,cell1,cell2);
1552 return AreCellsEqualPolicy2NoType(conn,connI,cell1,cell2);
1554 return AreCellsEqualPolicy7(conn,connI,cell1,cell2);
1556 throw INTERP_KERNEL::Exception("Unknown comparison asked ! Must be in 0,1,2,3 or 7.");
1560 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 0.
1562 int MEDCouplingUMesh::AreCellsEqualPolicy0(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1564 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1565 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;
1570 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 1.
1572 int MEDCouplingUMesh::AreCellsEqualPolicy1(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1574 mcIdType sz=connI[cell1+1]-connI[cell1];
1575 if(sz==connI[cell2+1]-connI[cell2])
1577 if(conn[connI[cell1]]==conn[connI[cell2]])
1579 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1580 unsigned dim=cm.getDimension();
1585 mcIdType sz1=2*(sz-1);
1586 INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz1];
1587 mcIdType *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(mcIdType *)tmp);
1588 std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1589 work=std::search((mcIdType *)tmp,(mcIdType *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1590 return work!=tmp+sz1?1:0;
1593 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;//case of SEG2 and SEG3
1596 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy1 : not implemented yet for meshdim == 3 !");
1603 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 2.
1605 int MEDCouplingUMesh::AreCellsEqualPolicy2(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1607 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1609 if(conn[connI[cell1]]==conn[connI[cell2]])
1611 std::set<mcIdType> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1612 std::set<mcIdType> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1620 * This method is less restrictive than AreCellsEqualPolicy2. Here the geometric type is absolutely not taken into account !
1622 int MEDCouplingUMesh::AreCellsEqualPolicy2NoType(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1624 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1626 std::set<mcIdType> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1627 std::set<mcIdType> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1634 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 7.
1636 int MEDCouplingUMesh::AreCellsEqualPolicy7(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1638 mcIdType sz=connI[cell1+1]-connI[cell1];
1639 if(sz==connI[cell2+1]-connI[cell2])
1641 if(conn[connI[cell1]]==conn[connI[cell2]])
1643 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1644 unsigned dim=cm.getDimension();
1649 mcIdType sz1=2*(sz-1);
1650 INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz1];
1651 mcIdType *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(mcIdType *)tmp);
1652 std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1653 work=std::search((mcIdType *)tmp,(mcIdType *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1658 std::reverse_iterator<mcIdType *> it1((mcIdType *)tmp+sz1);
1659 std::reverse_iterator<mcIdType *> it2((mcIdType *)tmp);
1660 if(std::search(it1,it2,conn+connI[cell2]+1,conn+connI[cell2+1])!=it2)
1666 return work!=tmp+sz1?1:0;
1669 {//case of SEG2 and SEG3
1670 if(std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1))
1672 if(!cm.isQuadratic())
1674 std::reverse_iterator<const mcIdType *> it1(conn+connI[cell1+1]);
1675 std::reverse_iterator<const mcIdType *> it2(conn+connI[cell1]+1);
1676 if(std::equal(it1,it2,conn+connI[cell2]+1))
1682 if(conn[connI[cell1]+1]==conn[connI[cell2]+2] && conn[connI[cell1]+2]==conn[connI[cell2]+1] && conn[connI[cell1]+3]==conn[connI[cell2]+3])
1689 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy7 : not implemented yet for meshdim == 3 !");
1697 * This method find cells that are equal (regarding \a compType) in \a this. The comparison is specified
1699 * This method keeps the coordiantes of \a this. This method is time consuming.
1701 * \param [in] compType input specifying the technique used to compare cells each other.
1702 * - 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.
1703 * - 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)
1704 * and their type equal. For 1D mesh the policy 1 is equivalent to 0.
1705 * - 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
1706 * can be used for users not sensitive to orientation of cell
1707 * \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.
1708 * \param [out] commonCellsArr common cells ids (\ref numbering-indirect)
1709 * \param [out] commonCellsIArr common cells ids (\ref numbering-indirect)
1710 * \return the correspondence array old to new in a newly allocated array.
1713 void MEDCouplingUMesh::findCommonCells(int compType, mcIdType startCellId, DataArrayIdType *& commonCellsArr, DataArrayIdType *& commonCellsIArr) const
1715 MCAuto<DataArrayIdType> revNodal=DataArrayIdType::New(),revNodalI=DataArrayIdType::New();
1716 getReverseNodalConnectivity(revNodal,revNodalI);
1717 FindCommonCellsAlg(compType,startCellId,_nodal_connec,_nodal_connec_index,revNodal,revNodalI,commonCellsArr,commonCellsIArr);
1720 void MEDCouplingUMesh::FindCommonCellsAlg(int compType, mcIdType startCellId, const DataArrayIdType *nodal, const DataArrayIdType *nodalI, const DataArrayIdType *revNodal, const DataArrayIdType *revNodalI,
1721 DataArrayIdType *& commonCellsArr, DataArrayIdType *& commonCellsIArr)
1723 MCAuto<DataArrayIdType> commonCells=DataArrayIdType::New(),commonCellsI=DataArrayIdType::New(); commonCells->alloc(0,1);
1724 mcIdType nbOfCells=nodalI->getNumberOfTuples()-1;
1725 commonCellsI->reserve(1); commonCellsI->pushBackSilent(0);
1726 const mcIdType *revNodalPtr=revNodal->getConstPointer(),*revNodalIPtr=revNodalI->getConstPointer();
1727 const mcIdType *connPtr=nodal->getConstPointer(),*connIPtr=nodalI->getConstPointer();
1728 std::vector<bool> isFetched(nbOfCells,false);
1731 for(mcIdType i=0;i<nbOfCells;i++)
1735 const mcIdType *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind2nd(std::not_equal_to<mcIdType>(),-1));
1736 std::vector<mcIdType> v,v2;
1737 if(connOfNode!=connPtr+connIPtr[i+1])
1739 const mcIdType *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1740 v2.insert(v2.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1]);
1743 for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1747 const mcIdType *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1748 std::vector<mcIdType>::iterator it=std::set_intersection(v.begin(),v.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1749 v2.resize(std::distance(v2.begin(),it));
1753 if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1755 mcIdType pos=commonCellsI->back();
1756 commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1757 for(const mcIdType *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1758 isFetched[*it]=true;
1766 for(mcIdType i=startCellId;i<nbOfCells;i++)
1770 const mcIdType *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind2nd(std::not_equal_to<mcIdType>(),-1));
1771 std::vector<mcIdType> v,v2;
1772 if(connOfNode!=connPtr+connIPtr[i+1])
1774 v2.insert(v2.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1]);
1777 for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1781 std::vector<mcIdType>::iterator it=std::set_intersection(v.begin(),v.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1782 v2.resize(std::distance(v2.begin(),it));
1786 if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1788 mcIdType pos=commonCellsI->back();
1789 commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1790 for(const mcIdType *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1791 isFetched[*it]=true;
1797 commonCellsArr=commonCells.retn();
1798 commonCellsIArr=commonCellsI.retn();
1802 * Checks if \a this mesh includes all cells of an \a other mesh, and returns an array
1803 * giving for each cell of the \a other an id of a cell in \a this mesh. A value larger
1804 * than \a this->getNumberOfCells() in the returned array means that there is no
1805 * corresponding cell in \a this mesh.
1806 * It is expected that \a this and \a other meshes share the same node coordinates
1807 * array, if it is not so an exception is thrown.
1808 * \param [in] other - the mesh to compare with.
1809 * \param [in] compType - specifies a cell comparison technique. For meaning of its
1810 * valid values [0,1,2], see zipConnectivityTraducer().
1811 * \param [out] arr - a new instance of DataArrayIdType returning correspondence
1812 * between cells of the two meshes. It contains \a other->getNumberOfCells()
1813 * values. The caller is to delete this array using
1814 * decrRef() as it is no more needed.
1815 * \return bool - \c true if all cells of \a other mesh are present in the \a this
1818 * \if ENABLE_EXAMPLES
1819 * \ref cpp_mcumesh_areCellsIncludedIn "Here is a C++ example".<br>
1820 * \ref py_mcumesh_areCellsIncludedIn "Here is a Python example".
1822 * \sa checkDeepEquivalOnSameNodesWith()
1823 * \sa checkGeoEquivalWith()
1825 bool MEDCouplingUMesh::areCellsIncludedIn(const MEDCouplingUMesh *other, int compType, DataArrayIdType *& arr) const
1827 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1828 mcIdType nbOfCells=getNumberOfCells();
1829 static const int possibleCompType[]={0,1,2};
1830 if(std::find(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),compType)==possibleCompType+sizeof(possibleCompType)/sizeof(int))
1832 std::ostringstream oss; oss << "MEDCouplingUMesh::areCellsIncludedIn : only following policies are possible : ";
1833 std::copy(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),std::ostream_iterator<int>(oss," "));
1835 throw INTERP_KERNEL::Exception(oss.str());
1837 MCAuto<DataArrayIdType> o2n=mesh->zipConnectivityTraducer(compType,nbOfCells);
1838 arr=o2n->subArray(nbOfCells);
1839 arr->setName(other->getName());
1841 if(other->getNumberOfCells()==0)
1843 return arr->getMaxValue(tmp)<nbOfCells;
1847 * This method makes the assumption that \a this and \a other share the same coords. If not an exception will be thrown !
1848 * This method tries to determine if \b other is fully included in \b this.
1849 * The main difference is that this method is not expected to throw exception.
1850 * This method has two outputs :
1852 * \param other other mesh
1853 * \param arr is an output parameter that returns a \b newly created instance. This array is of size 'other->getNumberOfCells()'.
1854 * \return If \a other is fully included in 'this 'true is returned. If not false is returned.
1856 bool MEDCouplingUMesh::areCellsIncludedInPolicy7(const MEDCouplingUMesh *other, DataArrayIdType *& arr) const
1858 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1859 DataArrayIdType *commonCells=0,*commonCellsI=0;
1860 mcIdType thisNbCells=getNumberOfCells();
1861 mesh->findCommonCells(7,thisNbCells,commonCells,commonCellsI);
1862 MCAuto<DataArrayIdType> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1863 const mcIdType *commonCellsPtr=commonCells->getConstPointer(),*commonCellsIPtr=commonCellsI->getConstPointer();
1864 mcIdType otherNbCells=other->getNumberOfCells();
1865 MCAuto<DataArrayIdType> arr2=DataArrayIdType::New();
1866 arr2->alloc(otherNbCells,1);
1867 arr2->fillWithZero();
1868 mcIdType *arr2Ptr=arr2->getPointer();
1869 mcIdType nbOfCommon=commonCellsI->getNumberOfTuples()-1;
1870 for(mcIdType i=0;i<nbOfCommon;i++)
1872 mcIdType start=commonCellsPtr[commonCellsIPtr[i]];
1873 if(start<thisNbCells)
1875 for(mcIdType j=commonCellsIPtr[i]+1;j!=commonCellsIPtr[i+1];j++)
1877 mcIdType sig=commonCellsPtr[j]>0?1:-1;
1878 mcIdType val=std::abs(commonCellsPtr[j])-1;
1879 if(val>=thisNbCells)
1880 arr2Ptr[val-thisNbCells]=sig*(start+1);
1884 arr2->setName(other->getName());
1885 if(arr2->presenceOfValue(0))
1891 MEDCouplingUMesh *MEDCouplingUMesh::mergeMyselfWithOnSameCoords(const MEDCouplingPointSet *other) const
1894 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : input other is null !");
1895 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
1897 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : the input other mesh is not of type unstructured !");
1898 std::vector<const MEDCouplingUMesh *> ms(2);
1901 return MergeUMeshesOnSameCoords(ms);
1905 * Build a sub part of \b this lying or not on the same coordinates than \b this (regarding value of \b keepCoords).
1906 * By default coordinates are kept. This method is close to MEDCouplingUMesh::buildPartOfMySelf except that here input
1907 * cellIds is not given explicitly but by a range python like.
1912 * \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.
1913 * \return a newly allocated
1915 * \warning This method modifies can generate an unstructured mesh whose cells are not sorted by geometric type order.
1916 * In view of the MED file writing, a renumbering of cells of returned unstructured mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
1918 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfSlice(mcIdType start, mcIdType end, mcIdType step, bool keepCoords) const
1920 if(getMeshDimension()!=-1)
1921 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelfSlice(start,end,step,keepCoords));
1924 mcIdType newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfSlice for -1 dimension mesh ");
1926 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
1928 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
1930 return const_cast<MEDCouplingUMesh *>(this);
1935 * Creates a new MEDCouplingUMesh containing specified cells of \a this mesh.
1936 * The result mesh shares or not the node coordinates array with \a this mesh depending
1937 * on \a keepCoords parameter.
1938 * \warning Cells of the result mesh can be \b not sorted by geometric type, hence,
1939 * to write this mesh to the MED file, its cells must be sorted using
1940 * sortCellsInMEDFileFrmt().
1941 * \param [in] begin - an array of cell ids to include to the new mesh.
1942 * \param [in] end - a pointer to last-plus-one-th element of \a begin.
1943 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
1944 * array of \a this mesh, else "free" nodes are removed from the result mesh
1945 * by calling zipCoords().
1946 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
1947 * to delete this mesh using decrRef() as it is no more needed.
1948 * \throw If the coordinates array is not set.
1949 * \throw If the nodal connectivity of cells is not defined.
1950 * \throw If any cell id in the array \a begin is not valid.
1952 * \if ENABLE_EXAMPLES
1953 * \ref cpp_mcumesh_buildPartOfMySelf "Here is a C++ example".<br>
1954 * \ref py_mcumesh_buildPartOfMySelf "Here is a Python example".
1957 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelf(const mcIdType *begin, const mcIdType *end, bool keepCoords) const
1959 if(getMeshDimension()!=-1)
1960 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelf(begin,end,keepCoords));
1964 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
1966 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
1968 return const_cast<MEDCouplingUMesh *>(this);
1973 * This method operates only on nodal connectivity on \b this. Coordinates of \b this is completely ignored here.
1975 * 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.
1976 * Size of [ \b cellIdsBg, \b cellIdsEnd ) ) must be equal to the number of cells of otherOnSameCoordsThanThis.
1977 * The number of cells of \b this will remain the same with this method.
1979 * \param [in] cellIdsBg begin of cell ids (included) of cells in this to assign
1980 * \param [in] cellIdsEnd end of cell ids (excluded) of cells in this to assign
1981 * \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 ).
1982 * Coordinate pointer of \b this and those of \b otherOnSameCoordsThanThis must be the same
1984 void MEDCouplingUMesh::setPartOfMySelf(const mcIdType *cellIdsBg, const mcIdType *cellIdsEnd, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
1986 checkConnectivityFullyDefined();
1987 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
1988 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
1989 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelf : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
1990 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
1992 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
1993 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
1994 throw INTERP_KERNEL::Exception(oss.str());
1996 mcIdType nbOfCellsToModify( ToIdType((std::distance(cellIdsBg,cellIdsEnd))));
1997 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
1999 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2000 throw INTERP_KERNEL::Exception(oss.str());
2002 mcIdType nbOfCells(getNumberOfCells());
2003 bool easyAssign(true);
2004 const mcIdType *connI(_nodal_connec_index->begin());
2005 const mcIdType *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->begin();
2006 for(const mcIdType *it=cellIdsBg;it!=cellIdsEnd && easyAssign;it++,connIOther++)
2008 if(*it>=0 && *it<nbOfCells)
2010 easyAssign=(connIOther[1]-connIOther[0])==(connI[*it+1]-connI[*it]);
2014 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : On pos #" << std::distance(cellIdsBg,it) << " id is equal to " << *it << " which is not in [0," << nbOfCells << ") !";
2015 throw INTERP_KERNEL::Exception(oss.str());
2020 DataArrayIdType::SetPartOfIndexedArraysSameIdx(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2025 DataArrayIdType *arrOut=0,*arrIOut=0;
2026 DataArrayIdType::SetPartOfIndexedArrays(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2028 MCAuto<DataArrayIdType> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2029 setConnectivity(arrOut,arrIOut,true);
2033 void MEDCouplingUMesh::setPartOfMySelfSlice(mcIdType start, mcIdType end, mcIdType step, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2035 checkConnectivityFullyDefined();
2036 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2037 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2038 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelfSlice : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2039 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2041 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2042 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2043 throw INTERP_KERNEL::Exception(oss.str());
2045 mcIdType nbOfCellsToModify=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::setPartOfMySelfSlice : ");
2046 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2048 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2049 throw INTERP_KERNEL::Exception(oss.str());
2051 mcIdType nbOfCells=getNumberOfCells();
2052 bool easyAssign=true;
2053 const mcIdType *connI=_nodal_connec_index->getConstPointer();
2054 const mcIdType *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2056 for(mcIdType i=0;i<nbOfCellsToModify && easyAssign;i++,it+=step,connIOther++)
2058 if(it>=0 && it<nbOfCells)
2060 easyAssign=(connIOther[1]-connIOther[0])==(connI[it+1]-connI[it]);
2064 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : On pos #" << i << " id is equal to " << it << " which is not in [0," << nbOfCells << ") !";
2065 throw INTERP_KERNEL::Exception(oss.str());
2070 DataArrayIdType::SetPartOfIndexedArraysSameIdxSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2075 DataArrayIdType *arrOut=0,*arrIOut=0;
2076 DataArrayIdType::SetPartOfIndexedArraysSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2078 MCAuto<DataArrayIdType> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2079 setConnectivity(arrOut,arrIOut,true);
2085 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2086 * this->getMeshDimension(), that bound some cells of \a this mesh.
2087 * The cells of lower dimension to include to the result mesh are selected basing on
2088 * specified node ids and the value of \a fullyIn parameter. If \a fullyIn ==\c true, a
2089 * cell is copied if its all nodes are in the array \a begin of node ids. If \a fullyIn
2090 * ==\c false, a cell is copied if any its node is in the array of node ids. The
2091 * created mesh shares the node coordinates array with \a this mesh.
2092 * \param [in] begin - the array of node ids.
2093 * \param [in] end - a pointer to the (last+1)-th element of \a begin.
2094 * \param [in] fullyIn - if \c true, then cells whose all nodes are in the
2095 * array \a begin are added, else cells whose any node is in the
2096 * array \a begin are added.
2097 * \return MEDCouplingUMesh * - new instance of MEDCouplingUMesh. The caller is
2098 * to delete this mesh using decrRef() as it is no more needed.
2099 * \throw If the coordinates array is not set.
2100 * \throw If the nodal connectivity of cells is not defined.
2101 * \throw If any node id in \a begin is not valid.
2103 * \if ENABLE_EXAMPLES
2104 * \ref cpp_mcumesh_buildFacePartOfMySelfNode "Here is a C++ example".<br>
2105 * \ref py_mcumesh_buildFacePartOfMySelfNode "Here is a Python example".
2108 MEDCouplingUMesh *MEDCouplingUMesh::buildFacePartOfMySelfNode(const mcIdType *begin, const mcIdType *end, bool fullyIn) const
2110 MCAuto<DataArrayIdType> desc,descIndx,revDesc,revDescIndx;
2111 desc=DataArrayIdType::New(); descIndx=DataArrayIdType::New(); revDesc=DataArrayIdType::New(); revDescIndx=DataArrayIdType::New();
2112 MCAuto<MEDCouplingUMesh> subMesh=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2113 desc=0; descIndx=0; revDesc=0; revDescIndx=0;
2114 return static_cast<MEDCouplingUMesh*>(subMesh->buildPartOfMySelfNode(begin,end,fullyIn));
2118 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2119 * this->getMeshDimension(), which bound only one cell of \a this mesh.
2120 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2121 * array of \a this mesh, else "free" nodes are removed from the result mesh
2122 * by calling zipCoords().
2123 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2124 * to delete this mesh using decrRef() as it is no more needed.
2125 * \throw If the coordinates array is not set.
2126 * \throw If the nodal connectivity of cells is not defined.
2128 * \if ENABLE_EXAMPLES
2129 * \ref cpp_mcumesh_buildBoundaryMesh "Here is a C++ example".<br>
2130 * \ref py_mcumesh_buildBoundaryMesh "Here is a Python example".
2133 MEDCouplingUMesh *MEDCouplingUMesh::buildBoundaryMesh(bool keepCoords) const
2135 DataArrayIdType *desc=DataArrayIdType::New();
2136 DataArrayIdType *descIndx=DataArrayIdType::New();
2137 DataArrayIdType *revDesc=DataArrayIdType::New();
2138 DataArrayIdType *revDescIndx=DataArrayIdType::New();
2140 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2143 descIndx->decrRef();
2144 mcIdType nbOfCells=meshDM1->getNumberOfCells();
2145 const mcIdType *revDescIndxC=revDescIndx->getConstPointer();
2146 std::vector<mcIdType> boundaryCells;
2147 for(mcIdType i=0;i<nbOfCells;i++)
2148 if(revDescIndxC[i+1]-revDescIndxC[i]==1)
2149 boundaryCells.push_back(i);
2150 revDescIndx->decrRef();
2151 MEDCouplingUMesh *ret=meshDM1->buildPartOfMySelf(&boundaryCells[0],&boundaryCells[0]+boundaryCells.size(),keepCoords);
2156 * This method returns a newly created DataArrayIdType instance containing ids of cells located in boundary.
2157 * A cell is detected to be on boundary if it contains one or more than one face having only one father.
2158 * This method makes the assumption that \a this is fully defined (coords,connectivity). If not an exception will be thrown.
2160 DataArrayIdType *MEDCouplingUMesh::findCellIdsOnBoundary() const
2162 checkFullyDefined();
2163 MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
2164 MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
2165 MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
2166 MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
2168 buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx)->decrRef();
2169 desc=(DataArrayIdType*)0; descIndx=(DataArrayIdType*)0;
2171 MCAuto<DataArrayIdType> tmp=revDescIndx->deltaShiftIndex();
2172 MCAuto<DataArrayIdType> faceIds=tmp->findIdsEqual(1); tmp=(DataArrayIdType*)0;
2173 const mcIdType *revDescPtr=revDesc->getConstPointer();
2174 const mcIdType *revDescIndxPtr=revDescIndx->getConstPointer();
2175 mcIdType nbOfCells=getNumberOfCells();
2176 std::vector<bool> ret1(nbOfCells,false);
2178 for(const mcIdType *pt=faceIds->begin();pt!=faceIds->end();pt++)
2179 if(!ret1[revDescPtr[revDescIndxPtr[*pt]]])
2180 { ret1[revDescPtr[revDescIndxPtr[*pt]]]=true; sz++; }
2182 DataArrayIdType *ret2=DataArrayIdType::New();
2184 mcIdType *ret2Ptr=ret2->getPointer();
2186 for(std::vector<bool>::const_iterator it=ret1.begin();it!=ret1.end();it++,sz++)
2189 ret2->setName("BoundaryCells");
2194 * This method finds in \b this the cell ids that lie on mesh \b otherDimM1OnSameCoords.
2195 * \b this and \b otherDimM1OnSameCoords have to lie on the same coordinate array pointer. The coherency of that coords array with connectivity
2196 * of \b this and \b otherDimM1OnSameCoords is not important here because this method works only on connectivity.
2197 * this->getMeshDimension() - 1 must be equal to otherDimM1OnSameCoords.getMeshDimension()
2199 * s0 is the cell ids set in \b this lying on at least one node in the fetched nodes in \b otherDimM1OnSameCoords.
2200 * 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
2201 * equals a cell in \b otherDimM1OnSameCoords.
2203 * \throw if \b otherDimM1OnSameCoords is not part of constituent of \b this, or if coordinate pointer of \b this and \b otherDimM1OnSameCoords
2204 * are not same, or if this->getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension()
2206 * \param [in] otherDimM1OnSameCoords
2207 * \param [out] cellIdsRk0 a newly allocated array containing the cell ids of s0 (which are cell ids of \b this) in the above algorithm.
2208 * \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
2209 * cellIdsRk1->transformWithIndArr(cellIdsRk0->begin(),cellIdsRk0->end());
2211 void MEDCouplingUMesh::findCellIdsLyingOn(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayIdType *&cellIdsRk0, DataArrayIdType *&cellIdsRk1) const
2213 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2214 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : coordinates pointer are not the same ! Use tryToShareSameCoords method !");
2215 checkConnectivityFullyDefined();
2216 otherDimM1OnSameCoords.checkConnectivityFullyDefined();
2217 if(getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension())
2218 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : invalid mesh dimension of input mesh regarding meshdimesion of this !");
2219 MCAuto<DataArrayIdType> fetchedNodeIds1=otherDimM1OnSameCoords.computeFetchedNodeIds();
2220 MCAuto<DataArrayIdType> s0arr=getCellIdsLyingOnNodes(fetchedNodeIds1->begin(),fetchedNodeIds1->end(),false);
2221 MCAuto<MEDCouplingUMesh> thisPart=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(s0arr->begin(),s0arr->end(),true));
2222 MCAuto<DataArrayIdType> descThisPart=DataArrayIdType::New(),descIThisPart=DataArrayIdType::New(),revDescThisPart=DataArrayIdType::New(),revDescIThisPart=DataArrayIdType::New();
2223 MCAuto<MEDCouplingUMesh> thisPartConsti=thisPart->buildDescendingConnectivity(descThisPart,descIThisPart,revDescThisPart,revDescIThisPart);
2224 const mcIdType *revDescThisPartPtr=revDescThisPart->getConstPointer(),*revDescIThisPartPtr=revDescIThisPart->getConstPointer();
2225 DataArrayIdType *idsOtherInConsti=0;
2226 bool b=thisPartConsti->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsOtherInConsti);
2227 MCAuto<DataArrayIdType> idsOtherInConstiAuto(idsOtherInConsti);
2229 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : the given mdim-1 mesh in other is not a constituent of this !");
2230 std::set<mcIdType> s1;
2231 for(const mcIdType *idOther=idsOtherInConsti->begin();idOther!=idsOtherInConsti->end();idOther++)
2232 s1.insert(revDescThisPartPtr+revDescIThisPartPtr[*idOther],revDescThisPartPtr+revDescIThisPartPtr[*idOther+1]);
2233 MCAuto<DataArrayIdType> s1arr_renum1=DataArrayIdType::New(); s1arr_renum1->alloc(s1.size(),1); std::copy(s1.begin(),s1.end(),s1arr_renum1->getPointer());
2234 s1arr_renum1->sort();
2235 cellIdsRk0=s0arr.retn();
2236 //cellIdsRk1=s_renum1.retn();
2237 cellIdsRk1=s1arr_renum1.retn();
2241 * 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
2242 * returned. This subpart of meshdim-1 mesh is built using meshdim-1 cells in it shared only one cell in \b this.
2244 * \return a newly allocated mesh lying on the same coordinates than \b this. The caller has to deal with returned mesh.
2246 MEDCouplingUMesh *MEDCouplingUMesh::computeSkin() const
2248 MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
2249 MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
2250 MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
2251 MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
2253 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2254 revDesc=0; desc=0; descIndx=0;
2255 MCAuto<DataArrayIdType> revDescIndx2=revDescIndx->deltaShiftIndex();
2256 MCAuto<DataArrayIdType> part=revDescIndx2->findIdsEqual(1);
2257 return static_cast<MEDCouplingUMesh *>(meshDM1->buildPartOfMySelf(part->begin(),part->end(),true));
2261 * Finds nodes lying on the boundary of \a this mesh.
2262 * \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of found
2263 * nodes. The caller is to delete this array using decrRef() as it is no
2265 * \throw If the coordinates array is not set.
2266 * \throw If the nodal connectivity of cells is node defined.
2268 * \if ENABLE_EXAMPLES
2269 * \ref cpp_mcumesh_findBoundaryNodes "Here is a C++ example".<br>
2270 * \ref py_mcumesh_findBoundaryNodes "Here is a Python example".
2273 DataArrayIdType *MEDCouplingUMesh::findBoundaryNodes() const
2275 MCAuto<MEDCouplingUMesh> skin=computeSkin();
2276 return skin->computeFetchedNodeIds();
2279 MEDCouplingUMesh *MEDCouplingUMesh::buildUnstructured() const
2282 return const_cast<MEDCouplingUMesh *>(this);
2286 * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2287 * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2288 * 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.
2289 * 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.
2290 * 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.
2292 * \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
2293 * parameter is altered during the call.
2294 * \param [out] nodeIdsToDuplicate node ids needed to be duplicated following the algorithm explain above.
2295 * \param [out] cellIdsNeededToBeRenum cell ids in \b this in which the renumber of nodes should be performed.
2296 * \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.
2298 * \warning This method modifies param \b otherDimM1OnSameCoords (for speed reasons).
2300 void MEDCouplingUMesh::findNodesToDuplicate(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayIdType *& nodeIdsToDuplicate,
2301 DataArrayIdType *& cellIdsNeededToBeRenum, DataArrayIdType *& cellIdsNotModified) const
2303 typedef MCAuto<DataArrayIdType> DAInt;
2304 typedef MCAuto<MEDCouplingUMesh> MCUMesh;
2306 checkFullyDefined();
2307 otherDimM1OnSameCoords.checkFullyDefined();
2308 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2309 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : meshes do not share the same coords array !");
2310 if(otherDimM1OnSameCoords.getMeshDimension()!=getMeshDimension()-1)
2311 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the mesh given in other parameter must have this->getMeshDimension()-1 !");
2313 // Checking star-shaped M1 group:
2314 DAInt dt0=DataArrayIdType::New(),dit0=DataArrayIdType::New(),rdt0=DataArrayIdType::New(),rdit0=DataArrayIdType::New();
2315 MCUMesh meshM2 = otherDimM1OnSameCoords.buildDescendingConnectivity(dt0, dit0, rdt0, rdit0);
2316 DAInt dsi = rdit0->deltaShiftIndex();
2317 DAInt idsTmp0 = dsi->findIdsNotInRange(-1, 3);
2318 if(idsTmp0->getNumberOfTuples())
2319 throw INTERP_KERNEL::Exception("MEDFileUMesh::buildInnerBoundaryAlongM1Group: group is too complex: some points (or edges) have more than two connected segments (or faces)!");
2320 dt0=0; dit0=0; rdt0=0; rdit0=0; idsTmp0=0;
2322 // Get extreme nodes from the group (they won't be duplicated), ie nodes belonging to boundary cells of M1
2323 DAInt xtremIdsM2 = dsi->findIdsEqual(1); dsi = 0;
2324 MCUMesh meshM2Part = static_cast<MEDCouplingUMesh *>(meshM2->buildPartOfMySelf(xtremIdsM2->begin(), xtremIdsM2->end(),true));
2325 DAInt xtrem = meshM2Part->computeFetchedNodeIds();
2326 // Remove from the list points on the boundary of the M0 mesh (those need duplication!)
2327 dt0=DataArrayIdType::New(),dit0=DataArrayIdType::New(),rdt0=DataArrayIdType::New(),rdit0=DataArrayIdType::New();
2328 MCUMesh m0desc = buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); dt0=0; dit0=0; rdt0=0;
2329 dsi = rdit0->deltaShiftIndex();
2330 DAInt boundSegs = dsi->findIdsEqual(1); // boundary segs/faces of the M0 mesh
2331 MCUMesh m0descSkin = static_cast<MEDCouplingUMesh *>(m0desc->buildPartOfMySelf(boundSegs->begin(),boundSegs->end(), true));
2332 DAInt fNodes = m0descSkin->computeFetchedNodeIds();
2333 // In 3D, some points on the boundary of M0 still need duplication:
2335 if (getMeshDimension() == 3)
2337 DAInt dnu1=DataArrayIdType::New(), dnu2=DataArrayIdType::New(), dnu3=DataArrayIdType::New(), dnu4=DataArrayIdType::New();
2338 MCUMesh m0descSkinDesc = m0descSkin->buildDescendingConnectivity(dnu1, dnu2, dnu3, dnu4);
2339 dnu1=0;dnu2=0;dnu3=0;dnu4=0;
2340 DataArrayIdType * corresp=0;
2341 meshM2->areCellsIncludedIn(m0descSkinDesc,2,corresp);
2342 DAInt validIds = corresp->findIdsInRange(0, meshM2->getNumberOfCells());
2344 if (validIds->getNumberOfTuples())
2346 MCUMesh m1IntersecSkin = static_cast<MEDCouplingUMesh *>(m0descSkinDesc->buildPartOfMySelf(validIds->begin(), validIds->end(), true));
2347 DAInt notDuplSkin = m1IntersecSkin->findBoundaryNodes();
2348 DAInt fNodes1 = fNodes->buildSubstraction(notDuplSkin);
2349 notDup = xtrem->buildSubstraction(fNodes1);
2352 notDup = xtrem->buildSubstraction(fNodes);
2355 notDup = xtrem->buildSubstraction(fNodes);
2357 // Now compute cells around group (i.e. cells where we will do the propagation to identify the two sub-sets delimited by the group)
2358 DAInt m1Nodes = otherDimM1OnSameCoords.computeFetchedNodeIds();
2359 DAInt dupl = m1Nodes->buildSubstraction(notDup);
2360 DAInt cellsAroundGroup = getCellIdsLyingOnNodes(dupl->begin(), dupl->end(), false); // false= take cell in, even if not all nodes are in notDup
2363 MCUMesh m0Part2=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(cellsAroundGroup->begin(),cellsAroundGroup->end(),true));
2364 mcIdType nCells2 = m0Part2->getNumberOfCells();
2365 DAInt desc00=DataArrayIdType::New(),descI00=DataArrayIdType::New(),revDesc00=DataArrayIdType::New(),revDescI00=DataArrayIdType::New();
2366 MCUMesh m01=m0Part2->buildDescendingConnectivity(desc00,descI00,revDesc00,revDescI00);
2368 // Neighbor information of the mesh without considering the crack (serves to count how many connex pieces it is made of)
2369 DataArrayIdType *tmp00=0,*tmp11=0;
2370 MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00, tmp00, tmp11);
2371 DAInt neighInit00(tmp00);
2372 DAInt neighIInit00(tmp11);
2373 // Neighbor information of the mesh WITH the crack (some neighbors are removed):
2374 DataArrayIdType *idsTmp=0;
2375 m01->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsTmp);
2377 // In the neighbor information remove the connection between high dimension cells and its low level constituents which are part
2378 // of the frontier given in parameter (i.e. the cells of low dimension from the group delimiting the crack):
2379 DataArrayIdType::RemoveIdsFromIndexedArrays(ids->begin(),ids->end(),desc00,descI00);
2380 DataArrayIdType *tmp0=0,*tmp1=0;
2381 // Compute the neighbor of each cell in m0Part2, taking into account the broken link above. Two
2382 // cells on either side of the crack (defined by the mesh of low dimension) are not neighbor anymore.
2383 ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00,tmp0,tmp1);
2384 DAInt neigh00(tmp0);
2385 DAInt neighI00(tmp1);
2387 // For each initial connex part of the sub-mesh (or said differently for each independent crack):
2388 mcIdType seed = 0, nIter = 0;
2389 mcIdType nIterMax = nCells2+1; // Safety net for the loop
2390 DAInt hitCells = DataArrayIdType::New(); hitCells->alloc(nCells2);
2391 hitCells->fillWithValue(-1);
2392 DAInt cellsToModifyConn0_torenum = DataArrayIdType::New();
2393 cellsToModifyConn0_torenum->alloc(0,1);
2394 while (nIter < nIterMax)
2396 DAInt t = hitCells->findIdsEqual(-1);
2397 if (!t->getNumberOfTuples())
2399 // Connex zone without the crack (to compute the next seed really)
2401 DAInt connexCheck = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neighInit00,neighIInit00, -1, dnu);
2403 for (mcIdType * ptr = connexCheck->getPointer(); cnt < connexCheck->getNumberOfTuples(); ptr++, cnt++)
2404 hitCells->setIJ(*ptr,0,1);
2405 // Connex zone WITH the crack (to identify cells lying on either part of the crack)
2406 DAInt spreadZone = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neigh00,neighI00, -1, dnu);
2407 cellsToModifyConn0_torenum = DataArrayIdType::Aggregate(cellsToModifyConn0_torenum, spreadZone, 0);
2408 // Compute next seed, i.e. a cell in another connex part, which was not covered by the previous iterations
2409 DAInt comple = cellsToModifyConn0_torenum->buildComplement(nCells2);
2410 DAInt nonHitCells = hitCells->findIdsEqual(-1);
2411 DAInt intersec = nonHitCells->buildIntersection(comple);
2412 if (intersec->getNumberOfTuples())
2413 { seed = intersec->getIJ(0,0); }
2418 if (nIter >= nIterMax)
2419 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate(): internal error - too many iterations.");
2421 DAInt cellsToModifyConn1_torenum=cellsToModifyConn0_torenum->buildComplement(neighI00->getNumberOfTuples()-1);
2422 cellsToModifyConn0_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2423 cellsToModifyConn1_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2425 cellIdsNeededToBeRenum=cellsToModifyConn0_torenum.retn();
2426 cellIdsNotModified=cellsToModifyConn1_torenum.retn();
2427 nodeIdsToDuplicate=dupl.retn();
2431 * This method operates a modification of the connectivity and coords in \b this.
2432 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2433 * its ids will be modified to id this->getNumberOfNodes()+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2434 * 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
2435 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id this->getNumberOfNodes()+0, node id nodeIdsToDuplicateBg[1] will have id this->getNumberOfNodes()+1,
2436 * node id nodeIdsToDuplicateBg[2] will have id this->getNumberOfNodes()+2...
2438 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2440 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2441 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2443 void MEDCouplingUMesh::duplicateNodes(const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd)
2445 mcIdType nbOfNodes=getNumberOfNodes();
2446 duplicateNodesInCoords(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd);
2447 duplicateNodesInConn(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,nbOfNodes);
2451 * This method renumbers only nodal connectivity in \a this. The renumbering is only an offset applied. So this method is a specialization of
2452 * \a renumberNodesInConn. \b WARNING, this method does not check that the resulting node ids in the nodal connectivity is in a valid range !
2454 * \param [in] offset - specifies the offset to be applied on each element of connectivity.
2456 * \sa renumberNodesInConn
2458 void MEDCouplingUMesh::renumberNodesWithOffsetInConn(mcIdType offset)
2460 checkConnectivityFullyDefined();
2461 mcIdType *conn(getNodalConnectivity()->getPointer());
2462 const mcIdType *connIndex(getNodalConnectivityIndex()->getConstPointer());
2463 mcIdType nbOfCells=getNumberOfCells();
2464 for(mcIdType i=0;i<nbOfCells;i++)
2465 for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2467 mcIdType& node=conn[iconn];
2468 if(node>=0)//avoid polyhedron separator
2473 _nodal_connec->declareAsNew();
2478 * Same than renumberNodesInConn(const mcIdType *) except that here the format of old-to-new traducer is using map instead
2479 * 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
2482 void MEDCouplingUMesh::renumberNodesInConn(const INTERP_KERNEL::HashMap<mcIdType,mcIdType>& newNodeNumbersO2N)
2484 this->renumberNodesInConnT< INTERP_KERNEL::HashMap<mcIdType,mcIdType> >(newNodeNumbersO2N);
2488 * Same than renumberNodesInConn(const mcIdType *) except that here the format of old-to-new traducer is using map instead
2489 * 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
2492 void MEDCouplingUMesh::renumberNodesInConn(const std::map<mcIdType,mcIdType>& newNodeNumbersO2N)
2494 this->renumberNodesInConnT< std::map<mcIdType,mcIdType> >(newNodeNumbersO2N);
2498 * Changes ids of nodes within the nodal connectivity arrays according to a permutation
2499 * array in "Old to New" mode. The node coordinates array is \b not changed by this method.
2500 * This method is a generalization of shiftNodeNumbersInConn().
2501 * \warning This method performs no check of validity of new ids. **Use it with care !**
2502 * \param [in] newNodeNumbersO2N - a permutation array, of length \a
2503 * this->getNumberOfNodes(), in "Old to New" mode.
2504 * See \ref numbering for more info on renumbering modes.
2505 * \throw If the nodal connectivity of cells is not defined.
2507 * \if ENABLE_EXAMPLES
2508 * \ref cpp_mcumesh_renumberNodesInConn "Here is a C++ example".<br>
2509 * \ref py_mcumesh_renumberNodesInConn "Here is a Python example".
2512 void MEDCouplingUMesh::renumberNodesInConn(const mcIdType *newNodeNumbersO2N)
2514 checkConnectivityFullyDefined();
2515 mcIdType *conn=getNodalConnectivity()->getPointer();
2516 const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2517 mcIdType nbOfCells=getNumberOfCells();
2518 for(mcIdType i=0;i<nbOfCells;i++)
2519 for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2521 mcIdType& node=conn[iconn];
2522 if(node>=0)//avoid polyhedron separator
2524 node=newNodeNumbersO2N[node];
2527 _nodal_connec->declareAsNew();
2532 * This method renumbers nodes \b in \b connectivity \b only \b without \b any \b reference \b to \b coords.
2533 * This method performs no check on the fact that new coordinate ids are valid. \b Use \b it \b with \b care !
2534 * This method is an specialization of \ref MEDCoupling::MEDCouplingUMesh::renumberNodesInConn "renumberNodesInConn method".
2536 * \param [in] delta specifies the shift size applied to nodeId in nodal connectivity in \b this.
2538 void MEDCouplingUMesh::shiftNodeNumbersInConn(mcIdType delta)
2540 checkConnectivityFullyDefined();
2541 mcIdType *conn=getNodalConnectivity()->getPointer();
2542 const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2543 mcIdType nbOfCells=getNumberOfCells();
2544 for(mcIdType i=0;i<nbOfCells;i++)
2545 for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2547 mcIdType& node=conn[iconn];
2548 if(node>=0)//avoid polyhedron separator
2553 _nodal_connec->declareAsNew();
2558 * This method operates a modification of the connectivity in \b this.
2559 * 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.
2560 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2561 * its ids will be modified to id offset+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2562 * 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
2563 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id offset+0, node id nodeIdsToDuplicateBg[1] will have id offset+1,
2564 * node id nodeIdsToDuplicateBg[2] will have id offset+2...
2566 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2567 * As an another consequense after the call of this method \b this can be transiently non cohrent.
2569 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2570 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2571 * \param [in] offset the offset applied to all node ids in connectivity that are in [ \a nodeIdsToDuplicateBg, \a nodeIdsToDuplicateEnd ).
2573 void MEDCouplingUMesh::duplicateNodesInConn(const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd, mcIdType offset)
2575 checkConnectivityFullyDefined();
2576 std::map<mcIdType,mcIdType> m;
2577 mcIdType val=offset;
2578 for(const mcIdType *work=nodeIdsToDuplicateBg;work!=nodeIdsToDuplicateEnd;work++,val++)
2580 mcIdType *conn=getNodalConnectivity()->getPointer();
2581 const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2582 mcIdType nbOfCells=getNumberOfCells();
2583 for(mcIdType i=0;i<nbOfCells;i++)
2584 for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2586 mcIdType& node=conn[iconn];
2587 if(node>=0)//avoid polyhedron separator
2589 std::map<mcIdType,mcIdType>::iterator it=m.find(node);
2598 * This method renumbers cells of \a this using the array specified by [old2NewBg;old2NewBg+getNumberOfCells())
2600 * Contrary to MEDCouplingPointSet::renumberNodes, this method makes a permutation without any fuse of cell.
2601 * After the call of this method the number of cells remains the same as before.
2603 * If 'check' equals true the method will check that any elements in [ \a old2NewBg; \a old2NewEnd ) is unique ; if not
2604 * an INTERP_KERNEL::Exception will be thrown. When 'check' equals true [ \a old2NewBg ; \a old2NewEnd ) is not expected to
2605 * be strictly in [0;this->getNumberOfCells()).
2607 * If 'check' equals false the method will not check the content of [ \a old2NewBg ; \a old2NewEnd ).
2608 * To avoid any throw of SIGSEGV when 'check' equals false, the elements in [ \a old2NewBg ; \a old2NewEnd ) should be unique and
2609 * should be contained in[0;this->getNumberOfCells()).
2611 * \param [in] old2NewBg is expected to be a dynamically allocated pointer of size at least equal to this->getNumberOfCells()
2614 void MEDCouplingUMesh::renumberCells(const mcIdType *old2NewBg, bool check)
2616 checkConnectivityFullyDefined();
2617 mcIdType nbCells=getNumberOfCells();
2618 const mcIdType *array=old2NewBg;
2620 array=DataArrayIdType::CheckAndPreparePermutation(old2NewBg,old2NewBg+nbCells);
2622 const mcIdType *conn=_nodal_connec->getConstPointer();
2623 const mcIdType *connI=_nodal_connec_index->getConstPointer();
2624 MCAuto<DataArrayIdType> o2n=DataArrayIdType::New(); o2n->useArray(array,false,DeallocType::C_DEALLOC,nbCells,1);
2625 MCAuto<DataArrayIdType> n2o=o2n->invertArrayO2N2N2O(nbCells);
2626 const mcIdType *n2oPtr=n2o->begin();
2627 MCAuto<DataArrayIdType> newConn=DataArrayIdType::New();
2628 newConn->alloc(_nodal_connec->getNumberOfTuples(),_nodal_connec->getNumberOfComponents());
2629 newConn->copyStringInfoFrom(*_nodal_connec);
2630 MCAuto<DataArrayIdType> newConnI=DataArrayIdType::New();
2631 newConnI->alloc(_nodal_connec_index->getNumberOfTuples(),_nodal_connec_index->getNumberOfComponents());
2632 newConnI->copyStringInfoFrom(*_nodal_connec_index);
2634 mcIdType *newC=newConn->getPointer();
2635 mcIdType *newCI=newConnI->getPointer();
2638 for(mcIdType i=0;i<nbCells;i++)
2640 mcIdType pos=n2oPtr[i];
2641 mcIdType nbOfElts=connI[pos+1]-connI[pos];
2642 newC=std::copy(conn+connI[pos],conn+connI[pos+1],newC);
2647 setConnectivity(newConn,newConnI);
2649 free(const_cast<mcIdType *>(array));
2653 * Finds cells whose bounding boxes intersect a given bounding box.
2654 * \param [in] bbox - an array defining the bounding box via coordinates of its
2655 * extremum points in "no interlace" mode, i.e. xMin, xMax, yMin, yMax, zMin,
2657 * \param [in] eps - a factor used to increase size of the bounding box of cell
2658 * before comparing it with \a bbox. This factor is multiplied by the maximal
2659 * extent of the bounding box of cell to produce an addition to this bounding box.
2660 * \return DataArrayIdType * - a new instance of DataArrayIdType holding ids for found
2661 * cells. The caller is to delete this array using decrRef() as it is no more
2663 * \throw If the coordinates array is not set.
2664 * \throw If the nodal connectivity of cells is not defined.
2666 * \if ENABLE_EXAMPLES
2667 * \ref cpp_mcumesh_getCellsInBoundingBox "Here is a C++ example".<br>
2668 * \ref py_mcumesh_getCellsInBoundingBox "Here is a Python example".
2671 DataArrayIdType *MEDCouplingUMesh::getCellsInBoundingBox(const double *bbox, double eps) const
2673 MCAuto<DataArrayIdType> elems=DataArrayIdType::New(); elems->alloc(0,1);
2674 if(getMeshDimension()==-1)
2676 elems->pushBackSilent(0);
2677 return elems.retn();
2679 int dim=getSpaceDimension();
2680 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2681 const mcIdType* conn = getNodalConnectivity()->getConstPointer();
2682 const mcIdType* conn_index= getNodalConnectivityIndex()->getConstPointer();
2683 const double* coords = getCoords()->getConstPointer();
2684 mcIdType nbOfCells=getNumberOfCells();
2685 for ( mcIdType ielem=0; ielem<nbOfCells;ielem++ )
2687 for (int i=0; i<dim; i++)
2689 elem_bb[i*2]=std::numeric_limits<double>::max();
2690 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2693 for (mcIdType inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2695 mcIdType node= conn[inode];
2696 if(node>=0)//avoid polyhedron separator
2698 for (int idim=0; idim<dim; idim++)
2700 if ( coords[node*dim+idim] < elem_bb[idim*2] )
2702 elem_bb[idim*2] = coords[node*dim+idim] ;
2704 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2706 elem_bb[idim*2+1] = coords[node*dim+idim] ;
2711 if (intersectsBoundingBox(elem_bb, bbox, dim, eps))
2712 elems->pushBackSilent(ielem);
2714 return elems.retn();
2718 * Given a boundary box 'bbox' returns elements 'elems' contained in this 'bbox' or touching 'bbox' (within 'eps' distance).
2719 * Warning 'elems' is incremented during the call so if elems is not empty before call returned elements will be
2720 * added in 'elems' parameter.
2722 DataArrayIdType *MEDCouplingUMesh::getCellsInBoundingBox(const INTERP_KERNEL::DirectedBoundingBox& bbox, double eps)
2724 MCAuto<DataArrayIdType> elems=DataArrayIdType::New(); elems->alloc(0,1);
2725 if(getMeshDimension()==-1)
2727 elems->pushBackSilent(0);
2728 return elems.retn();
2730 int dim=getSpaceDimension();
2731 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2732 const mcIdType* conn = getNodalConnectivity()->getConstPointer();
2733 const mcIdType* conn_index= getNodalConnectivityIndex()->getConstPointer();
2734 const double* coords = getCoords()->getConstPointer();
2735 mcIdType nbOfCells=getNumberOfCells();
2736 for ( mcIdType ielem=0; ielem<nbOfCells;ielem++ )
2738 for (int i=0; i<dim; i++)
2740 elem_bb[i*2]=std::numeric_limits<double>::max();
2741 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2744 for (mcIdType inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2746 mcIdType node= conn[inode];
2747 if(node>=0)//avoid polyhedron separator
2749 for (int idim=0; idim<dim; idim++)
2751 if ( coords[node*dim+idim] < elem_bb[idim*2] )
2753 elem_bb[idim*2] = coords[node*dim+idim] ;
2755 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2757 elem_bb[idim*2+1] = coords[node*dim+idim] ;
2762 if(intersectsBoundingBox(bbox, elem_bb, dim, eps))
2763 elems->pushBackSilent(ielem);
2765 return elems.retn();
2769 * Returns a type of a cell by its id.
2770 * \param [in] cellId - the id of the cell of interest.
2771 * \return INTERP_KERNEL::NormalizedCellType - enumeration item describing the cell type.
2772 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2774 INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::getTypeOfCell(mcIdType cellId) const
2776 const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
2777 if(cellId<_nodal_connec_index->getNbOfElems()-1)
2778 return (INTERP_KERNEL::NormalizedCellType) pt[ptI[cellId]];
2781 std::ostringstream oss; oss << "MEDCouplingUMesh::getTypeOfCell : Requesting type of cell #" << cellId << " but it should be in [0," << _nodal_connec_index->getNbOfElems()-1 << ") !";
2782 throw INTERP_KERNEL::Exception(oss.str());
2787 * This method returns a newly allocated array containing cell ids (ascendingly sorted) whose geometric type are equal to type.
2788 * This method does not throw exception if geometric type \a type is not in \a this.
2789 * This method throws an INTERP_KERNEL::Exception if meshdimension of \b this is not equal to those of \b type.
2790 * The coordinates array is not considered here.
2792 * \param [in] type the geometric type
2793 * \return cell ids in this having geometric type \a type.
2795 DataArrayIdType *MEDCouplingUMesh::giveCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2798 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
2800 checkConnectivityFullyDefined();
2801 mcIdType nbCells=getNumberOfCells();
2802 int mdim=getMeshDimension();
2803 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
2804 if(mdim!=ToIdType(cm.getDimension()))
2805 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::giveCellsWithType : Mismatch between mesh dimension and dimension of the cell !");
2806 const mcIdType *ptI=_nodal_connec_index->getConstPointer();
2807 const mcIdType *pt=_nodal_connec->getConstPointer();
2808 for(mcIdType i=0;i<nbCells;i++)
2810 if((INTERP_KERNEL::NormalizedCellType)pt[ptI[i]]==type)
2811 ret->pushBackSilent(i);
2817 * Returns nb of cells having the geometric type \a type. No throw if no cells in \a this has the geometric type \a type.
2819 mcIdType MEDCouplingUMesh::getNumberOfCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2821 const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
2822 mcIdType nbOfCells(getNumberOfCells()),ret(0);
2823 for(mcIdType i=0;i<nbOfCells;i++)
2824 if((INTERP_KERNEL::NormalizedCellType) pt[ptI[i]]==type)
2830 * Returns the nodal connectivity of a given cell.
2831 * The separator of faces within polyhedron connectivity (-1) is not returned, thus
2832 * all returned node ids can be used in getCoordinatesOfNode().
2833 * \param [in] cellId - an id of the cell of interest.
2834 * \param [in,out] conn - a vector where the node ids are appended. It is not
2835 * cleared before the appending.
2836 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2838 void MEDCouplingUMesh::getNodeIdsOfCell(mcIdType cellId, std::vector<mcIdType>& conn) const
2840 const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
2841 for(const mcIdType *w=pt+ptI[cellId]+1;w!=pt+ptI[cellId+1];w++)
2846 std::string MEDCouplingUMesh::simpleRepr() const
2848 static const char msg0[]="No coordinates specified !";
2849 std::ostringstream ret;
2850 ret << "Unstructured mesh with name : \"" << getName() << "\"\n";
2851 ret << "Description of mesh : \"" << getDescription() << "\"\n";
2853 double tt=getTime(tmpp1,tmpp2);
2854 ret << "Time attached to the mesh [unit] : " << tt << " [" << getTimeUnit() << "]\n";
2855 ret << "Iteration : " << tmpp1 << " Order : " << tmpp2 << "\n";
2857 { ret << "Mesh dimension : " << _mesh_dim << "\nSpace dimension : "; }
2859 { ret << " Mesh dimension has not been set or is invalid !"; }
2862 const int spaceDim=getSpaceDimension();
2863 ret << spaceDim << "\nInfo attached on space dimension : ";
2864 for(int i=0;i<spaceDim;i++)
2865 ret << "\"" << _coords->getInfoOnComponent(i) << "\" ";
2869 ret << msg0 << "\n";
2870 ret << "Number of nodes : ";
2872 ret << getNumberOfNodes() << "\n";
2874 ret << msg0 << "\n";
2875 ret << "Number of cells : ";
2876 if(_nodal_connec!=0 && _nodal_connec_index!=0)
2877 ret << getNumberOfCells() << "\n";
2879 ret << "No connectivity specified !" << "\n";
2880 ret << "Cell types present : ";
2881 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
2883 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter);
2884 ret << cm.getRepr() << " ";
2890 std::string MEDCouplingUMesh::advancedRepr() const
2892 std::ostringstream ret;
2893 ret << simpleRepr();
2894 ret << "\nCoordinates array : \n___________________\n\n";
2896 _coords->reprWithoutNameStream(ret);
2898 ret << "No array set !\n";
2899 ret << "\n\nConnectivity arrays : \n_____________________\n\n";
2900 reprConnectivityOfThisLL(ret);
2905 * This method returns a C++ code that is a dump of \a this.
2906 * This method will throw if this is not fully defined.
2908 std::string MEDCouplingUMesh::cppRepr() const
2910 static const char coordsName[]="coords";
2911 static const char connName[]="conn";
2912 static const char connIName[]="connI";
2913 checkFullyDefined();
2914 std::ostringstream ret; ret << "// coordinates" << std::endl;
2915 _coords->reprCppStream(coordsName,ret); ret << std::endl << "// connectivity" << std::endl;
2916 _nodal_connec->reprCppStream(connName,ret); ret << std::endl;
2917 _nodal_connec_index->reprCppStream(connIName,ret); ret << std::endl;
2918 ret << "MEDCouplingUMesh *mesh=MEDCouplingUMesh::New(\"" << getName() << "\"," << getMeshDimension() << ");" << std::endl;
2919 ret << "mesh->setCoords(" << coordsName << ");" << std::endl;
2920 ret << "mesh->setConnectivity(" << connName << "," << connIName << ",true);" << std::endl;
2921 ret << coordsName << "->decrRef(); " << connName << "->decrRef(); " << connIName << "->decrRef();" << std::endl;
2925 std::string MEDCouplingUMesh::reprConnectivityOfThis() const
2927 std::ostringstream ret;
2928 reprConnectivityOfThisLL(ret);
2933 * This method builds a newly allocated instance (with the same name than \a this) that the caller has the responsibility to deal with.
2934 * This method returns an instance with all arrays allocated (connectivity, connectivity index, coordinates)
2935 * but with length of these arrays set to 0. It allows to define an "empty" mesh (with nor cells nor nodes but compliant with
2938 * This method expects that \a this has a mesh dimension set and higher or equal to 0. If not an exception will be thrown.
2939 * 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
2940 * with number of tuples set to 0, if not the array is taken as this in the returned instance.
2942 MEDCouplingUMesh *MEDCouplingUMesh::buildSetInstanceFromThis(std::size_t spaceDim) const
2944 int mdim=getMeshDimension();
2946 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSetInstanceFromThis : invalid mesh dimension ! Should be >= 0 !");
2947 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
2948 MCAuto<DataArrayIdType> tmp1,tmp2;
2949 bool needToCpyCT=true;
2952 tmp1=DataArrayIdType::New(); tmp1->alloc(0,1);
2960 if(!_nodal_connec_index)
2962 tmp2=DataArrayIdType::New(); tmp2->alloc(1,1); tmp2->setIJ(0,0,0);
2967 tmp2=_nodal_connec_index;
2970 ret->setConnectivity(tmp1,tmp2,false);
2975 MCAuto<DataArrayDouble> coords=DataArrayDouble::New(); coords->alloc(0,spaceDim);
2976 ret->setCoords(coords);
2979 ret->setCoords(_coords);
2983 mcIdType MEDCouplingUMesh::getNumberOfNodesInCell(mcIdType cellId) const
2985 const mcIdType *ptI=_nodal_connec_index->getConstPointer();
2986 const mcIdType *pt=_nodal_connec->getConstPointer();
2987 if(pt[ptI[cellId]]!=INTERP_KERNEL::NORM_POLYHED)
2988 return ptI[cellId+1]-ptI[cellId]-1;
2990 return ToIdType(std::count_if(pt+ptI[cellId]+1,pt+ptI[cellId+1],std::bind2nd(std::not_equal_to<mcIdType>(),-1)));
2994 * Returns types of cells of the specified part of \a this mesh.
2995 * This method avoids computing sub-mesh explicitly to get its types.
2996 * \param [in] begin - an array of cell ids of interest.
2997 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
2998 * \return std::set<INTERP_KERNEL::NormalizedCellType> - a set of enumeration items
2999 * describing the cell types.
3000 * \throw If the coordinates array is not set.
3001 * \throw If the nodal connectivity of cells is not defined.
3002 * \sa getAllGeoTypes()
3004 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getTypesOfPart(const mcIdType *begin, const mcIdType *end) const
3006 checkFullyDefined();
3007 std::set<INTERP_KERNEL::NormalizedCellType> ret;
3008 const mcIdType *conn=_nodal_connec->getConstPointer();
3009 const mcIdType *connIndex=_nodal_connec_index->getConstPointer();
3010 for(const mcIdType *w=begin;w!=end;w++)
3011 ret.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]);
3016 * Defines the nodal connectivity using given connectivity arrays in \ref numbering-indirect format.
3017 * Optionally updates
3018 * a set of types of cells constituting \a this mesh.
3019 * This method is for advanced users having prepared their connectivity before. For
3020 * more info on using this method see \ref MEDCouplingUMeshAdvBuild.
3021 * \param [in] conn - the nodal connectivity array.
3022 * \param [in] connIndex - the nodal connectivity index array.
3023 * \param [in] isComputingTypes - if \c true, the set of types constituting \a this
3026 void MEDCouplingUMesh::setConnectivity(DataArrayIdType *conn, DataArrayIdType *connIndex, bool isComputingTypes)
3028 DataArrayIdType::SetArrayIn(conn,_nodal_connec);
3029 DataArrayIdType::SetArrayIn(connIndex,_nodal_connec_index);
3030 if(isComputingTypes)
3036 * Copy constructor. If 'deepCopy' is false \a this is a shallow copy of other.
3037 * If 'deeCpy' is true all arrays (coordinates and connectivities) are deeply copied.
3039 MEDCouplingUMesh::MEDCouplingUMesh(const MEDCouplingUMesh& other, bool deepCpy):MEDCouplingPointSet(other,deepCpy),_mesh_dim(other._mesh_dim),
3040 _nodal_connec(0),_nodal_connec_index(0),
3041 _types(other._types)
3043 if(other._nodal_connec)
3044 _nodal_connec=other._nodal_connec->performCopyOrIncrRef(deepCpy);
3045 if(other._nodal_connec_index)
3046 _nodal_connec_index=other._nodal_connec_index->performCopyOrIncrRef(deepCpy);
3049 MEDCouplingUMesh::~MEDCouplingUMesh()
3052 _nodal_connec->decrRef();
3053 if(_nodal_connec_index)
3054 _nodal_connec_index->decrRef();
3058 * Recomputes a set of cell types of \a this mesh. For more info see
3059 * \ref MEDCouplingUMeshNodalConnectivity.
3061 void MEDCouplingUMesh::computeTypes()
3063 ComputeAllTypesInternal(_types,_nodal_connec,_nodal_connec_index);
3068 * Returns a number of cells constituting \a this mesh.
3069 * \return mcIdType - the number of cells in \a this mesh.
3070 * \throw If the nodal connectivity of cells is not defined.
3072 mcIdType MEDCouplingUMesh::getNumberOfCells() const
3074 if(_nodal_connec_index)
3075 return _nodal_connec_index->getNumberOfTuples()-1;
3080 throw INTERP_KERNEL::Exception("Unable to get number of cells because no connectivity specified !");
3084 * Returns a dimension of \a this mesh, i.e. a dimension of cells constituting \a this
3085 * mesh. For more info see \ref meshes.
3086 * \return int - the dimension of \a this mesh.
3087 * \throw If the mesh dimension is not defined using setMeshDimension().
3089 int MEDCouplingUMesh::getMeshDimension() const
3092 throw INTERP_KERNEL::Exception("No mesh dimension specified !");
3097 * Returns a length of the nodal connectivity array.
3098 * This method is for test reason. Normally the integer returned is not useable by
3099 * user. For more info see \ref MEDCouplingUMeshNodalConnectivity.
3100 * \return mcIdType - the length of the nodal connectivity array.
3102 mcIdType MEDCouplingUMesh::getNodalConnectivityArrayLen() const
3104 return _nodal_connec->getNbOfElems();
3108 * First step of serialization process. Used by ParaMEDMEM and MEDCouplingCorba to transfert data between process.
3110 void MEDCouplingUMesh::getTinySerializationInformation(std::vector<double>& tinyInfoD, std::vector<mcIdType>& tinyInfo, std::vector<std::string>& littleStrings) const
3112 MEDCouplingPointSet::getTinySerializationInformation(tinyInfoD,tinyInfo,littleStrings);
3113 tinyInfo.push_back(ToIdType(getMeshDimension()));
3114 tinyInfo.push_back(getNumberOfCells());
3116 tinyInfo.push_back(getNodalConnectivityArrayLen());
3118 tinyInfo.push_back(-1);
3122 * First step of unserialization process.
3124 bool MEDCouplingUMesh::isEmptyMesh(const std::vector<mcIdType>& tinyInfo) const
3126 return tinyInfo[6]<=0;
3130 * Second step of serialization process.
3131 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3134 * \param littleStrings
3136 void MEDCouplingUMesh::resizeForUnserialization(const std::vector<mcIdType>& tinyInfo, DataArrayIdType *a1, DataArrayDouble *a2, std::vector<std::string>& littleStrings) const
3138 MEDCouplingPointSet::resizeForUnserialization(tinyInfo,a1,a2,littleStrings);
3140 a1->alloc(tinyInfo[7]+tinyInfo[6]+1,1);
3144 * Third and final step of serialization process.
3146 void MEDCouplingUMesh::serialize(DataArrayIdType *&a1, DataArrayDouble *&a2) const
3148 MEDCouplingPointSet::serialize(a1,a2);
3149 if(getMeshDimension()>-1)
3151 a1=DataArrayIdType::New();
3152 a1->alloc(getNodalConnectivityArrayLen()+getNumberOfCells()+1,1);
3153 mcIdType *ptA1=a1->getPointer();
3154 const mcIdType *conn=getNodalConnectivity()->getConstPointer();
3155 const mcIdType *index=getNodalConnectivityIndex()->getConstPointer();
3156 ptA1=std::copy(index,index+getNumberOfCells()+1,ptA1);
3157 std::copy(conn,conn+getNodalConnectivityArrayLen(),ptA1);
3164 * Second and final unserialization process.
3165 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3167 void MEDCouplingUMesh::unserialization(const std::vector<double>& tinyInfoD, const std::vector<mcIdType>& tinyInfo, const DataArrayIdType *a1, DataArrayDouble *a2, const std::vector<std::string>& littleStrings)
3169 MEDCouplingPointSet::unserialization(tinyInfoD,tinyInfo,a1,a2,littleStrings);
3170 setMeshDimension(FromIdType<int>(tinyInfo[5]));
3174 const mcIdType *recvBuffer=a1->getConstPointer();
3175 MCAuto<DataArrayIdType> myConnecIndex=DataArrayIdType::New();
3176 myConnecIndex->alloc(tinyInfo[6]+1,1);
3177 std::copy(recvBuffer,recvBuffer+tinyInfo[6]+1,myConnecIndex->getPointer());
3178 MCAuto<DataArrayIdType> myConnec=DataArrayIdType::New();
3179 myConnec->alloc(tinyInfo[7],1);
3180 std::copy(recvBuffer+tinyInfo[6]+1,recvBuffer+tinyInfo[6]+1+tinyInfo[7],myConnec->getPointer());
3181 setConnectivity(myConnec, myConnecIndex);
3188 * Returns a new MEDCouplingFieldDouble containing volumes of cells constituting \a this
3190 * For 1D cells, the returned field contains lengths.<br>
3191 * For 2D cells, the returned field contains areas.<br>
3192 * For 3D cells, the returned field contains volumes.
3193 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3194 * orientation, i.e. the volume is always positive.
3195 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on cells
3196 * and one time . The caller is to delete this field using decrRef() as it is no
3199 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureField(bool isAbs) const
3201 std::string name="MeasureOfMesh_";
3203 mcIdType nbelem=getNumberOfCells();
3204 MCAuto<MEDCouplingFieldDouble> field=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3205 field->setName(name);
3206 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3207 array->alloc(nbelem,1);
3208 double *area_vol=array->getPointer();
3209 field->setArray(array) ; array=0;
3210 field->setMesh(const_cast<MEDCouplingUMesh *>(this));
3211 field->synchronizeTimeWithMesh();
3212 if(getMeshDimension()!=-1)
3215 INTERP_KERNEL::NormalizedCellType type;
3216 int dim_space=getSpaceDimension();
3217 const double *coords=getCoords()->getConstPointer();
3218 const mcIdType *connec=getNodalConnectivity()->getConstPointer();
3219 const mcIdType *connec_index=getNodalConnectivityIndex()->getConstPointer();
3220 for(mcIdType iel=0;iel<nbelem;iel++)
3222 ipt=connec_index[iel];
3223 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3224 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);
3227 std::transform(area_vol,area_vol+nbelem,area_vol,std::ptr_fun<double,double>(fabs));
3231 area_vol[0]=std::numeric_limits<double>::max();
3233 return field.retn();
3237 * Returns a new DataArrayDouble containing volumes of specified cells of \a this
3239 * For 1D cells, the returned array contains lengths.<br>
3240 * For 2D cells, the returned array contains areas.<br>
3241 * For 3D cells, the returned array contains volumes.
3242 * This method avoids building explicitly a part of \a this mesh to perform the work.
3243 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3244 * orientation, i.e. the volume is always positive.
3245 * \param [in] begin - an array of cell ids of interest.
3246 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3247 * \return DataArrayDouble * - a new instance of DataArrayDouble. The caller is to
3248 * delete this array using decrRef() as it is no more needed.
3250 * \if ENABLE_EXAMPLES
3251 * \ref cpp_mcumesh_getPartMeasureField "Here is a C++ example".<br>
3252 * \ref py_mcumesh_getPartMeasureField "Here is a Python example".
3254 * \sa getMeasureField()
3256 DataArrayDouble *MEDCouplingUMesh::getPartMeasureField(bool isAbs, const mcIdType *begin, const mcIdType *end) const
3258 std::string name="PartMeasureOfMesh_";
3260 std::size_t nbelem=std::distance(begin,end);
3261 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3262 array->setName(name);
3263 array->alloc(nbelem,1);
3264 double *area_vol=array->getPointer();
3265 if(getMeshDimension()!=-1)
3268 INTERP_KERNEL::NormalizedCellType type;
3269 int dim_space=getSpaceDimension();
3270 const double *coords=getCoords()->getConstPointer();
3271 const mcIdType *connec=getNodalConnectivity()->getConstPointer();
3272 const mcIdType *connec_index=getNodalConnectivityIndex()->getConstPointer();
3273 for(const mcIdType *iel=begin;iel!=end;iel++)
3275 ipt=connec_index[*iel];
3276 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3277 *area_vol++=INTERP_KERNEL::computeVolSurfOfCell2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,connec+ipt+1,connec_index[*iel+1]-ipt-1,coords,dim_space);
3280 std::transform(array->getPointer(),area_vol,array->getPointer(),std::ptr_fun<double,double>(fabs));
3284 area_vol[0]=std::numeric_limits<double>::max();
3286 return array.retn();
3290 * Returns a new MEDCouplingFieldDouble containing volumes of cells of a dual mesh of
3291 * \a this one. The returned field contains the dual cell volume for each corresponding
3292 * node in \a this mesh. In other words, the field returns the getMeasureField() of
3293 * the dual mesh in P1 sens of \a this.<br>
3294 * For 1D cells, the returned field contains lengths.<br>
3295 * For 2D cells, the returned field contains areas.<br>
3296 * For 3D cells, the returned field contains volumes.
3297 * This method is useful to check "P1*" conservative interpolators.
3298 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3299 * orientation, i.e. the volume is always positive.
3300 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3301 * nodes and one time. The caller is to delete this array using decrRef() as
3302 * it is no more needed.
3304 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureFieldOnNode(bool isAbs) const
3306 MCAuto<MEDCouplingFieldDouble> tmp=getMeasureField(isAbs);
3307 std::string name="MeasureOnNodeOfMesh_";
3309 mcIdType nbNodes=getNumberOfNodes();
3310 MCAuto<DataArrayDouble> nnpc;
3312 MCAuto<DataArrayIdType> tmp(computeNbOfNodesPerCell());
3313 nnpc=tmp->convertToDblArr();
3315 std::for_each(nnpc->rwBegin(),nnpc->rwEnd(),[](double& v) { v=1./v; });
3316 const double *nnpcPtr(nnpc->begin());
3317 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_NODES);
3318 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3319 array->alloc(nbNodes,1);
3320 double *valsToFill=array->getPointer();
3321 std::fill(valsToFill,valsToFill+nbNodes,0.);
3322 const double *values=tmp->getArray()->getConstPointer();
3323 MCAuto<DataArrayIdType> da=DataArrayIdType::New();
3324 MCAuto<DataArrayIdType> daInd=DataArrayIdType::New();
3325 getReverseNodalConnectivity(da,daInd);
3326 const mcIdType *daPtr=da->getConstPointer();
3327 const mcIdType *daIPtr=daInd->getConstPointer();
3328 for(mcIdType i=0;i<nbNodes;i++)
3329 for(const mcIdType *cell=daPtr+daIPtr[i];cell!=daPtr+daIPtr[i+1];cell++)
3330 valsToFill[i]+=nnpcPtr[*cell]*values[*cell];
3332 ret->setArray(array);
3337 * Returns a new MEDCouplingFieldDouble holding normal vectors to cells of \a this
3338 * mesh. The returned normal vectors to each cell have a norm2 equal to 1.
3339 * The computed vectors have <em> this->getMeshDimension()+1 </em> components
3340 * and are normalized.
3341 * <br> \a this can be either
3342 * - a 2D mesh in 2D or 3D space or
3343 * - an 1D mesh in 2D space.
3345 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3346 * cells and one time. The caller is to delete this field using decrRef() as
3347 * it is no more needed.
3348 * \throw If the nodal connectivity of cells is not defined.
3349 * \throw If the coordinates array is not set.
3350 * \throw If the mesh dimension is not set.
3351 * \throw If the mesh and space dimension is not as specified above.
3353 MEDCouplingFieldDouble *MEDCouplingUMesh::buildOrthogonalField() const
3355 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3356 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3357 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3358 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3359 mcIdType nbOfCells=getNumberOfCells();
3360 int nbComp=getMeshDimension()+1;
3361 array->alloc(nbOfCells,nbComp);
3362 double *vals=array->getPointer();
3363 const mcIdType *connI=_nodal_connec_index->getConstPointer();
3364 const mcIdType *conn=_nodal_connec->getConstPointer();
3365 const double *coords=_coords->getConstPointer();
3366 if(getMeshDimension()==2)
3368 if(getSpaceDimension()==3)
3370 MCAuto<DataArrayDouble> loc=computeCellCenterOfMass();
3371 const double *locPtr=loc->getConstPointer();
3372 for(mcIdType i=0;i<nbOfCells;i++,vals+=3)
3374 mcIdType offset=connI[i];
3375 INTERP_KERNEL::crossprod<3>(locPtr+3*i,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3376 double n=INTERP_KERNEL::norm<3>(vals);
3377 std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3382 MCAuto<MEDCouplingFieldDouble> isAbs=getMeasureField(false);
3383 const double *isAbsPtr=isAbs->getArray()->begin();
3384 for(mcIdType i=0;i<nbOfCells;i++,isAbsPtr++)
3385 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=*isAbsPtr>0.?1.:-1.; }
3388 else//meshdimension==1
3391 for(mcIdType i=0;i<nbOfCells;i++)
3393 mcIdType offset=connI[i];
3394 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3395 double n=INTERP_KERNEL::norm<2>(tmp);
3396 std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3401 ret->setArray(array);
3403 ret->synchronizeTimeWithSupport();
3408 * Returns a new MEDCouplingFieldDouble holding normal vectors to specified cells of
3409 * \a this mesh. The computed vectors have <em> this->getMeshDimension()+1 </em> components
3410 * and are normalized.
3411 * <br> \a this can be either
3412 * - a 2D mesh in 2D or 3D space or
3413 * - an 1D mesh in 2D space.
3415 * This method avoids building explicitly a part of \a this mesh to perform the work.
3416 * \param [in] begin - an array of cell ids of interest.
3417 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3418 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3419 * cells and one time. The caller is to delete this field using decrRef() as
3420 * it is no more needed.
3421 * \throw If the nodal connectivity of cells is not defined.
3422 * \throw If the coordinates array is not set.
3423 * \throw If the mesh dimension is not set.
3424 * \throw If the mesh and space dimension is not as specified above.
3425 * \sa buildOrthogonalField()
3427 * \if ENABLE_EXAMPLES
3428 * \ref cpp_mcumesh_buildPartOrthogonalField "Here is a C++ example".<br>
3429 * \ref py_mcumesh_buildPartOrthogonalField "Here is a Python example".
3432 MEDCouplingFieldDouble *MEDCouplingUMesh::buildPartOrthogonalField(const mcIdType *begin, const mcIdType *end) const
3434 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3435 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3436 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3437 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3438 std::size_t nbelems=std::distance(begin,end);
3439 int nbComp=getMeshDimension()+1;
3440 array->alloc(nbelems,nbComp);
3441 double *vals=array->getPointer();
3442 const mcIdType *connI=_nodal_connec_index->getConstPointer();
3443 const mcIdType *conn=_nodal_connec->getConstPointer();
3444 const double *coords=_coords->getConstPointer();
3445 if(getMeshDimension()==2)
3447 if(getSpaceDimension()==3)
3449 MCAuto<DataArrayDouble> loc=getPartBarycenterAndOwner(begin,end);
3450 const double *locPtr=loc->getConstPointer();
3451 for(const mcIdType *i=begin;i!=end;i++,vals+=3,locPtr+=3)
3453 mcIdType offset=connI[*i];
3454 INTERP_KERNEL::crossprod<3>(locPtr,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3455 double n=INTERP_KERNEL::norm<3>(vals);
3456 std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3461 for(std::size_t i=0;i<nbelems;i++)
3462 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=1.; }
3465 else//meshdimension==1
3468 for(const mcIdType *i=begin;i!=end;i++)
3470 mcIdType offset=connI[*i];
3471 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3472 double n=INTERP_KERNEL::norm<2>(tmp);
3473 std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3478 ret->setArray(array);
3480 ret->synchronizeTimeWithSupport();
3485 * Returns a new MEDCouplingFieldDouble holding a direction vector for each SEG2 in \a
3486 * this 1D mesh. The computed vectors have <em> this->getSpaceDimension() </em> components
3487 * and are \b not normalized.
3488 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3489 * cells and one time. The caller is to delete this field using decrRef() as
3490 * it is no more needed.
3491 * \throw If the nodal connectivity of cells is not defined.
3492 * \throw If the coordinates array is not set.
3493 * \throw If \a this->getMeshDimension() != 1.
3494 * \throw If \a this mesh includes cells of type other than SEG2.
3496 MEDCouplingFieldDouble *MEDCouplingUMesh::buildDirectionVectorField() const
3498 if(getMeshDimension()!=1)
3499 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for buildDirectionVectorField !");
3500 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3501 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for buildDirectionVectorField !");
3502 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3503 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3504 mcIdType nbOfCells=getNumberOfCells();
3505 int spaceDim=getSpaceDimension();
3506 array->alloc(nbOfCells,spaceDim);
3507 double *pt=array->getPointer();
3508 const double *coo=getCoords()->getConstPointer();
3509 std::vector<mcIdType> conn;
3511 for(mcIdType i=0;i<nbOfCells;i++)
3514 getNodeIdsOfCell(i,conn);
3515 pt=std::transform(coo+conn[1]*spaceDim,coo+(conn[1]+1)*spaceDim,coo+conn[0]*spaceDim,pt,std::minus<double>());
3517 ret->setArray(array);
3519 ret->synchronizeTimeWithSupport();
3524 * Creates a 2D mesh by cutting \a this 3D mesh with a plane. In addition to the mesh,
3525 * returns a new DataArrayIdType, of length equal to the number of 2D cells in the result
3526 * mesh, holding, for each cell in the result mesh, an id of a 3D cell it comes
3527 * from. If a result face is shared by two 3D cells, then the face in included twice in
3529 * \param [in] origin - 3 components of a point defining location of the plane.
3530 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3531 * must be greater than 1e-6.
3532 * \param [in] eps - half-thickness of the plane.
3533 * \param [out] cellIds - a new instance of DataArrayIdType holding ids of 3D cells
3534 * producing correspondent 2D cells. The caller is to delete this array
3535 * using decrRef() as it is no more needed.
3536 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This mesh does
3537 * not share the node coordinates array with \a this mesh. The caller is to
3538 * delete this mesh using decrRef() as it is no more needed.
3539 * \throw If the coordinates array is not set.
3540 * \throw If the nodal connectivity of cells is not defined.
3541 * \throw If \a this->getMeshDimension() != 3 or \a this->getSpaceDimension() != 3.
3542 * \throw If magnitude of \a vec is less than 1e-6.
3543 * \throw If the plane does not intersect any 3D cell of \a this mesh.
3544 * \throw If \a this includes quadratic cells.
3546 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3D(const double *origin, const double *vec, double eps, DataArrayIdType *&cellIds) const
3548 checkFullyDefined();
3549 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3550 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3551 MCAuto<DataArrayIdType> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3552 if(candidates->empty())
3553 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane considering bounding boxes !");
3554 std::vector<mcIdType> nodes;
3555 DataArrayIdType *cellIds1D=0;
3556 MCAuto<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3557 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3558 MCAuto<DataArrayIdType> desc1=DataArrayIdType::New(),desc2=DataArrayIdType::New();
3559 MCAuto<DataArrayIdType> descIndx1=DataArrayIdType::New(),descIndx2=DataArrayIdType::New();
3560 MCAuto<DataArrayIdType> revDesc1=DataArrayIdType::New(),revDesc2=DataArrayIdType::New();
3561 MCAuto<DataArrayIdType> revDescIndx1=DataArrayIdType::New(),revDescIndx2=DataArrayIdType::New();
3562 MCAuto<MEDCouplingUMesh> mDesc2=subMesh->buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2);//meshDim==2 spaceDim==3
3563 revDesc2=0; revDescIndx2=0;
3564 MCAuto<MEDCouplingUMesh> mDesc1=mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3565 revDesc1=0; revDescIndx1=0;
3566 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3567 MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3569 std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3570 for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3572 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3573 std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(mDesc2->getNumberOfCells());
3574 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->getConstPointer(),mDesc2->getNodalConnectivityIndex()->getConstPointer(),
3575 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3576 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3577 MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New()),cellIds2(DataArrayIdType::New());
3578 connI->pushBackSilent(0); conn->alloc(0,1); cellIds2->alloc(0,1);
3579 subMesh->assemblyForSplitFrom3DSurf(cut3DSurf,desc2->getConstPointer(),descIndx2->getConstPointer(),conn,connI,cellIds2);
3580 if(cellIds2->empty())
3581 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3582 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3D",2);
3583 ret->setCoords(mDesc1->getCoords());
3584 ret->setConnectivity(conn,connI,true);
3585 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3590 * Creates an 1D mesh by cutting \a this 2D mesh in 3D space with a plane. In
3591 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
3592 from. If a result segment is shared by two 2D cells, then the segment in included twice in
3594 * \param [in] origin - 3 components of a point defining location of the plane.
3595 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3596 * must be greater than 1e-6.
3597 * \param [in] eps - half-thickness of the plane.
3598 * \param [out] cellIds - a new instance of DataArrayIdType holding ids of faces
3599 * producing correspondent segments. The caller is to delete this array
3600 * using decrRef() as it is no more needed.
3601 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This is an 1D
3602 * mesh in 3D space. This mesh does not share the node coordinates array with
3603 * \a this mesh. The caller is to delete this mesh using decrRef() as it is
3605 * \throw If the coordinates array is not set.
3606 * \throw If the nodal connectivity of cells is not defined.
3607 * \throw If \a this->getMeshDimension() != 2 or \a this->getSpaceDimension() != 3.
3608 * \throw If magnitude of \a vec is less than 1e-6.
3609 * \throw If the plane does not intersect any 2D cell of \a this mesh.
3610 * \throw If \a this includes quadratic cells.
3612 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3DSurf(const double *origin, const double *vec, double eps, DataArrayIdType *&cellIds) const
3614 checkFullyDefined();
3615 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
3616 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf works on umeshes with meshdim equal to 2 and spaceDim equal to 3 !");
3617 MCAuto<DataArrayIdType> candidates(getCellIdsCrossingPlane(origin,vec,eps));
3618 if(candidates->empty())
3619 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3D surf cells in this intercepts the specified plane considering bounding boxes !");
3620 std::vector<mcIdType> nodes;
3621 DataArrayIdType *cellIds1D(0);
3622 MCAuto<MEDCouplingUMesh> subMesh(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3623 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3624 MCAuto<DataArrayIdType> desc1(DataArrayIdType::New()),descIndx1(DataArrayIdType::New()),revDesc1(DataArrayIdType::New()),revDescIndx1(DataArrayIdType::New());
3625 MCAuto<MEDCouplingUMesh> mDesc1(subMesh->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3626 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3627 MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3629 std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3630 for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3632 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3633 mcIdType ncellsSub=subMesh->getNumberOfCells();
3634 std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(ncellsSub);
3635 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,subMesh->getNodalConnectivity()->getConstPointer(),subMesh->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()); connI->pushBackSilent(0);
3640 const mcIdType *nodal=subMesh->getNodalConnectivity()->getConstPointer();
3641 const mcIdType *nodalI=subMesh->getNodalConnectivityIndex()->getConstPointer();
3642 for(mcIdType i=0;i<ncellsSub;i++)
3644 if(cut3DSurf[i].first!=-1 && cut3DSurf[i].second!=-1)
3646 if(cut3DSurf[i].first!=-2)
3648 conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_SEG2)); conn->pushBackSilent(cut3DSurf[i].first); conn->pushBackSilent(cut3DSurf[i].second);
3649 connI->pushBackSilent(conn->getNumberOfTuples());
3650 cellIds2->pushBackSilent(i);
3654 mcIdType cellId3DSurf=cut3DSurf[i].second;
3655 mcIdType offset=nodalI[cellId3DSurf]+1;
3656 mcIdType nbOfEdges=nodalI[cellId3DSurf+1]-offset;
3657 for(mcIdType j=0;j<nbOfEdges;j++)
3659 conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_SEG2)); conn->pushBackSilent(nodal[offset+j]); conn->pushBackSilent(nodal[offset+(j+1)%nbOfEdges]);
3660 connI->pushBackSilent(conn->getNumberOfTuples());
3661 cellIds2->pushBackSilent(cellId3DSurf);
3666 if(cellIds2->empty())
3667 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3DSurf cells in this intercepts the specified plane !");
3668 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3DSurf",1);
3669 ret->setCoords(mDesc1->getCoords());
3670 ret->setConnectivity(conn,connI,true);
3671 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3675 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::clipSingle3DCellByPlane(const double origin[3], const double vec[3], double eps) const
3677 checkFullyDefined();
3678 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3679 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3680 if(getNumberOfCells()!=1)
3681 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works only on mesh containing exactly one cell !");
3683 std::vector<mcIdType> nodes;
3684 findNodesOnPlane(origin,vec,eps,nodes);
3685 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());
3686 MCAuto<MEDCouplingUMesh> mDesc2(buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2));//meshDim==2 spaceDim==3
3687 revDesc2=0; revDescIndx2=0;
3688 MCAuto<MEDCouplingUMesh> mDesc1(mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3689 revDesc1=0; revDescIndx1=0;
3690 DataArrayIdType *cellIds1D(0);
3691 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3692 MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3693 std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3694 for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3698 mcIdType oldNbNodes(mDesc1->getNumberOfNodes());
3699 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3700 sameNbNodes=(mDesc1->getNumberOfNodes()==oldNbNodes);
3702 std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(mDesc2->getNumberOfCells());
3703 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->begin(),mDesc2->getNodalConnectivityIndex()->begin(),
3704 mDesc1->getNodalConnectivity()->begin(),mDesc1->getNodalConnectivityIndex()->begin(),
3705 desc1->begin(),descIndx1->begin(),cut3DSurf);
3706 MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New());
3707 connI->pushBackSilent(0); conn->alloc(0,1);
3709 MCAuto<DataArrayIdType> cellIds2(DataArrayIdType::New()); cellIds2->alloc(0,1);
3710 assemblyForSplitFrom3DSurf(cut3DSurf,desc2->begin(),descIndx2->begin(),conn,connI,cellIds2);
3711 if(cellIds2->empty())
3712 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3714 std::vector<std::vector<mcIdType> > res;
3715 buildSubCellsFromCut(cut3DSurf,desc2->begin(),descIndx2->begin(),mDesc1->getCoords()->begin(),eps,res);
3716 std::size_t sz(res.size());
3717 if(ToIdType(res.size())==mDesc1->getNumberOfCells() && sameNbNodes)
3718 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane : cell is not clipped !");
3719 for(std::size_t i=0;i<sz;i++)
3721 conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYGON));
3722 conn->insertAtTheEnd(res[i].begin(),res[i].end());
3723 connI->pushBackSilent(conn->getNumberOfTuples());
3725 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
3726 ret->setCoords(mDesc1->getCoords());
3727 ret->setConnectivity(conn,connI,true);
3728 mcIdType nbCellsRet(ret->getNumberOfCells());
3730 MCAuto<DataArrayDouble> vec2(DataArrayDouble::New()); vec2->alloc(1,3); std::copy(vec,vec+3,vec2->getPointer());
3731 MCAuto<MEDCouplingFieldDouble> ortho(ret->buildOrthogonalField());
3732 MCAuto<DataArrayDouble> ortho2(ortho->getArray()->selectByTupleIdSafeSlice(0,1,1));
3733 MCAuto<DataArrayDouble> dott(DataArrayDouble::Dot(ortho2,vec2));
3734 MCAuto<DataArrayDouble> ccm(ret->computeCellCenterOfMass());
3735 MCAuto<DataArrayDouble> occm;
3737 MCAuto<DataArrayDouble> pt(DataArrayDouble::New()); pt->alloc(1,3); std::copy(origin,origin+3,pt->getPointer());
3738 occm=DataArrayDouble::Substract(ccm,pt);
3740 vec2=DataArrayDouble::New(); vec2->alloc(nbCellsRet,3);
3741 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);
3742 MCAuto<DataArrayDouble> dott2(DataArrayDouble::Dot(occm,vec2));
3744 const mcIdType *cPtr(ret->getNodalConnectivity()->begin()),*ciPtr(ret->getNodalConnectivityIndex()->begin());
3745 MCAuto<MEDCouplingUMesh> ret2(MEDCouplingUMesh::New("Clip3D",3));
3746 ret2->setCoords(mDesc1->getCoords());
3747 MCAuto<DataArrayIdType> conn2(DataArrayIdType::New()),conn2I(DataArrayIdType::New());
3748 conn2I->pushBackSilent(0); conn2->alloc(0,1);
3749 std::vector<mcIdType> cell0(1,ToIdType(INTERP_KERNEL::NORM_POLYHED));
3750 std::vector<mcIdType> cell1(1,ToIdType(INTERP_KERNEL::NORM_POLYHED));
3751 if(dott->getIJ(0,0)>0)
3753 cell0.insert(cell0.end(),cPtr+1,cPtr+ciPtr[1]);
3754 std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell1,cell1.end()));
3758 cell1.insert(cell1.end(),cPtr+1,cPtr+ciPtr[1]);
3759 std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell0,cell0.end()));
3761 for(mcIdType i=1;i<nbCellsRet;i++)
3763 if(dott2->getIJ(i,0)<0)
3765 if(ciPtr[i+1]-ciPtr[i]>=4)
3767 cell0.push_back(-1);
3768 cell0.insert(cell0.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
3773 if(ciPtr[i+1]-ciPtr[i]>=4)
3775 cell1.push_back(-1);
3776 cell1.insert(cell1.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
3780 conn2->insertAtTheEnd(cell0.begin(),cell0.end());
3781 conn2I->pushBackSilent(conn2->getNumberOfTuples());
3782 conn2->insertAtTheEnd(cell1.begin(),cell1.end());
3783 conn2I->pushBackSilent(conn2->getNumberOfTuples());
3784 ret2->setConnectivity(conn2,conn2I,true);
3785 ret2->checkConsistencyLight();
3786 ret2->orientCorrectlyPolyhedrons();
3791 * Finds cells whose bounding boxes intersect a given plane.
3792 * \param [in] origin - 3 components of a point defining location of the plane.
3793 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3794 * must be greater than 1e-6.
3795 * \param [in] eps - half-thickness of the plane.
3796 * \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of the found
3797 * cells. The caller is to delete this array using decrRef() as it is no more
3799 * \throw If the coordinates array is not set.
3800 * \throw If the nodal connectivity of cells is not defined.
3801 * \throw If \a this->getSpaceDimension() != 3.
3802 * \throw If magnitude of \a vec is less than 1e-6.
3803 * \sa buildSlice3D()
3805 DataArrayIdType *MEDCouplingUMesh::getCellIdsCrossingPlane(const double *origin, const double *vec, double eps) const
3807 checkFullyDefined();
3808 if(getSpaceDimension()!=3)
3809 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with spaceDim equal to 3 !");
3810 double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
3812 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellIdsCrossingPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
3814 vec2[0]=vec[1]; vec2[1]=-vec[0]; vec2[2]=0.;//vec2 is the result of cross product of vec with (0,0,1)
3815 double angle=acos(vec[2]/normm);
3816 MCAuto<DataArrayIdType> cellIds;
3820 MCAuto<DataArrayDouble> coo=_coords->deepCopy();
3821 double normm2(sqrt(vec2[0]*vec2[0]+vec2[1]*vec2[1]+vec2[2]*vec2[2]));
3822 if(normm2/normm>1e-6)
3823 DataArrayDouble::Rotate3DAlg(origin,vec2,angle,coo->getNumberOfTuples(),coo->getPointer(),coo->getPointer());
3824 MCAuto<MEDCouplingUMesh> mw=clone(false);//false -> shallow copy
3826 mw->getBoundingBox(bbox);
3827 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3828 cellIds=mw->getCellsInBoundingBox(bbox,eps);
3832 getBoundingBox(bbox);
3833 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3834 cellIds=getCellsInBoundingBox(bbox,eps);
3836 return cellIds.retn();
3840 * This method checks that \a this is a contiguous mesh. The user is expected to call this method on a mesh with meshdim==1.
3841 * If not an exception will thrown. If this is an empty mesh with no cell an exception will be thrown too.
3842 * No consideration of coordinate is done by this method.
3843 * 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)
3844 * If not false is returned. In case that false is returned a call to MEDCoupling::MEDCouplingUMesh::mergeNodes could be useful.
3846 bool MEDCouplingUMesh::isContiguous1D() const
3848 if(getMeshDimension()!=1)
3849 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense only for 1D mesh !");
3850 mcIdType nbCells=getNumberOfCells();
3852 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense for non empty mesh !");
3853 const mcIdType *connI(_nodal_connec_index->begin()),*conn(_nodal_connec->begin());
3854 mcIdType ref=conn[connI[0]+2];
3855 for(mcIdType i=1;i<nbCells;i++)
3857 if(conn[connI[i]+1]!=ref)
3859 ref=conn[connI[i]+2];
3865 * This method is only callable on mesh with meshdim == 1 containing only SEG2 and spaceDim==3.
3866 * This method projects this on the 3D line defined by (pt,v). This methods first checks that all SEG2 are along v vector.
3867 * \param pt reference point of the line
3868 * \param v normalized director vector of the line
3869 * \param eps max precision before throwing an exception
3870 * \param res output of size this->getNumberOfCells
3872 void MEDCouplingUMesh::project1D(const double *pt, const double *v, double eps, double *res) const
3874 if(getMeshDimension()!=1)
3875 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for project1D !");
3876 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3877 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for project1D !");
3878 if(getSpaceDimension()!=3)
3879 throw INTERP_KERNEL::Exception("Expected a umesh with spaceDim==3 for project1D !");
3880 MCAuto<MEDCouplingFieldDouble> f=buildDirectionVectorField();
3881 const double *fPtr=f->getArray()->getConstPointer();
3883 for(mcIdType i=0;i<getNumberOfCells();i++)
3885 const double *tmp1=fPtr+3*i;
3886 tmp[0]=tmp1[1]*v[2]-tmp1[2]*v[1];
3887 tmp[1]=tmp1[2]*v[0]-tmp1[0]*v[2];
3888 tmp[2]=tmp1[0]*v[1]-tmp1[1]*v[0];
3889 double n1=INTERP_KERNEL::norm<3>(tmp);
3890 n1/=INTERP_KERNEL::norm<3>(tmp1);
3892 throw INTERP_KERNEL::Exception("UMesh::Projection 1D failed !");
3894 const double *coo=getCoords()->getConstPointer();
3895 for(mcIdType i=0;i<getNumberOfNodes();i++)
3897 std::transform(coo+i*3,coo+i*3+3,pt,tmp,std::minus<double>());
3898 std::transform(tmp,tmp+3,v,tmp,std::multiplies<double>());
3899 res[i]=std::accumulate(tmp,tmp+3,0.);
3904 * 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.
3905 * \a this is expected to be a mesh so that its space dimension is equal to its
3906 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
3907 * 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).
3909 * 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
3910 * 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).
3911 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
3913 * So this method is more accurate (so, more costly) than simply searching for the closest point in \a this.
3914 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
3916 * \param [in] ptBg the start pointer (included) of the coordinates of the point
3917 * \param [in] ptEnd the end pointer (not included) of the coordinates of the point
3918 * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
3919 * \return the positive value of the distance.
3920 * \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
3922 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoints
3924 double MEDCouplingUMesh::distanceToPoint(const double *ptBg, const double *ptEnd, mcIdType& cellId) const
3926 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
3927 if(meshDim!=spaceDim-1)
3928 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint works only for spaceDim=meshDim+1 !");
3929 if(meshDim!=2 && meshDim!=1)
3930 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint : only mesh dimension 2 and 1 are implemented !");
3931 checkFullyDefined();
3932 if(ToIdType(std::distance(ptBg,ptEnd))!=spaceDim)
3933 { 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()); }
3934 DataArrayIdType *ret1=0;
3935 MCAuto<DataArrayDouble> pts=DataArrayDouble::New(); pts->useArray(ptBg,false,DeallocType::C_DEALLOC,1,spaceDim);
3936 MCAuto<DataArrayDouble> ret0=distanceToPoints(pts,ret1);
3937 MCAuto<DataArrayIdType> ret1Safe(ret1);
3938 cellId=*ret1Safe->begin();
3939 return *ret0->begin();
3943 * This method computes the distance from each point of points serie \a pts (stored in a DataArrayDouble in which each tuple represents a point)
3944 * to \a this and the first \a cellId in \a this corresponding to the returned distance.
3945 * 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
3946 * 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).
3947 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
3949 * \a this is expected to be a mesh so that its space dimension is equal to its
3950 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
3951 * 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).
3953 * So this method is more accurate (so, more costly) than simply searching for each point in \a pts the closest point in \a this.
3954 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
3956 * \param [in] pts the list of points in which each tuple represents a point
3957 * \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.
3958 * \return a newly allocated object to be dealed by the caller that tells for each point in \a pts the distance to \a this.
3959 * \throw if number of components of \a pts is not equal to the space dimension.
3960 * \throw if mesh dimension of \a this is not equal to space dimension - 1.
3961 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoint
3963 DataArrayDouble *MEDCouplingUMesh::distanceToPoints(const DataArrayDouble *pts, DataArrayIdType *& cellIds) const
3966 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : input points pointer is NULL !");
3967 pts->checkAllocated();
3968 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
3969 if(meshDim!=spaceDim-1)
3970 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints works only for spaceDim=meshDim+1 !");
3971 if(meshDim!=2 && meshDim!=1)
3972 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only mesh dimension 2 and 1 are implemented !");
3973 if(ToIdType(pts->getNumberOfComponents())!=spaceDim)
3975 std::ostringstream oss; oss << "MEDCouplingUMesh::distanceToPoints : input pts DataArrayDouble has " << pts->getNumberOfComponents() << " components whereas it should be equal to " << spaceDim << " (mesh spaceDimension) !";
3976 throw INTERP_KERNEL::Exception(oss.str());
3978 checkFullyDefined();
3979 mcIdType nbCells=getNumberOfCells();
3981 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : no cells in this !");
3982 mcIdType nbOfPts=pts->getNumberOfTuples();
3983 MCAuto<DataArrayDouble> ret0=DataArrayDouble::New(); ret0->alloc(nbOfPts,1);
3984 MCAuto<DataArrayIdType> ret1=DataArrayIdType::New(); ret1->alloc(nbOfPts,1);
3985 const mcIdType *nc=_nodal_connec->begin(),*ncI=_nodal_connec_index->begin(); const double *coords=_coords->begin();
3986 double *ret0Ptr=ret0->getPointer(); mcIdType *ret1Ptr=ret1->getPointer(); const double *ptsPtr=pts->begin();
3987 MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree());
3988 const double *bbox(bboxArr->begin());
3993 BBTreeDst<3> myTree(bbox,0,0,nbCells);
3994 for(mcIdType i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=3)
3996 double x=std::numeric_limits<double>::max();
3997 std::vector<mcIdType> elems;
3998 myTree.getMinDistanceOfMax(ptsPtr,x);
3999 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4000 DistanceToPoint3DSurfAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4006 BBTreeDst<2> myTree(bbox,0,0,nbCells);
4007 for(mcIdType i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=2)
4009 double x=std::numeric_limits<double>::max();
4010 std::vector<mcIdType> elems;
4011 myTree.getMinDistanceOfMax(ptsPtr,x);
4012 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4013 DistanceToPoint2DCurveAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4018 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only spacedim 2 and 3 supported !");
4020 cellIds=ret1.retn();
4029 * Finds cells in contact with a ball (i.e. a point with precision).
4030 * 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.
4031 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4033 * \warning This method is suitable if the caller intends to evaluate only one
4034 * point, for more points getCellsContainingPoints() is recommended as it is
4036 * \param [in] pos - array of coordinates of the ball central point.
4037 * \param [in] eps - ball radius.
4038 * \return mcIdType - a smallest id of cells being in contact with the ball, -1 in case
4039 * if there are no such cells.
4040 * \throw If the coordinates array is not set.
4041 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4043 mcIdType MEDCouplingUMesh::getCellContainingPoint(const double *pos, double eps) const
4045 std::vector<mcIdType> elts;
4046 getCellsContainingPoint(pos,eps,elts);
4049 return elts.front();
4053 * Finds cells in contact with a ball (i.e. a point with precision).
4054 * 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.
4055 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4056 * \warning This method is suitable if the caller intends to evaluate only one
4057 * point, for more points getCellsContainingPoints() is recommended as it is
4059 * \param [in] pos - array of coordinates of the ball central point.
4060 * \param [in] eps - ball radius.
4061 * \param [out] elts - vector returning ids of the found cells. It is cleared
4062 * before inserting ids.
4063 * \throw If the coordinates array is not set.
4064 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4066 * \if ENABLE_EXAMPLES
4067 * \ref cpp_mcumesh_getCellsContainingPoint "Here is a C++ example".<br>
4068 * \ref py_mcumesh_getCellsContainingPoint "Here is a Python example".
4071 void MEDCouplingUMesh::getCellsContainingPoint(const double *pos, double eps, std::vector<mcIdType>& elts) const
4073 MCAuto<DataArrayIdType> eltsUg,eltsIndexUg;
4074 getCellsContainingPoints(pos,1,eps,eltsUg,eltsIndexUg);
4075 elts.clear(); elts.insert(elts.end(),eltsUg->begin(),eltsUg->end());
4078 void MEDCouplingUMesh::getCellsContainingPointsZeAlg(const double *pos, mcIdType nbOfPoints, double eps,
4079 MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex,
4080 std::function<bool(INTERP_KERNEL::NormalizedCellType,mcIdType)> sensibilityTo2DQuadraticLinearCellsFunc) const
4082 int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
4087 const double *coords=_coords->getConstPointer();
4088 getCellsContainingPointsAlg<3>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4091 throw INTERP_KERNEL::Exception("For spaceDim==3 only meshDim==3 implemented for getelementscontainingpoints !");
4093 else if(spaceDim==2)
4097 const double *coords=_coords->getConstPointer();
4098 getCellsContainingPointsAlg<2>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4101 throw INTERP_KERNEL::Exception("For spaceDim==2 only meshDim==2 implemented for getelementscontainingpoints !");
4103 else if(spaceDim==1)
4107 const double *coords=_coords->getConstPointer();
4108 getCellsContainingPointsAlg<1>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4111 throw INTERP_KERNEL::Exception("For spaceDim==1 only meshDim==1 implemented for getelementscontainingpoints !");
4114 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPoints : not managed for mdim not in [1,2,3] !");
4118 * Finds cells in contact with several balls (i.e. points with precision).
4119 * This method is an extension of getCellContainingPoint() and
4120 * getCellsContainingPoint() for the case of multiple points.
4121 * 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.
4122 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4123 * \param [in] pos - an array of coordinates of points in full interlace mode :
4124 * X0,Y0,Z0,X1,Y1,Z1,... Size of the array must be \a
4125 * this->getSpaceDimension() * \a nbOfPoints
4126 * \param [in] nbOfPoints - number of points to locate within \a this mesh.
4127 * \param [in] eps - radius of balls (i.e. the precision).
4128 * \param [out] elts - vector returning ids of found cells.
4129 * \param [out] eltsIndex - an array, of length \a nbOfPoints + 1,
4130 * dividing cell ids in \a elts into groups each referring to one
4131 * point. Its every element (except the last one) is an index pointing to the
4132 * first id of a group of cells. For example cells in contact with the *i*-th
4133 * point are described by following range of indices:
4134 * [ \a eltsIndex[ *i* ], \a eltsIndex[ *i*+1 ] ) and the cell ids are
4135 * \a elts[ \a eltsIndex[ *i* ]], \a elts[ \a eltsIndex[ *i* ] + 1 ], ...
4136 * Number of cells in contact with the *i*-th point is
4137 * \a eltsIndex[ *i*+1 ] - \a eltsIndex[ *i* ].
4138 * \throw If the coordinates array is not set.
4139 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4141 * \if ENABLE_EXAMPLES
4142 * \ref cpp_mcumesh_getCellsContainingPoints "Here is a C++ example".<br>
4143 * \ref py_mcumesh_getCellsContainingPoints "Here is a Python example".
4146 void MEDCouplingUMesh::getCellsContainingPoints(const double *pos, mcIdType nbOfPoints, double eps,
4147 MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex) const
4149 auto yesImSensibleTo2DQuadraticLinearCellsFunc([](INTERP_KERNEL::NormalizedCellType ct, int mdim) { return INTERP_KERNEL::CellModel::GetCellModel(ct).isQuadratic() && mdim == 2; } );
4150 this->getCellsContainingPointsZeAlg(pos,nbOfPoints,eps,elts,eltsIndex,yesImSensibleTo2DQuadraticLinearCellsFunc);
4154 * Behaves like MEDCouplingMesh::getCellsContainingPoints for cells in \a this that are linear.
4155 * For quadratic cells in \a this, this method behaves by just considering linear part of cells.
4156 * This method is here only for backward compatibility (interpolation GaussPoints to GaussPoints).
4158 * \sa MEDCouplingUMesh::getCellsContainingPoints, MEDCouplingRemapper::prepareNotInterpKernelOnlyGaussGauss
4160 void MEDCouplingUMesh::getCellsContainingPointsLinearPartOnlyOnNonDynType(const double *pos, mcIdType nbOfPoints, double eps, MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex) const
4162 auto noImNotSensibleTo2DQuadraticLinearCellsFunc([](INTERP_KERNEL::NormalizedCellType,mcIdType) { return false; } );
4163 this->getCellsContainingPointsZeAlg(pos,nbOfPoints,eps,elts,eltsIndex,noImNotSensibleTo2DQuadraticLinearCellsFunc);
4167 * Finds butterfly cells in \a this mesh. A 2D cell is considered to be butterfly if at
4168 * least two its edges intersect each other anywhere except their extremities. An
4169 * INTERP_KERNEL::NORM_NORI3 cell can \b not be butterfly.
4170 * \param [in,out] cells - a vector returning ids of the found cells. It is not
4171 * cleared before filling in.
4172 * \param [in] eps - precision.
4173 * \throw If \a this->getMeshDimension() != 2.
4174 * \throw If \a this->getSpaceDimension() != 2 && \a this->getSpaceDimension() != 3.
4176 void MEDCouplingUMesh::checkButterflyCells(std::vector<mcIdType>& cells, double eps) const
4178 const char msg[]="Butterfly detection work only for 2D cells with spaceDim==2 or 3!";
4179 if(getMeshDimension()!=2)
4180 throw INTERP_KERNEL::Exception(msg);
4181 int spaceDim=getSpaceDimension();
4182 if(spaceDim!=2 && spaceDim!=3)
4183 throw INTERP_KERNEL::Exception(msg);
4184 const mcIdType *conn=_nodal_connec->getConstPointer();
4185 const mcIdType *connI=_nodal_connec_index->getConstPointer();
4186 mcIdType nbOfCells=getNumberOfCells();
4187 std::vector<double> cell2DinS2;
4188 for(mcIdType i=0;i<nbOfCells;i++)
4190 mcIdType offset=connI[i];
4191 mcIdType nbOfNodesForCell=connI[i+1]-offset-1;
4192 if(nbOfNodesForCell<=3)
4194 bool isQuad=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[offset]).isQuadratic();
4195 project2DCellOnXY(conn+offset+1,conn+connI[i+1],cell2DinS2);
4196 if(isButterfly2DCell(cell2DinS2,isQuad,eps))
4203 * This method is typically requested to unbutterfly 2D linear cells in \b this.
4205 * 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.
4206 * 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.
4208 * For each 2D linear cell in \b this, this method builds the convex envelop (or the convex hull) of the current cell.
4209 * This convex envelop is computed using Jarvis march algorithm.
4210 * The coordinates and the number of cells of \b this remain unchanged on invocation of this method.
4211 * 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)
4212 * 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.
4214 * \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.
4215 * \sa MEDCouplingUMesh::colinearize2D
4217 DataArrayIdType *MEDCouplingUMesh::convexEnvelop2D()
4219 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
4220 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convexEnvelop2D works only for meshDim=2 and spaceDim=2 !");
4221 checkFullyDefined();
4222 const double *coords=getCoords()->getConstPointer();
4223 mcIdType nbOfCells=getNumberOfCells();
4224 MCAuto<DataArrayIdType> nodalConnecIndexOut=DataArrayIdType::New();
4225 nodalConnecIndexOut->alloc(nbOfCells+1,1);
4226 MCAuto<DataArrayIdType> nodalConnecOut(DataArrayIdType::New());
4227 mcIdType *workIndexOut=nodalConnecIndexOut->getPointer();
4229 const mcIdType *nodalConnecIn=_nodal_connec->getConstPointer();
4230 const mcIdType *nodalConnecIndexIn=_nodal_connec_index->getConstPointer();
4231 std::set<INTERP_KERNEL::NormalizedCellType> types;
4232 MCAuto<DataArrayIdType> isChanged(DataArrayIdType::New());
4233 isChanged->alloc(0,1);
4234 for(mcIdType i=0;i<nbOfCells;i++,workIndexOut++)
4236 mcIdType pos=nodalConnecOut->getNumberOfTuples();
4237 if(BuildConvexEnvelopOf2DCellJarvis(coords,nodalConnecIn+nodalConnecIndexIn[i],nodalConnecIn+nodalConnecIndexIn[i+1],nodalConnecOut))
4238 isChanged->pushBackSilent(i);
4239 types.insert((INTERP_KERNEL::NormalizedCellType)nodalConnecOut->getIJ(pos,0));
4240 workIndexOut[1]=nodalConnecOut->getNumberOfTuples();
4242 if(isChanged->empty())
4244 setConnectivity(nodalConnecOut,nodalConnecIndexOut,false);
4246 return isChanged.retn();
4250 * This method is \b NOT const because it can modify \a this.
4251 * \a this is expected to be an unstructured mesh with meshDim==2 and spaceDim==3. If not an exception will be thrown.
4252 * \param mesh1D is an unstructured mesh with MeshDim==1 and spaceDim==3. If not an exception will be thrown.
4253 * \param policy specifies the type of extrusion chosen:
4254 * - \b 0 for translation only (most simple): the cells of the 1D mesh represent the vectors along which the 2D mesh
4255 * will be repeated to build each level
4256 * - \b 1 for translation and rotation: the translation is done as above. For each level, an arc of circle is fitted on
4257 * 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
4258 * 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
4260 * \return an unstructured mesh with meshDim==3 and spaceDim==3. The returned mesh has the same coords than \a this.
4262 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMesh(const MEDCouplingUMesh *mesh1D, int policy)
4264 checkFullyDefined();
4265 mesh1D->checkFullyDefined();
4266 if(!mesh1D->isContiguous1D())
4267 throw INTERP_KERNEL::Exception("buildExtrudedMesh : 1D mesh passed in parameter is not contiguous !");
4268 if(getSpaceDimension()!=mesh1D->getSpaceDimension())
4269 throw INTERP_KERNEL::Exception("Invalid call to buildExtrudedMesh this and mesh1D must have same space dimension !");
4270 if((getMeshDimension()!=2 || getSpaceDimension()!=3) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
4271 throw INTERP_KERNEL::Exception("Invalid 'this' for buildExtrudedMesh method : must be (meshDim==2 and spaceDim==3) or (meshDim==1 and spaceDim==2) !");
4272 if(mesh1D->getMeshDimension()!=1)
4273 throw INTERP_KERNEL::Exception("Invalid 'mesh1D' for buildExtrudedMesh method : must be meshDim==1 !");
4275 if(isPresenceOfQuadratic())
4277 if(mesh1D->isFullyQuadratic())
4280 throw INTERP_KERNEL::Exception("Invalid 2D mesh and 1D mesh because 2D mesh has quadratic cells and 1D is not fully quadratic !");
4282 mcIdType oldNbOfNodes(getNumberOfNodes());
4283 MCAuto<DataArrayDouble> newCoords;
4288 newCoords=fillExtCoordsUsingTranslation(mesh1D,isQuad);
4293 newCoords=fillExtCoordsUsingTranslAndAutoRotation(mesh1D,isQuad);
4297 throw INTERP_KERNEL::Exception("Not implemented extrusion policy : must be in (0) !");
4299 setCoords(newCoords);
4300 MCAuto<MEDCouplingUMesh> ret(buildExtrudedMeshFromThisLowLev(oldNbOfNodes,isQuad));
4307 * Checks if \a this mesh is constituted by only quadratic cells.
4308 * \return bool - \c true if there are only quadratic cells in \a this mesh.
4309 * \throw If the coordinates array is not set.
4310 * \throw If the nodal connectivity of cells is not defined.
4312 bool MEDCouplingUMesh::isFullyQuadratic() const
4314 checkFullyDefined();
4316 mcIdType nbOfCells=getNumberOfCells();
4317 for(mcIdType i=0;i<nbOfCells && ret;i++)
4319 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4320 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4321 ret=cm.isQuadratic();
4327 * Checks if \a this mesh includes any quadratic cell.
4328 * \return bool - \c true if there is at least one quadratic cells in \a this mesh.
4329 * \throw If the coordinates array is not set.
4330 * \throw If the nodal connectivity of cells is not defined.
4332 bool MEDCouplingUMesh::isPresenceOfQuadratic() const
4334 checkFullyDefined();
4336 mcIdType nbOfCells=getNumberOfCells();
4337 for(mcIdType i=0;i<nbOfCells && !ret;i++)
4339 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4340 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4341 ret=cm.isQuadratic();
4347 * Converts all quadratic cells to linear ones. If there are no quadratic cells in \a
4348 * this mesh, it remains unchanged.
4349 * \throw If the coordinates array is not set.
4350 * \throw If the nodal connectivity of cells is not defined.
4352 void MEDCouplingUMesh::convertQuadraticCellsToLinear()
4354 checkFullyDefined();
4355 mcIdType nbOfCells=getNumberOfCells();
4357 const mcIdType *iciptr=_nodal_connec_index->begin();
4358 for(mcIdType i=0;i<nbOfCells;i++)
4360 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4361 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4362 if(cm.isQuadratic())
4364 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4365 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4366 if(!cml.isDynamic())
4367 delta+=cm.getNumberOfNodes()-cml.getNumberOfNodes();
4369 delta+=(iciptr[i+1]-iciptr[i]-1)/2;
4374 MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()),newConnI(DataArrayIdType::New());
4375 const mcIdType *icptr(_nodal_connec->begin());
4376 newConn->alloc(getNodalConnectivityArrayLen()-delta,1);
4377 newConnI->alloc(nbOfCells+1,1);
4378 mcIdType *ocptr(newConn->getPointer()),*ociptr(newConnI->getPointer());
4381 for(mcIdType i=0;i<nbOfCells;i++,ociptr++)
4383 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)icptr[iciptr[i]];
4384 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4385 if(!cm.isQuadratic())
4387 _types.insert(type);
4388 ocptr=std::copy(icptr+iciptr[i],icptr+iciptr[i+1],ocptr);
4389 ociptr[1]=ociptr[0]+iciptr[i+1]-iciptr[i];
4393 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4394 _types.insert(typel);
4395 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4396 mcIdType newNbOfNodes=cml.getNumberOfNodes();
4398 newNbOfNodes=(iciptr[i+1]-iciptr[i]-1)/2;
4399 *ocptr++=ToIdType(typel);
4400 ocptr=std::copy(icptr+iciptr[i]+1,icptr+iciptr[i]+newNbOfNodes+1,ocptr);
4401 ociptr[1]=ociptr[0]+newNbOfNodes+1;
4404 setConnectivity(newConn,newConnI,false);
4408 * This method converts all linear cell in \a this to quadratic one.
4409 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, here it is needed to specify the target
4410 * 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)
4411 * 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.
4412 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, the coordinates in \a this can be become bigger. All created nodes will be put at the
4413 * end of the existing coordinates.
4415 * \param [in] conversionType specifies the type of conversion expected. Only 0 (default) and 1 are supported presently. 0 those that creates the 'most' simple
4416 * corresponding quadratic cells. 1 is those creating the 'most' complex.
4417 * \return a newly created DataArrayIdType instance that the caller should deal with containing cell ids of converted cells.
4419 * \throw if \a this is not fully defined. It throws too if \a conversionType is not in [0,1].
4421 * \sa MEDCouplingUMesh::convertQuadraticCellsToLinear
4423 DataArrayIdType *MEDCouplingUMesh::convertLinearCellsToQuadratic(int conversionType)
4425 DataArrayIdType *conn=0,*connI=0;
4426 DataArrayDouble *coords=0;
4427 std::set<INTERP_KERNEL::NormalizedCellType> types;
4428 checkFullyDefined();
4429 MCAuto<DataArrayIdType> ret,connSafe,connISafe;
4430 MCAuto<DataArrayDouble> coordsSafe;
4431 int meshDim=getMeshDimension();
4432 switch(conversionType)
4438 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);
4439 connSafe=conn; connISafe=connI; coordsSafe=coords;
4442 ret=convertLinearCellsToQuadratic2D0(conn,connI,coords,types);
4443 connSafe=conn; connISafe=connI; coordsSafe=coords;
4446 ret=convertLinearCellsToQuadratic3D0(conn,connI,coords,types);
4447 connSafe=conn; connISafe=connI; coordsSafe=coords;
4450 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 0 mesh dimensions available are [1,2,3] !");
4458 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);//it is not a bug. In 1D policy 0 and 1 are equals
4459 connSafe=conn; connISafe=connI; coordsSafe=coords;
4462 ret=convertLinearCellsToQuadratic2D1(conn,connI,coords,types);
4463 connSafe=conn; connISafe=connI; coordsSafe=coords;
4466 ret=convertLinearCellsToQuadratic3D1(conn,connI,coords,types);
4467 connSafe=conn; connISafe=connI; coordsSafe=coords;
4470 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 1 mesh dimensions available are [1,2,3] !");
4475 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion type available are 0 (default, the simplest) and 1 (the most complex) !");
4477 setConnectivity(connSafe,connISafe,false);
4479 setCoords(coordsSafe);
4484 * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
4485 * so that the number of cells remains the same. Quadratic faces are converted to
4486 * polygons. This method works only for 2D meshes in
4487 * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
4488 * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
4489 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
4490 * \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
4491 * a polylinized edge constituting the input polygon.
4492 * \throw If the coordinates array is not set.
4493 * \throw If the nodal connectivity of cells is not defined.
4494 * \throw If \a this->getMeshDimension() != 2.
4495 * \throw If \a this->getSpaceDimension() != 2.
4497 void MEDCouplingUMesh::tessellate2D(double eps)
4499 int meshDim(getMeshDimension()),spaceDim(getSpaceDimension());
4501 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : works only with space dimension equal to 2 !");
4505 return tessellate2DCurveInternal(eps);
4507 return tessellate2DInternal(eps);
4509 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : mesh dimension must be in [1,2] !");
4515 * This method only works if \a this has spaceDimension equal to 2 and meshDimension also equal to 2.
4516 * This method allows to modify connectivity of cells in \a this that shares some edges in \a edgeIdsToBeSplit.
4517 * The nodes to be added in those 2D cells are defined by the pair of \a nodeIdsToAdd and \a nodeIdsIndexToAdd.
4518 * Length of \a nodeIdsIndexToAdd is expected to equal to length of \a edgeIdsToBeSplit + 1.
4519 * The node ids in \a nodeIdsToAdd should be valid. Those nodes have to be sorted exactly following exactly the direction of the edge.
4520 * This method can be seen as the opposite method of colinearize2D.
4521 * 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
4522 * to avoid to modify the numbering of existing nodes.
4524 * \param [in] nodeIdsToAdd - the list of node ids to be added (\a nodeIdsIndexToAdd array allows to walk on this array)
4525 * \param [in] nodeIdsIndexToAdd - the entry point of \a nodeIdsToAdd to point to the corresponding nodes to be added.
4526 * \param [in] mesh1Desc - 1st output of buildDescendingConnectivity2 on \a this.
4527 * \param [in] desc - 2nd output of buildDescendingConnectivity2 on \a this.
4528 * \param [in] descI - 3rd output of buildDescendingConnectivity2 on \a this.
4529 * \param [in] revDesc - 4th output of buildDescendingConnectivity2 on \a this.
4530 * \param [in] revDescI - 5th output of buildDescendingConnectivity2 on \a this.
4532 * \sa buildDescendingConnectivity2
4534 void MEDCouplingUMesh::splitSomeEdgesOf2DMesh(const DataArrayIdType *nodeIdsToAdd, const DataArrayIdType *nodeIdsIndexToAdd, const DataArrayIdType *edgeIdsToBeSplit,
4535 const MEDCouplingUMesh *mesh1Desc, const DataArrayIdType *desc, const DataArrayIdType *descI, const DataArrayIdType *revDesc, const DataArrayIdType *revDescI)
4537 if(!nodeIdsToAdd || !nodeIdsIndexToAdd || !edgeIdsToBeSplit || !mesh1Desc || !desc || !descI || !revDesc || !revDescI)
4538 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : input pointers must be not NULL !");
4539 nodeIdsToAdd->checkAllocated(); nodeIdsIndexToAdd->checkAllocated(); edgeIdsToBeSplit->checkAllocated(); desc->checkAllocated(); descI->checkAllocated(); revDesc->checkAllocated(); revDescI->checkAllocated();
4540 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
4541 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : this must have spacedim=meshdim=2 !");
4542 if(mesh1Desc->getSpaceDimension()!=2 || mesh1Desc->getMeshDimension()!=1)
4543 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : mesh1Desc must be the explosion of this with spaceDim=2 and meshDim = 1 !");
4544 //DataArrayIdType *out0(0),*outi0(0);
4545 //MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
4546 //MCAuto<DataArrayIdType> out0s(out0),outi0s(outi0);
4547 //out0s=out0s->buildUnique(); out0s->sort(true);
4553 * Divides every cell of \a this mesh into simplices (triangles in 2D and tetrahedra in 3D).
4554 * In addition, returns an array mapping new cells to old ones. <br>
4555 * This method typically increases the number of cells in \a this mesh
4556 * but the number of nodes remains \b unchanged.
4557 * That's why the 3D splitting policies
4558 * INTERP_KERNEL::GENERAL_24 and INTERP_KERNEL::GENERAL_48 are not available here.
4559 * \param [in] policy - specifies a pattern used for splitting.
4560 * The semantic of \a policy is:
4561 * - 0 - to split QUAD4 by cutting it along 0-2 diagonal (for 2D mesh only).
4562 * - 1 - to split QUAD4 by cutting it along 1-3 diagonal (for 2D mesh only).
4563 * - INTERP_KERNEL::PLANAR_FACE_5 - to split HEXA8 into 5 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4564 * - INTERP_KERNEL::PLANAR_FACE_6 - to split HEXA8 into 6 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4567 * \return DataArrayIdType * - a new instance of DataArrayIdType holding, for each new cell,
4568 * an id of old cell producing it. The caller is to delete this array using
4569 * decrRef() as it is no more needed.
4571 * \throw If \a policy is 0 or 1 and \a this->getMeshDimension() != 2.
4572 * \throw If \a policy is INTERP_KERNEL::PLANAR_FACE_5 or INTERP_KERNEL::PLANAR_FACE_6
4573 * and \a this->getMeshDimension() != 3.
4574 * \throw If \a policy is not one of the four discussed above.
4575 * \throw If the nodal connectivity of cells is not defined.
4576 * \sa MEDCouplingUMesh::tetrahedrize, MEDCoupling1SGTUMesh::sortHexa8EachOther
4578 DataArrayIdType *MEDCouplingUMesh::simplexize(int policy)
4583 return simplexizePol0();
4585 return simplexizePol1();
4586 case INTERP_KERNEL::PLANAR_FACE_5:
4587 return simplexizePlanarFace5();
4588 case INTERP_KERNEL::PLANAR_FACE_6:
4589 return simplexizePlanarFace6();
4591 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)");
4596 * Checks if \a this mesh is constituted by simplex cells only. Simplex cells are:
4597 * - 1D: INTERP_KERNEL::NORM_SEG2
4598 * - 2D: INTERP_KERNEL::NORM_TRI3
4599 * - 3D: INTERP_KERNEL::NORM_TETRA4.
4601 * This method is useful for users that need to use P1 field services as
4602 * MEDCouplingFieldDouble::getValueOn(), MEDCouplingField::buildMeasureField() etc.
4603 * All these methods need mesh support containing only simplex cells.
4604 * \return bool - \c true if there are only simplex cells in \a this mesh.
4605 * \throw If the coordinates array is not set.
4606 * \throw If the nodal connectivity of cells is not defined.
4607 * \throw If \a this->getMeshDimension() < 1.
4609 bool MEDCouplingUMesh::areOnlySimplexCells() const
4611 checkFullyDefined();
4612 int mdim=getMeshDimension();
4613 if(mdim<1 || mdim>3)
4614 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::areOnlySimplexCells : only available with meshes having a meshdim 1, 2 or 3 !");
4615 mcIdType nbCells=getNumberOfCells();
4616 const mcIdType *conn=_nodal_connec->begin();
4617 const mcIdType *connI=_nodal_connec_index->begin();
4618 for(mcIdType i=0;i<nbCells;i++)
4620 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4630 * Converts degenerated 2D or 3D linear cells of \a this mesh into cells of simpler
4631 * type. For example an INTERP_KERNEL::NORM_QUAD4 cell having only three unique nodes in
4632 * its connectivity is transformed into an INTERP_KERNEL::NORM_TRI3 cell.
4633 * Quadratic cells in 2D are also handled. In those cells edges where start=end=midpoint are removed.
4634 * This method does \b not perform geometrical checks and checks only nodal connectivity of cells,
4635 * so it can be useful to call mergeNodes() before calling this method.
4636 * \throw If \a this->getMeshDimension() <= 1.
4637 * \throw If the coordinates array is not set.
4638 * \throw If the nodal connectivity of cells is not defined.
4640 void MEDCouplingUMesh::convertDegeneratedCells()
4642 checkFullyDefined();
4643 if(getMeshDimension()<=1)
4644 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4645 mcIdType nbOfCells=getNumberOfCells();
4648 mcIdType initMeshLgth=getNodalConnectivityArrayLen();
4649 mcIdType *conn=_nodal_connec->getPointer();
4650 mcIdType *index=_nodal_connec_index->getPointer();
4651 mcIdType posOfCurCell=0;
4653 mcIdType lgthOfCurCell;
4654 for(mcIdType i=0;i<nbOfCells;i++)
4656 lgthOfCurCell=index[i+1]-posOfCurCell;
4657 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4659 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
4660 conn+newPos+1,newLgth);
4661 conn[newPos]=newType;
4663 posOfCurCell=index[i+1];
4666 if(newPos!=initMeshLgth)
4667 _nodal_connec->reAlloc(newPos);
4672 * Same as MEDCouplingUMesh::convertDegeneratedCells() plus deletion of the flat cells.
4673 * A cell is flat in the following cases:
4674 * - for a linear cell, all points in the connectivity are equal
4675 * - for a quadratic cell, either the above, or a quadratic polygon with two (linear) points and two
4676 * identical quadratic points
4677 * \return a new instance of DataArrayIdType holding ids of removed cells. The caller is to delete
4678 * this array using decrRef() as it is no more needed.
4680 DataArrayIdType *MEDCouplingUMesh::convertDegeneratedCellsAndRemoveFlatOnes()
4682 checkFullyDefined();
4683 if(getMeshDimension()<=1)
4684 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4685 mcIdType nbOfCells=getNumberOfCells();
4686 MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(0,1);
4689 mcIdType initMeshLgth=getNodalConnectivityArrayLen();
4690 mcIdType *conn=_nodal_connec->getPointer();
4691 mcIdType *index=_nodal_connec_index->getPointer();
4692 mcIdType posOfCurCell=0;
4694 mcIdType lgthOfCurCell, nbDelCells(0);
4695 for(mcIdType i=0;i<nbOfCells;i++)
4697 lgthOfCurCell=index[i+1]-posOfCurCell;
4698 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4700 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
4701 conn+newPos+1,newLgth);
4702 // Shall we delete the cell if it is completely degenerated:
4703 bool delCell=INTERP_KERNEL::CellSimplify::isFlatCell(conn, newPos, newLgth, newType);
4707 ret->pushBackSilent(i);
4709 else //if the cell is to be deleted, simply stay at the same place
4711 conn[newPos]=newType;
4714 posOfCurCell=index[i+1];
4715 index[i+1-nbDelCells]=newPos;
4717 if(newPos!=initMeshLgth)
4718 _nodal_connec->reAlloc(newPos);
4719 const mcIdType nCellDel=ret->getNumberOfTuples();
4721 _nodal_connec_index->reAlloc(nbOfCells-nCellDel+1);
4727 * This method remove null 1D cells from \a this. A 1D cell is considered null if start node is equal to end node.
4728 * Only connectivity is considered here.
4730 bool MEDCouplingUMesh::removeDegenerated1DCells()
4732 checkConnectivityFullyDefined();
4733 if(getMeshDimension()!=1)
4734 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::removeDegenerated1DCells works on umeshes with meshdim equals to 1 !");
4735 std::size_t nbCells(getNumberOfCells()),newSize(0),newSize2(0);
4736 const mcIdType *conn(getNodalConnectivity()->begin()),*conni(getNodalConnectivityIndex()->begin());
4738 for(std::size_t i=0;i<nbCells;i++)
4740 INTERP_KERNEL::NormalizedCellType ct((INTERP_KERNEL::NormalizedCellType)conn[conni[i]]);
4741 if(ct==INTERP_KERNEL::NORM_SEG2 || ct==INTERP_KERNEL::NORM_SEG3)
4743 if(conn[conni[i]+1]!=conn[conni[i]+2])
4746 newSize2+=conni[i+1]-conni[i];
4751 std::ostringstream oss; oss << "MEDCouplingUMesh::removeDegenerated1DCells : cell #" << i << " in this is not of type SEG2/SEG3 !";
4752 throw INTERP_KERNEL::Exception(oss.str());
4756 if(newSize==nbCells)//no cells has been removed -> do nothing
4758 MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()),newConnI(DataArrayIdType::New()); newConnI->alloc(newSize+1,1); newConn->alloc(newSize2,1);
4759 mcIdType *newConnPtr(newConn->getPointer()),*newConnIPtr(newConnI->getPointer()); newConnIPtr[0]=0;
4760 for(std::size_t i=0;i<nbCells;i++)
4762 if(conn[conni[i]+1]!=conn[conni[i]+2])
4764 newConnIPtr[1]=newConnIPtr[0]+conni[i+1]-conni[i];
4765 newConnPtr=std::copy(conn+conni[i],conn+conni[i+1],newConnPtr);
4769 setConnectivity(newConn,newConnI,true);
4774 * Finds incorrectly oriented cells of this 2D mesh in 3D space.
4775 * A cell is considered to be oriented correctly if an angle between its
4776 * normal vector and a given vector is less than \c PI / \c 2.
4777 * \param [in] vec - 3 components of the vector specifying the correct orientation of
4779 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
4781 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
4782 * is not cleared before filling in.
4783 * \throw If \a this->getMeshDimension() != 2.
4784 * \throw If \a this->getSpaceDimension() != 3.
4786 * \if ENABLE_EXAMPLES
4787 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
4788 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
4791 void MEDCouplingUMesh::are2DCellsNotCorrectlyOriented(const double *vec, bool polyOnly, std::vector<mcIdType>& cells) const
4793 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
4794 throw INTERP_KERNEL::Exception("Invalid mesh to apply are2DCellsNotCorrectlyOriented on it : must be meshDim==2 and spaceDim==3 !");
4795 mcIdType nbOfCells=getNumberOfCells();
4796 const mcIdType *conn=_nodal_connec->begin();
4797 const mcIdType *connI=_nodal_connec_index->begin();
4798 const double *coordsPtr=_coords->begin();
4799 for(mcIdType i=0;i<nbOfCells;i++)
4801 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4802 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
4804 bool isQuadratic=INTERP_KERNEL::CellModel::GetCellModel(type).isQuadratic();
4805 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4812 * Reverse connectivity of 2D cells whose orientation is not correct. A cell is
4813 * considered to be oriented correctly if an angle between its normal vector and a
4814 * given vector is less than \c PI / \c 2.
4815 * \param [in] vec - 3 components of the vector specifying the correct orientation of
4817 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
4819 * \throw If \a this->getMeshDimension() != 2.
4820 * \throw If \a this->getSpaceDimension() != 3.
4822 * \if ENABLE_EXAMPLES
4823 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
4824 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
4827 * \sa changeOrientationOfCells
4829 void MEDCouplingUMesh::orientCorrectly2DCells(const double *vec, bool polyOnly)
4831 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
4832 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectly2DCells on it : must be meshDim==2 and spaceDim==3 !");
4833 mcIdType nbOfCells=getNumberOfCells();
4834 mcIdType *conn(_nodal_connec->getPointer());
4835 const mcIdType *connI(_nodal_connec_index->begin());
4836 const double *coordsPtr(_coords->begin());
4837 bool isModified(false);
4838 for(mcIdType i=0;i<nbOfCells;i++)
4840 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4841 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
4843 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
4844 bool isQuadratic(cm.isQuadratic());
4845 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4848 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
4853 _nodal_connec->declareAsNew();
4858 * This method change the orientation of cells in \a this without any consideration of coordinates. Only connectivity is impacted.
4860 * \sa orientCorrectly2DCells
4862 void MEDCouplingUMesh::changeOrientationOfCells()
4864 int mdim(getMeshDimension());
4865 if(mdim!=2 && mdim!=1)
4866 throw INTERP_KERNEL::Exception("Invalid mesh to apply changeOrientationOfCells on it : must be meshDim==2 or meshDim==1 !");
4867 mcIdType nbOfCells=getNumberOfCells();
4868 mcIdType *conn(_nodal_connec->getPointer());
4869 const mcIdType *connI(_nodal_connec_index->begin());
4872 for(mcIdType i=0;i<nbOfCells;i++)
4874 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4875 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
4876 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
4881 for(mcIdType i=0;i<nbOfCells;i++)
4883 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4884 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
4885 cm.changeOrientationOf1D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
4891 * Finds incorrectly oriented polyhedral cells, i.e. polyhedrons having correctly
4892 * oriented facets. The normal vector of the facet should point out of the cell.
4893 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
4894 * is not cleared before filling in.
4895 * \throw If \a this->getMeshDimension() != 3.
4896 * \throw If \a this->getSpaceDimension() != 3.
4897 * \throw If the coordinates array is not set.
4898 * \throw If the nodal connectivity of cells is not defined.
4900 * \if ENABLE_EXAMPLES
4901 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
4902 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
4905 void MEDCouplingUMesh::arePolyhedronsNotCorrectlyOriented(std::vector<mcIdType>& cells) const
4907 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
4908 throw INTERP_KERNEL::Exception("Invalid mesh to apply arePolyhedronsNotCorrectlyOriented on it : must be meshDim==3 and spaceDim==3 !");
4909 mcIdType nbOfCells=getNumberOfCells();
4910 const mcIdType *conn=_nodal_connec->begin();
4911 const mcIdType *connI=_nodal_connec_index->begin();
4912 const double *coordsPtr=_coords->begin();
4913 for(mcIdType i=0;i<nbOfCells;i++)
4915 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4916 if(type==INTERP_KERNEL::NORM_POLYHED)
4918 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4925 * Tries to fix connectivity of polyhedra, so that normal vector of all facets to point
4927 * \throw If \a this->getMeshDimension() != 3.
4928 * \throw If \a this->getSpaceDimension() != 3.
4929 * \throw If the coordinates array is not set.
4930 * \throw If the nodal connectivity of cells is not defined.
4931 * \throw If the reparation fails.
4933 * \if ENABLE_EXAMPLES
4934 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
4935 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
4937 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
4939 void MEDCouplingUMesh::orientCorrectlyPolyhedrons()
4941 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
4942 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectlyPolyhedrons on it : must be meshDim==3 and spaceDim==3 !");
4943 mcIdType nbOfCells=getNumberOfCells();
4944 mcIdType *conn=_nodal_connec->getPointer();
4945 const mcIdType *connI=_nodal_connec_index->begin();
4946 const double *coordsPtr=_coords->begin();
4947 for(mcIdType i=0;i<nbOfCells;i++)
4949 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4950 if(type==INTERP_KERNEL::NORM_POLYHED)
4954 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4955 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
4957 catch(INTERP_KERNEL::Exception& e)
4959 std::ostringstream oss; oss << "Something wrong in polyhedron #" << i << " : " << e.what();
4960 throw INTERP_KERNEL::Exception(oss.str());
4968 * This method invert orientation of all cells in \a this.
4969 * After calling this method the absolute value of measure of cells in \a this are the same than before calling.
4970 * This method only operates on the connectivity so coordinates are not touched at all.
4972 void MEDCouplingUMesh::invertOrientationOfAllCells()
4974 checkConnectivityFullyDefined();
4975 std::set<INTERP_KERNEL::NormalizedCellType> gts(getAllGeoTypes());
4976 mcIdType *conn(_nodal_connec->getPointer());
4977 const mcIdType *conni(_nodal_connec_index->begin());
4978 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator gt=gts.begin();gt!=gts.end();gt++)
4980 INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::OrientationInverter> oi(INTERP_KERNEL::OrientationInverter::BuildInstanceFrom(*gt));
4981 MCAuto<DataArrayIdType> cwt(giveCellsWithType(*gt));
4982 for(const mcIdType *it=cwt->begin();it!=cwt->end();it++)
4983 oi->operate(conn+conni[*it]+1,conn+conni[*it+1]);
4989 * Finds and fixes incorrectly oriented linear extruded volumes (INTERP_KERNEL::NORM_HEXA8,
4990 * INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXGP12 etc) to respect the MED convention
4991 * according to which the first facet of the cell should be oriented to have the normal vector
4992 * pointing out of cell.
4993 * \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of fixed
4994 * cells. The caller is to delete this array using decrRef() as it is no more
4996 * \throw If \a this->getMeshDimension() != 3.
4997 * \throw If \a this->getSpaceDimension() != 3.
4998 * \throw If the coordinates array is not set.
4999 * \throw If the nodal connectivity of cells is not defined.
5001 * \if ENABLE_EXAMPLES
5002 * \ref cpp_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a C++ example".<br>
5003 * \ref py_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a Python example".
5005 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
5007 DataArrayIdType *MEDCouplingUMesh::findAndCorrectBadOriented3DExtrudedCells()
5009 const char msg[]="check3DCellsWellOriented detection works only for 3D cells !";
5010 if(getMeshDimension()!=3)
5011 throw INTERP_KERNEL::Exception(msg);
5012 int spaceDim=getSpaceDimension();
5014 throw INTERP_KERNEL::Exception(msg);
5016 mcIdType nbOfCells=getNumberOfCells();
5017 mcIdType *conn=_nodal_connec->getPointer();
5018 const mcIdType *connI=_nodal_connec_index->begin();
5019 const double *coo=getCoords()->begin();
5020 MCAuto<DataArrayIdType> cells(DataArrayIdType::New()); cells->alloc(0,1);
5021 for(mcIdType i=0;i<nbOfCells;i++)
5023 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5024 if(cm.isExtruded() && !cm.isDynamic() && !cm.isQuadratic())
5026 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coo))
5028 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
5029 cells->pushBackSilent(i);
5033 return cells.retn();
5037 * This method is a faster method to correct orientation of all 3D cells in \a this.
5038 * 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.
5039 * This method makes the hypothesis that \a this a coherent that is to say MEDCouplingUMesh::checkConsistency should throw no exception.
5041 * \return a newly allocated mcIdType array with one components containing cell ids renumbered to fit the convention of MED (MED file and MEDCoupling)
5042 * \sa MEDCouplingUMesh::orientCorrectlyPolyhedrons,
5044 DataArrayIdType *MEDCouplingUMesh::findAndCorrectBadOriented3DCells()
5046 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
5047 throw INTERP_KERNEL::Exception("Invalid mesh to apply findAndCorrectBadOriented3DCells on it : must be meshDim==3 and spaceDim==3 !");
5048 mcIdType nbOfCells=getNumberOfCells();
5049 mcIdType *conn=_nodal_connec->getPointer();
5050 const mcIdType *connI=_nodal_connec_index->begin();
5051 const double *coordsPtr=_coords->begin();
5052 MCAuto<DataArrayIdType> ret=DataArrayIdType::New(); ret->alloc(0,1);
5053 for(mcIdType i=0;i<nbOfCells;i++)
5055 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5058 case INTERP_KERNEL::NORM_TETRA4:
5060 if(!IsTetra4WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5062 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+3));
5063 ret->pushBackSilent(i);
5067 case INTERP_KERNEL::NORM_PYRA5:
5069 if(!IsPyra5WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5071 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+4));
5072 ret->pushBackSilent(i);
5076 case INTERP_KERNEL::NORM_PENTA6:
5077 case INTERP_KERNEL::NORM_HEXA8:
5078 case INTERP_KERNEL::NORM_HEXGP12:
5080 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5082 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
5083 ret->pushBackSilent(i);
5087 case INTERP_KERNEL::NORM_POLYHED:
5089 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5091 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
5092 ret->pushBackSilent(i);
5097 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 !");
5105 * This method has a sense for meshes with spaceDim==3 and meshDim==2.
5106 * If it is not the case an exception will be thrown.
5107 * This method is fast because the first cell of \a this is used to compute the plane.
5108 * \param vec output of size at least 3 used to store the normal vector (with norm equal to Area ) of searched plane.
5109 * \param pos output of size at least 3 used to store a point owned of searched plane.
5111 void MEDCouplingUMesh::getFastAveragePlaneOfThis(double *vec, double *pos) const
5113 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
5114 throw INTERP_KERNEL::Exception("Invalid mesh to apply getFastAveragePlaneOfThis on it : must be meshDim==2 and spaceDim==3 !");
5115 const mcIdType *conn=_nodal_connec->begin();
5116 const mcIdType *connI=_nodal_connec_index->begin();
5117 const double *coordsPtr=_coords->begin();
5118 INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(conn+1,connI[1]-connI[0]-1,coordsPtr,vec);
5119 std::copy(coordsPtr+3*conn[1],coordsPtr+3*conn[1]+3,pos);
5123 * Creates a new MEDCouplingFieldDouble holding Edge Ratio values of all
5124 * cells. Currently cells of the following types are treated:
5125 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5126 * For a cell of other type an exception is thrown.
5127 * Space dimension of a 2D mesh can be either 2 or 3.
5128 * The Edge Ratio of a cell \f$t\f$ is:
5129 * \f$\frac{|t|_\infty}{|t|_0}\f$,
5130 * where \f$|t|_\infty\f$ and \f$|t|_0\f$ respectively denote the greatest and
5131 * the smallest edge lengths of \f$t\f$.
5132 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5133 * cells and one time, lying on \a this mesh. The caller is to delete this
5134 * field using decrRef() as it is no more needed.
5135 * \throw If the coordinates array is not set.
5136 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5137 * \throw If the connectivity data array has more than one component.
5138 * \throw If the connectivity data array has a named component.
5139 * \throw If the connectivity index data array has more than one component.
5140 * \throw If the connectivity index data array has a named component.
5141 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
5142 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5143 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5145 MEDCouplingFieldDouble *MEDCouplingUMesh::getEdgeRatioField() const
5147 checkConsistencyLight();
5148 int spaceDim=getSpaceDimension();
5149 int meshDim=getMeshDimension();
5150 if(spaceDim!=2 && spaceDim!=3)
5151 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : SpaceDimension must be equal to 2 or 3 !");
5152 if(meshDim!=2 && meshDim!=3)
5153 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : MeshDimension must be equal to 2 or 3 !");
5154 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5156 mcIdType nbOfCells=getNumberOfCells();
5157 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5158 arr->alloc(nbOfCells,1);
5159 double *pt=arr->getPointer();
5160 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5161 const mcIdType *conn=_nodal_connec->begin();
5162 const mcIdType *connI=_nodal_connec_index->begin();
5163 const double *coo=_coords->begin();
5165 for(mcIdType i=0;i<nbOfCells;i++,pt++)
5167 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5170 case INTERP_KERNEL::NORM_TRI3:
5172 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5173 *pt=INTERP_KERNEL::triEdgeRatio(tmp);
5176 case INTERP_KERNEL::NORM_QUAD4:
5178 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5179 *pt=INTERP_KERNEL::quadEdgeRatio(tmp);
5182 case INTERP_KERNEL::NORM_TETRA4:
5184 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5185 *pt=INTERP_KERNEL::tetraEdgeRatio(tmp);
5189 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5191 conn+=connI[i+1]-connI[i];
5193 ret->setName("EdgeRatio");
5194 ret->synchronizeTimeWithSupport();
5199 * Creates a new MEDCouplingFieldDouble holding Aspect Ratio values of all
5200 * cells. Currently cells of the following types are treated:
5201 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5202 * For a cell of other type an exception is thrown.
5203 * Space dimension of a 2D mesh can be either 2 or 3.
5204 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5205 * cells and one time, lying on \a this mesh. The caller is to delete this
5206 * field using decrRef() as it is no more needed.
5207 * \throw If the coordinates array is not set.
5208 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5209 * \throw If the connectivity data array has more than one component.
5210 * \throw If the connectivity data array has a named component.
5211 * \throw If the connectivity index data array has more than one component.
5212 * \throw If the connectivity index data array has a named component.
5213 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
5214 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5215 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5217 MEDCouplingFieldDouble *MEDCouplingUMesh::getAspectRatioField() const
5219 checkConsistencyLight();
5220 int spaceDim=getSpaceDimension();
5221 int meshDim=getMeshDimension();
5222 if(spaceDim!=2 && spaceDim!=3)
5223 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : SpaceDimension must be equal to 2 or 3 !");
5224 if(meshDim!=2 && meshDim!=3)
5225 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : MeshDimension must be equal to 2 or 3 !");
5226 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5228 mcIdType nbOfCells=getNumberOfCells();
5229 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5230 arr->alloc(nbOfCells,1);
5231 double *pt=arr->getPointer();
5232 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5233 const mcIdType *conn=_nodal_connec->begin();
5234 const mcIdType *connI=_nodal_connec_index->begin();
5235 const double *coo=_coords->begin();
5237 for(mcIdType i=0;i<nbOfCells;i++,pt++)
5239 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5242 case INTERP_KERNEL::NORM_TRI3:
5244 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5245 *pt=INTERP_KERNEL::triAspectRatio(tmp);
5248 case INTERP_KERNEL::NORM_QUAD4:
5250 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5251 *pt=INTERP_KERNEL::quadAspectRatio(tmp);
5254 case INTERP_KERNEL::NORM_TETRA4:
5256 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5257 *pt=INTERP_KERNEL::tetraAspectRatio(tmp);
5261 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5263 conn+=connI[i+1]-connI[i];
5265 ret->setName("AspectRatio");
5266 ret->synchronizeTimeWithSupport();
5271 * Creates a new MEDCouplingFieldDouble holding Warping factor values of all
5272 * cells of \a this 2D mesh in 3D space. It is a measure of the "planarity" of 2D cell
5273 * in 3D space. Currently only cells of the following types are
5274 * treated: INTERP_KERNEL::NORM_QUAD4.
5275 * For a cell of other type an exception is thrown.
5276 * The warp field is computed as follows: let (a,b,c,d) be the points of the quad.
5278 * \f$t=\vec{da}\times\vec{ab}\f$,
5279 * \f$u=\vec{ab}\times\vec{bc}\f$
5280 * \f$v=\vec{bc}\times\vec{cd}\f$
5281 * \f$w=\vec{cd}\times\vec{da}\f$, the warp is defined as \f$W^3\f$ with
5283 * W=min(\frac{t}{|t|}\cdot\frac{v}{|v|}, \frac{u}{|u|}\cdot\frac{w}{|w|})
5285 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5286 * cells and one time, lying on \a this mesh. The caller is to delete this
5287 * field using decrRef() as it is no more needed.
5288 * \throw If the coordinates array is not set.
5289 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5290 * \throw If the connectivity data array has more than one component.
5291 * \throw If the connectivity data array has a named component.
5292 * \throw If the connectivity index data array has more than one component.
5293 * \throw If the connectivity index data array has a named component.
5294 * \throw If \a this->getMeshDimension() != 2.
5295 * \throw If \a this->getSpaceDimension() != 3.
5296 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5298 MEDCouplingFieldDouble *MEDCouplingUMesh::getWarpField() const
5300 checkConsistencyLight();
5301 int spaceDim=getSpaceDimension();
5302 int meshDim=getMeshDimension();
5304 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : SpaceDimension must be equal to 3 !");
5306 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : MeshDimension must be equal to 2 !");
5307 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5309 mcIdType nbOfCells=getNumberOfCells();
5310 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5311 arr->alloc(nbOfCells,1);
5312 double *pt=arr->getPointer();
5313 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5314 const mcIdType *conn=_nodal_connec->begin();
5315 const mcIdType *connI=_nodal_connec_index->begin();
5316 const double *coo=_coords->begin();
5318 for(mcIdType i=0;i<nbOfCells;i++,pt++)
5320 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5323 case INTERP_KERNEL::NORM_QUAD4:
5325 FillInCompact3DMode(3,4,conn+1,coo,tmp);
5326 *pt=INTERP_KERNEL::quadWarp(tmp);
5330 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : A cell with not manged type (NORM_QUAD4) has been detected !");
5332 conn+=connI[i+1]-connI[i];
5334 ret->setName("Warp");
5335 ret->synchronizeTimeWithSupport();
5341 * Creates a new MEDCouplingFieldDouble holding Skew factor values of all
5342 * cells of \a this 2D mesh in 3D space. Currently cells of the following types are
5343 * treated: INTERP_KERNEL::NORM_QUAD4.
5344 * The skew is computed as follow for a quad with points (a,b,c,d): let
5345 * \f$u=\vec{ab}+\vec{dc}\f$ and \f$v=\vec{ac}+\vec{bd}\f$
5346 * then the skew is computed as:
5348 * s=\frac{u}{|u|}\cdot\frac{v}{|v|}
5351 * For a cell of other type an exception is thrown.
5352 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5353 * cells and one time, lying on \a this mesh. The caller is to delete this
5354 * field using decrRef() as it is no more needed.
5355 * \throw If the coordinates array is not set.
5356 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5357 * \throw If the connectivity data array has more than one component.
5358 * \throw If the connectivity data array has a named component.
5359 * \throw If the connectivity index data array has more than one component.
5360 * \throw If the connectivity index data array has a named component.
5361 * \throw If \a this->getMeshDimension() != 2.
5362 * \throw If \a this->getSpaceDimension() != 3.
5363 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5365 MEDCouplingFieldDouble *MEDCouplingUMesh::getSkewField() const
5367 checkConsistencyLight();
5368 int spaceDim=getSpaceDimension();
5369 int meshDim=getMeshDimension();
5371 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : SpaceDimension must be equal to 3 !");
5373 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : MeshDimension must be equal to 2 !");
5374 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5376 mcIdType nbOfCells=getNumberOfCells();
5377 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5378 arr->alloc(nbOfCells,1);
5379 double *pt=arr->getPointer();
5380 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5381 const mcIdType *conn=_nodal_connec->begin();
5382 const mcIdType *connI=_nodal_connec_index->begin();
5383 const double *coo=_coords->begin();
5385 for(mcIdType i=0;i<nbOfCells;i++,pt++)
5387 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5390 case INTERP_KERNEL::NORM_QUAD4:
5392 FillInCompact3DMode(3,4,conn+1,coo,tmp);
5393 *pt=INTERP_KERNEL::quadSkew(tmp);
5397 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : A cell with not manged type (NORM_QUAD4) has been detected !");
5399 conn+=connI[i+1]-connI[i];
5401 ret->setName("Skew");
5402 ret->synchronizeTimeWithSupport();
5407 * 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.
5409 * \return a new instance of field containing the result. The returned instance has to be deallocated by the caller.
5411 * \sa getSkewField, getWarpField, getAspectRatioField, getEdgeRatioField
5413 MEDCouplingFieldDouble *MEDCouplingUMesh::computeDiameterField() const
5415 checkConsistencyLight();
5416 MCAuto<MEDCouplingFieldDouble> ret(MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME));
5418 std::set<INTERP_KERNEL::NormalizedCellType> types;
5419 ComputeAllTypesInternal(types,_nodal_connec,_nodal_connec_index);
5420 int spaceDim(getSpaceDimension());
5421 mcIdType nbCells(getNumberOfCells());
5422 MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
5423 arr->alloc(nbCells,1);
5424 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++)
5426 INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::DiameterCalculator> dc(INTERP_KERNEL::CellModel::GetCellModel(*it).buildInstanceOfDiameterCalulator(spaceDim));
5427 MCAuto<DataArrayIdType> cellIds(giveCellsWithType(*it));
5428 dc->computeForListOfCellIdsUMeshFrmt(cellIds->begin(),cellIds->end(),_nodal_connec_index->begin(),_nodal_connec->begin(),getCoords()->begin(),arr->getPointer());
5431 ret->setName("Diameter");
5436 * This method aggregate the bbox of each cell and put it into bbox parameter (xmin,xmax,ymin,ymax,zmin,zmax).
5438 * \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)
5439 * For all other cases this input parameter is ignored.
5440 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5442 * \throw If \a this is not fully set (coordinates and connectivity).
5443 * \throw If a cell in \a this has no valid nodeId.
5444 * \sa MEDCouplingUMesh::getBoundingBoxForBBTreeFast, MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5446 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree(double arcDetEps) const
5448 int mDim(getMeshDimension()),sDim(getSpaceDimension());
5449 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.
5450 return getBoundingBoxForBBTreeFast();
5451 if((mDim==2 && sDim==2) || (mDim==1 && sDim==2))
5453 bool presenceOfQuadratic(false);
5454 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=_types.begin();it!=_types.end();it++)
5456 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(*it));
5457 if(cm.isQuadratic())
5458 presenceOfQuadratic=true;
5460 if(!presenceOfQuadratic)
5461 return getBoundingBoxForBBTreeFast();
5462 if(mDim==2 && sDim==2)
5463 return getBoundingBoxForBBTree2DQuadratic(arcDetEps);
5465 return getBoundingBoxForBBTree1DQuadratic(arcDetEps);
5467 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) !");
5471 * This method aggregate the bbox of each cell only considering the nodes constituting each cell and put it into bbox parameter.
5472 * So meshes having quadratic cells the computed bounding boxes can be invalid !
5474 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5476 * \throw If \a this is not fully set (coordinates and connectivity).
5477 * \throw If a cell in \a this has no valid nodeId.
5479 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTreeFast() const
5481 checkFullyDefined();
5482 int spaceDim(getSpaceDimension());
5483 mcIdType nbOfCells(getNumberOfCells()), nbOfNodes(getNumberOfNodes());
5484 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5485 double *bbox(ret->getPointer());
5486 for(mcIdType i=0;i<nbOfCells*spaceDim;i++)
5488 bbox[2*i]=std::numeric_limits<double>::max();
5489 bbox[2*i+1]=-std::numeric_limits<double>::max();
5491 const double *coordsPtr(_coords->begin());
5492 const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5493 for(mcIdType i=0;i<nbOfCells;i++)
5495 mcIdType offset=connI[i]+1;
5496 mcIdType nbOfNodesForCell(connI[i+1]-offset),kk(0);
5497 for(mcIdType j=0;j<nbOfNodesForCell;j++)
5499 mcIdType nodeId=conn[offset+j];
5500 if(nodeId>=0 && nodeId<nbOfNodes)
5502 for(int k=0;k<spaceDim;k++)
5504 bbox[2*spaceDim*i+2*k]=std::min(bbox[2*spaceDim*i+2*k],coordsPtr[spaceDim*nodeId+k]);
5505 bbox[2*spaceDim*i+2*k+1]=std::max(bbox[2*spaceDim*i+2*k+1],coordsPtr[spaceDim*nodeId+k]);
5512 std::ostringstream oss; oss << "MEDCouplingUMesh::getBoundingBoxForBBTree : cell #" << i << " contains no valid nodeId !";
5513 throw INTERP_KERNEL::Exception(oss.str());
5520 * This method aggregates the bbox of each 2D cell in \a this considering the whole shape. This method is particularly
5521 * useful for 2D meshes having quadratic cells
5522 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5523 * the two extremities of the arc of circle).
5525 * \param [in] arcDetEps - a parameter specifying in case of 2D quadratic polygon cell the detection limit between linear and arc circle. (By default 1e-12)
5526 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5527 * \throw If \a this is not fully defined.
5528 * \throw If \a this is not a mesh with meshDimension equal to 2.
5529 * \throw If \a this is not a mesh with spaceDimension equal to 2.
5530 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic
5532 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic(double arcDetEps) const
5534 checkFullyDefined();
5535 INTERP_KERNEL::QuadraticPlanarPrecision arcPrec(arcDetEps);
5537 int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
5538 mcIdType nbOfCells=getNumberOfCells();
5539 if(spaceDim!=2 || mDim!=2)
5540 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!");
5541 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5542 double *bbox(ret->getPointer());
5543 const double *coords(_coords->begin());
5544 const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5545 for(mcIdType i=0;i<nbOfCells;i++,bbox+=4,connI++)
5547 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5548 mcIdType sz(connI[1]-connI[0]-1);
5549 std::vector<INTERP_KERNEL::Node *> nodes(sz);
5550 INTERP_KERNEL::QuadraticPolygon *pol(0);
5551 for(mcIdType j=0;j<sz;j++)
5553 mcIdType nodeId(conn[*connI+1+j]);
5554 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5556 if(!cm.isQuadratic())
5557 pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
5559 pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
5560 INTERP_KERNEL::Bounds b; b.prepareForAggregation(); pol->fillBounds(b); delete pol;
5561 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax();
5567 * This method aggregates the bbox of each 1D cell in \a this considering the whole shape. This method is particularly
5568 * useful for 2D meshes having quadratic cells
5569 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5570 * the two extremities of the arc of circle).
5572 * \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)
5573 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5574 * \throw If \a this is not fully defined.
5575 * \throw If \a this is not a mesh with meshDimension equal to 1.
5576 * \throw If \a this is not a mesh with spaceDimension equal to 2.
5577 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5579 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic(double arcDetEps) const
5581 checkFullyDefined();
5582 int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
5583 mcIdType nbOfCells=getNumberOfCells();
5584 if(spaceDim!=2 || mDim!=1)
5585 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!");
5586 INTERP_KERNEL::QuadraticPlanarPrecision arcPrec(arcDetEps);
5587 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5588 double *bbox(ret->getPointer());
5589 const double *coords(_coords->begin());
5590 const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5591 for(mcIdType i=0;i<nbOfCells;i++,bbox+=4,connI++)
5593 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5594 mcIdType sz(connI[1]-connI[0]-1);
5595 std::vector<INTERP_KERNEL::Node *> nodes(sz);
5596 INTERP_KERNEL::Edge *edge(0);
5597 for(mcIdType j=0;j<sz;j++)
5599 mcIdType nodeId(conn[*connI+1+j]);
5600 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5602 if(!cm.isQuadratic())
5603 edge=INTERP_KERNEL::QuadraticPolygon::BuildLinearEdge(nodes);
5605 edge=INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(nodes);
5606 const INTERP_KERNEL::Bounds& b(edge->getBounds());
5607 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax(); edge->decrRef();
5614 namespace MEDCouplingImpl
5619 ConnReader(const mcIdType *c, mcIdType val):_conn(c),_val(val) { }
5620 bool operator() (const mcIdType& pos) { return _conn[pos]!=_val; }
5622 const mcIdType *_conn;
5629 ConnReader2(const mcIdType *c, mcIdType val):_conn(c),_val(val) { }
5630 bool operator() (const mcIdType& pos) { return _conn[pos]==_val; }
5632 const mcIdType *_conn;
5640 * This method expects that \a this is sorted by types. If not an exception will be thrown.
5641 * This method returns in the same format as code (see MEDCouplingUMesh::checkTypeConsistencyAndContig or MEDCouplingUMesh::splitProfilePerType) how
5642 * \a this is composed in cell types.
5643 * The returned array is of size 3*n where n is the number of different types present in \a this.
5644 * For every k in [0,n] ret[3*k+2]==-1 because it has no sense here.
5645 * This parameter is kept only for compatibility with other method listed above.
5647 std::vector<mcIdType> MEDCouplingUMesh::getDistributionOfTypes() const
5649 checkConnectivityFullyDefined();
5650 const mcIdType *conn=_nodal_connec->begin();
5651 const mcIdType *connI=_nodal_connec_index->begin();
5652 const mcIdType *work=connI;
5653 mcIdType nbOfCells=getNumberOfCells();
5654 std::size_t n=getAllGeoTypes().size();
5655 std::vector<mcIdType> ret(3*n,-1); //ret[3*k+2]==-1 because it has no sense here
5656 std::set<INTERP_KERNEL::NormalizedCellType> types;
5657 for(std::size_t i=0;work!=connI+nbOfCells;i++)
5659 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn[*work];
5660 if(types.find(typ)!=types.end())
5662 std::ostringstream oss; oss << "MEDCouplingUMesh::getDistributionOfTypes : Type " << INTERP_KERNEL::CellModel::GetCellModel(typ).getRepr();
5663 oss << " is not contiguous !";
5664 throw INTERP_KERNEL::Exception(oss.str());
5668 const mcIdType *work2=std::find_if(work+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,typ));
5669 ret[3*i+1]=ToIdType(std::distance(work,work2));
5676 * This method is used to check that this has contiguous cell type in same order than described in \a code.
5677 * only for types cell, type node is not managed.
5678 * Format of \a code is the following. \a code should be of size 3*n and non empty. If not an exception is thrown.
5679 * foreach k in [0,n) on 3*k pos represent the geometric type and 3*k+1 number of elements of type 3*k.
5680 * 3*k+2 refers if different from -1 the pos in 'idsPerType' to get the corresponding array.
5681 * If 2 or more same geometric type is in \a code and exception is thrown too.
5683 * This method firstly checks
5684 * If it exists k so that 3*k geometric type is not in geometric types of this an exception will be thrown.
5685 * If it exists k so that 3*k geometric type exists but the number of consecutive cell types does not match,
5686 * an exception is thrown too.
5688 * If all geometric types in \a code are exactly those in \a this null pointer is returned.
5689 * If it exists a geometric type in \a this \b not in \a code \b no exception is thrown
5690 * and a DataArrayIdType instance is returned that the user has the responsibility to deallocate.
5692 DataArrayIdType *MEDCouplingUMesh::checkTypeConsistencyAndContig(const std::vector<mcIdType>& code, const std::vector<const DataArrayIdType *>& idsPerType) const
5695 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code is empty, should not !");
5696 std::size_t sz=code.size();
5699 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code size is NOT %3 !");
5700 std::vector<INTERP_KERNEL::NormalizedCellType> types;
5702 bool isNoPflUsed=true;
5703 for(std::size_t i=0;i<n;i++)
5704 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)code[3*i])==types.end())
5706 types.push_back((INTERP_KERNEL::NormalizedCellType)code[3*i]);
5708 if(_types.find((INTERP_KERNEL::NormalizedCellType)code[3*i])==_types.end())
5709 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : expected geo types not in this !");
5710 isNoPflUsed=isNoPflUsed && (code[3*i+2]==-1);
5713 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code contains duplication of types in unstructured mesh !");
5716 if(!checkConsecutiveCellTypesAndOrder(&types[0],&types[0]+types.size()))
5717 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : non contiguous type !");
5718 if(types.size()==_types.size())
5721 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
5723 mcIdType *retPtr=ret->getPointer();
5724 const mcIdType *connI=_nodal_connec_index->begin();
5725 const mcIdType *conn=_nodal_connec->begin();
5726 mcIdType nbOfCells=getNumberOfCells();
5727 const mcIdType *i=connI;
5729 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++,kk++)
5731 i=std::find_if(i,connI+nbOfCells,MEDCouplingImpl::ConnReader2(conn,ToIdType((*it))));
5732 mcIdType offset=ToIdType(std::distance(connI,i));
5733 const mcIdType *j=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType((*it))));
5734 mcIdType nbOfCellsOfCurType=ToIdType(std::distance(i,j));
5735 if(code[3*kk+2]==-1)
5736 for(mcIdType k=0;k<nbOfCellsOfCurType;k++)
5740 mcIdType idInIdsPerType=code[3*kk+2];
5741 if(idInIdsPerType>=0 && idInIdsPerType<ToIdType(idsPerType.size()))
5743 const DataArrayIdType *zePfl=idsPerType[idInIdsPerType];
5746 zePfl->checkAllocated();
5747 if(zePfl->getNumberOfComponents()==1)
5749 for(const mcIdType *k=zePfl->begin();k!=zePfl->end();k++,retPtr++)
5751 if(*k>=0 && *k<nbOfCellsOfCurType)
5752 *retPtr=(*k)+offset;
5755 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : the section " << kk << " points to the profile #" << idInIdsPerType;
5756 oss << ", and this profile contains a value " << *k << " should be in [0," << nbOfCellsOfCurType << ") !";
5757 throw INTERP_KERNEL::Exception(oss.str());
5762 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of a profile with nb of compo != 1 !");
5765 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of null profile !");
5769 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : at section " << kk << " of code it points to the array #" << idInIdsPerType;
5770 oss << " should be in [0," << idsPerType.size() << ") !";
5771 throw INTERP_KERNEL::Exception(oss.str());
5780 * This method makes the hypothesis that \a this is sorted by type. If not an exception will be thrown.
5781 * 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.
5782 * 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.
5783 * This method has 1 input \a profile and 3 outputs \a code \a idsInPflPerType and \a idsPerType.
5785 * \param [in] profile
5786 * \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.
5787 * \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,
5788 * \a idsInPflPerType[i] stores the tuple ids in \a profile that correspond to the geometric type code[3*i+0]
5789 * \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.
5790 * This vector can be empty in case of all geometric type cells are fully covered in ascending in the given input \a profile.
5791 * \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
5793 void MEDCouplingUMesh::splitProfilePerType(const DataArrayIdType *profile, std::vector<mcIdType>& code, std::vector<DataArrayIdType *>& idsInPflPerType, std::vector<DataArrayIdType *>& idsPerType, bool smartPflKiller) const
5796 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile is NULL !");
5797 if(profile->getNumberOfComponents()!=1)
5798 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile should have exactly one component !");
5799 checkConnectivityFullyDefined();
5800 const mcIdType *conn=_nodal_connec->begin();
5801 const mcIdType *connI=_nodal_connec_index->begin();
5802 mcIdType nbOfCells=getNumberOfCells();
5803 std::vector<INTERP_KERNEL::NormalizedCellType> types;
5804 std::vector<mcIdType> typeRangeVals(1);
5805 for(const mcIdType *i=connI;i!=connI+nbOfCells;)
5807 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5808 if(std::find(types.begin(),types.end(),curType)!=types.end())
5810 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : current mesh is not sorted by type !");
5812 types.push_back(curType);
5813 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
5814 typeRangeVals.push_back(ToIdType(std::distance(connI,i)));
5817 DataArrayIdType *castArr=0,*rankInsideCast=0,*castsPresent=0;
5818 profile->splitByValueRange(&typeRangeVals[0],&typeRangeVals[0]+typeRangeVals.size(),castArr,rankInsideCast,castsPresent);
5819 MCAuto<DataArrayIdType> tmp0=castArr;
5820 MCAuto<DataArrayIdType> tmp1=rankInsideCast;
5821 MCAuto<DataArrayIdType> tmp2=castsPresent;
5823 mcIdType nbOfCastsFinal=castsPresent->getNumberOfTuples();
5824 code.resize(3*nbOfCastsFinal);
5825 std::vector< MCAuto<DataArrayIdType> > idsInPflPerType2;
5826 std::vector< MCAuto<DataArrayIdType> > idsPerType2;
5827 for(mcIdType i=0;i<nbOfCastsFinal;i++)
5829 mcIdType castId=castsPresent->getIJ(i,0);
5830 MCAuto<DataArrayIdType> tmp3=castArr->findIdsEqual(castId);
5831 idsInPflPerType2.push_back(tmp3);
5832 code[3*i]=ToIdType(types[castId]);
5833 code[3*i+1]=tmp3->getNumberOfTuples();
5834 MCAuto<DataArrayIdType> tmp4=rankInsideCast->selectByTupleId(tmp3->begin(),tmp3->begin()+tmp3->getNumberOfTuples());
5835 if(!smartPflKiller || !tmp4->isIota(typeRangeVals[castId+1]-typeRangeVals[castId]))
5837 tmp4->copyStringInfoFrom(*profile);
5838 idsPerType2.push_back(tmp4);
5839 code[3*i+2]=ToIdType(idsPerType2.size())-1;
5846 std::size_t sz2=idsInPflPerType2.size();
5847 idsInPflPerType.resize(sz2);
5848 for(std::size_t i=0;i<sz2;i++)
5850 DataArrayIdType *locDa=idsInPflPerType2[i];
5852 idsInPflPerType[i]=locDa;
5854 std::size_t sz=idsPerType2.size();
5855 idsPerType.resize(sz);
5856 for(std::size_t i=0;i<sz;i++)
5858 DataArrayIdType *locDa=idsPerType2[i];
5860 idsPerType[i]=locDa;
5865 * This method is here too emulate the MEDMEM behaviour on BDC (buildDescendingConnectivity). Hoping this method becomes deprecated very soon.
5866 * This method make the assumption that \a this and 'nM1LevMesh' mesh lyies on same coords (same pointer) as MED and MEDMEM does.
5867 * The following equality should be verified 'nM1LevMesh->getMeshDimension()==this->getMeshDimension()-1'
5868 * 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.
5870 MEDCouplingUMesh *MEDCouplingUMesh::emulateMEDMEMBDC(const MEDCouplingUMesh *nM1LevMesh, DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *&revDesc, DataArrayIdType *&revDescIndx, DataArrayIdType *& nM1LevMeshIds, DataArrayIdType *&meshnM1Old2New) const
5872 checkFullyDefined();
5873 nM1LevMesh->checkFullyDefined();
5874 if(getMeshDimension()-1!=nM1LevMesh->getMeshDimension())
5875 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : The mesh passed as first argument should have a meshDim equal to this->getMeshDimension()-1 !" );
5876 if(_coords!=nM1LevMesh->getCoords())
5877 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : 'this' and mesh in first argument should share the same coords : Use tryToShareSameCoords method !");
5878 MCAuto<DataArrayIdType> tmp0=DataArrayIdType::New();
5879 MCAuto<DataArrayIdType> tmp1=DataArrayIdType::New();
5880 MCAuto<MEDCouplingUMesh> ret1=buildDescendingConnectivity(desc,descIndx,tmp0,tmp1);
5881 MCAuto<DataArrayIdType> ret0=ret1->sortCellsInMEDFileFrmt();
5882 desc->transformWithIndArr(ret0->begin(),ret0->begin()+ret0->getNbOfElems());
5883 MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
5884 tmp->setConnectivity(tmp0,tmp1);
5885 tmp->renumberCells(ret0->begin(),false);
5886 revDesc=tmp->getNodalConnectivity();
5887 revDescIndx=tmp->getNodalConnectivityIndex();
5888 DataArrayIdType *ret=0;
5889 if(!ret1->areCellsIncludedIn(nM1LevMesh,2,ret))
5892 ret->getMaxValue(tmp2);
5894 std::ostringstream oss; oss << "MEDCouplingUMesh::emulateMEDMEMBDC : input N-1 mesh present a cell not in descending mesh ... Id of cell is " << tmp2 << " !";
5895 throw INTERP_KERNEL::Exception(oss.str());
5900 revDescIndx->incrRef();
5903 meshnM1Old2New=ret0;
5908 * Permutes the nodal connectivity arrays so that the cells are sorted by type, which is
5909 * necessary for writing the mesh to MED file. Additionally returns a permutation array
5910 * in "Old to New" mode.
5911 * \return DataArrayIdType * - a new instance of DataArrayIdType. The caller is to delete
5912 * this array using decrRef() as it is no more needed.
5913 * \throw If the nodal connectivity of cells is not defined.
5915 DataArrayIdType *MEDCouplingUMesh::sortCellsInMEDFileFrmt()
5917 checkConnectivityFullyDefined();
5918 MCAuto<DataArrayIdType> ret=getRenumArrForMEDFileFrmt();
5919 renumberCells(ret->begin(),false);
5924 * This methods checks that cells are sorted by their types.
5925 * This method makes asumption (no check) that connectivity is correctly set before calling.
5927 bool MEDCouplingUMesh::checkConsecutiveCellTypes() const
5929 checkFullyDefined();
5930 const mcIdType *conn=_nodal_connec->begin();
5931 const mcIdType *connI=_nodal_connec_index->begin();
5932 mcIdType nbOfCells=getNumberOfCells();
5933 std::set<INTERP_KERNEL::NormalizedCellType> types;
5934 for(const mcIdType *i=connI;i!=connI+nbOfCells;)
5936 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5937 if(types.find(curType)!=types.end())
5939 types.insert(curType);
5940 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
5946 * This method is a specialization of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method that is called here.
5947 * The geometric type order is specified by MED file.
5949 * \sa MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder
5951 bool MEDCouplingUMesh::checkConsecutiveCellTypesForMEDFileFrmt() const
5953 return checkConsecutiveCellTypesAndOrder(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
5957 * This method performs the same job as checkConsecutiveCellTypes except that the order of types sequence is analyzed to check
5958 * that the order is specified in array defined by [ \a orderBg , \a orderEnd ).
5959 * If there is some geo types in \a this \b NOT in [ \a orderBg, \a orderEnd ) it is OK (return true) if contiguous.
5960 * If there is some geo types in [ \a orderBg, \a orderEnd ) \b NOT in \a this it is OK too (return true) if contiguous.
5962 bool MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
5964 checkFullyDefined();
5965 const mcIdType *conn=_nodal_connec->begin();
5966 const mcIdType *connI=_nodal_connec_index->begin();
5967 mcIdType nbOfCells=getNumberOfCells();
5970 mcIdType lastPos=-1;
5971 std::set<INTERP_KERNEL::NormalizedCellType> sg;
5972 for(const mcIdType *i=connI;i!=connI+nbOfCells;)
5974 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5975 const INTERP_KERNEL::NormalizedCellType *isTypeExists=std::find(orderBg,orderEnd,curType);
5976 if(isTypeExists!=orderEnd)
5978 mcIdType pos=ToIdType(std::distance(orderBg,isTypeExists));
5982 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
5986 if(sg.find(curType)==sg.end())
5988 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
5999 * This method returns 2 newly allocated DataArrayIdType instances. The first is an array of size 'this->getNumberOfCells()' with one component,
6000 * 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
6001 * 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'.
6003 DataArrayIdType *MEDCouplingUMesh::getLevArrPerCellTypes(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd, DataArrayIdType *&nbPerType) const
6005 checkConnectivityFullyDefined();
6006 mcIdType nbOfCells=getNumberOfCells();
6007 const mcIdType *conn=_nodal_connec->begin();
6008 const mcIdType *connI=_nodal_connec_index->begin();
6009 MCAuto<DataArrayIdType> tmpa=DataArrayIdType::New();
6010 MCAuto<DataArrayIdType> tmpb=DataArrayIdType::New();
6011 tmpa->alloc(nbOfCells,1);
6012 tmpb->alloc(std::distance(orderBg,orderEnd),1);
6013 tmpb->fillWithZero();
6014 mcIdType *tmp=tmpa->getPointer();
6015 mcIdType *tmp2=tmpb->getPointer();
6016 for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6018 const INTERP_KERNEL::NormalizedCellType *where=std::find(orderBg,orderEnd,(INTERP_KERNEL::NormalizedCellType)conn[*i]);
6021 mcIdType pos=ToIdType(std::distance(orderBg,where));
6023 tmp[std::distance(connI,i)]=pos;
6027 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*i]);
6028 std::ostringstream oss; oss << "MEDCouplingUMesh::getLevArrPerCellTypes : Cell #" << std::distance(connI,i);
6029 oss << " has a type " << cm.getRepr() << " not in input array of type !";
6030 throw INTERP_KERNEL::Exception(oss.str());
6033 nbPerType=tmpb.retn();
6038 * This method behaves exactly as MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec but the order is those defined in MED file spec.
6040 * \return a new object containing the old to new correspondence.
6042 * \sa MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec, MEDCouplingUMesh::sortCellsInMEDFileFrmt.
6044 DataArrayIdType *MEDCouplingUMesh::getRenumArrForMEDFileFrmt() const
6046 return getRenumArrForConsecutiveCellTypesSpec(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
6050 * 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.
6051 * This method returns an array of size getNumberOfCells() that gives a renumber array old2New that can be used as input of MEDCouplingMesh::renumberCells.
6052 * The mesh after this call to MEDCouplingMesh::renumberCells will pass the test of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder with the same inputs.
6053 * The returned array minimizes the permutations that is to say the order of cells inside same geometric type remains the same.
6055 DataArrayIdType *MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
6057 DataArrayIdType *nbPerType=0;
6058 MCAuto<DataArrayIdType> tmpa=getLevArrPerCellTypes(orderBg,orderEnd,nbPerType);
6059 nbPerType->decrRef();
6060 return tmpa->buildPermArrPerLevel();
6064 * This method reorganize the cells of \a this so that the cells with same geometric types are put together.
6065 * The number of cells remains unchanged after the call of this method.
6066 * This method tries to minimizes the number of needed permutations. So, this method behaves not exactly as
6067 * MEDCouplingUMesh::sortCellsInMEDFileFrmt.
6069 * \return the array giving the correspondence old to new.
6071 DataArrayIdType *MEDCouplingUMesh::rearrange2ConsecutiveCellTypes()
6073 checkFullyDefined();
6075 const mcIdType *conn=_nodal_connec->begin();
6076 const mcIdType *connI=_nodal_connec_index->begin();
6077 mcIdType nbOfCells=getNumberOfCells();
6078 std::vector<INTERP_KERNEL::NormalizedCellType> types;
6079 for(const mcIdType *i=connI;i!=connI+nbOfCells && (types.size()!=_types.size());)
6080 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)conn[*i])==types.end())
6082 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6083 types.push_back(curType);
6084 for(i++;i!=connI+nbOfCells && (INTERP_KERNEL::NormalizedCellType)conn[*i]==curType;i++);
6086 DataArrayIdType *ret=DataArrayIdType::New();
6087 ret->alloc(nbOfCells,1);
6088 mcIdType *retPtr=ret->getPointer();
6089 std::fill(retPtr,retPtr+nbOfCells,-1);
6090 mcIdType newCellId=0;
6091 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
6093 for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6094 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
6095 retPtr[std::distance(connI,i)]=newCellId++;
6097 renumberCells(retPtr,false);
6102 * This method splits \a this into as mush as untructured meshes that consecutive set of same type cells.
6103 * So this method has typically a sense if MEDCouplingUMesh::checkConsecutiveCellTypes has a sense.
6104 * This method makes asumption that connectivity is correctly set before calling.
6106 std::vector<MEDCouplingUMesh *> MEDCouplingUMesh::splitByType() const
6108 checkConnectivityFullyDefined();
6109 const mcIdType *conn=_nodal_connec->begin();
6110 const mcIdType *connI=_nodal_connec_index->begin();
6111 mcIdType nbOfCells=getNumberOfCells();
6112 std::vector<MEDCouplingUMesh *> ret;
6113 for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6115 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6116 mcIdType beginCellId=ToIdType(std::distance(connI,i));
6117 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6118 mcIdType endCellId=ToIdType(std::distance(connI,i));
6119 mcIdType sz=endCellId-beginCellId;
6120 mcIdType *cells=new mcIdType[sz];
6121 for(mcIdType j=0;j<sz;j++)
6122 cells[j]=beginCellId+j;
6123 MEDCouplingUMesh *m=(MEDCouplingUMesh *)buildPartOfMySelf(cells,cells+sz,true);
6131 * This method performs the opposite operation than those in MEDCoupling1SGTUMesh::buildUnstructured.
6132 * If \a this is a single geometric type unstructured mesh, it will be converted into a more compact data structure,
6133 * MEDCoupling1GTUMesh instance. The returned instance will aggregate the same DataArrayDouble instance of coordinates than \a this.
6135 * \return a newly allocated instance, that the caller must manage.
6136 * \throw If \a this contains more than one geometric type.
6137 * \throw If the nodal connectivity of \a this is not fully defined.
6138 * \throw If the internal data is not coherent.
6140 MEDCoupling1GTUMesh *MEDCouplingUMesh::convertIntoSingleGeoTypeMesh() const
6142 checkConnectivityFullyDefined();
6143 if(_types.size()!=1)
6144 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6145 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6146 MCAuto<MEDCoupling1GTUMesh> ret=MEDCoupling1GTUMesh::New(getName(),typ);
6147 ret->setCoords(getCoords());
6148 MEDCoupling1SGTUMesh *retC=dynamic_cast<MEDCoupling1SGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6151 MCAuto<DataArrayIdType> c=convertNodalConnectivityToStaticGeoTypeMesh();
6152 retC->setNodalConnectivity(c);
6156 MEDCoupling1DGTUMesh *retD=dynamic_cast<MEDCoupling1DGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6158 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : Internal error !");
6159 DataArrayIdType *c=0,*ci=0;
6160 convertNodalConnectivityToDynamicGeoTypeMesh(c,ci);
6161 MCAuto<DataArrayIdType> cs(c),cis(ci);
6162 retD->setNodalConnectivity(cs,cis);
6167 DataArrayIdType *MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh() const
6169 checkConnectivityFullyDefined();
6170 if(_types.size()!=1)
6171 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6172 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6173 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6176 std::ostringstream oss; oss << "MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : this contains a single geo type (" << cm.getRepr() << ") but ";
6177 oss << "this type is dynamic ! Only static geometric type is possible for that type ! call convertNodalConnectivityToDynamicGeoTypeMesh instead !";
6178 throw INTERP_KERNEL::Exception(oss.str());
6180 mcIdType nbCells=getNumberOfCells();
6181 mcIdType typi=ToIdType(typ);
6182 mcIdType nbNodesPerCell=ToIdType(cm.getNumberOfNodes());
6183 MCAuto<DataArrayIdType> connOut=DataArrayIdType::New(); connOut->alloc(nbCells*nbNodesPerCell,1);
6184 mcIdType *outPtr=connOut->getPointer();
6185 const mcIdType *conn=_nodal_connec->begin();
6186 const mcIdType *connI=_nodal_connec_index->begin();
6188 for(mcIdType i=0;i<nbCells;i++,connI++)
6190 if(conn[connI[0]]==typi && connI[1]-connI[0]==nbNodesPerCell)
6191 outPtr=std::copy(conn+connI[0]+1,conn+connI[1],outPtr);
6194 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 << ") !";
6195 throw INTERP_KERNEL::Exception(oss.str());
6198 return connOut.retn();
6202 * Convert the nodal connectivity of the mesh so that all the cells are of dynamic types (polygon or quadratic
6203 * polygon). This returns the corresponding new nodal connectivity in \ref numbering-indirect format.
6207 void MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh(DataArrayIdType *&nodalConn, DataArrayIdType *&nodalConnIndex) const
6209 static const char msg0[]="MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : nodal connectivity in this are invalid ! Call checkConsistency !";
6210 checkConnectivityFullyDefined();
6211 if(_types.size()!=1)
6212 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6213 mcIdType nbCells=getNumberOfCells(),
6214 lgth=_nodal_connec->getNumberOfTuples();
6216 throw INTERP_KERNEL::Exception(msg0);
6217 MCAuto<DataArrayIdType> c(DataArrayIdType::New()),ci(DataArrayIdType::New());
6218 c->alloc(lgth-nbCells,1); ci->alloc(nbCells+1,1);
6219 mcIdType *cp(c->getPointer()),*cip(ci->getPointer());
6220 const mcIdType *incp(_nodal_connec->begin()),*incip(_nodal_connec_index->begin());
6222 for(mcIdType i=0;i<nbCells;i++,cip++,incip++)
6224 mcIdType strt(incip[0]+1),stop(incip[1]);//+1 to skip geo type
6225 mcIdType delta(stop-strt);
6228 if((strt>=0 && strt<lgth) && (stop>=0 && stop<=lgth))
6229 cp=std::copy(incp+strt,incp+stop,cp);
6231 throw INTERP_KERNEL::Exception(msg0);
6234 throw INTERP_KERNEL::Exception(msg0);
6235 cip[1]=cip[0]+delta;
6237 nodalConn=c.retn(); nodalConnIndex=ci.retn();
6241 * This method takes in input a vector of MEDCouplingUMesh instances lying on the same coordinates with same mesh dimensions.
6242 * Each mesh in \b ms must be sorted by type with the same order (typically using MEDCouplingUMesh::sortCellsInMEDFileFrmt).
6243 * This method is particularly useful for MED file interaction. It allows to aggregate several meshes and keeping the type sorting
6244 * and the track of the permutation by chunk of same geotype cells to retrieve it. The traditional formats old2new and new2old
6245 * are not used here to avoid the build of big permutation array.
6247 * \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
6248 * those specified in MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6249 * \param [out] szOfCellGrpOfSameType is a newly allocated DataArrayIdType instance whose number of tuples is equal to the number of chunks of same geotype
6250 * in all meshes in \b ms. The accumulation of all values of this array is equal to the number of cells of returned mesh.
6251 * \param [out] idInMsOfCellGrpOfSameType is a newly allocated DataArrayIdType instance having the same size than \b szOfCellGrpOfSameType. This
6252 * output array gives for each chunck of same type the corresponding mesh id in \b ms.
6253 * \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
6254 * is sorted by type following the geo cell types order of MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6256 MEDCouplingUMesh *MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& ms,
6257 DataArrayIdType *&szOfCellGrpOfSameType,
6258 DataArrayIdType *&idInMsOfCellGrpOfSameType)
6260 std::vector<const MEDCouplingUMesh *> ms2;
6261 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms.begin();it!=ms.end();it++)
6264 (*it)->checkConnectivityFullyDefined();
6268 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : input vector is empty !");
6269 const DataArrayDouble *refCoo=ms2[0]->getCoords();
6270 int meshDim=ms2[0]->getMeshDimension();
6271 std::vector<const MEDCouplingUMesh *> m1ssm;
6272 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmAuto;
6274 std::vector<const MEDCouplingUMesh *> m1ssmSingle;
6275 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmSingleAuto;
6276 mcIdType fake=0,rk=0;
6277 MCAuto<DataArrayIdType> ret1(DataArrayIdType::New()),ret2(DataArrayIdType::New());
6278 ret1->alloc(0,1); ret2->alloc(0,1);
6279 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms2.begin();it!=ms2.end();it++,rk++)
6281 if(meshDim!=(*it)->getMeshDimension())
6282 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshdims mismatch !");
6283 if(refCoo!=(*it)->getCoords())
6284 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshes are not shared by a single coordinates coords !");
6285 std::vector<MEDCouplingUMesh *> sp=(*it)->splitByType();
6286 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<const MEDCouplingUMesh *> >(m1ssm));
6287 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<MCAuto<MEDCouplingUMesh> > >(m1ssmAuto));
6288 for(std::vector<MEDCouplingUMesh *>::const_iterator it2=sp.begin();it2!=sp.end();it2++)
6290 MEDCouplingUMesh *singleCell=static_cast<MEDCouplingUMesh *>((*it2)->buildPartOfMySelf(&fake,&fake+1,true));
6291 m1ssmSingleAuto.push_back(singleCell);
6292 m1ssmSingle.push_back(singleCell);
6293 ret1->pushBackSilent((*it2)->getNumberOfCells()); ret2->pushBackSilent(rk);
6296 MCAuto<MEDCouplingUMesh> m1ssmSingle2=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmSingle);
6297 MCAuto<DataArrayIdType> renum=m1ssmSingle2->sortCellsInMEDFileFrmt();
6298 std::vector<const MEDCouplingUMesh *> m1ssmfinal(m1ssm.size());
6299 for(mcIdType i=0;i<ToIdType(m1ssm.size());i++)
6300 m1ssmfinal[renum->getIJ(i,0)]=m1ssm[i];
6301 MCAuto<MEDCouplingUMesh> ret0=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmfinal);
6302 szOfCellGrpOfSameType=ret1->renumber(renum->begin());
6303 idInMsOfCellGrpOfSameType=ret2->renumber(renum->begin());
6308 * This method returns a newly created DataArrayIdType instance.
6309 * This method retrieves cell ids in [ \a begin, \a end ) that have the type \a type.
6311 DataArrayIdType *MEDCouplingUMesh::keepCellIdsByType(INTERP_KERNEL::NormalizedCellType type, const mcIdType *begin, const mcIdType *end) const
6313 checkFullyDefined();
6314 const mcIdType *conn=_nodal_connec->begin();
6315 const mcIdType *connIndex=_nodal_connec_index->begin();
6316 MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(0,1);
6317 for(const mcIdType *w=begin;w!=end;w++)
6318 if((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]==type)
6319 ret->pushBackSilent(*w);
6324 * This method makes the assumption that da->getNumberOfTuples()<this->getNumberOfCells(). This method makes the assumption that ids contained in 'da'
6325 * are in [0:getNumberOfCells())
6327 DataArrayIdType *MEDCouplingUMesh::convertCellArrayPerGeoType(const DataArrayIdType *da) const
6329 checkFullyDefined();
6330 const mcIdType *conn=_nodal_connec->begin();
6331 const mcIdType *connI=_nodal_connec_index->begin();
6332 mcIdType nbOfCells=getNumberOfCells();
6333 std::set<INTERP_KERNEL::NormalizedCellType> types(getAllGeoTypes());
6334 mcIdType *tmp=new mcIdType[nbOfCells];
6335 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
6338 for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6339 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
6340 tmp[std::distance(connI,i)]=j++;
6342 DataArrayIdType *ret=DataArrayIdType::New();
6343 ret->alloc(da->getNumberOfTuples(),da->getNumberOfComponents());
6344 ret->copyStringInfoFrom(*da);
6345 mcIdType *retPtr=ret->getPointer();
6346 const mcIdType *daPtr=da->begin();
6347 mcIdType nbOfElems=da->getNbOfElems();
6348 for(mcIdType k=0;k<nbOfElems;k++)
6349 retPtr[k]=tmp[daPtr[k]];
6355 * This method reduced number of cells of this by keeping cells whose type is different from 'type' and if type=='type'
6356 * This method \b works \b for mesh sorted by type.
6357 * cells whose ids is in 'idsPerGeoType' array.
6358 * This method conserves coords and name of mesh.
6360 MEDCouplingUMesh *MEDCouplingUMesh::keepSpecifiedCells(INTERP_KERNEL::NormalizedCellType type, const mcIdType *idsPerGeoTypeBg, const mcIdType *idsPerGeoTypeEnd) const
6362 std::vector<mcIdType> code=getDistributionOfTypes();
6363 std::size_t nOfTypesInThis=code.size()/3;
6364 mcIdType sz=0,szOfType=0;
6365 for(std::size_t i=0;i<nOfTypesInThis;i++)
6370 szOfType=code[3*i+1];
6372 for(const mcIdType *work=idsPerGeoTypeBg;work!=idsPerGeoTypeEnd;work++)
6373 if(*work<0 || *work>=szOfType)
6375 std::ostringstream oss; oss << "MEDCouplingUMesh::keepSpecifiedCells : Request on type " << type << " at place #" << std::distance(idsPerGeoTypeBg,work) << " value " << *work;
6376 oss << ". It should be in [0," << szOfType << ") !";
6377 throw INTERP_KERNEL::Exception(oss.str());
6379 MCAuto<DataArrayIdType> idsTokeep=DataArrayIdType::New(); idsTokeep->alloc(sz+std::distance(idsPerGeoTypeBg,idsPerGeoTypeEnd),1);
6380 mcIdType *idsPtr=idsTokeep->getPointer();
6382 for(std::size_t i=0;i<nOfTypesInThis;i++)
6385 for(mcIdType j=0;j<code[3*i+1];j++)
6388 idsPtr=std::transform(idsPerGeoTypeBg,idsPerGeoTypeEnd,idsPtr,std::bind2nd(std::plus<mcIdType>(),offset));
6389 offset+=code[3*i+1];
6391 MCAuto<MEDCouplingUMesh> ret=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(idsTokeep->begin(),idsTokeep->end(),true));
6392 ret->copyTinyInfoFrom(this);
6397 * This method returns a vector of size 'this->getNumberOfCells()'.
6398 * This method retrieves for each cell in \a this if it is linear (false) or quadratic(true).
6400 std::vector<bool> MEDCouplingUMesh::getQuadraticStatus() const
6402 mcIdType ncell=getNumberOfCells();
6403 std::vector<bool> ret(ncell);
6404 const mcIdType *cI=getNodalConnectivityIndex()->begin();
6405 const mcIdType *c=getNodalConnectivity()->begin();
6406 for(mcIdType i=0;i<ncell;i++)
6408 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[i]];
6409 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6410 ret[i]=cm.isQuadratic();
6416 * Returns a newly created mesh (with ref count ==1) that contains merge of \a this and \a other.
6418 MEDCouplingMesh *MEDCouplingUMesh::mergeMyselfWith(const MEDCouplingMesh *other) const
6420 if(other->getType()!=UNSTRUCTURED)
6421 throw INTERP_KERNEL::Exception("Merge of umesh only available with umesh each other !");
6422 const MEDCouplingUMesh *otherC=static_cast<const MEDCouplingUMesh *>(other);
6423 return MergeUMeshes(this,otherC);
6427 * Returns a new DataArrayDouble holding barycenters of all cells. The barycenter is
6428 * computed by averaging coordinates of cell nodes, so this method is not a right
6429 * choice for degenerated meshes (not well oriented, cells with measure close to zero).
6430 * Beware also that for quadratic meshes, degenerated arc of circles are turned into linear edges for the computation.
6431 * This happens with a default detection precision of eps=1.0e-14. If you need control over this use computeCellCenterOfMassWithPrecision().
6432 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
6433 * this->getNumberOfCells() tuples per \a this->getSpaceDimension()
6434 * components. The caller is to delete this array using decrRef() as it is
6436 * \throw If the coordinates array is not set.
6437 * \throw If the nodal connectivity of cells is not defined.
6438 * \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
6439 * \sa MEDCouplingUMesh::computeCellCenterOfMassWithPrecision
6441 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMass() const
6443 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6444 int spaceDim=getSpaceDimension();
6445 mcIdType nbOfCells=getNumberOfCells();
6446 ret->alloc(nbOfCells,spaceDim);
6447 ret->copyStringInfoFrom(*getCoords());
6448 double *ptToFill=ret->getPointer();
6449 const mcIdType *nodal=_nodal_connec->begin();
6450 const mcIdType *nodalI=_nodal_connec_index->begin();
6451 const double *coor=_coords->begin();
6452 for(mcIdType i=0;i<nbOfCells;i++)
6454 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6455 INTERP_KERNEL::computeBarycenter2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[i]+1,nodalI[i+1]-nodalI[i]-1,coor,spaceDim,ptToFill);
6463 * See computeCellCenterOfMass().
6464 * \param eps a precision for the detection of degenerated arc of circles.
6465 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
6466 * this->getNumberOfCells() tuples per \a this->getSpaceDimension()
6467 * components. The caller is to delete this array using decrRef() as it is
6469 * \throw If the coordinates array is not set.
6470 * \throw If the nodal connectivity of cells is not defined.
6471 * \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
6472 * \sa MEDCouplingUMesh::computeCellCenterOfMassWithPrecision
6474 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMassWithPrecision(double eps) const
6476 INTERP_KERNEL::QuadraticPlanarPrecision prec(eps);
6477 MCAuto<DataArrayDouble> ret = computeCellCenterOfMass();
6483 * This method computes for each cell in \a this, the location of the iso barycenter of nodes constituting
6484 * the cell. Contrary to badly named MEDCouplingUMesh::computeCellCenterOfMass method that returns the center of inertia of the
6486 * \return a newly allocated DataArrayDouble instance that the caller has to deal with. The returned
6487 * DataArrayDouble instance will have \c this->getNumberOfCells() tuples and \c this->getSpaceDimension() components.
6489 * \sa MEDCouplingUMesh::computeCellCenterOfMass
6490 * \throw If \a this is not fully defined (coordinates and connectivity)
6491 * \throw If there is presence in nodal connectivity in \a this of node ids not in [0, \c this->getNumberOfNodes() )
6493 DataArrayDouble *MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell() const
6495 checkFullyDefined();
6496 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6497 int spaceDim=getSpaceDimension();
6498 mcIdType nbOfCells=getNumberOfCells();
6499 mcIdType nbOfNodes=getNumberOfNodes();
6500 ret->alloc(nbOfCells,spaceDim);
6501 double *ptToFill=ret->getPointer();
6502 const mcIdType *nodal=_nodal_connec->begin();
6503 const mcIdType *nodalI=_nodal_connec_index->begin();
6504 const double *coor=_coords->begin();
6505 for(mcIdType i=0;i<nbOfCells;i++,ptToFill+=spaceDim)
6507 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6508 std::fill(ptToFill,ptToFill+spaceDim,0.);
6509 if(type!=INTERP_KERNEL::NORM_POLYHED)
6511 for(const mcIdType *conn=nodal+nodalI[i]+1;conn!=nodal+nodalI[i+1];conn++)
6513 if(*conn>=0 && *conn<nbOfNodes)
6514 std::transform(coor+spaceDim*conn[0],coor+spaceDim*(conn[0]+1),ptToFill,ptToFill,std::plus<double>());
6517 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of nodeId #" << *conn << " should be in [0," << nbOfNodes << ") !";
6518 throw INTERP_KERNEL::Exception(oss.str());
6521 mcIdType nbOfNodesInCell=nodalI[i+1]-nodalI[i]-1;
6522 if(nbOfNodesInCell>0)
6523 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies<double>(),1./(double)nbOfNodesInCell));
6526 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of cell with no nodes !";
6527 throw INTERP_KERNEL::Exception(oss.str());
6532 std::set<mcIdType> s(nodal+nodalI[i]+1,nodal+nodalI[i+1]);
6534 for(std::set<mcIdType>::const_iterator it=s.begin();it!=s.end();it++)
6536 if(*it>=0 && *it<nbOfNodes)
6537 std::transform(coor+spaceDim*(*it),coor+spaceDim*((*it)+1),ptToFill,ptToFill,std::plus<double>());
6540 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell polyhedron cell #" << i << " presence of nodeId #" << *it << " should be in [0," << nbOfNodes << ") !";
6541 throw INTERP_KERNEL::Exception(oss.str());
6545 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies<double>(),1./(double)s.size()));
6548 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on polyhedron cell #" << i << " there are no nodes !";
6549 throw INTERP_KERNEL::Exception(oss.str());
6557 * Returns a new DataArrayDouble holding barycenters of specified cells. The
6558 * barycenter is computed by averaging coordinates of cell nodes. The cells to treat
6559 * are specified via an array of cell ids.
6560 * \warning Validity of the specified cell ids is not checked!
6561 * Valid range is [ 0, \a this->getNumberOfCells() ).
6562 * \param [in] begin - an array of cell ids of interest.
6563 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
6564 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size ( \a
6565 * end - \a begin ) tuples per \a this->getSpaceDimension() components. The
6566 * caller is to delete this array using decrRef() as it is no more needed.
6567 * \throw If the coordinates array is not set.
6568 * \throw If the nodal connectivity of cells is not defined.
6570 * \if ENABLE_EXAMPLES
6571 * \ref cpp_mcumesh_getPartBarycenterAndOwner "Here is a C++ example".<br>
6572 * \ref py_mcumesh_getPartBarycenterAndOwner "Here is a Python example".
6575 DataArrayDouble *MEDCouplingUMesh::getPartBarycenterAndOwner(const mcIdType *begin, const mcIdType *end) const
6577 DataArrayDouble *ret=DataArrayDouble::New();
6578 int spaceDim=getSpaceDimension();
6579 std::size_t nbOfTuple=std::distance(begin,end);
6580 ret->alloc(nbOfTuple,spaceDim);
6581 double *ptToFill=ret->getPointer();
6582 double *tmp=new double[spaceDim];
6583 const mcIdType *nodal=_nodal_connec->begin();
6584 const mcIdType *nodalI=_nodal_connec_index->begin();
6585 const double *coor=_coords->begin();
6586 for(const mcIdType *w=begin;w!=end;w++)
6588 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[*w]];
6589 INTERP_KERNEL::computeBarycenter2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[*w]+1,nodalI[*w+1]-nodalI[*w]-1,coor,spaceDim,ptToFill);
6597 * 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".
6598 * So the returned instance will have 4 components and \c this->getNumberOfCells() tuples.
6599 * So this method expects that \a this has a spaceDimension equal to 3 and meshDimension equal to 2.
6600 * The computation of the plane equation is done using each time the 3 first nodes of 2D cells.
6601 * This method is useful to detect 2D cells in 3D space that are not coplanar.
6603 * \return DataArrayDouble * - a new instance of DataArrayDouble having 4 components and a number of tuples equal to number of cells in \a this.
6604 * \throw If spaceDim!=3 or meshDim!=2.
6605 * \throw If connectivity of \a this is invalid.
6606 * \throw If connectivity of a cell in \a this points to an invalid node.
6608 DataArrayDouble *MEDCouplingUMesh::computePlaneEquationOf3DFaces() const
6610 MCAuto<DataArrayDouble> ret(DataArrayDouble::New());
6611 mcIdType nbOfCells=getNumberOfCells();
6612 mcIdType nbOfNodes(getNumberOfNodes());
6613 if(getSpaceDimension()!=3 || getMeshDimension()!=2)
6614 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computePlaneEquationOf3DFaces : This method must be applied on a mesh having meshDimension equal 2 and a spaceDimension equal to 3 !");
6615 ret->alloc(nbOfCells,4);
6616 double *retPtr(ret->getPointer());
6617 const mcIdType *nodal(_nodal_connec->begin()),*nodalI(_nodal_connec_index->begin());
6618 const double *coor(_coords->begin());
6619 for(mcIdType i=0;i<nbOfCells;i++,nodalI++,retPtr+=4)
6621 double matrix[16]={0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,0},matrix2[16];
6622 if(nodalI[1]-nodalI[0]>=4)
6624 double aa[3]={coor[nodal[nodalI[0]+1+1]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6625 coor[nodal[nodalI[0]+1+1]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6626 coor[nodal[nodalI[0]+1+1]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]}
6627 ,bb[3]={coor[nodal[nodalI[0]+1+2]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6628 coor[nodal[nodalI[0]+1+2]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6629 coor[nodal[nodalI[0]+1+2]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]};
6630 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]};
6631 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]));
6632 for(int j=0;j<3;j++)
6634 mcIdType nodeId(nodal[nodalI[0]+1+j]);
6635 if(nodeId>=0 && nodeId<nbOfNodes)
6636 std::copy(coor+nodeId*3,coor+(nodeId+1)*3,matrix+4*j);
6639 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! This cell points to an invalid nodeId : " << nodeId << " !";
6640 throw INTERP_KERNEL::Exception(oss.str());
6643 if(sqrt(cc[0]*cc[0]+cc[1]*cc[1]+cc[2]*cc[2])>(1e-3*aa_norm*bb_norm))
6645 INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6646 retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6650 if(nodalI[1]-nodalI[0]==4)
6652 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : cell" << i << " : Presence of The 3 colinear points !";
6653 throw INTERP_KERNEL::Exception(oss.str());
6656 double dd[3]={0.,0.,0.};
6657 for(mcIdType offset=nodalI[0]+1;offset<nodalI[1];offset++)
6658 std::transform(coor+3*nodal[offset],coor+3*(nodal[offset]+1),dd,dd,std::plus<double>());
6659 mcIdType nbOfNodesInCell(nodalI[1]-nodalI[0]-1);
6660 std::transform(dd,dd+3,dd,std::bind2nd(std::multiplies<double>(),1./(double)nbOfNodesInCell));
6661 std::copy(dd,dd+3,matrix+4*2);
6662 INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6663 retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6668 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! Must be constitued by more than 3 nodes !";
6669 throw INTERP_KERNEL::Exception(oss.str());
6676 * This method expects as input a DataArrayDouble non nul instance 'da' that should be allocated. If not an exception is thrown.
6679 MEDCouplingUMesh *MEDCouplingUMesh::Build0DMeshFromCoords(DataArrayDouble *da)
6682 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build0DMeshFromCoords : instance of DataArrayDouble must be not null !");
6683 da->checkAllocated();
6684 std::string name(da->getName());
6685 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New(name,0));
6687 ret->setName("Mesh");
6689 mcIdType nbOfTuples(da->getNumberOfTuples());
6690 MCAuto<DataArrayIdType> c(DataArrayIdType::New()),cI(DataArrayIdType::New());
6691 c->alloc(2*nbOfTuples,1);
6692 cI->alloc(nbOfTuples+1,1);
6693 mcIdType *cp(c->getPointer()),*cip(cI->getPointer());
6695 for(mcIdType i=0;i<nbOfTuples;i++)
6697 *cp++=INTERP_KERNEL::NORM_POINT1;
6701 ret->setConnectivity(c,cI,true);
6705 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::Build1DMeshFromCoords(DataArrayDouble *da)
6708 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build01MeshFromCoords : instance of DataArrayDouble must be not null !");
6709 da->checkAllocated();
6710 std::string name(da->getName());
6711 MCAuto<MEDCouplingUMesh> ret;
6713 MCAuto<MEDCouplingCMesh> tmp(MEDCouplingCMesh::New());
6714 MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
6715 arr->alloc(da->getNumberOfTuples());
6716 tmp->setCoordsAt(0,arr);
6717 ret=tmp->buildUnstructured();
6721 ret->setName("Mesh");
6728 * Creates a new MEDCouplingUMesh by concatenating two given meshes of the same dimension.
6729 * Cells and nodes of
6730 * the first mesh precede cells and nodes of the second mesh within the result mesh.
6731 * \param [in] mesh1 - the first mesh.
6732 * \param [in] mesh2 - the second mesh.
6733 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6734 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6735 * is no more needed.
6736 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
6737 * \throw If the coordinates array is not set in none of the meshes.
6738 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
6739 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
6741 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
6743 std::vector<const MEDCouplingUMesh *> tmp(2);
6744 tmp[0]=const_cast<MEDCouplingUMesh *>(mesh1); tmp[1]=const_cast<MEDCouplingUMesh *>(mesh2);
6745 return MergeUMeshes(tmp);
6749 * Creates a new MEDCouplingUMesh by concatenating all given meshes of the same dimension.
6750 * Cells and nodes of
6751 * the *i*-th mesh precede cells and nodes of the (*i*+1)-th mesh within the result mesh.
6752 * \param [in] a - a vector of meshes (MEDCouplingUMesh) to concatenate.
6753 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6754 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6755 * is no more needed.
6756 * \throw If \a a.size() == 0.
6757 * \throw If \a a[ *i* ] == NULL.
6758 * \throw If the coordinates array is not set in none of the meshes.
6759 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
6760 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
6762 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const std::vector<const MEDCouplingUMesh *>& a)
6764 std::size_t sz=a.size();
6766 return MergeUMeshesLL(a);
6767 for(std::size_t ii=0;ii<sz;ii++)
6770 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshes : item #" << ii << " in input array of size "<< sz << " is empty !";
6771 throw INTERP_KERNEL::Exception(oss.str());
6773 std::vector< MCAuto<MEDCouplingUMesh> > bb(sz);
6774 std::vector< const MEDCouplingUMesh * > aa(sz);
6776 for(std::size_t i=0;i<sz && spaceDim==-3;i++)
6778 const MEDCouplingUMesh *cur=a[i];
6779 const DataArrayDouble *coo=cur->getCoords();
6781 spaceDim=int(coo->getNumberOfComponents());
6784 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : no spaceDim specified ! unable to perform merge !");
6785 for(std::size_t i=0;i<sz;i++)
6787 bb[i]=a[i]->buildSetInstanceFromThis(spaceDim);
6790 return MergeUMeshesLL(aa);
6794 * Creates a new MEDCouplingUMesh by concatenating cells of two given meshes of same
6795 * dimension and sharing the node coordinates array.
6796 * All cells of the first mesh precede all cells of the second mesh
6797 * within the result mesh.
6798 * \param [in] mesh1 - the first mesh.
6799 * \param [in] mesh2 - the second mesh.
6800 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6801 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6802 * is no more needed.
6803 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
6804 * \throw If the meshes do not share the node coordinates array.
6805 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
6806 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
6808 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
6810 std::vector<const MEDCouplingUMesh *> tmp(2);
6811 tmp[0]=mesh1; tmp[1]=mesh2;
6812 return MergeUMeshesOnSameCoords(tmp);
6816 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
6817 * dimension and sharing the node coordinates array.
6818 * All cells of the *i*-th mesh precede all cells of the
6819 * (*i*+1)-th mesh within the result mesh.
6820 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
6821 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6822 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6823 * is no more needed.
6824 * \throw If \a a.size() == 0.
6825 * \throw If \a a[ *i* ] == NULL.
6826 * \throw If the meshes do not share the node coordinates array.
6827 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
6828 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
6830 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes)
6833 throw INTERP_KERNEL::Exception("meshes input parameter is expected to be non empty.");
6834 for(std::size_t ii=0;ii<meshes.size();ii++)
6837 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshesOnSameCoords : item #" << ii << " in input array of size "<< meshes.size() << " is empty !";
6838 throw INTERP_KERNEL::Exception(oss.str());
6840 const DataArrayDouble *coords=meshes.front()->getCoords();
6841 int meshDim=meshes.front()->getMeshDimension();
6842 std::vector<const MEDCouplingUMesh *>::const_iterator iter=meshes.begin();
6843 mcIdType meshLgth=0;
6844 mcIdType meshIndexLgth=0;
6845 for(;iter!=meshes.end();iter++)
6847 if(coords!=(*iter)->getCoords())
6848 throw INTERP_KERNEL::Exception("meshes does not share the same coords ! Try using tryToShareSameCoords method !");
6849 if(meshDim!=(*iter)->getMeshDimension())
6850 throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, FuseUMeshesOnSameCoords impossible !");
6851 meshLgth+=(*iter)->getNodalConnectivityArrayLen();
6852 meshIndexLgth+=(*iter)->getNumberOfCells();
6854 MCAuto<DataArrayIdType> nodal=DataArrayIdType::New();
6855 nodal->alloc(meshLgth,1);
6856 mcIdType *nodalPtr=nodal->getPointer();
6857 MCAuto<DataArrayIdType> nodalIndex=DataArrayIdType::New();
6858 nodalIndex->alloc(meshIndexLgth+1,1);
6859 mcIdType *nodalIndexPtr=nodalIndex->getPointer();
6861 for(iter=meshes.begin();iter!=meshes.end();iter++)
6863 const mcIdType *nod=(*iter)->getNodalConnectivity()->begin();
6864 const mcIdType *index=(*iter)->getNodalConnectivityIndex()->begin();
6865 mcIdType nbOfCells=(*iter)->getNumberOfCells();
6866 mcIdType meshLgth2=(*iter)->getNodalConnectivityArrayLen();
6867 nodalPtr=std::copy(nod,nod+meshLgth2,nodalPtr);
6868 if(iter!=meshes.begin())
6869 nodalIndexPtr=std::transform(index+1,index+nbOfCells+1,nodalIndexPtr,std::bind2nd(std::plus<mcIdType>(),offset));
6871 nodalIndexPtr=std::copy(index,index+nbOfCells+1,nodalIndexPtr);
6874 MEDCouplingUMesh *ret=MEDCouplingUMesh::New();
6875 ret->setName("merge");
6876 ret->setMeshDimension(meshDim);
6877 ret->setConnectivity(nodal,nodalIndex,true);
6878 ret->setCoords(coords);
6883 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
6884 * dimension and sharing the node coordinates array. Cells of the *i*-th mesh precede
6885 * cells of the (*i*+1)-th mesh within the result mesh. Duplicates of cells are
6886 * removed from \a this mesh and arrays mapping between new and old cell ids in "Old to
6887 * New" mode are returned for each input mesh.
6888 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
6889 * \param [in] compType - specifies a cell comparison technique. For meaning of its
6890 * valid values [0,1,2], see zipConnectivityTraducer().
6891 * \param [in,out] corr - an array of DataArrayIdType, of the same size as \a
6892 * meshes. The *i*-th array describes cell ids mapping for \a meshes[ *i* ]
6893 * mesh. The caller is to delete each of the arrays using decrRef() as it is
6895 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6896 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6897 * is no more needed.
6898 * \throw If \a meshes.size() == 0.
6899 * \throw If \a meshes[ *i* ] == NULL.
6900 * \throw If the meshes do not share the node coordinates array.
6901 * \throw If \a meshes[ *i* ]->getMeshDimension() < 0.
6902 * \throw If the \a meshes are of different dimension (getMeshDimension()).
6903 * \throw If the nodal connectivity of cells of any of \a meshes is not defined.
6904 * \throw If the nodal connectivity any of \a meshes includes an invalid id.
6906 MEDCouplingUMesh *MEDCouplingUMesh::FuseUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes, int compType, std::vector<DataArrayIdType *>& corr)
6908 //All checks are delegated to MergeUMeshesOnSameCoords
6909 MCAuto<MEDCouplingUMesh> ret=MergeUMeshesOnSameCoords(meshes);
6910 MCAuto<DataArrayIdType> o2n=ret->zipConnectivityTraducer(compType);
6911 corr.resize(meshes.size());
6912 std::size_t nbOfMeshes=meshes.size();
6914 const mcIdType *o2nPtr=o2n->begin();
6915 for(std::size_t i=0;i<nbOfMeshes;i++)
6917 DataArrayIdType *tmp=DataArrayIdType::New();
6918 mcIdType curNbOfCells=meshes[i]->getNumberOfCells();
6919 tmp->alloc(curNbOfCells,1);
6920 std::copy(o2nPtr+offset,o2nPtr+offset+curNbOfCells,tmp->getPointer());
6921 offset+=curNbOfCells;
6922 tmp->setName(meshes[i]->getName());
6929 * Makes all given meshes share the nodal connectivity array. The common connectivity
6930 * array is created by concatenating the connectivity arrays of all given meshes. All
6931 * the given meshes must be of the same space dimension but dimension of cells **can
6932 * differ**. This method is particularly useful in MEDLoader context to build a \ref
6933 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
6934 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
6935 * \param [in,out] meshes - a vector of meshes to update.
6936 * \throw If any of \a meshes is NULL.
6937 * \throw If the coordinates array is not set in any of \a meshes.
6938 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
6939 * \throw If \a meshes are of different space dimension.
6941 void MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords(const std::vector<MEDCouplingUMesh *>& meshes)
6943 std::size_t sz=meshes.size();
6946 std::vector< const DataArrayDouble * > coords(meshes.size());
6947 std::vector< const DataArrayDouble * >::iterator it2=coords.begin();
6948 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++,it2++)
6952 (*it)->checkConnectivityFullyDefined();
6953 const DataArrayDouble *coo=(*it)->getCoords();
6958 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
6959 oss << " has no coordinate array defined !";
6960 throw INTERP_KERNEL::Exception(oss.str());
6965 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
6966 oss << " is null !";
6967 throw INTERP_KERNEL::Exception(oss.str());
6970 MCAuto<DataArrayDouble> res=DataArrayDouble::Aggregate(coords);
6971 std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();
6972 mcIdType offset=(*it)->getNumberOfNodes();
6973 (*it++)->setCoords(res);
6974 for(;it!=meshes.end();it++)
6976 mcIdType oldNumberOfNodes=(*it)->getNumberOfNodes();
6977 (*it)->setCoords(res);
6978 (*it)->shiftNodeNumbersInConn(offset);
6979 offset+=oldNumberOfNodes;
6984 * Merges nodes coincident with a given precision within all given meshes that share
6985 * the nodal connectivity array. The given meshes **can be of different** mesh
6986 * dimension. This method is particularly useful in MEDLoader context to build a \ref
6987 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
6988 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
6989 * \param [in,out] meshes - a vector of meshes to update.
6990 * \param [in] eps - the precision used to detect coincident nodes (infinite norm).
6991 * \throw If any of \a meshes is NULL.
6992 * \throw If the \a meshes do not share the same node coordinates array.
6993 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
6995 void MEDCouplingUMesh::MergeNodesOnUMeshesSharingSameCoords(const std::vector<MEDCouplingUMesh *>& meshes, double eps)
6999 std::set<const DataArrayDouble *> s;
7000 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
7003 s.insert((*it)->getCoords());
7006 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 !";
7007 throw INTERP_KERNEL::Exception(oss.str());
7012 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 !";
7013 throw INTERP_KERNEL::Exception(oss.str());
7015 const DataArrayDouble *coo=*(s.begin());
7019 DataArrayIdType *comm,*commI;
7020 coo->findCommonTuples(eps,-1,comm,commI);
7021 MCAuto<DataArrayIdType> tmp1(comm),tmp2(commI);
7022 mcIdType oldNbOfNodes=coo->getNumberOfTuples();
7023 mcIdType newNbOfNodes;
7024 MCAuto<DataArrayIdType> o2n=DataArrayIdType::ConvertIndexArrayToO2N(oldNbOfNodes,comm->begin(),commI->begin(),commI->end(),newNbOfNodes);
7025 if(oldNbOfNodes==newNbOfNodes)
7027 MCAuto<DataArrayDouble> newCoords=coo->renumberAndReduce(o2n->begin(),newNbOfNodes);
7028 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
7030 (*it)->renumberNodesInConn(o2n->begin());
7031 (*it)->setCoords(newCoords);
7037 * This static operates only for coords in 3D. The polygon is specified by its connectivity nodes in [ \a begin , \a end ).
7039 bool MEDCouplingUMesh::IsPolygonWellOriented(bool isQuadratic, const double *vec, const mcIdType *begin, const mcIdType *end, const double *coords)
7042 double v[3]={0.,0.,0.};
7043 std::size_t sz=std::distance(begin,end);
7047 // Algorithm: sum in v the cross products of (e1, e2) where e_i it the vector between (0,0,0) and point i
7048 // and e2 is linear point directly following e1 in the connectivity. All points are used.
7049 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];
7050 v[1]+=coords[3*begin[i]+2]*coords[3*begin[(i+1)%sz]]-coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+2];
7051 v[2]+=coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+1]-coords[3*begin[i]+1]*coords[3*begin[(i+1)%sz]];
7055 // Same algorithm as above but also using intermediate quadratic points.
7056 // (taking only linear points might lead to issues if the linearized version of the
7057 // polygon is not convex or self-intersecting ... see testCellOrientation4)
7058 std::size_t hsz = sz/2;
7059 for(std::size_t j=0;j<sz;j++)
7061 if (j%2) // current point i is quadratic, next point i+1 is standard
7064 ip1 = ((j-1)/2 + 1)%hsz; // ip1 means "i+1", i.e. next point
7066 else // current point i is standard, next point i+1 is quadratic
7071 v[0]+=coords[3*begin[i]+1]*coords[3*begin[ip1]+2]-coords[3*begin[i]+2]*coords[3*begin[ip1]+1];
7072 v[1]+=coords[3*begin[i]+2]*coords[3*begin[ip1]]-coords[3*begin[i]]*coords[3*begin[ip1]+2];
7073 v[2]+=coords[3*begin[i]]*coords[3*begin[ip1]+1]-coords[3*begin[i]+1]*coords[3*begin[ip1]];
7076 double ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
7081 * The polyhedron is specified by its connectivity nodes in [ \a begin , \a end ).
7083 bool MEDCouplingUMesh::IsPolyhedronWellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7085 std::vector<std::pair<mcIdType,mcIdType> > edges;
7086 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
7087 const mcIdType *bgFace=begin;
7088 for(std::size_t i=0;i<nbOfFaces;i++)
7090 const mcIdType *endFace=std::find(bgFace+1,end,-1);
7091 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
7092 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7094 std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7095 if(std::find(edges.begin(),edges.end(),p1)!=edges.end())
7097 edges.push_back(p1);
7101 return INTERP_KERNEL::calculateVolumeForPolyh2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,ToIdType(std::distance(begin,end)),coords)>-EPS_FOR_POLYH_ORIENTATION;
7105 * The 3D extruded static cell (PENTA6,HEXA8,HEXAGP12...) its connectivity nodes in [ \a begin , \a end ).
7107 bool MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7109 double vec0[3],vec1[3];
7110 std::size_t sz=std::distance(begin,end);
7112 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented : the length of nodal connectivity of extruded cell is not even !");
7113 mcIdType nbOfNodes=ToIdType(sz/2);
7114 INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,nbOfNodes,coords,vec0);
7115 const double *pt0=coords+3*begin[0];
7116 const double *pt1=coords+3*begin[nbOfNodes];
7117 vec1[0]=pt1[0]-pt0[0]; vec1[1]=pt1[1]-pt0[1]; vec1[2]=pt1[2]-pt0[2];
7118 return (vec0[0]*vec1[0]+vec0[1]*vec1[1]+vec0[2]*vec1[2])<0.;
7121 void MEDCouplingUMesh::CorrectExtrudedStaticCell(mcIdType *begin, mcIdType *end)
7123 std::size_t sz=std::distance(begin,end);
7124 INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz];
7125 std::size_t nbOfNodes(sz/2);
7126 std::copy(begin,end,(mcIdType *)tmp);
7127 for(std::size_t j=1;j<nbOfNodes;j++)
7129 begin[j]=tmp[nbOfNodes-j];
7130 begin[j+nbOfNodes]=tmp[nbOfNodes+nbOfNodes-j];
7134 bool MEDCouplingUMesh::IsTetra4WellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7136 std::size_t sz=std::distance(begin,end);
7138 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsTetra4WellOriented : Tetra4 cell with not 4 nodes ! Call checkConsistency !");
7139 double vec0[3],vec1[3];
7140 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[1],*pt2=coords+3*begin[2],*pt3=coords+3*begin[3];
7141 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];
7142 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;
7145 bool MEDCouplingUMesh::IsPyra5WellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7147 std::size_t sz=std::distance(begin,end);
7149 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsPyra5WellOriented : Pyra5 cell with not 5 nodes ! Call checkConsistency !");
7151 INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,4,coords,vec0);
7152 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[4];
7153 return (vec0[0]*(pt1[0]-pt0[0])+vec0[1]*(pt1[1]-pt0[1])+vec0[2]*(pt1[2]-pt0[2]))<0.;
7157 * 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 )
7158 * 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
7161 * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not.
7162 * \param [in] coords the coordinates with nb of components exactly equal to 3
7163 * \param [in] begin begin of the nodal connectivity (geometric type included) of a single polyhedron cell
7164 * \param [in] end end of nodal connectivity of a single polyhedron cell (excluded)
7165 * \param [out] res the result is put at the end of the vector without any alteration of the data.
7167 void MEDCouplingUMesh::SimplifyPolyhedronCell(double eps, const DataArrayDouble *coords, mcIdType index, DataArrayIdType *res, MEDCouplingUMesh *faces,
7168 DataArrayIdType *E_Fi, DataArrayIdType *E_F, DataArrayIdType *F_Ei, DataArrayIdType *F_E)
7170 mcIdType nbFaces = E_Fi->getIJ(index + 1, 0) - E_Fi->getIJ(index, 0);
7171 MCAuto<DataArrayDouble> v=DataArrayDouble::New(); v->alloc(nbFaces,3);
7172 double *vPtr=v->getPointer();
7173 MCAuto<DataArrayDouble> p=DataArrayDouble::New(); p->alloc(nbFaces,2);
7174 double *pPtr=p->getPointer();
7175 mcIdType *e_fi = E_Fi->getPointer(), *e_f = E_F->getPointer(), *f_ei = F_Ei->getPointer(), *f_e = F_E->getPointer();
7176 const mcIdType *f_idx = faces->getNodalConnectivityIndex()->getPointer(), *f_cnn = faces->getNodalConnectivity()->getPointer();
7177 for(mcIdType i=0;i<nbFaces;i++,vPtr+=3,pPtr++)
7179 mcIdType face = e_f[e_fi[index] + i];
7180 ComputeVecAndPtOfFace(eps, coords->begin(), f_cnn + f_idx[face] + 1, f_cnn + f_idx[face + 1], vPtr, pPtr);
7181 // to differentiate faces going to different cells:
7183 for (mcIdType j = f_ei[face]; j < f_ei[face + 1]; j++)
7184 *pPtr += FromIdType<double>(f_e[j]);
7186 pPtr=p->getPointer(); vPtr=v->getPointer();
7187 DataArrayIdType *comm1=0,*commI1=0;
7188 v->findCommonTuples(eps,-1,comm1,commI1);
7189 for (mcIdType i = 0; i < nbFaces; i++)
7190 if (comm1->findIdFirstEqual(i) < 0)
7192 comm1->pushBackSilent(i);
7193 commI1->pushBackSilent(comm1->getNumberOfTuples());
7195 MCAuto<DataArrayIdType> comm1Auto(comm1),commI1Auto(commI1);
7196 const mcIdType *comm1Ptr=comm1->begin();
7197 const mcIdType *commI1Ptr=commI1->begin();
7198 mcIdType nbOfGrps1=commI1Auto->getNumberOfTuples()-1;
7199 res->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYHED));
7201 for(mcIdType i=0;i<nbOfGrps1;i++)
7203 mcIdType vecId=comm1Ptr[commI1Ptr[i]];
7204 MCAuto<DataArrayDouble> tmpgrp2=p->selectByTupleId(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7205 DataArrayIdType *comm2=0,*commI2=0;
7206 tmpgrp2->findCommonTuples(eps,-1,comm2,commI2);
7207 for (mcIdType j = 0; j < commI1Ptr[i+1] - commI1Ptr[i]; j++)
7208 if (comm2->findIdFirstEqual(j) < 0)
7210 comm2->pushBackSilent(j);
7211 commI2->pushBackSilent(comm2->getNumberOfTuples());
7213 MCAuto<DataArrayIdType> comm2Auto(comm2),commI2Auto(commI2);
7214 const mcIdType *comm2Ptr=comm2->begin();
7215 const mcIdType *commI2Ptr=commI2->begin();
7216 mcIdType nbOfGrps2=commI2Auto->getNumberOfTuples()-1;
7217 for(mcIdType j=0;j<nbOfGrps2;j++)
7219 if(commI2Ptr[j+1] == commI2Ptr[j] + 1)
7221 mcIdType face = e_f[e_fi[index] + comm1Ptr[commI1Ptr[i] + comm2Ptr[commI2Ptr[j]]]]; //hmmm
7222 res->insertAtTheEnd(f_cnn + f_idx[face] + 1, f_cnn + f_idx[face + 1]);
7223 res->pushBackSilent(-1);
7227 mcIdType pointId=comm1Ptr[commI1Ptr[i]+comm2Ptr[commI2Ptr[j]]];
7228 MCAuto<DataArrayIdType> ids2=comm2->selectByTupleIdSafeSlice(commI2Ptr[j],commI2Ptr[j+1],1);
7229 ids2->transformWithIndArr(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7230 ids2->transformWithIndArr(e_f + e_fi[index], e_f + e_fi[index + 1]);
7231 MCAuto<MEDCouplingUMesh> mm3=static_cast<MEDCouplingUMesh *>(faces->buildPartOfMySelf(ids2->begin(),ids2->end(),true));
7232 MCAuto<DataArrayIdType> idsNodeTmp=mm3->zipCoordsTraducer();
7233 MCAuto<DataArrayIdType> idsNode=idsNodeTmp->invertArrayO2N2N2O(mm3->getNumberOfNodes());
7234 const mcIdType *idsNodePtr=idsNode->begin();
7235 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];
7236 double vec[3]; vec[0]=vPtr[3*vecId+1]; vec[1]=-vPtr[3*vecId]; vec[2]=0.;
7237 double norm=vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2];
7238 if(std::abs(norm)>eps)
7240 double angle=INTERP_KERNEL::EdgeArcCircle::SafeAsin(norm);
7241 mm3->rotate(center,vec,angle);
7243 mm3->changeSpaceDimension(2);
7244 MCAuto<MEDCouplingUMesh> mm4=mm3->buildSpreadZonesWithPoly();
7245 const mcIdType *conn4=mm4->getNodalConnectivity()->begin();
7246 const mcIdType *connI4=mm4->getNodalConnectivityIndex()->begin();
7247 mcIdType nbOfCells=mm4->getNumberOfCells();
7248 for(mcIdType k=0;k<nbOfCells;k++)
7251 for(const mcIdType *work=conn4+connI4[k]+1;work!=conn4+connI4[k+1];work++,l++)
7252 res->pushBackSilent(idsNodePtr[*work]);
7253 res->pushBackSilent(-1);
7258 res->popBackSilent();
7262 * 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
7263 * through origin. The plane is defined by its nodal connectivity [ \b begin, \b end ).
7265 * \param [in] eps below that value the dot product of 2 vectors is considered as colinears
7266 * \param [in] coords coordinates expected to have 3 components.
7267 * \param [in] begin start of the nodal connectivity of the face.
7268 * \param [in] end end of the nodal connectivity (excluded) of the face.
7269 * \param [out] v the normalized vector of size 3
7270 * \param [out] p the pos of plane
7272 void MEDCouplingUMesh::ComputeVecAndPtOfFace(double eps, const double *coords, const mcIdType *begin, const mcIdType *end, double *v, double *p)
7274 std::size_t nbPoints=std::distance(begin,end);
7276 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeVecAndPtOfFace : < of 3 points in face ! not able to find a plane on that face !");
7277 double vec[3]={0.,0.,0.};
7279 bool refFound=false;
7280 for(;j<nbPoints-1 && !refFound;j++)
7282 vec[0]=coords[3*begin[j+1]]-coords[3*begin[j]];
7283 vec[1]=coords[3*begin[j+1]+1]-coords[3*begin[j]+1];
7284 vec[2]=coords[3*begin[j+1]+2]-coords[3*begin[j]+2];
7285 double norm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
7289 vec[0]/=norm; vec[1]/=norm; vec[2]/=norm;
7292 for(std::size_t i=j;i<nbPoints-1;i++)
7295 curVec[0]=coords[3*begin[i+1]]-coords[3*begin[i]];
7296 curVec[1]=coords[3*begin[i+1]+1]-coords[3*begin[i]+1];
7297 curVec[2]=coords[3*begin[i+1]+2]-coords[3*begin[i]+2];
7298 double norm=sqrt(curVec[0]*curVec[0]+curVec[1]*curVec[1]+curVec[2]*curVec[2]);
7301 curVec[0]/=norm; curVec[1]/=norm; curVec[2]/=norm;
7302 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];
7303 norm=sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
7306 v[0]/=norm; v[1]/=norm; v[2]/=norm;
7307 *p=v[0]*coords[3*begin[i]]+v[1]*coords[3*begin[i]+1]+v[2]*coords[3*begin[i]+2];
7311 throw INTERP_KERNEL::Exception("Not able to find a normal vector of that 3D face !");
7315 * This method tries to obtain a well oriented polyhedron.
7316 * If the algorithm fails, an exception will be thrown.
7318 void MEDCouplingUMesh::TryToCorrectPolyhedronOrientation(mcIdType *begin, mcIdType *end, const double *coords)
7320 std::list< std::pair<mcIdType,mcIdType> > edgesOK,edgesFinished;
7321 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
7322 std::vector<bool> isPerm(nbOfFaces,false);//field on faces False: I don't know, True : oriented
7324 mcIdType *bgFace=begin,*endFace=std::find(begin+1,end,-1);
7325 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
7326 for(std::size_t l=0;l<nbOfEdgesInFace;l++) { std::pair<mcIdType,mcIdType> p1(bgFace[l],bgFace[(l+1)%nbOfEdgesInFace]); edgesOK.push_back(p1); }
7328 while(std::find(isPerm.begin(),isPerm.end(),false)!=isPerm.end())
7331 std::size_t smthChanged=0;
7332 for(std::size_t i=0;i<nbOfFaces;i++)
7334 endFace=std::find(bgFace+1,end,-1);
7335 nbOfEdgesInFace=std::distance(bgFace,endFace);
7339 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7341 std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7342 std::pair<mcIdType,mcIdType> p2(p1.second,p1.first);
7343 bool b1=std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end();
7344 bool b2=std::find(edgesOK.begin(),edgesOK.end(),p2)!=edgesOK.end();
7345 if(b1 || b2) { b=b2; isPerm[i]=true; smthChanged++; break; }
7350 std::reverse(bgFace+1,endFace);
7351 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7353 std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7354 std::pair<mcIdType,mcIdType> p2(p1.second,p1.first);
7355 if(std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end())
7356 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7357 if(std::find(edgesFinished.begin(),edgesFinished.end(),p1)!=edgesFinished.end() || std::find(edgesFinished.begin(),edgesFinished.end(),p2)!=edgesFinished.end())
7358 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7359 std::list< std::pair<mcIdType,mcIdType> >::iterator it=std::find(edgesOK.begin(),edgesOK.end(),p2);
7360 if(it!=edgesOK.end())
7363 edgesFinished.push_back(p1);
7366 edgesOK.push_back(p1);
7373 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired !"); }
7375 if(!edgesOK.empty())
7376 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired : Some edges are shared only once !"); }
7377 if(INTERP_KERNEL::calculateVolumeForPolyh2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,ToIdType(std::distance(begin,end)),coords)<-EPS_FOR_POLYH_ORIENTATION)
7378 {//not lucky ! The first face was not correctly oriented : reorient all faces...
7380 for(std::size_t i=0;i<nbOfFaces;i++)
7382 endFace=std::find(bgFace+1,end,-1);
7383 std::reverse(bgFace+1,endFace);
7391 * This method makes the assumption spacedimension == meshdimension == 2.
7392 * This method works only for linear cells.
7394 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYGON in pos#0)
7396 DataArrayIdType *MEDCouplingUMesh::buildUnionOf2DMesh() const
7398 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
7399 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : meshdimension, spacedimension must be equal to 2 !");
7400 MCAuto<MEDCouplingUMesh> skin(computeSkin());
7401 mcIdType oldNbOfNodes(skin->getNumberOfNodes());
7402 MCAuto<DataArrayIdType> o2n(skin->zipCoordsTraducer());
7403 mcIdType nbOfNodesExpected(skin->getNumberOfNodes());
7404 MCAuto<DataArrayIdType> n2o(o2n->invertArrayO2N2N2O(oldNbOfNodes));
7405 mcIdType nbCells=skin->getNumberOfCells();
7406 if(nbCells==nbOfNodesExpected)
7407 return buildUnionOf2DMeshLinear(skin,n2o);
7408 else if(2*nbCells==nbOfNodesExpected)
7409 return buildUnionOf2DMeshQuadratic(skin,n2o);
7411 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : the mesh 2D in input appears to be not in a single part of a 2D mesh !");
7415 * This method makes the assumption spacedimension == meshdimension == 3.
7416 * This method works only for linear cells.
7418 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYHED in pos#0)
7420 DataArrayIdType *MEDCouplingUMesh::buildUnionOf3DMesh() const
7422 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
7423 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf3DMesh : meshdimension, spacedimension must be equal to 2 !");
7424 MCAuto<MEDCouplingUMesh> m=computeSkin();
7425 const mcIdType *conn=m->getNodalConnectivity()->begin();
7426 const mcIdType *connI=m->getNodalConnectivityIndex()->begin();
7427 mcIdType nbOfCells=m->getNumberOfCells();
7428 MCAuto<DataArrayIdType> ret=DataArrayIdType::New(); ret->alloc(m->getNodalConnectivity()->getNumberOfTuples(),1);
7429 mcIdType *work=ret->getPointer(); *work++=INTERP_KERNEL::NORM_POLYHED;
7432 work=std::copy(conn+connI[0]+1,conn+connI[1],work);
7433 for(mcIdType i=1;i<nbOfCells;i++)
7436 work=std::copy(conn+connI[i]+1,conn+connI[i+1],work);
7442 * \brief Creates a graph of cell neighbors
7443 * \return MEDCouplingSkyLineArray * - an sky line array the user should delete.
7444 * In the sky line array, graph arcs are stored in terms of (index,value) notation.
7446 * - index: 0 3 5 6 6
7447 * - value: 1 2 3 2 3 3
7448 * means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7449 * Arcs are not doubled but reflexive (1,1) arcs are present for each cell
7451 MEDCouplingSkyLineArray* MEDCouplingUMesh::generateGraph() const
7453 checkConnectivityFullyDefined();
7455 int meshDim = this->getMeshDimension();
7456 MEDCoupling::DataArrayIdType* indexr=MEDCoupling::DataArrayIdType::New();
7457 MEDCoupling::DataArrayIdType* revConn=MEDCoupling::DataArrayIdType::New();
7458 this->getReverseNodalConnectivity(revConn,indexr);
7459 const mcIdType* indexr_ptr=indexr->begin();
7460 const mcIdType* revConn_ptr=revConn->begin();
7462 const MEDCoupling::DataArrayIdType* index;
7463 const MEDCoupling::DataArrayIdType* conn;
7464 conn=this->getNodalConnectivity(); // it includes a type as the 1st element!!!
7465 index=this->getNodalConnectivityIndex();
7466 mcIdType nbCells=this->getNumberOfCells();
7467 const mcIdType* index_ptr=index->begin();
7468 const mcIdType* conn_ptr=conn->begin();
7470 //creating graph arcs (cell to cell relations)
7471 //arcs are stored in terms of (index,value) notation
7474 // means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7475 // in present version arcs are not doubled but reflexive (1,1) arcs are present for each cell
7477 //warning here one node have less than or equal effective number of cell with it
7478 //but cell could have more than effective nodes
7479 //because other equals nodes in other domain (with other global inode)
7480 std::vector <mcIdType> cell2cell_index(nbCells+1,0);
7481 std::vector <mcIdType> cell2cell;
7482 cell2cell.reserve(3*nbCells);
7484 for (mcIdType icell=0; icell<nbCells;icell++)
7486 std::map<mcIdType,mcIdType > counter;
7487 for (mcIdType iconn=index_ptr[icell]+1; iconn<index_ptr[icell+1];iconn++)
7489 mcIdType inode=conn_ptr[iconn];
7490 for (mcIdType iconnr=indexr_ptr[inode]; iconnr<indexr_ptr[inode+1];iconnr++)
7492 mcIdType icell2=revConn_ptr[iconnr];
7493 std::map<mcIdType,mcIdType>::iterator iter=counter.find(icell2);
7494 if (iter!=counter.end()) (iter->second)++;
7495 else counter.insert(std::make_pair(icell2,1));
7498 for (std::map<mcIdType,mcIdType>::const_iterator iter=counter.begin();
7499 iter!=counter.end(); iter++)
7500 if (iter->second >= meshDim)
7502 cell2cell_index[icell+1]++;
7503 cell2cell.push_back(iter->first);
7508 cell2cell_index[0]=0;
7509 for (mcIdType icell=0; icell<nbCells;icell++)
7510 cell2cell_index[icell+1]=cell2cell_index[icell]+cell2cell_index[icell+1];
7512 //filling up index and value to create skylinearray structure
7513 MEDCouplingSkyLineArray * array(MEDCouplingSkyLineArray::New(cell2cell_index,cell2cell));
7518 void MEDCouplingUMesh::writeVTKLL(std::ostream& ofs, const std::string& cellData, const std::string& pointData, DataArrayByte *byteData) const
7520 mcIdType nbOfCells=getNumberOfCells();
7522 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::writeVTK : the unstructured mesh has no cells !");
7523 ofs << " <" << getVTKDataSetType() << ">\n";
7524 ofs << " <Piece NumberOfPoints=\"" << getNumberOfNodes() << "\" NumberOfCells=\"" << nbOfCells << "\">\n";
7525 ofs << " <PointData>\n" << pointData << std::endl;
7526 ofs << " </PointData>\n";
7527 ofs << " <CellData>\n" << cellData << std::endl;
7528 ofs << " </CellData>\n";
7529 ofs << " <Points>\n";
7530 if(getSpaceDimension()==3)
7531 _coords->writeVTK(ofs,8,"Points",byteData);
7534 MCAuto<DataArrayDouble> coo=_coords->changeNbOfComponents(3,0.);
7535 coo->writeVTK(ofs,8,"Points",byteData);
7537 ofs << " </Points>\n";
7538 ofs << " <Cells>\n";
7539 const mcIdType *cPtr=_nodal_connec->begin();
7540 const mcIdType *cIPtr=_nodal_connec_index->begin();
7541 MCAuto<DataArrayIdType> faceoffsets=DataArrayIdType::New(); faceoffsets->alloc(nbOfCells,1);
7542 MCAuto<DataArrayIdType> types=DataArrayIdType::New(); types->alloc(nbOfCells,1);
7543 MCAuto<DataArrayIdType> offsets=DataArrayIdType::New(); offsets->alloc(nbOfCells,1);
7544 MCAuto<DataArrayIdType> connectivity=DataArrayIdType::New(); connectivity->alloc(_nodal_connec->getNumberOfTuples()-nbOfCells,1);
7545 mcIdType *w1=faceoffsets->getPointer(),*w2=types->getPointer(),*w3=offsets->getPointer(),*w4=connectivity->getPointer();
7546 mcIdType szFaceOffsets=0,szConn=0;
7547 for(mcIdType i=0;i<nbOfCells;i++,w1++,w2++,w3++)
7550 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]!=INTERP_KERNEL::NORM_POLYHED)
7553 *w3=szConn+cIPtr[i+1]-cIPtr[i]-1; szConn+=cIPtr[i+1]-cIPtr[i]-1;
7554 w4=std::copy(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],w4);
7558 mcIdType deltaFaceOffset=cIPtr[i+1]-cIPtr[i]+1;
7559 *w1=szFaceOffsets+deltaFaceOffset; szFaceOffsets+=deltaFaceOffset;
7560 std::set<mcIdType> c(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1]); c.erase(-1);
7561 *w3=szConn+ToIdType(c.size()); szConn+=ToIdType(c.size());
7562 w4=std::copy(c.begin(),c.end(),w4);
7565 types->transformWithIndArr(MEDCOUPLING2VTKTYPETRADUCER,MEDCOUPLING2VTKTYPETRADUCER+INTERP_KERNEL::NORM_MAXTYPE+1);
7566 types->writeVTK(ofs,8,"UInt8","types",byteData);
7567 std::string vtkTypeName = Traits<mcIdType>::VTKReprStr;
7568 offsets->writeVTK(ofs,8,vtkTypeName,"offsets",byteData);
7569 if(szFaceOffsets!=0)
7570 {//presence of Polyhedra
7571 connectivity->reAlloc(szConn);
7572 faceoffsets->writeVTK(ofs,8,vtkTypeName,"faceoffsets",byteData);
7573 MCAuto<DataArrayIdType> faces=DataArrayIdType::New(); faces->alloc(szFaceOffsets,1);
7574 w1=faces->getPointer();
7575 for(mcIdType i=0;i<nbOfCells;i++)
7576 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]==INTERP_KERNEL::NORM_POLYHED)
7578 mcIdType nbFaces=ToIdType(std::count(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],-1))+1;
7580 const mcIdType *w6=cPtr+cIPtr[i]+1,*w5=0;
7581 for(mcIdType j=0;j<nbFaces;j++)
7583 w5=std::find(w6,cPtr+cIPtr[i+1],-1);
7584 *w1++=ToIdType(std::distance(w6,w5));
7585 w1=std::copy(w6,w5,w1);
7589 faces->writeVTK(ofs,8,vtkTypeName,"faces",byteData);
7591 connectivity->writeVTK(ofs,8,vtkTypeName,"connectivity",byteData);
7592 ofs << " </Cells>\n";
7593 ofs << " </Piece>\n";
7594 ofs << " </" << getVTKDataSetType() << ">\n";
7597 void MEDCouplingUMesh::reprQuickOverview(std::ostream& stream) const
7599 stream << "MEDCouplingUMesh C++ instance at " << this << ". Name : \"" << getName() << "\".";
7601 { stream << " Not set !"; return ; }
7602 stream << " Mesh dimension : " << _mesh_dim << ".";
7606 { stream << " No coordinates set !"; return ; }
7607 if(!_coords->isAllocated())
7608 { stream << " Coordinates set but not allocated !"; return ; }
7609 stream << " Space dimension : " << _coords->getNumberOfComponents() << "." << std::endl;
7610 stream << "Number of nodes : " << _coords->getNumberOfTuples() << ".";
7611 if(!_nodal_connec_index)
7612 { stream << std::endl << "Nodal connectivity NOT set !"; return ; }
7613 if(!_nodal_connec_index->isAllocated())
7614 { stream << std::endl << "Nodal connectivity set but not allocated !"; return ; }
7615 mcIdType lgth=_nodal_connec_index->getNumberOfTuples();
7616 std::size_t cpt=_nodal_connec_index->getNumberOfComponents();
7617 if(cpt!=1 || lgth<1)
7619 stream << std::endl << "Number of cells : " << lgth-1 << ".";
7622 std::string MEDCouplingUMesh::getVTKDataSetType() const
7624 return std::string("UnstructuredGrid");
7627 std::string MEDCouplingUMesh::getVTKFileExtension() const
7629 return std::string("vtu");
7635 * Provides a renumbering of the cells of this (which has to be a piecewise connected 1D line), so that
7636 * the segments of the line are indexed in consecutive order (i.e. cells \a i and \a i+1 are neighbors).
7637 * This doesn't modify the mesh. This method only works using nodal connectivity consideration. Coordinates of nodes are ignored here.
7638 * The caller is to deal with the resulting DataArrayIdType.
7639 * \throw If the coordinate array is not set.
7640 * \throw If the nodal connectivity of the cells is not defined.
7641 * \throw If m1 is not a mesh of dimension 2, or m1 is not a mesh of dimension 1
7642 * \throw If m2 is not a (piecewise) line (i.e. if a point has more than 2 adjacent segments)
7644 * \sa DataArrayIdType::sortEachPairToMakeALinkedList
7646 DataArrayIdType *MEDCouplingUMesh::orderConsecutiveCells1D() const
7648 checkFullyDefined();
7649 if(getMeshDimension()!=1)
7650 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D works on unstructured mesh with meshdim = 1 !");
7652 // Check that this is a line (and not a more complex 1D mesh) - each point is used at most by 2 segments:
7653 MCAuto<DataArrayIdType> _d(DataArrayIdType::New()),_dI(DataArrayIdType::New());
7654 MCAuto<DataArrayIdType> _rD(DataArrayIdType::New()),_rDI(DataArrayIdType::New());
7655 MCAuto<MEDCouplingUMesh> m_points(buildDescendingConnectivity(_d, _dI, _rD, _rDI));
7656 const mcIdType *d(_d->begin()), *dI(_dI->begin());
7657 const mcIdType *rD(_rD->begin()), *rDI(_rDI->begin());
7658 MCAuto<DataArrayIdType> _dsi(_rDI->deltaShiftIndex());
7659 const mcIdType * dsi(_dsi->begin());
7660 MCAuto<DataArrayIdType> dsii = _dsi->findIdsNotInRange(0,3);
7662 if (dsii->getNumberOfTuples())
7663 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D only work with a mesh being a (piecewise) connected line!");
7665 mcIdType nc=getNumberOfCells();
7666 MCAuto<DataArrayIdType> result(DataArrayIdType::New());
7667 result->alloc(nc,1);
7669 // set of edges not used so far
7670 std::set<mcIdType> edgeSet;
7671 for (mcIdType i=0; i<nc; edgeSet.insert(i), i++);
7673 mcIdType startSeg=0;
7675 // while we have points with only one neighbor segments
7678 std::list<mcIdType> linePiece;
7679 // fills a list of consecutive segment linked to startSeg. This can go forward or backward.
7680 for (int direction=0;direction<2;direction++) // direction=0 --> forward, direction=1 --> backward
7682 // Fill the list forward (resp. backward) from the start segment:
7683 mcIdType activeSeg = startSeg;
7684 mcIdType prevPointId = -20;
7686 while (!edgeSet.empty())
7688 if (!(direction == 1 && prevPointId==-20)) // prevent adding twice startSeg
7691 linePiece.push_back(activeSeg);
7693 linePiece.push_front(activeSeg);
7694 edgeSet.erase(activeSeg);
7697 mcIdType ptId1 = d[dI[activeSeg]], ptId2 = d[dI[activeSeg]+1];
7698 ptId = direction ? (ptId1 == prevPointId ? ptId2 : ptId1) : (ptId2 == prevPointId ? ptId1 : ptId2);
7699 if (dsi[ptId] == 1) // hitting the end of the line
7702 mcIdType seg1 = rD[rDI[ptId]], seg2 = rD[rDI[ptId]+1];
7703 activeSeg = (seg1 == activeSeg) ? seg2 : seg1;
7706 // Done, save final piece into DA:
7707 std::copy(linePiece.begin(), linePiece.end(), result->getPointer()+newIdx);
7708 newIdx += ToIdType(linePiece.size());
7710 // identify next valid start segment (one which is not consumed)
7711 if(!edgeSet.empty())
7712 startSeg = *(edgeSet.begin());
7714 while (!edgeSet.empty());
7715 return result.retn();
7719 * This method split some of edges of 2D cells in \a this. The edges to be split are specified in \a subNodesInSeg
7720 * and in \a subNodesInSegI using \ref numbering-indirect storage mode.
7721 * To do the work this method can optionally needs information about middle of subedges for quadratic cases if
7722 * a minimal creation of new nodes is wanted.
7723 * So this method try to reduce at most the number of new nodes. The only case that can lead this method to add
7724 * nodes if a SEG3 is split without information of middle.
7725 * \b WARNING : is returned value is different from 0 a call to MEDCouplingUMesh::mergeNodes is necessary to
7726 * avoid to have a non conform mesh.
7728 * \return mcIdType - the number of new nodes created (in most of cases 0).
7730 * \throw If \a this is not coherent.
7731 * \throw If \a this has not spaceDim equal to 2.
7732 * \throw If \a this has not meshDim equal to 2.
7733 * \throw If some subcells needed to be split are orphan.
7734 * \sa MEDCouplingUMesh::conformize2D
7736 mcIdType MEDCouplingUMesh::split2DCells(const DataArrayIdType *desc, const DataArrayIdType *descI, const DataArrayIdType *subNodesInSeg, const DataArrayIdType *subNodesInSegI, const DataArrayIdType *midOpt, const DataArrayIdType *midOptI)
7738 if(!desc || !descI || !subNodesInSeg || !subNodesInSegI)
7739 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : the 4 first arrays must be not null !");
7740 desc->checkAllocated(); descI->checkAllocated(); subNodesInSeg->checkAllocated(); subNodesInSegI->checkAllocated();
7741 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
7742 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : This method only works for meshes with spaceDim=2 and meshDim=2 !");
7743 if(midOpt==0 && midOptI==0)
7745 split2DCellsLinear(desc,descI,subNodesInSeg,subNodesInSegI);
7748 else if(midOpt!=0 && midOptI!=0)
7749 return split2DCellsQuadratic(desc,descI,subNodesInSeg,subNodesInSegI,midOpt,midOptI);
7751 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : middle parameters must be set to null for all or not null for all.");
7755 * 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
7756 * 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
7757 * the geometric cell type set to INTERP_KERNEL::NORM_POLYGON.
7758 * 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
7759 * 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.
7761 * \return false if the input connectivity represents already the convex hull, true if the input cell needs to be reordered.
7763 bool MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis(const double *coords, const mcIdType *nodalConnBg, const mcIdType *nodalConnEnd, DataArrayIdType *nodalConnecOut)
7765 std::size_t sz=std::distance(nodalConnBg,nodalConnEnd);
7768 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)*nodalConnBg);
7769 if(cm.getDimension()==2)
7771 const mcIdType *node=nodalConnBg+1;
7772 mcIdType startNode=*node++;
7773 double refX=coords[2*startNode];
7774 for(;node!=nodalConnEnd;node++)
7776 if(coords[2*(*node)]<refX)
7779 refX=coords[2*startNode];
7782 std::vector<mcIdType> tmpOut; tmpOut.reserve(sz); tmpOut.push_back(startNode);
7786 double angle0=-M_PI/2;
7788 mcIdType nextNode=-1;
7789 mcIdType prevNode=-1;
7791 double angleNext=0.;
7792 while(nextNode!=startNode)
7796 for(node=nodalConnBg+1;node!=nodalConnEnd;node++)
7798 if(*node!=tmpOut.back() && *node!=prevNode)
7800 tmp2[0]=coords[2*(*node)]-coords[2*tmpOut.back()]; tmp2[1]=coords[2*(*node)+1]-coords[2*tmpOut.back()+1];
7801 double angleM=INTERP_KERNEL::EdgeArcCircle::GetAbsoluteAngle(tmp2,tmp1);
7806 res=angle0-angleM+2.*M_PI;
7815 if(nextNode!=startNode)
7817 angle0=angleNext-M_PI;
7820 prevNode=tmpOut.back();
7821 tmpOut.push_back(nextNode);
7824 std::vector<mcIdType> tmp3(2*(sz-1));
7825 std::vector<mcIdType>::iterator it=std::copy(nodalConnBg+1,nodalConnEnd,tmp3.begin());
7826 std::copy(nodalConnBg+1,nodalConnEnd,it);
7827 if(std::search(tmp3.begin(),tmp3.end(),tmpOut.begin(),tmpOut.end())!=tmp3.end())
7829 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
7832 if(std::search(tmp3.rbegin(),tmp3.rend(),tmpOut.begin(),tmpOut.end())!=tmp3.rend())
7834 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
7839 nodalConnecOut->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYGON));
7840 nodalConnecOut->insertAtTheEnd(tmpOut.begin(),tmpOut.end());
7845 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
7848 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
7852 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
7853 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
7854 * 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]].
7855 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
7856 * A negative value in \b arrIn means that it is ignored.
7857 * 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.
7859 * \param [in] arrIn arr origin array from which the extraction will be done.
7860 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7861 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
7862 * \sa MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed, MEDCouplingUMesh::partitionBySpreadZone
7864 DataArrayIdType *MEDCouplingUMesh::ComputeSpreadZoneGradually(const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn)
7866 mcIdType seed=0,nbOfDepthPeelingPerformed=0;
7867 return ComputeSpreadZoneGraduallyFromSeed(&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfDepthPeelingPerformed);
7871 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
7872 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
7873 * 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]].
7874 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
7875 * A negative value in \b arrIn means that it is ignored.
7876 * 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.
7877 * \param [in] seedBg the begin pointer (included) of an array containing the seed of the search zone
7878 * \param [in] seedEnd the end pointer (not included) of an array containing the seed of the search zone
7879 * \param [in] arrIn arr origin array from which the extraction will be done.
7880 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7881 * \param [in] nbOfDepthPeeling the max number of peels requested in search. By default -1, that is to say, no limit.
7882 * \param [out] nbOfDepthPeelingPerformed the number of peels effectively performed. May be different from \a nbOfDepthPeeling
7883 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
7884 * \sa MEDCouplingUMesh::partitionBySpreadZone
7886 DataArrayIdType *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(const mcIdType *seedBg, const mcIdType *seedEnd, const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn, mcIdType nbOfDepthPeeling, mcIdType& nbOfDepthPeelingPerformed)
7888 nbOfDepthPeelingPerformed=0;
7890 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed : arrIndxIn input pointer is NULL !");
7891 mcIdType nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
7894 DataArrayIdType *ret=DataArrayIdType::New(); ret->alloc(0,1);
7898 std::vector<bool> fetched(nbOfTuples,false);
7899 return ComputeSpreadZoneGraduallyFromSeedAlg(fetched,seedBg,seedEnd,arrIn,arrIndxIn,nbOfDepthPeeling,nbOfDepthPeelingPerformed);
7905 * \b this is expected to be a mesh fully defined whose spaceDim==meshDim.
7906 * It returns a new allocated mesh having the same mesh dimension and lying on same coordinates.
7907 * The returned mesh contains as poly cells as number of contiguous zone (regarding connectivity).
7908 * A spread contiguous zone is built using poly cells (polyhedra in 3D, polygons in 2D and polyline in 1D).
7909 * The sum of measure field of returned mesh is equal to the sum of measure field of this.
7911 * \return a newly allocated mesh lying on the same coords than \b this with same meshdimension than \b this.
7913 MEDCouplingUMesh *MEDCouplingUMesh::buildSpreadZonesWithPoly() const
7915 checkFullyDefined();
7916 int mdim=getMeshDimension();
7917 int spaceDim=getSpaceDimension();
7919 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension and spacedimension do not match !");
7920 std::vector<DataArrayIdType *> partition=partitionBySpreadZone();
7921 std::vector< MCAuto<DataArrayIdType> > partitionAuto; partitionAuto.reserve(partition.size());
7922 std::copy(partition.begin(),partition.end(),std::back_insert_iterator<std::vector< MCAuto<DataArrayIdType> > >(partitionAuto));
7923 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
7924 ret->setCoords(getCoords());
7925 ret->allocateCells(ToIdType(partition.size()));
7927 for(std::vector<DataArrayIdType *>::const_iterator it=partition.begin();it!=partition.end();it++)
7929 MCAuto<MEDCouplingUMesh> tmp=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf((*it)->begin(),(*it)->end(),true));
7930 MCAuto<DataArrayIdType> cell;
7934 cell=tmp->buildUnionOf2DMesh();
7937 cell=tmp->buildUnionOf3DMesh();
7940 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension supported are [2,3] ! Not implemented yet for others !");
7943 ret->insertNextCell((INTERP_KERNEL::NormalizedCellType)cell->getIJSafe(0,0),cell->getNumberOfTuples()-1,cell->begin()+1);
7946 ret->finishInsertingCells();
7951 * This method partitions \b this into contiguous zone.
7952 * This method only needs a well defined connectivity. Coordinates are not considered here.
7953 * This method returns a vector of \b newly allocated arrays that the caller has to deal with.
7955 std::vector<DataArrayIdType *> MEDCouplingUMesh::partitionBySpreadZone() const
7957 DataArrayIdType *neigh=0,*neighI=0;
7958 computeNeighborsOfCells(neigh,neighI);
7959 MCAuto<DataArrayIdType> neighAuto(neigh),neighIAuto(neighI);
7960 return PartitionBySpreadZone(neighAuto,neighIAuto);
7963 std::vector<DataArrayIdType *> MEDCouplingUMesh::PartitionBySpreadZone(const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn)
7965 if(!arrIn || !arrIndxIn)
7966 throw INTERP_KERNEL::Exception("PartitionBySpreadZone : null input pointers !");
7967 arrIn->checkAllocated(); arrIndxIn->checkAllocated();
7968 mcIdType nbOfTuples(arrIndxIn->getNumberOfTuples());
7969 if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1 || nbOfTuples<1)
7970 throw INTERP_KERNEL::Exception("PartitionBySpreadZone : invalid arrays in input !");
7971 mcIdType nbOfCellsCur(nbOfTuples-1);
7972 std::vector<DataArrayIdType *> ret;
7975 std::vector<bool> fetchedCells(nbOfCellsCur,false);
7976 std::vector< MCAuto<DataArrayIdType> > ret2;
7978 while(seed<nbOfCellsCur)
7980 mcIdType nbOfPeelPerformed=0;
7981 ret2.push_back(ComputeSpreadZoneGraduallyFromSeedAlg(fetchedCells,&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfPeelPerformed));
7982 seed=ToIdType(std::distance(fetchedCells.begin(),std::find(fetchedCells.begin()+seed,fetchedCells.end(),false)));
7984 for(std::vector< MCAuto<DataArrayIdType> >::iterator it=ret2.begin();it!=ret2.end();it++)
7985 ret.push_back((*it).retn());
7990 * This method returns given a distribution of cell type (returned for example by MEDCouplingUMesh::getDistributionOfTypes method and customized after) a
7991 * newly allocated DataArrayIdType instance with 2 components ready to be interpreted as input of DataArrayIdType::findRangeIdForEachTuple method.
7993 * \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.
7994 * \return a newly allocated DataArrayIdType to be managed by the caller.
7995 * \throw In case of \a code has not the right format (typically of size 3*n)
7997 DataArrayIdType *MEDCouplingUMesh::ComputeRangesFromTypeDistribution(const std::vector<mcIdType>& code)
7999 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
8000 std::size_t nb=code.size()/3;
8001 if(code.size()%3!=0)
8002 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeRangesFromTypeDistribution : invalid input code !");
8004 mcIdType *retPtr=ret->getPointer();
8005 for(std::size_t i=0;i<nb;i++,retPtr+=2)
8007 retPtr[0]=code[3*i+2];
8008 retPtr[1]=code[3*i+2]+code[3*i+1];
8014 * This method expects that \a this a 3D mesh (spaceDim=3 and meshDim=3) with all coordinates and connectivities set.
8015 * All cells in \a this are expected to be linear 3D cells.
8016 * This method will split **all** 3D cells in \a this into INTERP_KERNEL::NORM_TETRA4 cells and put them in the returned mesh.
8017 * It leads to an increase to number of cells.
8018 * This method contrary to MEDCouplingUMesh::simplexize can append coordinates in \a this to perform its work.
8019 * The \a nbOfAdditionalPoints returned value informs about it. If > 0, the coordinates array in returned mesh will have \a nbOfAdditionalPoints
8020 * more tuples (nodes) than in \a this. Anyway, all the nodes in \a this (with the same order) will be in the returned mesh.
8022 * \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.
8023 * For all other cells, the splitting policy will be ignored. See INTERP_KERNEL::SplittingPolicy for the images.
8024 * \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.
8025 * \param [out] n2oCells - A new instance of DataArrayIdType holding, for each new cell,
8026 * an id of old cell producing it. The caller is to delete this array using
8027 * decrRef() as it is no more needed.
8028 * \return MEDCoupling1SGTUMesh * - the mesh containing only INTERP_KERNEL::NORM_TETRA4 cells.
8030 * \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
8031 * the policy PLANAR_FACE_6 should be used on a mesh sorted with MEDCoupling1SGTUMesh::sortHexa8EachOther.
8033 * \throw If \a this is not a 3D mesh (spaceDim==3 and meshDim==3).
8034 * \throw If \a this is not fully constituted with linear 3D cells.
8035 * \sa MEDCouplingUMesh::simplexize, MEDCoupling1SGTUMesh::sortHexa8EachOther
8037 MEDCoupling1SGTUMesh *MEDCouplingUMesh::tetrahedrize(int policy, DataArrayIdType *& n2oCells, mcIdType& nbOfAdditionalPoints) const
8039 INTERP_KERNEL::SplittingPolicy pol((INTERP_KERNEL::SplittingPolicy)policy);
8040 checkConnectivityFullyDefined();
8041 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
8042 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tetrahedrize : only available for mesh with meshdim == 3 and spacedim == 3 !");
8043 mcIdType nbOfCells=getNumberOfCells();
8044 mcIdType nbNodes(getNumberOfNodes());
8045 MCAuto<MEDCoupling1SGTUMesh> ret0(MEDCoupling1SGTUMesh::New(getName(),INTERP_KERNEL::NORM_TETRA4));
8046 MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(nbOfCells,1);
8047 mcIdType *retPt(ret->getPointer());
8048 MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()); newConn->alloc(0,1);
8049 MCAuto<DataArrayDouble> addPts(DataArrayDouble::New()); addPts->alloc(0,1);
8050 const mcIdType *oldc(_nodal_connec->begin());
8051 const mcIdType *oldci(_nodal_connec_index->begin());
8052 const double *coords(_coords->begin());
8053 for(mcIdType i=0;i<nbOfCells;i++,oldci++,retPt++)
8055 std::vector<mcIdType> a; std::vector<double> b;
8056 INTERP_KERNEL::SplitIntoTetras(pol,(INTERP_KERNEL::NormalizedCellType)oldc[oldci[0]],oldc+oldci[0]+1,oldc+oldci[1],coords,a,b);
8057 std::size_t nbOfTet(a.size()/4); *retPt=ToIdType(nbOfTet);
8058 const mcIdType *aa(&a[0]);
8061 for(std::vector<mcIdType>::iterator it=a.begin();it!=a.end();it++)
8063 *it=(-(*(it))-1+nbNodes);
8064 addPts->insertAtTheEnd(b.begin(),b.end());
8065 nbNodes+=ToIdType(b.size()/3);
8067 for(std::size_t j=0;j<nbOfTet;j++,aa+=4)
8068 newConn->insertAtTheEnd(aa,aa+4);
8070 if(!addPts->empty())
8072 addPts->rearrange(3);
8073 nbOfAdditionalPoints=addPts->getNumberOfTuples();
8074 addPts=DataArrayDouble::Aggregate(getCoords(),addPts);
8075 ret0->setCoords(addPts);
8079 nbOfAdditionalPoints=0;
8080 ret0->setCoords(getCoords());
8082 ret0->setNodalConnectivity(newConn);
8084 ret->computeOffsetsFull();
8085 n2oCells=ret->buildExplicitArrOfSliceOnScaledArr(0,nbOfCells,1);
8089 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),
8090 _own_cell(true),_cell_id(-1),_nb_cell(0)
8095 _nb_cell=mesh->getNumberOfCells();
8099 MEDCouplingUMeshCellIterator::~MEDCouplingUMeshCellIterator()
8107 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh, MEDCouplingUMeshCell *itc, mcIdType bg, mcIdType end):_mesh(mesh),_cell(itc),
8108 _own_cell(false),_cell_id(bg-1),
8115 MEDCouplingUMeshCell *MEDCouplingUMeshCellIterator::nextt()
8118 if(_cell_id<_nb_cell)
8127 MEDCouplingUMeshCellByTypeEntry::MEDCouplingUMeshCellByTypeEntry(MEDCouplingUMesh *mesh):_mesh(mesh)
8133 MEDCouplingUMeshCellByTypeIterator *MEDCouplingUMeshCellByTypeEntry::iterator()
8135 return new MEDCouplingUMeshCellByTypeIterator(_mesh);
8138 MEDCouplingUMeshCellByTypeEntry::~MEDCouplingUMeshCellByTypeEntry()
8144 MEDCouplingUMeshCellEntry::MEDCouplingUMeshCellEntry(MEDCouplingUMesh *mesh, INTERP_KERNEL::NormalizedCellType type, MEDCouplingUMeshCell *itc, mcIdType bg, mcIdType end):_mesh(mesh),_type(type),
8152 MEDCouplingUMeshCellEntry::~MEDCouplingUMeshCellEntry()
8158 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCellEntry::getType() const
8163 mcIdType MEDCouplingUMeshCellEntry::getNumberOfElems() const
8168 MEDCouplingUMeshCellIterator *MEDCouplingUMeshCellEntry::iterator()
8170 return new MEDCouplingUMeshCellIterator(_mesh,_itc,_bg,_end);
8173 MEDCouplingUMeshCellByTypeIterator::MEDCouplingUMeshCellByTypeIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),_cell_id(0),_nb_cell(0)
8178 _nb_cell=mesh->getNumberOfCells();
8182 MEDCouplingUMeshCellByTypeIterator::~MEDCouplingUMeshCellByTypeIterator()
8189 MEDCouplingUMeshCellEntry *MEDCouplingUMeshCellByTypeIterator::nextt()
8191 const mcIdType *c=_mesh->getNodalConnectivity()->begin();
8192 const mcIdType *ci=_mesh->getNodalConnectivityIndex()->begin();
8193 if(_cell_id<_nb_cell)
8195 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[_cell_id]];
8196 mcIdType nbOfElems=ToIdType(std::distance(ci+_cell_id,std::find_if(ci+_cell_id,ci+_nb_cell,MEDCouplingImpl::ConnReader(c,type))));
8197 mcIdType startId=_cell_id;
8198 _cell_id+=nbOfElems;
8199 return new MEDCouplingUMeshCellEntry(_mesh,type,_cell,startId,_cell_id);
8205 MEDCouplingUMeshCell::MEDCouplingUMeshCell(MEDCouplingUMesh *mesh):_conn(0),_conn_indx(0),_conn_lgth(NOTICABLE_FIRST_VAL)
8209 _conn=mesh->getNodalConnectivity()->getPointer();
8210 _conn_indx=mesh->getNodalConnectivityIndex()->getPointer();
8214 void MEDCouplingUMeshCell::next()
8216 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8221 _conn_lgth=_conn_indx[1]-_conn_indx[0];
8224 std::string MEDCouplingUMeshCell::repr() const
8226 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8228 std::ostringstream oss; oss << "Cell Type " << INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)_conn[0]).getRepr();
8230 std::copy(_conn+1,_conn+_conn_lgth,std::ostream_iterator<mcIdType>(oss," "));
8234 return std::string("MEDCouplingUMeshCell::repr : Invalid pos");
8237 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCell::getType() const
8239 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8240 return (INTERP_KERNEL::NormalizedCellType)_conn[0];
8242 return INTERP_KERNEL::NORM_ERROR;
8245 const mcIdType *MEDCouplingUMeshCell::getAllConn(mcIdType& lgth) const
8248 if(_conn_lgth!=NOTICABLE_FIRST_VAL)