1 // Copyright (C) 2007-2020 CEA/DEN, EDF R&D
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 // Author : Anthony Geay (EDF R&D)
21 #include "MEDCouplingUMesh.txx"
22 #include "MEDCouplingCMesh.hxx"
23 #include "MEDCoupling1GTUMesh.hxx"
24 #include "MEDCouplingFieldDouble.hxx"
25 #include "MEDCouplingSkyLineArray.hxx"
26 #include "CellModel.hxx"
27 #include "VolSurfUser.txx"
28 #include "InterpolationUtils.hxx"
29 #include "PointLocatorAlgos.txx"
31 #include "BBTreeDst.txx"
32 #include "SplitterTetra.hxx"
33 #include "DiameterCalculator.hxx"
34 #include "DirectedBoundingBox.hxx"
35 #include "InterpKernelMatrixTools.hxx"
36 #include "InterpKernelMeshQuality.hxx"
37 #include "InterpKernelCellSimplify.hxx"
38 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
39 #include "InterpKernelAutoPtr.hxx"
40 #include "InterpKernelGeo2DNode.hxx"
41 #include "InterpKernelGeo2DEdgeLin.hxx"
42 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
43 #include "InterpKernelGeo2DQuadraticPolygon.hxx"
44 #include "OrientationInverter.hxx"
45 #include "MEDCouplingUMesh_internal.hxx"
55 using namespace MEDCoupling;
57 double MEDCouplingUMesh::EPS_FOR_POLYH_ORIENTATION=1.e-14;
61 const INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::MEDMEM_ORDER[N_MEDMEM_ORDER] = { INTERP_KERNEL::NORM_POINT1, INTERP_KERNEL::NORM_SEG2, INTERP_KERNEL::NORM_SEG3, INTERP_KERNEL::NORM_SEG4, INTERP_KERNEL::NORM_POLYL, INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4, INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_TRI7, INTERP_KERNEL::NORM_QUAD8, INTERP_KERNEL::NORM_QUAD9, INTERP_KERNEL::NORM_POLYGON, INTERP_KERNEL::NORM_QPOLYG, INTERP_KERNEL::NORM_TETRA4, INTERP_KERNEL::NORM_PYRA5, INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXA8, INTERP_KERNEL::NORM_HEXGP12, INTERP_KERNEL::NORM_TETRA10, INTERP_KERNEL::NORM_PYRA13, INTERP_KERNEL::NORM_PENTA15, INTERP_KERNEL::NORM_PENTA18, INTERP_KERNEL::NORM_HEXA20, INTERP_KERNEL::NORM_HEXA27, INTERP_KERNEL::NORM_POLYHED };
64 MEDCouplingUMesh *MEDCouplingUMesh::New()
66 return new MEDCouplingUMesh;
69 MEDCouplingUMesh *MEDCouplingUMesh::New(const std::string& meshName, int meshDim)
71 MEDCouplingUMesh *ret=new MEDCouplingUMesh;
72 ret->setName(meshName);
73 ret->setMeshDimension(meshDim);
78 * Returns a new MEDCouplingUMesh which is a full copy of \a this one. No data is shared
79 * between \a this and the new mesh.
80 * \return MEDCouplingUMesh * - a new instance of MEDCouplingMesh. The caller is to
81 * delete this mesh using decrRef() as it is no more needed.
83 MEDCouplingUMesh *MEDCouplingUMesh::deepCopy() const
90 * Returns a new MEDCouplingUMesh which is a copy of \a this one.
91 * \param [in] recDeepCpy - if \a true, the copy is deep, else all data arrays of \a
92 * this mesh are shared by the new mesh.
93 * \return MEDCouplingUMesh * - a new instance of MEDCouplingMesh. The caller is to
94 * delete this mesh using decrRef() as it is no more needed.
96 MEDCouplingUMesh *MEDCouplingUMesh::clone(bool recDeepCpy) const
98 return new MEDCouplingUMesh(*this,recDeepCpy);
102 * This method behaves mostly like MEDCouplingUMesh::deepCopy method, except that only nodal connectivity arrays are deeply copied.
103 * The coordinates are shared between \a this and the returned instance.
105 * \return MEDCouplingUMesh * - A new object instance holding the copy of \a this (deep for connectivity, shallow for coordiantes)
106 * \sa MEDCouplingUMesh::deepCopy
108 MEDCouplingUMesh *MEDCouplingUMesh::deepCopyConnectivityOnly() const
110 checkConnectivityFullyDefined();
111 MCAuto<MEDCouplingUMesh> ret=clone(false);
112 MCAuto<DataArrayIdType> c(getNodalConnectivity()->deepCopy()),ci(getNodalConnectivityIndex()->deepCopy());
113 ret->setConnectivity(c,ci);
117 void MEDCouplingUMesh::shallowCopyConnectivityFrom(const MEDCouplingPointSet *other)
120 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is null !");
121 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
123 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is not an MEDCouplingUMesh instance !");
124 MEDCouplingUMesh *otherC2=const_cast<MEDCouplingUMesh *>(otherC);//sorry :(
125 setConnectivity(otherC2->getNodalConnectivity(),otherC2->getNodalConnectivityIndex(),true);
128 std::size_t MEDCouplingUMesh::getHeapMemorySizeWithoutChildren() const
130 std::size_t ret(MEDCouplingPointSet::getHeapMemorySizeWithoutChildren());
134 std::vector<const BigMemoryObject *> MEDCouplingUMesh::getDirectChildrenWithNull() const
136 std::vector<const BigMemoryObject *> ret(MEDCouplingPointSet::getDirectChildrenWithNull());
137 ret.push_back(_nodal_connec);
138 ret.push_back(_nodal_connec_index);
142 void MEDCouplingUMesh::updateTime() const
144 MEDCouplingPointSet::updateTime();
147 updateTimeWith(*_nodal_connec);
149 if(_nodal_connec_index)
151 updateTimeWith(*_nodal_connec_index);
155 MEDCouplingUMesh::MEDCouplingUMesh():_mesh_dim(-2),_nodal_connec(0),_nodal_connec_index(0)
160 * Checks if \a this mesh is well defined. If no exception is thrown by this method,
161 * then \a this mesh is most probably is writable, exchangeable and available for most
162 * of algorithms. When a mesh is constructed from scratch, it is a good habit to call
163 * this method to check that all is in order with \a this mesh.
164 * \throw If the mesh dimension is not set.
165 * \throw If the coordinates array is not set (if mesh dimension != -1 ).
166 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
167 * \throw If the connectivity data array has more than one component.
168 * \throw If the connectivity data array has a named component.
169 * \throw If the connectivity index data array has more than one component.
170 * \throw If the connectivity index data array has a named component.
172 void MEDCouplingUMesh::checkConsistencyLight() const
175 throw INTERP_KERNEL::Exception("No mesh dimension specified !");
177 MEDCouplingPointSet::checkConsistencyLight();
178 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
180 if(ToIdType(INTERP_KERNEL::CellModel::GetCellModel(*iter).getDimension())!=_mesh_dim)
182 std::ostringstream message;
183 message << "Mesh invalid because dimension is " << _mesh_dim << " and there is presence of cell(s) with type " << (*iter);
184 throw INTERP_KERNEL::Exception(message.str().c_str());
189 if(_nodal_connec->getNumberOfComponents()!=1)
190 throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to be with number of components set to one !");
191 if(_nodal_connec->getInfoOnComponent(0)!="")
192 throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to have no info on its single component !");
196 throw INTERP_KERNEL::Exception("Nodal connectivity array is not defined !");
197 if(_nodal_connec_index)
199 if(_nodal_connec_index->getNumberOfComponents()!=1)
200 throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to be with number of components set to one !");
201 if(_nodal_connec_index->getInfoOnComponent(0)!="")
202 throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to have no info on its single component !");
206 throw INTERP_KERNEL::Exception("Nodal connectivity index array is not defined !");
210 * Checks if \a this mesh is well defined. If no exception is thrown by this method,
211 * then \a this mesh is most probably is writable, exchangeable and available for all
212 * algorithms. <br> In addition to the checks performed by checkConsistencyLight(), this
213 * method thoroughly checks the nodal connectivity.
214 * \param [in] eps - a not used parameter.
215 * \throw If the mesh dimension is not set.
216 * \throw If the coordinates array is not set (if mesh dimension != -1 ).
217 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
218 * \throw If the connectivity data array has more than one component.
219 * \throw If the connectivity data array has a named component.
220 * \throw If the connectivity index data array has more than one component.
221 * \throw If the connectivity index data array has a named component.
222 * \throw If number of nodes defining an element does not correspond to the type of element.
223 * \throw If the nodal connectivity includes an invalid node id.
225 void MEDCouplingUMesh::checkConsistency(double eps) const
227 checkConsistencyLight();
230 int meshDim=getMeshDimension();
231 mcIdType nbOfNodes=getNumberOfNodes();
232 mcIdType nbOfCells=getNumberOfCells();
233 const mcIdType *ptr=_nodal_connec->getConstPointer();
234 const mcIdType *ptrI=_nodal_connec_index->getConstPointer();
235 for(mcIdType i=0;i<nbOfCells;i++)
237 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)ptr[ptrI[i]]);
238 if(ToIdType(cm.getDimension())!=meshDim)
240 std::ostringstream oss;
241 oss << "MEDCouplingUMesh::checkConsistency : cell << #" << i<< " with type Type " << cm.getRepr() << " in 'this' whereas meshdim == " << meshDim << " !";
242 throw INTERP_KERNEL::Exception(oss.str());
244 mcIdType nbOfNodesInCell=ptrI[i+1]-ptrI[i]-1;
246 if(nbOfNodesInCell!=ToIdType(cm.getNumberOfNodes()))
248 std::ostringstream oss;
249 oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with static Type '" << cm.getRepr() << "' has " << cm.getNumberOfNodes();
250 oss << " nodes whereas in connectivity there is " << nbOfNodesInCell << " nodes ! Looks very bad !";
251 throw INTERP_KERNEL::Exception(oss.str());
253 if(cm.isQuadratic() && cm.isDynamic() && meshDim == 2)
254 if (nbOfNodesInCell % 2 || nbOfNodesInCell < 4)
256 std::ostringstream oss;
257 oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with quadratic type '" << cm.getRepr() << "' has " << nbOfNodesInCell;
258 oss << " nodes. This should be even, and greater or equal than 4!! Looks very bad!";
259 throw INTERP_KERNEL::Exception(oss.str());
261 for(const mcIdType *w=ptr+ptrI[i]+1;w!=ptr+ptrI[i+1];w++)
266 if(nodeId>=nbOfNodes)
268 std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " whereas there are only " << nbOfNodes << " nodes in the mesh !";
269 throw INTERP_KERNEL::Exception(oss.str());
274 std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " in connectivity ! sounds bad !";
275 throw INTERP_KERNEL::Exception(oss.str());
279 if((INTERP_KERNEL::NormalizedCellType)(ptr[ptrI[i]])!=INTERP_KERNEL::NORM_POLYHED)
281 std::ostringstream oss; oss << "Cell #" << i << " is built with node #-1 in connectivity ! sounds bad !";
282 throw INTERP_KERNEL::Exception(oss.str());
290 * Sets dimension of \a this mesh. The mesh dimension in general depends on types of
291 * elements contained in the mesh. For more info on the mesh dimension see
292 * \ref MEDCouplingUMeshPage.
293 * \param [in] meshDim - a new mesh dimension.
294 * \throw If \a meshDim is invalid. A valid range is <em> -1 <= meshDim <= 3</em>.
296 void MEDCouplingUMesh::setMeshDimension(int meshDim)
298 if(meshDim<-1 || meshDim>3)
299 throw INTERP_KERNEL::Exception("Invalid meshDim specified ! Must be greater or equal to -1 and lower or equal to 3 !");
305 * Allocates memory to store an estimation of the given number of cells.
306 * The closer the estimation to the number of cells effectively inserted, the less need the library requires
307 * to reallocate memory. If the number of cells to be inserted is not known simply assign 0 to this parameter.
308 * If a nodal connectivity previously existed before the call of this method, it will be reset.
310 * \param [in] nbOfCells - estimation of the number of cell \a this mesh will contain.
312 * \if ENABLE_EXAMPLES
313 * \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
314 * \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
317 void MEDCouplingUMesh::allocateCells(mcIdType nbOfCells)
320 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::allocateCells : the input number of cells should be >= 0 !");
321 if(_nodal_connec_index)
323 _nodal_connec_index->decrRef();
327 _nodal_connec->decrRef();
329 _nodal_connec_index=DataArrayIdType::New();
330 _nodal_connec_index->reserve(nbOfCells+1);
331 _nodal_connec_index->pushBackSilent(0);
332 _nodal_connec=DataArrayIdType::New();
333 _nodal_connec->reserve(2*nbOfCells);
339 * Appends a cell to the connectivity array. For deeper understanding what is
340 * happening see \ref MEDCouplingUMeshNodalConnectivity.
341 * \param [in] type - type of cell to add.
342 * \param [in] size - number of nodes constituting this cell.
343 * \param [in] nodalConnOfCell - the connectivity of the cell to add.
345 * \if ENABLE_EXAMPLES
346 * \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
347 * \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
350 void MEDCouplingUMesh::insertNextCell(INTERP_KERNEL::NormalizedCellType type, mcIdType size, const mcIdType *nodalConnOfCell)
352 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
353 if(_nodal_connec_index==0)
354 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::insertNextCell : nodal connectivity not set ! invoke allocateCells before calling insertNextCell !");
355 if(ToIdType(cm.getDimension())==_mesh_dim)
358 if(size!=ToIdType(cm.getNumberOfNodes()))
360 std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : Trying to push a " << cm.getRepr() << " cell with a size of " << size;
361 oss << " ! Expecting " << cm.getNumberOfNodes() << " !";
362 throw INTERP_KERNEL::Exception(oss.str());
364 mcIdType idx=_nodal_connec_index->back();
365 mcIdType val=idx+size+1;
366 _nodal_connec_index->pushBackSilent(val);
367 _nodal_connec->writeOnPlace(idx,type,nodalConnOfCell,size);
372 std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : cell type " << cm.getRepr() << " has a dimension " << cm.getDimension();
373 oss << " whereas Mesh Dimension of current UMesh instance is set to " << _mesh_dim << " ! Please invoke \"setMeshDimension\" method before or invoke ";
374 oss << "\"MEDCouplingUMesh::New\" static method with 2 parameters name and meshDimension !";
375 throw INTERP_KERNEL::Exception(oss.str());
380 * Compacts data arrays to release unused memory. This method is to be called after
381 * finishing cell insertion using \a this->insertNextCell().
383 * \if ENABLE_EXAMPLES
384 * \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
385 * \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
388 void MEDCouplingUMesh::finishInsertingCells()
390 _nodal_connec->pack();
391 _nodal_connec_index->pack();
392 _nodal_connec->declareAsNew();
393 _nodal_connec_index->declareAsNew();
398 * Entry point for iteration over cells of this. Warning the returned cell iterator should be deallocated.
399 * Useful for python users.
401 MEDCouplingUMeshCellIterator *MEDCouplingUMesh::cellIterator()
403 return new MEDCouplingUMeshCellIterator(this);
407 * Entry point for iteration over cells groups geo types per geotypes. Warning the returned cell iterator should be deallocated.
408 * If \a this is not so that the cells are grouped by geo types, this method will throw an exception.
409 * In this case MEDCouplingUMesh::sortCellsInMEDFileFrmt or MEDCouplingUMesh::rearrange2ConsecutiveCellTypes methods for example can be called before invoking this method.
410 * Useful for python users.
412 MEDCouplingUMeshCellByTypeEntry *MEDCouplingUMesh::cellsByType()
414 if(!checkConsecutiveCellTypes())
415 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::cellsByType : this mesh is not sorted by type !");
416 return new MEDCouplingUMeshCellByTypeEntry(this);
420 * Returns a set of all cell types available in \a this mesh.
421 * \return std::set<INTERP_KERNEL::NormalizedCellType> - the set of cell types.
422 * \warning this method does not throw any exception even if \a this is not defined.
423 * \sa MEDCouplingUMesh::getAllGeoTypesSorted
425 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypes() const
431 * This method returns the sorted list of geometric types in \a this.
432 * Sorted means in the same order than the cells in \a this. A single entry in return vector means the maximal chunk of consecutive cells in \a this
433 * having the same geometric type. So a same geometric type can appear more than once if the cells are not sorted per geometric type.
435 * \throw if connectivity in \a this is not correctly defined.
437 * \sa MEDCouplingMesh::getAllGeoTypes
439 std::vector<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypesSorted() const
441 std::vector<INTERP_KERNEL::NormalizedCellType> ret;
442 checkConnectivityFullyDefined();
443 mcIdType nbOfCells=getNumberOfCells();
446 if(getNodalConnectivityArrayLen()<1)
447 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAllGeoTypesSorted : the connectivity in this seems invalid !");
448 const mcIdType *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin());
449 ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci++]);
450 for(mcIdType i=1;i<nbOfCells;i++,ci++)
451 if(ret.back()!=((INTERP_KERNEL::NormalizedCellType)c[*ci]))
452 ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci]);
457 * This method is a method that compares \a this and \a other.
458 * This method compares \b all attributes, even names and component names.
460 bool MEDCouplingUMesh::isEqualIfNotWhy(const MEDCouplingMesh *other, double prec, std::string& reason) const
463 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isEqualIfNotWhy : input other pointer is null !");
464 std::ostringstream oss; oss.precision(15);
465 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
468 reason="mesh given in input is not castable in MEDCouplingUMesh !";
471 if(!MEDCouplingPointSet::isEqualIfNotWhy(other,prec,reason))
473 if(_mesh_dim!=otherC->_mesh_dim)
475 oss << "umesh dimension mismatch : this mesh dimension=" << _mesh_dim << " other mesh dimension=" << otherC->_mesh_dim;
479 if(_types!=otherC->_types)
481 oss << "umesh geometric type mismatch :\nThis geometric types are :";
482 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
483 { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
484 oss << "\nOther geometric types are :";
485 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=otherC->_types.begin();iter!=otherC->_types.end();iter++)
486 { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
490 if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
491 if(_nodal_connec==0 || otherC->_nodal_connec==0)
493 reason="Only one UMesh between the two this and other has its nodal connectivity DataArrayInt defined !";
496 if(_nodal_connec!=otherC->_nodal_connec)
497 if(!_nodal_connec->isEqualIfNotWhy(*otherC->_nodal_connec,reason))
499 reason.insert(0,"Nodal connectivity DataArrayInt differ : ");
502 if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
503 if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
505 reason="Only one UMesh between the two this and other has its nodal connectivity index DataArrayInt defined !";
508 if(_nodal_connec_index!=otherC->_nodal_connec_index)
509 if(!_nodal_connec_index->isEqualIfNotWhy(*otherC->_nodal_connec_index,reason))
511 reason.insert(0,"Nodal connectivity index DataArrayInt differ : ");
518 * Checks if data arrays of this mesh (node coordinates, nodal
519 * connectivity of cells, etc) of two meshes are same. Textual data like name etc. are
521 * \param [in] other - the mesh to compare with.
522 * \param [in] prec - precision value used to compare node coordinates.
523 * \return bool - \a true if the two meshes are same.
525 bool MEDCouplingUMesh::isEqualWithoutConsideringStr(const MEDCouplingMesh *other, double prec) const
527 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
530 if(!MEDCouplingPointSet::isEqualWithoutConsideringStr(other,prec))
532 if(_mesh_dim!=otherC->_mesh_dim)
534 if(_types!=otherC->_types)
536 if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
537 if(_nodal_connec==0 || otherC->_nodal_connec==0)
539 if(_nodal_connec!=otherC->_nodal_connec)
540 if(!_nodal_connec->isEqualWithoutConsideringStr(*otherC->_nodal_connec))
542 if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
543 if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
545 if(_nodal_connec_index!=otherC->_nodal_connec_index)
546 if(!_nodal_connec_index->isEqualWithoutConsideringStr(*otherC->_nodal_connec_index))
552 * Checks if \a this and \a other meshes are geometrically equivalent with high
553 * probability, else an exception is thrown. The meshes are considered equivalent if
554 * (1) meshes contain the same number of nodes and the same number of elements of the
555 * same types (2) three cells of the two meshes (first, last and middle) are based
556 * on coincident nodes (with a specified precision).
557 * \param [in] other - the mesh to compare with.
558 * \param [in] prec - the precision used to compare nodes of the two meshes.
559 * \throw If the two meshes do not match.
561 void MEDCouplingUMesh::checkFastEquivalWith(const MEDCouplingMesh *other, double prec) const
563 MEDCouplingPointSet::checkFastEquivalWith(other,prec);
564 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
566 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkFastEquivalWith : Two meshes are not not unstructured !");
570 * Returns the reverse nodal connectivity. The reverse nodal connectivity enumerates
571 * cells each node belongs to.
572 * \warning For speed reasons, this method does not check if node ids in the nodal
573 * connectivity correspond to the size of node coordinates array.
574 * \param [in,out] revNodal - an array holding ids of cells sharing each node.
575 * \param [in,out] revNodalIndx - an array, of length \a this->getNumberOfNodes() + 1,
576 * dividing cell ids in \a revNodal into groups each referring to one
577 * node. Its every element (except the last one) is an index pointing to the
578 * first id of a group of cells. For example cells sharing the node #1 are
579 * described by following range of indices:
580 * [ \a revNodalIndx[1], \a revNodalIndx[2] ) and the cell ids are
581 * \a revNodal[ \a revNodalIndx[1] ], \a revNodal[ \a revNodalIndx[1] + 1], ...
582 * Number of cells sharing the *i*-th node is
583 * \a revNodalIndx[ *i*+1 ] - \a revNodalIndx[ *i* ].
584 * \throw If the coordinates array is not set.
585 * \throw If the nodal connectivity of cells is not defined.
587 * \if ENABLE_EXAMPLES
588 * \ref cpp_mcumesh_getReverseNodalConnectivity "Here is a C++ example".<br>
589 * \ref py_mcumesh_getReverseNodalConnectivity "Here is a Python example".
592 void MEDCouplingUMesh::getReverseNodalConnectivity(DataArrayIdType *revNodal, DataArrayIdType *revNodalIndx) const
595 mcIdType nbOfNodes(getNumberOfNodes());
596 mcIdType *revNodalIndxPtr=(mcIdType *)malloc((nbOfNodes+1)*sizeof(mcIdType));
597 revNodalIndx->useArray(revNodalIndxPtr,true,DeallocType::C_DEALLOC,nbOfNodes+1,1);
598 std::fill(revNodalIndxPtr,revNodalIndxPtr+nbOfNodes+1,0);
599 const mcIdType *conn(_nodal_connec->begin()),*connIndex(_nodal_connec_index->begin());
600 mcIdType nbOfCells(getNumberOfCells()),nbOfEltsInRevNodal(0);
601 for(mcIdType eltId=0;eltId<nbOfCells;eltId++)
603 const mcIdType *strtNdlConnOfCurCell(conn+connIndex[eltId]+1),*endNdlConnOfCurCell(conn+connIndex[eltId+1]);
604 for(const mcIdType *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
605 if(*iter>=0)//for polyhedrons
607 nbOfEltsInRevNodal++;
608 revNodalIndxPtr[(*iter)+1]++;
611 std::transform(revNodalIndxPtr+1,revNodalIndxPtr+nbOfNodes+1,revNodalIndxPtr,revNodalIndxPtr+1,std::plus<mcIdType>());
612 mcIdType *revNodalPtr=(mcIdType *)malloc(nbOfEltsInRevNodal*sizeof(mcIdType));
613 revNodal->useArray(revNodalPtr,true,DeallocType::C_DEALLOC,nbOfEltsInRevNodal,1);
614 std::fill(revNodalPtr,revNodalPtr+nbOfEltsInRevNodal,-1);
615 for(mcIdType eltId=0;eltId<nbOfCells;eltId++)
617 const mcIdType *strtNdlConnOfCurCell=conn+connIndex[eltId]+1;
618 const mcIdType *endNdlConnOfCurCell=conn+connIndex[eltId+1];
619 for(const mcIdType *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
620 if(*iter>=0)//for polyhedrons
621 *std::find_if(revNodalPtr+revNodalIndxPtr[*iter],revNodalPtr+revNodalIndxPtr[*iter+1],std::bind2nd(std::equal_to<mcIdType>(),-1))=eltId;
626 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
627 * this->getMeshDimension(), that bound cells of \a this mesh. In addition arrays
628 * describing correspondence between cells of \a this and the result meshes are
629 * returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending connectivity,
630 * i.e. enumerate cells of the result mesh bounding each cell of \a this mesh. The
631 * arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
632 * i.e. enumerate cells of \a this mesh bounded by each cell of the result mesh.
633 * \warning For speed reasons, this method does not check if node ids in the nodal
634 * connectivity correspond to the size of node coordinates array.
635 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
636 * to write this mesh to the MED file, its cells must be sorted using
637 * sortCellsInMEDFileFrmt().
638 * \param [in,out] desc - the array containing cell ids of the result mesh bounding
639 * each cell of \a this mesh.
640 * \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
641 * dividing cell ids in \a desc into groups each referring to one
642 * cell of \a this mesh. Its every element (except the last one) is an index
643 * pointing to the first id of a group of cells. For example cells of the
644 * result mesh bounding the cell #1 of \a this mesh are described by following
646 * [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
647 * \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
648 * Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
649 * \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
650 * \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
651 * by each cell of the result mesh.
652 * \param [in,out] revDescIndx - the array, of length one more than number of cells
653 * in the result mesh,
654 * dividing cell ids in \a revDesc into groups each referring to one
655 * cell of the result mesh the same way as \a descIndx divides \a desc.
656 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is to
657 * delete this mesh using decrRef() as it is no more needed.
658 * \throw If the coordinates array is not set.
659 * \throw If the nodal connectivity of cells is node defined.
660 * \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
661 * revDescIndx == NULL.
663 * \if ENABLE_EXAMPLES
664 * \ref cpp_mcumesh_buildDescendingConnectivity "Here is a C++ example".<br>
665 * \ref py_mcumesh_buildDescendingConnectivity "Here is a Python example".
667 * \sa buildDescendingConnectivity2()
669 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
671 return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
675 * \a this has to have a mesh dimension equal to 3. If it is not the case an INTERP_KERNEL::Exception will be thrown.
676 * This behaves exactly as MEDCouplingUMesh::buildDescendingConnectivity does except that this method compute directly the transition from mesh dimension 3 to sub edges (dimension 1)
677 * in one shot. That is to say that this method is equivalent to 2 successive calls to MEDCouplingUMesh::buildDescendingConnectivity.
678 * This method returns 4 arrays and a mesh as MEDCouplingUMesh::buildDescendingConnectivity does.
679 * \sa MEDCouplingUMesh::buildDescendingConnectivity
681 MEDCouplingUMesh *MEDCouplingUMesh::explode3DMeshTo1D(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
684 if(getMeshDimension()!=3)
685 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explode3DMeshTo1D : This has to have a mesh dimension to 3 !");
686 return buildDescendingConnectivityGen<MinusTwoSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
690 * This method computes the micro edges constituting each cell in \a this. Micro edge is an edge for non quadratic cells. Micro edge is an half edge for quadratic cells.
691 * This method works for both meshes with mesh dimension equal to 2 or 3. Dynamical cells are not supported (polygons, polyhedrons...)
693 * \sa explode3DMeshTo1D, buildDescendingConnectiviy
695 MEDCouplingUMesh *MEDCouplingUMesh::explodeMeshIntoMicroEdges(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
698 switch(getMeshDimension())
701 return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
703 return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
705 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explodeMeshIntoMicroEdges : Only 2D and 3D supported !");
710 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
711 * this->getMeshDimension(), that bound cells of \a this mesh. In
712 * addition arrays describing correspondence between cells of \a this and the result
713 * meshes are returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending
714 * connectivity, i.e. enumerate cells of the result mesh bounding each cell of \a this
715 * mesh. This method differs from buildDescendingConnectivity() in that apart
716 * from cell ids, \a desc returns mutual orientation of cells in \a this and the
717 * result meshes. So a positive id means that order of nodes in corresponding cells
718 * of two meshes is same, and a negative id means a reverse order of nodes. Since a
719 * cell with id #0 can't be negative, the array \a desc returns ids in FORTRAN mode,
720 * i.e. cell ids are one-based.
721 * Arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
722 * i.e. enumerate cells of \a this mesh bounded by each cell of the result mesh.
723 * \warning For speed reasons, this method does not check if node ids in the nodal
724 * connectivity correspond to the size of node coordinates array.
725 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
726 * to write this mesh to the MED file, its cells must be sorted using
727 * sortCellsInMEDFileFrmt().
728 * \param [in,out] desc - the array containing cell ids of the result mesh bounding
729 * each cell of \a this mesh.
730 * \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
731 * dividing cell ids in \a desc into groups each referring to one
732 * cell of \a this mesh. Its every element (except the last one) is an index
733 * pointing to the first id of a group of cells. For example cells of the
734 * result mesh bounding the cell #1 of \a this mesh are described by following
736 * [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
737 * \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
738 * Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
739 * \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
740 * \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
741 * by each cell of the result mesh.
742 * \param [in,out] revDescIndx - the array, of length one more than number of cells
743 * in the result mesh,
744 * dividing cell ids in \a revDesc into groups each referring to one
745 * cell of the result mesh the same way as \a descIndx divides \a desc.
746 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This result mesh
747 * shares the node coordinates array with \a this mesh. The caller is to
748 * delete this mesh using decrRef() as it is no more needed.
749 * \throw If the coordinates array is not set.
750 * \throw If the nodal connectivity of cells is node defined.
751 * \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
752 * revDescIndx == NULL.
754 * \if ENABLE_EXAMPLES
755 * \ref cpp_mcumesh_buildDescendingConnectivity2 "Here is a C++ example".<br>
756 * \ref py_mcumesh_buildDescendingConnectivity2 "Here is a Python example".
758 * \sa buildDescendingConnectivity()
760 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity2(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
762 return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingOrientationSensitiveNbrer);
766 * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
767 * For speed reasons no check of this will be done. This method calls
768 * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
769 * This method lists cell by cell in \b this which are its neighbors. To compute the result
770 * only connectivities are considered.
771 * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
772 * The format of return is hence \ref numbering-indirect.
774 * \param [out] neighbors is an array storing all the neighbors of all cells in \b this. This array is newly
775 * allocated and should be dealt by the caller. \b neighborsIndx 2nd output
776 * parameter allows to select the right part in this array (\ref numbering-indirect). The number of tuples
777 * is equal to the last values in \b neighborsIndx.
778 * \param [out] neighborsIndx is an array of size this->getNumberOfCells()+1 newly allocated and should be
779 * dealt by the caller. This arrays allow to use the first output parameter \b neighbors (\ref numbering-indirect).
781 void MEDCouplingUMesh::computeNeighborsOfCells(DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIndx) const
783 MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
784 MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
785 MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
786 MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
787 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
789 ComputeNeighborsOfCellsAdv(desc,descIndx,revDesc,revDescIndx,neighbors,neighborsIndx);
792 void MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne(const DataArrayIdType *nodeNeigh, const DataArrayIdType *nodeNeighI, MCAuto<DataArrayIdType>& cellNeigh, MCAuto<DataArrayIdType>& cellNeighIndex) const
794 if(!nodeNeigh || !nodeNeighI)
795 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : null pointer !");
796 checkConsistencyLight();
797 nodeNeigh->checkAllocated(); nodeNeighI->checkAllocated();
798 nodeNeigh->checkNbOfComps(1,"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : node neigh");
799 nodeNeighI->checkNbOfComps(1,"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : node neigh index");
800 nodeNeighI->checkNbOfTuples(1+getNumberOfNodes(),"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : invalid length");
801 mcIdType nbCells=getNumberOfCells();
802 const mcIdType *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin()),*ne(nodeNeigh->begin()),*nei(nodeNeighI->begin());
803 cellNeigh=DataArrayIdType::New(); cellNeigh->alloc(0,1); cellNeighIndex=DataArrayIdType::New(); cellNeighIndex->alloc(1,1); cellNeighIndex->setIJ(0,0,0);
804 for(mcIdType i=0;i<nbCells;i++)
806 std::set<mcIdType> s;
807 for(const mcIdType *it=c+ci[i]+1;it!=c+ci[i+1];it++)
809 s.insert(ne+nei[*it],ne+nei[*it+1]);
811 cellNeigh->insertAtTheEnd(s.begin(),s.end());
812 cellNeighIndex->pushBackSilent(cellNeigh->getNumberOfTuples());
817 * This method is called by MEDCouplingUMesh::computeNeighborsOfCells. This methods performs the algorithm
818 * of MEDCouplingUMesh::computeNeighborsOfCells.
819 * This method is useful for users that want to reduce along a criterion the set of neighbours cell. This is
820 * typically the case to extract a set a neighbours,
821 * excluding a set of meshdim-1 cells in input descending connectivity.
822 * Typically \b desc, \b descIndx, \b revDesc and \b revDescIndx (\ref numbering-indirect) input params are
823 * the result of MEDCouplingUMesh::buildDescendingConnectivity.
824 * This method lists cell by cell in \b this which are its neighbors. To compute the result only connectivities
826 * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
828 * \param [in] desc descending connectivity array.
829 * \param [in] descIndx descending connectivity index array used to walk through \b desc (\ref numbering-indirect).
830 * \param [in] revDesc reverse descending connectivity array.
831 * \param [in] revDescIndx reverse descending connectivity index array used to walk through \b revDesc (\ref numbering-indirect).
832 * \param [out] neighbors is an array storing all the neighbors of all cells in \b this. This array is newly allocated and should be dealt by the caller. \b neighborsIndx 2nd output
833 * parameter allows to select the right part in this array. The number of tuples is equal to the last values in \b neighborsIndx.
834 * \param [out] neighborsIndx is an array of size this->getNumberOfCells()+1 newly allocated and should be dealt by the caller. This arrays allow to use the first output parameter \b neighbors.
836 void MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(const DataArrayIdType *desc, const DataArrayIdType *descIndx, const DataArrayIdType *revDesc, const DataArrayIdType *revDescIndx,
837 DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIndx)
839 if(!desc || !descIndx || !revDesc || !revDescIndx)
840 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeNeighborsOfCellsAdv some input array is empty !");
841 const mcIdType *descPtr=desc->begin();
842 const mcIdType *descIPtr=descIndx->begin();
843 const mcIdType *revDescPtr=revDesc->begin();
844 const mcIdType *revDescIPtr=revDescIndx->begin();
846 mcIdType nbCells=descIndx->getNumberOfTuples()-1;
847 MCAuto<DataArrayIdType> out0=DataArrayIdType::New();
848 MCAuto<DataArrayIdType> out1=DataArrayIdType::New(); out1->alloc(nbCells+1,1);
849 mcIdType *out1Ptr=out1->getPointer();
851 out0->reserve(desc->getNumberOfTuples());
852 for(mcIdType i=0;i<nbCells;i++,descIPtr++,out1Ptr++)
854 for(const mcIdType *w1=descPtr+descIPtr[0];w1!=descPtr+descIPtr[1];w1++)
856 std::set<mcIdType> s(revDescPtr+revDescIPtr[*w1],revDescPtr+revDescIPtr[(*w1)+1]);
858 out0->insertAtTheEnd(s.begin(),s.end());
860 *out1Ptr=out0->getNumberOfTuples();
862 neighbors=out0.retn();
863 neighborsIndx=out1.retn();
867 * Explodes \a this into edges whatever its dimension.
869 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::explodeIntoEdges(MCAuto<DataArrayIdType>& desc, MCAuto<DataArrayIdType>& descIndex, MCAuto<DataArrayIdType>& revDesc, MCAuto<DataArrayIdType>& revDescIndx) const
872 int mdim(getMeshDimension());
873 desc=DataArrayIdType::New(); descIndex=DataArrayIdType::New(); revDesc=DataArrayIdType::New(); revDescIndx=DataArrayIdType::New();
874 MCAuto<MEDCouplingUMesh> mesh1D;
879 mesh1D=explode3DMeshTo1D(desc,descIndex,revDesc,revDescIndx);
884 mesh1D=buildDescendingConnectivity(desc,descIndex,revDesc,revDescIndx);
889 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2] !");
896 * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
897 * For speed reasons no check of this will be done. This method calls
898 * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
899 * This method lists node by node in \b this which are its neighbors. To compute the result
900 * only connectivities are considered.
901 * The neighbor nodes of node having id 'nodeId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
903 * \param [out] neighbors is an array storing all the neighbors of all nodes in \b this. This array
904 * is newly allocated and should be dealt by the caller. \b neighborsIndx 2nd output
905 * parameter allows to select the right part in this array (\ref numbering-indirect).
906 * The number of tuples is equal to the last values in \b neighborsIndx.
907 * \param [out] neighborsIdx is an array of size this->getNumberOfCells()+1 newly allocated and should
908 * be dealt by the caller. This arrays allow to use the first output parameter \b neighbors.
910 * \sa MEDCouplingUMesh::computeEnlargedNeighborsOfNodes
912 void MEDCouplingUMesh::computeNeighborsOfNodes(DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIdx) const
915 mcIdType mdim(getMeshDimension()),nbNodes(getNumberOfNodes());
916 MCAuto<DataArrayIdType> desc(DataArrayIdType::New()),descIndx(DataArrayIdType::New()),revDesc(DataArrayIdType::New()),revDescIndx(DataArrayIdType::New());
917 MCConstAuto<MEDCouplingUMesh> mesh1D;
922 mesh1D=explode3DMeshTo1D(desc,descIndx,revDesc,revDescIndx);
927 mesh1D=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
932 mesh1D.takeRef(this);
937 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2,1] !");
940 desc=DataArrayIdType::New(); descIndx=DataArrayIdType::New(); revDesc=0; revDescIndx=0;
941 mesh1D->getReverseNodalConnectivity(desc,descIndx);
942 MCAuto<DataArrayIdType> ret0(DataArrayIdType::New());
943 ret0->alloc(desc->getNumberOfTuples(),1);
944 mcIdType *r0Pt(ret0->getPointer());
945 const mcIdType *c1DPtr(mesh1D->getNodalConnectivity()->begin()),*rn(desc->begin()),*rni(descIndx->begin());
946 for(mcIdType i=0;i<nbNodes;i++,rni++)
948 for(const mcIdType *oneDCellIt=rn+rni[0];oneDCellIt!=rn+rni[1];oneDCellIt++)
949 *r0Pt++=c1DPtr[3*(*oneDCellIt)+1]==i?c1DPtr[3*(*oneDCellIt)+2]:c1DPtr[3*(*oneDCellIt)+1];
951 neighbors=ret0.retn();
952 neighborsIdx=descIndx.retn();
956 * Computes enlarged neighbors for each nodes in \a this. The behavior of this method is close to MEDCouplingUMesh::computeNeighborsOfNodes except that the neighborhood of each node is wider here.
957 * A node j is considered to be in the neighborhood of i if and only if there is a cell in \a this containing in its nodal connectivity both i and j.
958 * This method is useful to find ghost cells of a part of a mesh with a code based on fields on nodes.
960 * \sa MEDCouplingUMesh::computeNeighborsOfNodes
962 void MEDCouplingUMesh::computeEnlargedNeighborsOfNodes(MCAuto<DataArrayIdType> &neighbors, MCAuto<DataArrayIdType>& neighborsIdx) const
965 mcIdType nbOfNodes(getNumberOfNodes());
966 const mcIdType *conn(_nodal_connec->begin()),*connIndex(_nodal_connec_index->begin());
967 mcIdType nbOfCells=getNumberOfCells();
968 std::vector< std::set<mcIdType> > st0(nbOfNodes);
969 for(mcIdType eltId=0;eltId<nbOfCells;eltId++)
971 const mcIdType *strtNdlConnOfCurCell(conn+connIndex[eltId]+1),*endNdlConnOfCurCell(conn+connIndex[eltId+1]);
972 std::set<mcIdType> s(strtNdlConnOfCurCell,endNdlConnOfCurCell); s.erase(-1); //for polyhedrons
973 for(std::set<mcIdType>::const_iterator iter2=s.begin();iter2!=s.end();iter2++)
974 st0[*iter2].insert(s.begin(),s.end());
976 neighborsIdx=DataArrayIdType::New(); neighborsIdx->alloc(nbOfNodes+1,1); neighborsIdx->setIJ(0,0,0);
978 mcIdType *neighIdx(neighborsIdx->getPointer());
979 for(std::vector< std::set<mcIdType> >::const_iterator it=st0.begin();it!=st0.end();it++,neighIdx++)
982 neighIdx[1]=neighIdx[0];
984 neighIdx[1]=neighIdx[0]+ToIdType((*it).size())-1;
987 neighbors=DataArrayIdType::New(); neighbors->alloc(neighborsIdx->back(),1);
989 const mcIdType *neighIdx(neighborsIdx->begin());
990 mcIdType *neigh(neighbors->getPointer()),nodeId(0);
991 for(std::vector< std::set<mcIdType> >::const_iterator it=st0.begin();it!=st0.end();it++,neighIdx++,nodeId++)
993 std::set<mcIdType> s(*it); s.erase(nodeId);
994 std::copy(s.begin(),s.end(),neigh+*neighIdx);
1000 * Converts specified cells to either polygons (if \a this is a 2D mesh) or
1001 * polyhedrons (if \a this is a 3D mesh). The cells to convert are specified by an
1002 * array of cell ids. Pay attention that after conversion all algorithms work slower
1003 * with \a this mesh than before conversion. <br> If an exception is thrown during the
1004 * conversion due presence of invalid ids in the array of cells to convert, as a
1005 * result \a this mesh contains some already converted elements. In this case the 2D
1006 * mesh remains valid but 3D mesh becomes \b inconsistent!
1007 * \warning This method can significantly modify the order of geometric types in \a this,
1008 * hence, to write this mesh to the MED file, its cells must be sorted using
1009 * sortCellsInMEDFileFrmt().
1010 * \param [in] cellIdsToConvertBg - the array holding ids of cells to convert.
1011 * \param [in] cellIdsToConvertEnd - a pointer to the last-plus-one-th element of \a
1012 * cellIdsToConvertBg.
1013 * \throw If the coordinates array is not set.
1014 * \throw If the nodal connectivity of cells is node defined.
1015 * \throw If dimension of \a this mesh is not either 2 or 3.
1017 * \if ENABLE_EXAMPLES
1018 * \ref cpp_mcumesh_convertToPolyTypes "Here is a C++ example".<br>
1019 * \ref py_mcumesh_convertToPolyTypes "Here is a Python example".
1022 void MEDCouplingUMesh::convertToPolyTypes(const mcIdType *cellIdsToConvertBg, const mcIdType *cellIdsToConvertEnd)
1024 checkFullyDefined();
1025 int dim=getMeshDimension();
1027 throw INTERP_KERNEL::Exception("Invalid mesh dimension : must be 2 or 3 !");
1028 mcIdType nbOfCells=getNumberOfCells();
1031 const mcIdType *connIndex=_nodal_connec_index->begin();
1032 mcIdType *conn=_nodal_connec->getPointer();
1033 for(const mcIdType *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1035 if(*iter>=0 && *iter<nbOfCells)
1037 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*iter]]);
1038 if(!cm.isQuadratic())
1039 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_POLYGON;
1041 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_QPOLYG;
1045 std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1046 oss << " in range [0," << nbOfCells << ") !";
1047 throw INTERP_KERNEL::Exception(oss.str());
1053 mcIdType *connIndex(_nodal_connec_index->getPointer());
1054 const mcIdType *connOld(_nodal_connec->getConstPointer());
1055 MCAuto<DataArrayIdType> connNew(DataArrayIdType::New()),connNewI(DataArrayIdType::New()); connNew->alloc(0,1); connNewI->alloc(1,1); connNewI->setIJ(0,0,0);
1056 std::vector<bool> toBeDone(nbOfCells,false);
1057 for(const mcIdType *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1059 if(*iter>=0 && *iter<nbOfCells)
1060 toBeDone[*iter]=true;
1063 std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1064 oss << " in range [0," << nbOfCells << ") !";
1065 throw INTERP_KERNEL::Exception(oss.str());
1068 for(mcIdType cellId=0;cellId<nbOfCells;cellId++)
1070 mcIdType pos(connIndex[cellId]),posP1(connIndex[cellId+1]);
1071 mcIdType lgthOld(posP1-pos-1);
1072 if(toBeDone[cellId])
1074 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connOld[pos]);
1075 unsigned nbOfFaces(cm.getNumberOfSons2(connOld+pos+1,lgthOld));
1076 mcIdType *tmp(new mcIdType[nbOfFaces*lgthOld+1]);
1077 mcIdType *work=tmp; *work++=INTERP_KERNEL::NORM_POLYHED;
1078 for(unsigned j=0;j<nbOfFaces;j++)
1080 INTERP_KERNEL::NormalizedCellType type;
1081 unsigned offset=cm.fillSonCellNodalConnectivity2(j,connOld+pos+1,lgthOld,work,type);
1085 std::size_t newLgth(std::distance(tmp,work)-1);//-1 for last -1
1086 connNew->pushBackValsSilent(tmp,tmp+newLgth);
1087 connNewI->pushBackSilent(connNewI->back()+ToIdType(newLgth));
1092 connNew->pushBackValsSilent(connOld+pos,connOld+posP1);
1093 connNewI->pushBackSilent(connNewI->back()+posP1-pos);
1096 setConnectivity(connNew,connNewI,false);//false because computeTypes called just behind.
1102 * Converts all cells to either polygons (if \a this is a 2D mesh) or
1103 * polyhedrons (if \a this is a 3D mesh).
1104 * \warning As this method is purely for user-friendliness and no optimization is
1105 * done to avoid construction of a useless vector, this method can be costly
1107 * \throw If the coordinates array is not set.
1108 * \throw If the nodal connectivity of cells is node defined.
1109 * \throw If dimension of \a this mesh is not either 2 or 3.
1111 void MEDCouplingUMesh::convertAllToPoly()
1113 mcIdType nbOfCells=getNumberOfCells();
1114 std::vector<mcIdType> cellIds(nbOfCells);
1115 for(mcIdType i=0;i<nbOfCells;i++)
1117 convertToPolyTypes(&cellIds[0],&cellIds[0]+ToIdType(cellIds.size()));
1121 * Fixes nodal connectivity of invalid cells of type NORM_POLYHED. This method
1122 * expects that all NORM_POLYHED cells have connectivity similar to that of prismatic
1123 * volumes like NORM_HEXA8, NORM_PENTA6 etc., i.e. the first half of nodes describes a
1124 * base facet of the volume and the second half of nodes describes an opposite facet
1125 * having the same number of nodes as the base one. This method converts such
1126 * connectivity to a valid polyhedral format where connectivity of each facet is
1127 * explicitly described and connectivity of facets are separated by -1. If \a this mesh
1128 * contains a NORM_POLYHED cell with a valid connectivity, or an invalid connectivity is
1129 * not as expected, an exception is thrown and the mesh remains unchanged. Care of
1130 * a correct orientation of the first facet of a polyhedron, else orientation of a
1131 * corrected cell is reverse.<br>
1132 * This method is useful to build an extruded unstructured mesh with polyhedrons as
1133 * it releases the user from boring description of polyhedra connectivity in the valid
1135 * \throw If \a this->getMeshDimension() != 3.
1136 * \throw If \a this->getSpaceDimension() != 3.
1137 * \throw If the nodal connectivity of cells is not defined.
1138 * \throw If the coordinates array is not set.
1139 * \throw If \a this mesh contains polyhedrons with the valid connectivity.
1140 * \throw If \a this mesh contains polyhedrons with odd number of nodes.
1142 * \if ENABLE_EXAMPLES
1143 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
1144 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
1147 void MEDCouplingUMesh::convertExtrudedPolyhedra()
1149 checkFullyDefined();
1150 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1151 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertExtrudedPolyhedra works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
1152 mcIdType nbOfCells=getNumberOfCells();
1153 MCAuto<DataArrayIdType> newCi=DataArrayIdType::New();
1154 newCi->alloc(nbOfCells+1,1);
1155 mcIdType *newci=newCi->getPointer();
1156 const mcIdType *ci=_nodal_connec_index->getConstPointer();
1157 const mcIdType *c=_nodal_connec->getConstPointer();
1159 for(mcIdType i=0;i<nbOfCells;i++)
1161 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1162 if(type==INTERP_KERNEL::NORM_POLYHED)
1164 if(std::count(c+ci[i]+1,c+ci[i+1],-1)!=0)
1166 std::ostringstream oss; oss << "MEDCouplingUMesh::convertExtrudedPolyhedra : cell # " << i << " is a polhedron BUT it has NOT exactly 1 face !";
1167 throw INTERP_KERNEL::Exception(oss.str());
1169 std::size_t n2=std::distance(c+ci[i]+1,c+ci[i+1]);
1172 std::ostringstream oss; oss << "MEDCouplingUMesh::convertExtrudedPolyhedra : cell # " << i << " is a polhedron with 1 face but there is a mismatch of number of nodes in face should be even !";
1173 throw INTERP_KERNEL::Exception(oss.str());
1175 mcIdType n1=ToIdType(n2/2);
1176 newci[i+1]=7*n1+2+newci[i];//6*n1 (nodal length) + n1+2 (number of faces) - 1 (number of '-1' separator is equal to number of faces -1) + 1 (for cell type)
1179 newci[i+1]=(ci[i+1]-ci[i])+newci[i];
1181 MCAuto<DataArrayIdType> newC=DataArrayIdType::New();
1182 newC->alloc(newci[nbOfCells],1);
1183 mcIdType *newc=newC->getPointer();
1184 for(mcIdType i=0;i<nbOfCells;i++)
1186 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1187 if(type==INTERP_KERNEL::NORM_POLYHED)
1189 std::size_t n1=std::distance(c+ci[i]+1,c+ci[i+1])/2;
1190 newc=std::copy(c+ci[i],c+ci[i]+n1+1,newc);
1192 for(std::size_t j=0;j<n1;j++)
1194 newc[j]=c[ci[i]+1+n1+(n1-j)%n1];
1196 newc[n1+5*j+1]=c[ci[i]+1+j];
1197 newc[n1+5*j+2]=c[ci[i]+1+j+n1];
1198 newc[n1+5*j+3]=c[ci[i]+1+(j+1)%n1+n1];
1199 newc[n1+5*j+4]=c[ci[i]+1+(j+1)%n1];
1204 newc=std::copy(c+ci[i],c+ci[i+1],newc);
1206 _nodal_connec_index->decrRef(); _nodal_connec_index=newCi.retn();
1207 _nodal_connec->decrRef(); _nodal_connec=newC.retn();
1212 * Converts all polygons (if \a this is a 2D mesh) or polyhedrons (if \a this is a 3D
1213 * mesh) to cells of classical types. This method is opposite to convertToPolyTypes().
1214 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
1215 * to write this mesh to the MED file, its cells must be sorted using
1216 * sortCellsInMEDFileFrmt().
1217 * \warning Cells (and most notably polyhedrons) must be correctly oriented for this to work
1218 * properly. See orientCorrectlyPolyhedrons() and arePolyhedronsNotCorrectlyOriented().
1219 * \return \c true if at least one cell has been converted, \c false else. In the
1220 * last case the nodal connectivity remains unchanged.
1221 * \throw If the coordinates array is not set.
1222 * \throw If the nodal connectivity of cells is not defined.
1223 * \throw If \a this->getMeshDimension() < 0.
1225 bool MEDCouplingUMesh::unPolyze()
1227 checkFullyDefined();
1228 int mdim=getMeshDimension();
1230 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::unPolyze works on umeshes with meshdim equals to 0, 1 2 or 3 !");
1233 mcIdType nbOfCells=getNumberOfCells();
1236 mcIdType initMeshLgth=getNodalConnectivityArrayLen();
1237 mcIdType *conn=_nodal_connec->getPointer();
1238 mcIdType *index=_nodal_connec_index->getPointer();
1239 mcIdType posOfCurCell=0;
1241 mcIdType lgthOfCurCell;
1243 for(mcIdType i=0;i<nbOfCells;i++)
1245 lgthOfCurCell=index[i+1]-posOfCurCell;
1246 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
1247 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
1248 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::NORM_ERROR;
1252 switch(cm.getDimension())
1256 INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[lgthOfCurCell-1];
1257 std::copy(conn+posOfCurCell+1,conn+posOfCurCell+lgthOfCurCell,(mcIdType *)tmp);
1258 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly2D(cm.isQuadratic(),tmp,lgthOfCurCell-1,conn+newPos+1,newLgth);
1263 mcIdType nbOfFaces,lgthOfPolyhConn;
1264 INTERP_KERNEL::AutoPtr<mcIdType> zipFullReprOfPolyh=INTERP_KERNEL::CellSimplify::getFullPolyh3DCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,nbOfFaces,lgthOfPolyhConn);
1265 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly3D(zipFullReprOfPolyh,nbOfFaces,lgthOfPolyhConn,conn+newPos+1,newLgth);
1270 newType=(lgthOfCurCell==3)?INTERP_KERNEL::NORM_SEG2:INTERP_KERNEL::NORM_POLYL;
1274 ret=ret || (newType!=type);
1275 conn[newPos]=newType;
1277 posOfCurCell=index[i+1];
1282 std::copy(conn+posOfCurCell,conn+posOfCurCell+lgthOfCurCell,conn+newPos);
1283 newPos+=lgthOfCurCell;
1284 posOfCurCell+=lgthOfCurCell;
1288 if(newPos!=initMeshLgth)
1289 _nodal_connec->reAlloc(newPos);
1296 * This method expects that spaceDimension is equal to 3 and meshDimension equal to 3.
1297 * This method performs operation only on polyhedrons in \b this. If no polyhedrons exists in \b this, \b this remains unchanged.
1298 * This method allows to merge if any coplanar 3DSurf cells that may appear in some polyhedrons cells.
1300 * \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
1303 void MEDCouplingUMesh::simplifyPolyhedra(double eps)
1305 checkFullyDefined();
1306 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1307 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplifyPolyhedra : works on meshdimension 3 and spaceDimension 3 !");
1308 MCAuto<DataArrayDouble> coords=getCoords()->deepCopy();
1309 coords->recenterForMaxPrecision(eps);
1311 mcIdType nbOfCells=getNumberOfCells();
1312 const mcIdType *conn=_nodal_connec->getConstPointer();
1313 const mcIdType *index=_nodal_connec_index->getConstPointer();
1314 MCAuto<DataArrayIdType> connINew=DataArrayIdType::New();
1315 connINew->alloc(nbOfCells+1,1);
1316 mcIdType *connINewPtr=connINew->getPointer(); *connINewPtr++=0;
1317 MCAuto<DataArrayIdType> connNew=DataArrayIdType::New(); connNew->alloc(0,1);
1318 MCAuto<DataArrayIdType> E_Fi(DataArrayIdType::New()), E_F(DataArrayIdType::New()), F_Ei(DataArrayIdType::New()), F_E(DataArrayIdType::New());
1319 MCAuto<MEDCouplingUMesh> m_faces(buildDescendingConnectivity(E_F, E_Fi, F_E, F_Ei));
1321 for(mcIdType i=0;i<nbOfCells;i++,connINewPtr++)
1323 if(conn[index[i]]==ToIdType(INTERP_KERNEL::NORM_POLYHED))
1325 SimplifyPolyhedronCell(eps,coords, i,connNew, m_faces, E_Fi, E_F, F_Ei, F_E);
1329 connNew->insertAtTheEnd(conn+index[i],conn+index[i+1]);
1330 *connINewPtr=connNew->getNumberOfTuples();
1333 setConnectivity(connNew,connINew,false);
1337 * This method returns all node ids used in the connectivity of \b this. The data array returned has to be dealt by the caller.
1338 * The returned node ids are sorted ascendingly. This method is close to MEDCouplingUMesh::getNodeIdsInUse except
1339 * the format of the returned DataArrayIdType instance.
1341 * \return a newly allocated DataArrayIdType sorted ascendingly of fetched node ids.
1342 * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1344 DataArrayIdType *MEDCouplingUMesh::computeFetchedNodeIds() const
1346 checkConnectivityFullyDefined();
1347 const mcIdType *maxEltPt(std::max_element(_nodal_connec->begin(),_nodal_connec->end()));
1348 mcIdType maxElt(maxEltPt==_nodal_connec->end()?0:std::abs(*maxEltPt)+1);
1349 std::vector<bool> retS(maxElt,false);
1350 computeNodeIdsAlg(retS);
1351 return DataArrayIdType::BuildListOfSwitchedOn(retS);
1355 * \param [in,out] nodeIdsInUse an array of size typically equal to nbOfNodes.
1356 * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1358 void MEDCouplingUMesh::computeNodeIdsAlg(std::vector<bool>& nodeIdsInUse) const
1360 mcIdType nbOfNodes=ToIdType(nodeIdsInUse.size()),
1361 nbOfCells=getNumberOfCells();
1362 const mcIdType *connIndex(_nodal_connec_index->getConstPointer()),*conn(_nodal_connec->getConstPointer());
1363 for(mcIdType i=0;i<nbOfCells;i++)
1364 for(mcIdType j=connIndex[i]+1;j<connIndex[i+1];j++)
1367 if(conn[j]<nbOfNodes)
1368 nodeIdsInUse[conn[j]]=true;
1371 std::ostringstream oss; oss << "MEDCouplingUMesh::computeNodeIdsAlg : In cell #" << i << " presence of node id " << conn[j] << " not in [0," << nbOfNodes << ") !";
1372 throw INTERP_KERNEL::Exception(oss.str());
1379 struct MEDCouplingAccVisit
1381 MEDCouplingAccVisit():_new_nb_of_nodes(0) { }
1382 mcIdType operator()(mcIdType val) { if(val!=-1) return _new_nb_of_nodes++; else return -1; }
1383 mcIdType _new_nb_of_nodes;
1389 * Finds nodes not used in any cell and returns an array giving a new id to every node
1390 * by excluding the unused nodes, for which the array holds -1. The result array is
1391 * a mapping in "Old to New" mode.
1392 * \param [out] nbrOfNodesInUse - number of node ids present in the nodal connectivity.
1393 * \return DataArrayIdType * - a new instance of DataArrayIdType. Its length is \a
1394 * this->getNumberOfNodes(). It holds for each node of \a this mesh either -1
1395 * if the node is unused or a new id else. The caller is to delete this
1396 * array using decrRef() as it is no more needed.
1397 * \throw If the coordinates array is not set.
1398 * \throw If the nodal connectivity of cells is not defined.
1399 * \throw If the nodal connectivity includes an invalid id.
1401 * \if ENABLE_EXAMPLES
1402 * \ref cpp_mcumesh_getNodeIdsInUse "Here is a C++ example".<br>
1403 * \ref py_mcumesh_getNodeIdsInUse "Here is a Python example".
1405 * \sa computeFetchedNodeIds, computeNodeIdsAlg()
1407 DataArrayIdType *MEDCouplingUMesh::getNodeIdsInUse(mcIdType& nbrOfNodesInUse) const
1410 mcIdType nbOfNodes(getNumberOfNodes());
1411 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1412 ret->alloc(nbOfNodes,1);
1413 mcIdType *traducer=ret->getPointer();
1414 std::fill(traducer,traducer+nbOfNodes,-1);
1415 mcIdType nbOfCells=getNumberOfCells();
1416 const mcIdType *connIndex=_nodal_connec_index->getConstPointer();
1417 const mcIdType *conn=_nodal_connec->getConstPointer();
1418 for(mcIdType i=0;i<nbOfCells;i++)
1419 for(mcIdType j=connIndex[i]+1;j<connIndex[i+1];j++)
1422 if(conn[j]<nbOfNodes)
1423 traducer[conn[j]]=1;
1426 std::ostringstream oss; oss << "MEDCouplingUMesh::getNodeIdsInUse : In cell #" << i << " presence of node id " << conn[j] << " not in [0," << nbOfNodes << ") !";
1427 throw INTERP_KERNEL::Exception(oss.str());
1430 nbrOfNodesInUse=ToIdType(std::count(traducer,traducer+nbOfNodes,1));
1431 std::transform(traducer,traducer+nbOfNodes,traducer,MEDCouplingAccVisit());
1436 * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1437 * For each cell in \b this the number of nodes constituting cell is computed.
1438 * For each polyhedron cell, the sum of the number of nodes of each face constituting polyhedron cell is returned.
1439 * So for pohyhedrons some nodes can be counted several times in the returned result.
1441 * \return a newly allocated array
1442 * \sa MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell
1444 DataArrayIdType *MEDCouplingUMesh::computeNbOfNodesPerCell() const
1446 checkConnectivityFullyDefined();
1447 mcIdType nbOfCells=getNumberOfCells();
1448 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1449 ret->alloc(nbOfCells,1);
1450 mcIdType *retPtr=ret->getPointer();
1451 const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1452 const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1453 for(mcIdType i=0;i<nbOfCells;i++,retPtr++)
1455 if(conn[connI[i]]!=ToIdType(INTERP_KERNEL::NORM_POLYHED))
1456 *retPtr=connI[i+1]-connI[i]-1;
1458 *retPtr=connI[i+1]-connI[i]-1-ToIdType(std::count(conn+connI[i]+1,conn+connI[i+1],-1));
1464 * This method computes effective number of nodes per cell. That is to say nodes appearing several times in nodal connectivity of a cell,
1465 * will be counted only once here whereas it will be counted several times in MEDCouplingUMesh::computeNbOfNodesPerCell method.
1467 * \return DataArrayIdType * - new object to be deallocated by the caller.
1468 * \sa MEDCouplingUMesh::computeNbOfNodesPerCell
1470 DataArrayIdType *MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell() const
1472 checkConnectivityFullyDefined();
1473 mcIdType nbOfCells=getNumberOfCells();
1474 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1475 ret->alloc(nbOfCells,1);
1476 mcIdType *retPtr=ret->getPointer();
1477 const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1478 const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1479 for(mcIdType i=0;i<nbOfCells;i++,retPtr++)
1481 std::set<mcIdType> s(conn+connI[i]+1,conn+connI[i+1]);
1482 if(conn[connI[i]]!=ToIdType(INTERP_KERNEL::NORM_POLYHED))
1483 *retPtr=ToIdType(s.size());
1487 *retPtr=ToIdType(s.size());
1494 * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1495 * For each cell in \b this the number of faces constituting (entity of dimension this->getMeshDimension()-1) cell is computed.
1497 * \return a newly allocated array
1499 DataArrayIdType *MEDCouplingUMesh::computeNbOfFacesPerCell() const
1501 checkConnectivityFullyDefined();
1502 mcIdType nbOfCells=getNumberOfCells();
1503 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1504 ret->alloc(nbOfCells,1);
1505 mcIdType *retPtr=ret->getPointer();
1506 const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1507 const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1508 for(mcIdType i=0;i<nbOfCells;i++,retPtr++,connI++)
1510 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]);
1511 *retPtr=cm.getNumberOfSons2(conn+connI[0]+1,connI[1]-connI[0]-1);
1517 * Removes unused nodes (the node coordinates array is shorten) and returns an array
1518 * mapping between new and old node ids in "Old to New" mode. -1 values in the returned
1519 * array mean that the corresponding old node is no more used.
1520 * \return DataArrayIdType * - a new instance of DataArrayIdType of length \a
1521 * this->getNumberOfNodes() before call of this method. The caller is to
1522 * delete this array using decrRef() as it is no more needed.
1523 * \throw If the coordinates array is not set.
1524 * \throw If the nodal connectivity of cells is not defined.
1525 * \throw If the nodal connectivity includes an invalid id.
1526 * \sa areAllNodesFetched
1528 * \if ENABLE_EXAMPLES
1529 * \ref cpp_mcumesh_zipCoordsTraducer "Here is a C++ example".<br>
1530 * \ref py_mcumesh_zipCoordsTraducer "Here is a Python example".
1533 DataArrayIdType *MEDCouplingUMesh::zipCoordsTraducer()
1535 return MEDCouplingPointSet::zipCoordsTraducer();
1539 * This method stands if 'cell1' and 'cell2' are equals regarding 'compType' policy.
1540 * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1542 int MEDCouplingUMesh::AreCellsEqual(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2, int compType)
1547 return AreCellsEqualPolicy0(conn,connI,cell1,cell2);
1549 return AreCellsEqualPolicy1(conn,connI,cell1,cell2);
1551 return AreCellsEqualPolicy2(conn,connI,cell1,cell2);
1553 return AreCellsEqualPolicy2NoType(conn,connI,cell1,cell2);
1555 return AreCellsEqualPolicy7(conn,connI,cell1,cell2);
1557 throw INTERP_KERNEL::Exception("Unknown comparison asked ! Must be in 0,1,2,3 or 7.");
1561 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 0.
1563 int MEDCouplingUMesh::AreCellsEqualPolicy0(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1565 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1566 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;
1571 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 1.
1573 int MEDCouplingUMesh::AreCellsEqualPolicy1(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1575 mcIdType sz=connI[cell1+1]-connI[cell1];
1576 if(sz==connI[cell2+1]-connI[cell2])
1578 if(conn[connI[cell1]]==conn[connI[cell2]])
1580 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1581 unsigned dim=cm.getDimension();
1586 mcIdType sz1=2*(sz-1);
1587 INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz1];
1588 mcIdType *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(mcIdType *)tmp);
1589 std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1590 work=std::search((mcIdType *)tmp,(mcIdType *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1591 return work!=tmp+sz1?1:0;
1594 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;//case of SEG2 and SEG3
1597 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy1 : not implemented yet for meshdim == 3 !");
1604 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 2.
1606 int MEDCouplingUMesh::AreCellsEqualPolicy2(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1608 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1610 if(conn[connI[cell1]]==conn[connI[cell2]])
1612 std::set<mcIdType> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1613 std::set<mcIdType> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1621 * This method is less restrictive than AreCellsEqualPolicy2. Here the geometric type is absolutely not taken into account !
1623 int MEDCouplingUMesh::AreCellsEqualPolicy2NoType(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1625 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1627 std::set<mcIdType> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1628 std::set<mcIdType> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1635 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 7.
1637 int MEDCouplingUMesh::AreCellsEqualPolicy7(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1639 mcIdType sz=connI[cell1+1]-connI[cell1];
1640 if(sz==connI[cell2+1]-connI[cell2])
1642 if(conn[connI[cell1]]==conn[connI[cell2]])
1644 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1645 unsigned dim=cm.getDimension();
1650 mcIdType sz1=2*(sz-1);
1651 INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz1];
1652 mcIdType *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(mcIdType *)tmp);
1653 std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1654 work=std::search((mcIdType *)tmp,(mcIdType *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1659 std::reverse_iterator<mcIdType *> it1((mcIdType *)tmp+sz1);
1660 std::reverse_iterator<mcIdType *> it2((mcIdType *)tmp);
1661 if(std::search(it1,it2,conn+connI[cell2]+1,conn+connI[cell2+1])!=it2)
1667 return work!=tmp+sz1?1:0;
1670 {//case of SEG2 and SEG3
1671 if(std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1))
1673 if(!cm.isQuadratic())
1675 std::reverse_iterator<const mcIdType *> it1(conn+connI[cell1+1]);
1676 std::reverse_iterator<const mcIdType *> it2(conn+connI[cell1]+1);
1677 if(std::equal(it1,it2,conn+connI[cell2]+1))
1683 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])
1690 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy7 : not implemented yet for meshdim == 3 !");
1698 * This method find cells that are equal (regarding \a compType) in \a this. The comparison is specified
1700 * This method keeps the coordiantes of \a this. This method is time consuming.
1702 * \param [in] compType input specifying the technique used to compare cells each other.
1703 * - 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.
1704 * - 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)
1705 * and their type equal. For 1D mesh the policy 1 is equivalent to 0.
1706 * - 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
1707 * can be used for users not sensitive to orientation of cell
1708 * \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.
1709 * \param [out] commonCellsArr common cells ids (\ref numbering-indirect)
1710 * \param [out] commonCellsIArr common cells ids (\ref numbering-indirect)
1711 * \return the correspondence array old to new in a newly allocated array.
1714 void MEDCouplingUMesh::findCommonCells(int compType, mcIdType startCellId, DataArrayIdType *& commonCellsArr, DataArrayIdType *& commonCellsIArr) const
1716 MCAuto<DataArrayIdType> revNodal=DataArrayIdType::New(),revNodalI=DataArrayIdType::New();
1717 getReverseNodalConnectivity(revNodal,revNodalI);
1718 FindCommonCellsAlg(compType,startCellId,_nodal_connec,_nodal_connec_index,revNodal,revNodalI,commonCellsArr,commonCellsIArr);
1721 void MEDCouplingUMesh::FindCommonCellsAlg(int compType, mcIdType startCellId, const DataArrayIdType *nodal, const DataArrayIdType *nodalI, const DataArrayIdType *revNodal, const DataArrayIdType *revNodalI,
1722 DataArrayIdType *& commonCellsArr, DataArrayIdType *& commonCellsIArr)
1724 MCAuto<DataArrayIdType> commonCells=DataArrayIdType::New(),commonCellsI=DataArrayIdType::New(); commonCells->alloc(0,1);
1725 mcIdType nbOfCells=nodalI->getNumberOfTuples()-1;
1726 commonCellsI->reserve(1); commonCellsI->pushBackSilent(0);
1727 const mcIdType *revNodalPtr=revNodal->getConstPointer(),*revNodalIPtr=revNodalI->getConstPointer();
1728 const mcIdType *connPtr=nodal->getConstPointer(),*connIPtr=nodalI->getConstPointer();
1729 std::vector<bool> isFetched(nbOfCells,false);
1732 for(mcIdType i=0;i<nbOfCells;i++)
1736 const mcIdType *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind2nd(std::not_equal_to<mcIdType>(),-1));
1737 std::vector<mcIdType> v,v2;
1738 if(connOfNode!=connPtr+connIPtr[i+1])
1740 const mcIdType *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1741 v2.insert(v2.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1]);
1744 for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1748 const mcIdType *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1749 std::vector<mcIdType>::iterator it=std::set_intersection(v.begin(),v.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1750 v2.resize(std::distance(v2.begin(),it));
1754 if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1756 mcIdType pos=commonCellsI->back();
1757 commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1758 for(const mcIdType *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1759 isFetched[*it]=true;
1767 for(mcIdType i=startCellId;i<nbOfCells;i++)
1771 const mcIdType *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind2nd(std::not_equal_to<mcIdType>(),-1));
1772 std::vector<mcIdType> v,v2;
1773 if(connOfNode!=connPtr+connIPtr[i+1])
1775 v2.insert(v2.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1]);
1778 for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1782 std::vector<mcIdType>::iterator it=std::set_intersection(v.begin(),v.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1783 v2.resize(std::distance(v2.begin(),it));
1787 if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1789 mcIdType pos=commonCellsI->back();
1790 commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1791 for(const mcIdType *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1792 isFetched[*it]=true;
1798 commonCellsArr=commonCells.retn();
1799 commonCellsIArr=commonCellsI.retn();
1803 * Checks if \a this mesh includes all cells of an \a other mesh, and returns an array
1804 * giving for each cell of the \a other an id of a cell in \a this mesh. A value larger
1805 * than \a this->getNumberOfCells() in the returned array means that there is no
1806 * corresponding cell in \a this mesh.
1807 * It is expected that \a this and \a other meshes share the same node coordinates
1808 * array, if it is not so an exception is thrown.
1809 * \param [in] other - the mesh to compare with.
1810 * \param [in] compType - specifies a cell comparison technique. For meaning of its
1811 * valid values [0,1,2], see zipConnectivityTraducer().
1812 * \param [out] arr - a new instance of DataArrayIdType returning correspondence
1813 * between cells of the two meshes. It contains \a other->getNumberOfCells()
1814 * values. The caller is to delete this array using
1815 * decrRef() as it is no more needed.
1816 * \return bool - \c true if all cells of \a other mesh are present in the \a this
1819 * \if ENABLE_EXAMPLES
1820 * \ref cpp_mcumesh_areCellsIncludedIn "Here is a C++ example".<br>
1821 * \ref py_mcumesh_areCellsIncludedIn "Here is a Python example".
1823 * \sa checkDeepEquivalOnSameNodesWith()
1824 * \sa checkGeoEquivalWith()
1826 bool MEDCouplingUMesh::areCellsIncludedIn(const MEDCouplingUMesh *other, int compType, DataArrayIdType *& arr) const
1828 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1829 mcIdType nbOfCells=getNumberOfCells();
1830 static const int possibleCompType[]={0,1,2};
1831 if(std::find(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),compType)==possibleCompType+sizeof(possibleCompType)/sizeof(int))
1833 std::ostringstream oss; oss << "MEDCouplingUMesh::areCellsIncludedIn : only following policies are possible : ";
1834 std::copy(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),std::ostream_iterator<int>(oss," "));
1836 throw INTERP_KERNEL::Exception(oss.str());
1838 MCAuto<DataArrayIdType> o2n=mesh->zipConnectivityTraducer(compType,nbOfCells);
1839 arr=o2n->subArray(nbOfCells);
1840 arr->setName(other->getName());
1842 if(other->getNumberOfCells()==0)
1844 return arr->getMaxValue(tmp)<nbOfCells;
1848 * This method makes the assumption that \a this and \a other share the same coords. If not an exception will be thrown !
1849 * This method tries to determine if \b other is fully included in \b this.
1850 * The main difference is that this method is not expected to throw exception.
1851 * This method has two outputs :
1853 * \param other other mesh
1854 * \param arr is an output parameter that returns a \b newly created instance. This array is of size 'other->getNumberOfCells()'.
1855 * \return If \a other is fully included in 'this 'true is returned. If not false is returned.
1857 bool MEDCouplingUMesh::areCellsIncludedInPolicy7(const MEDCouplingUMesh *other, DataArrayIdType *& arr) const
1859 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1860 DataArrayIdType *commonCells=0,*commonCellsI=0;
1861 mcIdType thisNbCells=getNumberOfCells();
1862 mesh->findCommonCells(7,thisNbCells,commonCells,commonCellsI);
1863 MCAuto<DataArrayIdType> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1864 const mcIdType *commonCellsPtr=commonCells->getConstPointer(),*commonCellsIPtr=commonCellsI->getConstPointer();
1865 mcIdType otherNbCells=other->getNumberOfCells();
1866 MCAuto<DataArrayIdType> arr2=DataArrayIdType::New();
1867 arr2->alloc(otherNbCells,1);
1868 arr2->fillWithZero();
1869 mcIdType *arr2Ptr=arr2->getPointer();
1870 mcIdType nbOfCommon=commonCellsI->getNumberOfTuples()-1;
1871 for(mcIdType i=0;i<nbOfCommon;i++)
1873 mcIdType start=commonCellsPtr[commonCellsIPtr[i]];
1874 if(start<thisNbCells)
1876 for(mcIdType j=commonCellsIPtr[i]+1;j!=commonCellsIPtr[i+1];j++)
1878 mcIdType sig=commonCellsPtr[j]>0?1:-1;
1879 mcIdType val=std::abs(commonCellsPtr[j])-1;
1880 if(val>=thisNbCells)
1881 arr2Ptr[val-thisNbCells]=sig*(start+1);
1885 arr2->setName(other->getName());
1886 if(arr2->presenceOfValue(0))
1892 MEDCouplingUMesh *MEDCouplingUMesh::mergeMyselfWithOnSameCoords(const MEDCouplingPointSet *other) const
1895 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : input other is null !");
1896 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
1898 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : the input other mesh is not of type unstructured !");
1899 std::vector<const MEDCouplingUMesh *> ms(2);
1902 return MergeUMeshesOnSameCoords(ms);
1906 * Build a sub part of \b this lying or not on the same coordinates than \b this (regarding value of \b keepCoords).
1907 * By default coordinates are kept. This method is close to MEDCouplingUMesh::buildPartOfMySelf except that here input
1908 * cellIds is not given explicitly but by a range python like.
1913 * \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.
1914 * \return a newly allocated
1916 * \warning This method modifies can generate an unstructured mesh whose cells are not sorted by geometric type order.
1917 * In view of the MED file writing, a renumbering of cells of returned unstructured mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
1919 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfSlice(mcIdType start, mcIdType end, mcIdType step, bool keepCoords) const
1921 if(getMeshDimension()!=-1)
1922 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelfSlice(start,end,step,keepCoords));
1925 mcIdType newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfSlice for -1 dimension mesh ");
1927 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
1929 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
1931 return const_cast<MEDCouplingUMesh *>(this);
1936 * Creates a new MEDCouplingUMesh containing specified cells of \a this mesh.
1937 * The result mesh shares or not the node coordinates array with \a this mesh depending
1938 * on \a keepCoords parameter.
1939 * \warning Cells of the result mesh can be \b not sorted by geometric type, hence,
1940 * to write this mesh to the MED file, its cells must be sorted using
1941 * sortCellsInMEDFileFrmt().
1942 * \param [in] begin - an array of cell ids to include to the new mesh.
1943 * \param [in] end - a pointer to last-plus-one-th element of \a begin.
1944 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
1945 * array of \a this mesh, else "free" nodes are removed from the result mesh
1946 * by calling zipCoords().
1947 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
1948 * to delete this mesh using decrRef() as it is no more needed.
1949 * \throw If the coordinates array is not set.
1950 * \throw If the nodal connectivity of cells is not defined.
1951 * \throw If any cell id in the array \a begin is not valid.
1953 * \if ENABLE_EXAMPLES
1954 * \ref cpp_mcumesh_buildPartOfMySelf "Here is a C++ example".<br>
1955 * \ref py_mcumesh_buildPartOfMySelf "Here is a Python example".
1958 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelf(const mcIdType *begin, const mcIdType *end, bool keepCoords) const
1960 if(getMeshDimension()!=-1)
1961 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelf(begin,end,keepCoords));
1965 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
1967 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
1969 return const_cast<MEDCouplingUMesh *>(this);
1974 * This method operates only on nodal connectivity on \b this. Coordinates of \b this is completely ignored here.
1976 * 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.
1977 * Size of [ \b cellIdsBg, \b cellIdsEnd ) ) must be equal to the number of cells of otherOnSameCoordsThanThis.
1978 * The number of cells of \b this will remain the same with this method.
1980 * \param [in] cellIdsBg begin of cell ids (included) of cells in this to assign
1981 * \param [in] cellIdsEnd end of cell ids (excluded) of cells in this to assign
1982 * \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 ).
1983 * Coordinate pointer of \b this and those of \b otherOnSameCoordsThanThis must be the same
1985 void MEDCouplingUMesh::setPartOfMySelf(const mcIdType *cellIdsBg, const mcIdType *cellIdsEnd, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
1987 checkConnectivityFullyDefined();
1988 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
1989 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
1990 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelf : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
1991 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
1993 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
1994 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
1995 throw INTERP_KERNEL::Exception(oss.str());
1997 mcIdType nbOfCellsToModify( ToIdType((std::distance(cellIdsBg,cellIdsEnd))));
1998 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2000 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2001 throw INTERP_KERNEL::Exception(oss.str());
2003 mcIdType nbOfCells(getNumberOfCells());
2004 bool easyAssign(true);
2005 const mcIdType *connI(_nodal_connec_index->begin());
2006 const mcIdType *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->begin();
2007 for(const mcIdType *it=cellIdsBg;it!=cellIdsEnd && easyAssign;it++,connIOther++)
2009 if(*it>=0 && *it<nbOfCells)
2011 easyAssign=(connIOther[1]-connIOther[0])==(connI[*it+1]-connI[*it]);
2015 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : On pos #" << std::distance(cellIdsBg,it) << " id is equal to " << *it << " which is not in [0," << nbOfCells << ") !";
2016 throw INTERP_KERNEL::Exception(oss.str());
2021 DataArrayIdType::SetPartOfIndexedArraysSameIdx(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2026 DataArrayIdType *arrOut=0,*arrIOut=0;
2027 DataArrayIdType::SetPartOfIndexedArrays(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2029 MCAuto<DataArrayIdType> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2030 setConnectivity(arrOut,arrIOut,true);
2034 void MEDCouplingUMesh::setPartOfMySelfSlice(mcIdType start, mcIdType end, mcIdType step, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2036 checkConnectivityFullyDefined();
2037 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2038 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2039 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelfSlice : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2040 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2042 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2043 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2044 throw INTERP_KERNEL::Exception(oss.str());
2046 mcIdType nbOfCellsToModify=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::setPartOfMySelfSlice : ");
2047 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2049 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2050 throw INTERP_KERNEL::Exception(oss.str());
2052 mcIdType nbOfCells=getNumberOfCells();
2053 bool easyAssign=true;
2054 const mcIdType *connI=_nodal_connec_index->getConstPointer();
2055 const mcIdType *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2057 for(mcIdType i=0;i<nbOfCellsToModify && easyAssign;i++,it+=step,connIOther++)
2059 if(it>=0 && it<nbOfCells)
2061 easyAssign=(connIOther[1]-connIOther[0])==(connI[it+1]-connI[it]);
2065 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : On pos #" << i << " id is equal to " << it << " which is not in [0," << nbOfCells << ") !";
2066 throw INTERP_KERNEL::Exception(oss.str());
2071 DataArrayIdType::SetPartOfIndexedArraysSameIdxSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2076 DataArrayIdType *arrOut=0,*arrIOut=0;
2077 DataArrayIdType::SetPartOfIndexedArraysSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2079 MCAuto<DataArrayIdType> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2080 setConnectivity(arrOut,arrIOut,true);
2086 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2087 * this->getMeshDimension(), that bound some cells of \a this mesh.
2088 * The cells of lower dimension to include to the result mesh are selected basing on
2089 * specified node ids and the value of \a fullyIn parameter. If \a fullyIn ==\c true, a
2090 * cell is copied if its all nodes are in the array \a begin of node ids. If \a fullyIn
2091 * ==\c false, a cell is copied if any its node is in the array of node ids. The
2092 * created mesh shares the node coordinates array with \a this mesh.
2093 * \param [in] begin - the array of node ids.
2094 * \param [in] end - a pointer to the (last+1)-th element of \a begin.
2095 * \param [in] fullyIn - if \c true, then cells whose all nodes are in the
2096 * array \a begin are added, else cells whose any node is in the
2097 * array \a begin are added.
2098 * \return MEDCouplingUMesh * - new instance of MEDCouplingUMesh. The caller is
2099 * to delete this mesh using decrRef() as it is no more needed.
2100 * \throw If the coordinates array is not set.
2101 * \throw If the nodal connectivity of cells is not defined.
2102 * \throw If any node id in \a begin is not valid.
2104 * \if ENABLE_EXAMPLES
2105 * \ref cpp_mcumesh_buildFacePartOfMySelfNode "Here is a C++ example".<br>
2106 * \ref py_mcumesh_buildFacePartOfMySelfNode "Here is a Python example".
2109 MEDCouplingUMesh *MEDCouplingUMesh::buildFacePartOfMySelfNode(const mcIdType *begin, const mcIdType *end, bool fullyIn) const
2111 MCAuto<DataArrayIdType> desc,descIndx,revDesc,revDescIndx;
2112 desc=DataArrayIdType::New(); descIndx=DataArrayIdType::New(); revDesc=DataArrayIdType::New(); revDescIndx=DataArrayIdType::New();
2113 MCAuto<MEDCouplingUMesh> subMesh=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2114 desc=0; descIndx=0; revDesc=0; revDescIndx=0;
2115 return static_cast<MEDCouplingUMesh*>(subMesh->buildPartOfMySelfNode(begin,end,fullyIn));
2119 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2120 * this->getMeshDimension(), which bound only one cell of \a this mesh.
2121 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2122 * array of \a this mesh, else "free" nodes are removed from the result mesh
2123 * by calling zipCoords().
2124 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2125 * to delete this mesh using decrRef() as it is no more needed.
2126 * \throw If the coordinates array is not set.
2127 * \throw If the nodal connectivity of cells is not defined.
2129 * \if ENABLE_EXAMPLES
2130 * \ref cpp_mcumesh_buildBoundaryMesh "Here is a C++ example".<br>
2131 * \ref py_mcumesh_buildBoundaryMesh "Here is a Python example".
2134 MEDCouplingUMesh *MEDCouplingUMesh::buildBoundaryMesh(bool keepCoords) const
2136 DataArrayIdType *desc=DataArrayIdType::New();
2137 DataArrayIdType *descIndx=DataArrayIdType::New();
2138 DataArrayIdType *revDesc=DataArrayIdType::New();
2139 DataArrayIdType *revDescIndx=DataArrayIdType::New();
2141 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2144 descIndx->decrRef();
2145 mcIdType nbOfCells=meshDM1->getNumberOfCells();
2146 const mcIdType *revDescIndxC=revDescIndx->getConstPointer();
2147 std::vector<mcIdType> boundaryCells;
2148 for(mcIdType i=0;i<nbOfCells;i++)
2149 if(revDescIndxC[i+1]-revDescIndxC[i]==1)
2150 boundaryCells.push_back(i);
2151 revDescIndx->decrRef();
2152 MEDCouplingUMesh *ret=meshDM1->buildPartOfMySelf(&boundaryCells[0],&boundaryCells[0]+boundaryCells.size(),keepCoords);
2157 * This method returns a newly created DataArrayIdType instance containing ids of cells located in boundary.
2158 * A cell is detected to be on boundary if it contains one or more than one face having only one father.
2159 * This method makes the assumption that \a this is fully defined (coords,connectivity). If not an exception will be thrown.
2161 DataArrayIdType *MEDCouplingUMesh::findCellIdsOnBoundary() const
2163 checkFullyDefined();
2164 MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
2165 MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
2166 MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
2167 MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
2169 buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx)->decrRef();
2170 desc=(DataArrayIdType*)0; descIndx=(DataArrayIdType*)0;
2172 MCAuto<DataArrayIdType> tmp=revDescIndx->deltaShiftIndex();
2173 MCAuto<DataArrayIdType> faceIds=tmp->findIdsEqual(1); tmp=(DataArrayIdType*)0;
2174 const mcIdType *revDescPtr=revDesc->getConstPointer();
2175 const mcIdType *revDescIndxPtr=revDescIndx->getConstPointer();
2176 mcIdType nbOfCells=getNumberOfCells();
2177 std::vector<bool> ret1(nbOfCells,false);
2179 for(const mcIdType *pt=faceIds->begin();pt!=faceIds->end();pt++)
2180 if(!ret1[revDescPtr[revDescIndxPtr[*pt]]])
2181 { ret1[revDescPtr[revDescIndxPtr[*pt]]]=true; sz++; }
2183 DataArrayIdType *ret2=DataArrayIdType::New();
2185 mcIdType *ret2Ptr=ret2->getPointer();
2187 for(std::vector<bool>::const_iterator it=ret1.begin();it!=ret1.end();it++,sz++)
2190 ret2->setName("BoundaryCells");
2195 * This method finds in \b this the cell ids that lie on mesh \b otherDimM1OnSameCoords.
2196 * \b this and \b otherDimM1OnSameCoords have to lie on the same coordinate array pointer. The coherency of that coords array with connectivity
2197 * of \b this and \b otherDimM1OnSameCoords is not important here because this method works only on connectivity.
2198 * this->getMeshDimension() - 1 must be equal to otherDimM1OnSameCoords.getMeshDimension()
2200 * s0 is the cell ids set in \b this lying on at least one node in the fetched nodes in \b otherDimM1OnSameCoords.
2201 * 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
2202 * equals a cell in \b otherDimM1OnSameCoords.
2204 * \throw if \b otherDimM1OnSameCoords is not part of constituent of \b this, or if coordinate pointer of \b this and \b otherDimM1OnSameCoords
2205 * are not same, or if this->getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension()
2207 * \param [in] otherDimM1OnSameCoords
2208 * \param [out] cellIdsRk0 a newly allocated array containing the cell ids of s0 (which are cell ids of \b this) in the above algorithm.
2209 * \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
2210 * cellIdsRk1->transformWithIndArr(cellIdsRk0->begin(),cellIdsRk0->end());
2212 void MEDCouplingUMesh::findCellIdsLyingOn(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayIdType *&cellIdsRk0, DataArrayIdType *&cellIdsRk1) const
2214 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2215 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : coordinates pointer are not the same ! Use tryToShareSameCoords method !");
2216 checkConnectivityFullyDefined();
2217 otherDimM1OnSameCoords.checkConnectivityFullyDefined();
2218 if(getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension())
2219 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : invalid mesh dimension of input mesh regarding meshdimesion of this !");
2220 MCAuto<DataArrayIdType> fetchedNodeIds1=otherDimM1OnSameCoords.computeFetchedNodeIds();
2221 MCAuto<DataArrayIdType> s0arr=getCellIdsLyingOnNodes(fetchedNodeIds1->begin(),fetchedNodeIds1->end(),false);
2222 MCAuto<MEDCouplingUMesh> thisPart=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(s0arr->begin(),s0arr->end(),true));
2223 MCAuto<DataArrayIdType> descThisPart=DataArrayIdType::New(),descIThisPart=DataArrayIdType::New(),revDescThisPart=DataArrayIdType::New(),revDescIThisPart=DataArrayIdType::New();
2224 MCAuto<MEDCouplingUMesh> thisPartConsti=thisPart->buildDescendingConnectivity(descThisPart,descIThisPart,revDescThisPart,revDescIThisPart);
2225 const mcIdType *revDescThisPartPtr=revDescThisPart->getConstPointer(),*revDescIThisPartPtr=revDescIThisPart->getConstPointer();
2226 DataArrayIdType *idsOtherInConsti=0;
2227 bool b=thisPartConsti->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsOtherInConsti);
2228 MCAuto<DataArrayIdType> idsOtherInConstiAuto(idsOtherInConsti);
2230 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : the given mdim-1 mesh in other is not a constituent of this !");
2231 std::set<mcIdType> s1;
2232 for(const mcIdType *idOther=idsOtherInConsti->begin();idOther!=idsOtherInConsti->end();idOther++)
2233 s1.insert(revDescThisPartPtr+revDescIThisPartPtr[*idOther],revDescThisPartPtr+revDescIThisPartPtr[*idOther+1]);
2234 MCAuto<DataArrayIdType> s1arr_renum1=DataArrayIdType::New(); s1arr_renum1->alloc(s1.size(),1); std::copy(s1.begin(),s1.end(),s1arr_renum1->getPointer());
2235 s1arr_renum1->sort();
2236 cellIdsRk0=s0arr.retn();
2237 //cellIdsRk1=s_renum1.retn();
2238 cellIdsRk1=s1arr_renum1.retn();
2242 * 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
2243 * returned. This subpart of meshdim-1 mesh is built using meshdim-1 cells in it shared only one cell in \b this.
2245 * \return a newly allocated mesh lying on the same coordinates than \b this. The caller has to deal with returned mesh.
2247 MEDCouplingUMesh *MEDCouplingUMesh::computeSkin() const
2249 MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
2250 MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
2251 MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
2252 MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
2254 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2255 revDesc=0; desc=0; descIndx=0;
2256 MCAuto<DataArrayIdType> revDescIndx2=revDescIndx->deltaShiftIndex();
2257 MCAuto<DataArrayIdType> part=revDescIndx2->findIdsEqual(1);
2258 return static_cast<MEDCouplingUMesh *>(meshDM1->buildPartOfMySelf(part->begin(),part->end(),true));
2262 * Finds nodes lying on the boundary of \a this mesh.
2263 * \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of found
2264 * nodes. The caller is to delete this array using decrRef() as it is no
2266 * \throw If the coordinates array is not set.
2267 * \throw If the nodal connectivity of cells is node defined.
2269 * \if ENABLE_EXAMPLES
2270 * \ref cpp_mcumesh_findBoundaryNodes "Here is a C++ example".<br>
2271 * \ref py_mcumesh_findBoundaryNodes "Here is a Python example".
2274 DataArrayIdType *MEDCouplingUMesh::findBoundaryNodes() const
2276 MCAuto<MEDCouplingUMesh> skin=computeSkin();
2277 return skin->computeFetchedNodeIds();
2280 MEDCouplingUMesh *MEDCouplingUMesh::buildUnstructured() const
2283 return const_cast<MEDCouplingUMesh *>(this);
2287 * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2288 * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2289 * 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.
2290 * 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.
2291 * 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.
2293 * \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
2294 * parameter is altered during the call.
2295 * \param [out] nodeIdsToDuplicate node ids needed to be duplicated following the algorithm explain above.
2296 * \param [out] cellIdsNeededToBeRenum cell ids in \b this in which the renumber of nodes should be performed.
2297 * \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.
2299 * \warning This method modifies param \b otherDimM1OnSameCoords (for speed reasons).
2301 void MEDCouplingUMesh::findNodesToDuplicate(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayIdType *& nodeIdsToDuplicate,
2302 DataArrayIdType *& cellIdsNeededToBeRenum, DataArrayIdType *& cellIdsNotModified) const
2304 typedef MCAuto<DataArrayIdType> DAInt;
2305 typedef MCAuto<MEDCouplingUMesh> MCUMesh;
2307 checkFullyDefined();
2308 otherDimM1OnSameCoords.checkFullyDefined();
2309 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2310 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : meshes do not share the same coords array !");
2311 if(otherDimM1OnSameCoords.getMeshDimension()!=getMeshDimension()-1)
2312 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the mesh given in other parameter must have this->getMeshDimension()-1 !");
2314 // Checking star-shaped M1 group:
2315 DAInt dt0=DataArrayIdType::New(),dit0=DataArrayIdType::New(),rdt0=DataArrayIdType::New(),rdit0=DataArrayIdType::New();
2316 MCUMesh meshM2 = otherDimM1OnSameCoords.buildDescendingConnectivity(dt0, dit0, rdt0, rdit0);
2317 DAInt dsi = rdit0->deltaShiftIndex();
2318 DAInt idsTmp0 = dsi->findIdsNotInRange(-1, 3);
2319 if(idsTmp0->getNumberOfTuples())
2320 throw INTERP_KERNEL::Exception("MEDFileUMesh::buildInnerBoundaryAlongM1Group: group is too complex: some points (or edges) have more than two connected segments (or faces)!");
2321 dt0=0; dit0=0; rdt0=0; rdit0=0; idsTmp0=0;
2323 // Get extreme nodes from the group (they won't be duplicated), ie nodes belonging to boundary cells of M1
2324 DAInt xtremIdsM2 = dsi->findIdsEqual(1); dsi = 0;
2325 MCUMesh meshM2Part = static_cast<MEDCouplingUMesh *>(meshM2->buildPartOfMySelf(xtremIdsM2->begin(), xtremIdsM2->end(),true));
2326 DAInt xtrem = meshM2Part->computeFetchedNodeIds();
2327 // Remove from the list points on the boundary of the M0 mesh (those need duplication!)
2328 dt0=DataArrayIdType::New(),dit0=DataArrayIdType::New(),rdt0=DataArrayIdType::New(),rdit0=DataArrayIdType::New();
2329 MCUMesh m0desc = buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); dt0=0; dit0=0; rdt0=0;
2330 dsi = rdit0->deltaShiftIndex();
2331 DAInt boundSegs = dsi->findIdsEqual(1); // boundary segs/faces of the M0 mesh
2332 MCUMesh m0descSkin = static_cast<MEDCouplingUMesh *>(m0desc->buildPartOfMySelf(boundSegs->begin(),boundSegs->end(), true));
2333 DAInt fNodes = m0descSkin->computeFetchedNodeIds();
2334 // In 3D, some points on the boundary of M0 still need duplication:
2336 if (getMeshDimension() == 3)
2338 DAInt dnu1=DataArrayIdType::New(), dnu2=DataArrayIdType::New(), dnu3=DataArrayIdType::New(), dnu4=DataArrayIdType::New();
2339 MCUMesh m0descSkinDesc = m0descSkin->buildDescendingConnectivity(dnu1, dnu2, dnu3, dnu4);
2340 dnu1=0;dnu2=0;dnu3=0;dnu4=0;
2341 DataArrayIdType * corresp=0;
2342 meshM2->areCellsIncludedIn(m0descSkinDesc,2,corresp);
2343 DAInt validIds = corresp->findIdsInRange(0, meshM2->getNumberOfCells());
2345 if (validIds->getNumberOfTuples())
2347 MCUMesh m1IntersecSkin = static_cast<MEDCouplingUMesh *>(m0descSkinDesc->buildPartOfMySelf(validIds->begin(), validIds->end(), true));
2348 DAInt notDuplSkin = m1IntersecSkin->findBoundaryNodes();
2349 DAInt fNodes1 = fNodes->buildSubstraction(notDuplSkin);
2350 notDup = xtrem->buildSubstraction(fNodes1);
2353 notDup = xtrem->buildSubstraction(fNodes);
2356 notDup = xtrem->buildSubstraction(fNodes);
2358 // Now compute cells around group (i.e. cells where we will do the propagation to identify the two sub-sets delimited by the group)
2359 DAInt m1Nodes = otherDimM1OnSameCoords.computeFetchedNodeIds();
2360 DAInt dupl = m1Nodes->buildSubstraction(notDup);
2361 DAInt cellsAroundGroup = getCellIdsLyingOnNodes(dupl->begin(), dupl->end(), false); // false= take cell in, even if not all nodes are in notDup
2364 MCUMesh m0Part2=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(cellsAroundGroup->begin(),cellsAroundGroup->end(),true));
2365 mcIdType nCells2 = m0Part2->getNumberOfCells();
2366 DAInt desc00=DataArrayIdType::New(),descI00=DataArrayIdType::New(),revDesc00=DataArrayIdType::New(),revDescI00=DataArrayIdType::New();
2367 MCUMesh m01=m0Part2->buildDescendingConnectivity(desc00,descI00,revDesc00,revDescI00);
2369 // Neighbor information of the mesh without considering the crack (serves to count how many connex pieces it is made of)
2370 DataArrayIdType *tmp00=0,*tmp11=0;
2371 MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00, tmp00, tmp11);
2372 DAInt neighInit00(tmp00);
2373 DAInt neighIInit00(tmp11);
2374 // Neighbor information of the mesh WITH the crack (some neighbors are removed):
2375 DataArrayIdType *idsTmp=0;
2376 m01->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsTmp);
2378 // In the neighbor information remove the connection between high dimension cells and its low level constituents which are part
2379 // of the frontier given in parameter (i.e. the cells of low dimension from the group delimiting the crack):
2380 DataArrayIdType::RemoveIdsFromIndexedArrays(ids->begin(),ids->end(),desc00,descI00);
2381 DataArrayIdType *tmp0=0,*tmp1=0;
2382 // Compute the neighbor of each cell in m0Part2, taking into account the broken link above. Two
2383 // cells on either side of the crack (defined by the mesh of low dimension) are not neighbor anymore.
2384 ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00,tmp0,tmp1);
2385 DAInt neigh00(tmp0);
2386 DAInt neighI00(tmp1);
2388 // For each initial connex part of the sub-mesh (or said differently for each independent crack):
2389 mcIdType seed = 0, nIter = 0;
2390 mcIdType nIterMax = nCells2+1; // Safety net for the loop
2391 DAInt hitCells = DataArrayIdType::New(); hitCells->alloc(nCells2);
2392 hitCells->fillWithValue(-1);
2393 DAInt cellsToModifyConn0_torenum = DataArrayIdType::New();
2394 cellsToModifyConn0_torenum->alloc(0,1);
2395 while (nIter < nIterMax)
2397 DAInt t = hitCells->findIdsEqual(-1);
2398 if (!t->getNumberOfTuples())
2400 // Connex zone without the crack (to compute the next seed really)
2402 DAInt connexCheck = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neighInit00,neighIInit00, -1, dnu);
2404 for (mcIdType * ptr = connexCheck->getPointer(); cnt < connexCheck->getNumberOfTuples(); ptr++, cnt++)
2405 hitCells->setIJ(*ptr,0,1);
2406 // Connex zone WITH the crack (to identify cells lying on either part of the crack)
2407 DAInt spreadZone = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neigh00,neighI00, -1, dnu);
2408 cellsToModifyConn0_torenum = DataArrayIdType::Aggregate(cellsToModifyConn0_torenum, spreadZone, 0);
2409 // Compute next seed, i.e. a cell in another connex part, which was not covered by the previous iterations
2410 DAInt comple = cellsToModifyConn0_torenum->buildComplement(nCells2);
2411 DAInt nonHitCells = hitCells->findIdsEqual(-1);
2412 DAInt intersec = nonHitCells->buildIntersection(comple);
2413 if (intersec->getNumberOfTuples())
2414 { seed = intersec->getIJ(0,0); }
2419 if (nIter >= nIterMax)
2420 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate(): internal error - too many iterations.");
2422 DAInt cellsToModifyConn1_torenum=cellsToModifyConn0_torenum->buildComplement(neighI00->getNumberOfTuples()-1);
2423 cellsToModifyConn0_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2424 cellsToModifyConn1_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2426 cellIdsNeededToBeRenum=cellsToModifyConn0_torenum.retn();
2427 cellIdsNotModified=cellsToModifyConn1_torenum.retn();
2428 nodeIdsToDuplicate=dupl.retn();
2432 * This method operates a modification of the connectivity and coords in \b this.
2433 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2434 * its ids will be modified to id this->getNumberOfNodes()+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2435 * 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
2436 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id this->getNumberOfNodes()+0, node id nodeIdsToDuplicateBg[1] will have id this->getNumberOfNodes()+1,
2437 * node id nodeIdsToDuplicateBg[2] will have id this->getNumberOfNodes()+2...
2439 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2441 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2442 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2444 void MEDCouplingUMesh::duplicateNodes(const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd)
2446 mcIdType nbOfNodes=getNumberOfNodes();
2447 duplicateNodesInCoords(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd);
2448 duplicateNodesInConn(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,nbOfNodes);
2452 * This method renumbers only nodal connectivity in \a this. The renumbering is only an offset applied. So this method is a specialization of
2453 * \a renumberNodesInConn. \b WARNING, this method does not check that the resulting node ids in the nodal connectivity is in a valid range !
2455 * \param [in] offset - specifies the offset to be applied on each element of connectivity.
2457 * \sa renumberNodesInConn
2459 void MEDCouplingUMesh::renumberNodesWithOffsetInConn(mcIdType offset)
2461 checkConnectivityFullyDefined();
2462 mcIdType *conn(getNodalConnectivity()->getPointer());
2463 const mcIdType *connIndex(getNodalConnectivityIndex()->getConstPointer());
2464 mcIdType nbOfCells=getNumberOfCells();
2465 for(mcIdType i=0;i<nbOfCells;i++)
2466 for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2468 mcIdType& node=conn[iconn];
2469 if(node>=0)//avoid polyhedron separator
2474 _nodal_connec->declareAsNew();
2479 * Same than renumberNodesInConn(const mcIdType *) except that here the format of old-to-new traducer is using map instead
2480 * 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
2483 void MEDCouplingUMesh::renumberNodesInConn(const INTERP_KERNEL::HashMap<mcIdType,mcIdType>& newNodeNumbersO2N)
2485 this->renumberNodesInConnT< INTERP_KERNEL::HashMap<mcIdType,mcIdType> >(newNodeNumbersO2N);
2489 * Same than renumberNodesInConn(const mcIdType *) except that here the format of old-to-new traducer is using map instead
2490 * 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
2493 void MEDCouplingUMesh::renumberNodesInConn(const std::map<mcIdType,mcIdType>& newNodeNumbersO2N)
2495 this->renumberNodesInConnT< std::map<mcIdType,mcIdType> >(newNodeNumbersO2N);
2499 * Changes ids of nodes within the nodal connectivity arrays according to a permutation
2500 * array in "Old to New" mode. The node coordinates array is \b not changed by this method.
2501 * This method is a generalization of shiftNodeNumbersInConn().
2502 * \warning This method performs no check of validity of new ids. **Use it with care !**
2503 * \param [in] newNodeNumbersO2N - a permutation array, of length \a
2504 * this->getNumberOfNodes(), in "Old to New" mode.
2505 * See \ref numbering for more info on renumbering modes.
2506 * \throw If the nodal connectivity of cells is not defined.
2508 * \if ENABLE_EXAMPLES
2509 * \ref cpp_mcumesh_renumberNodesInConn "Here is a C++ example".<br>
2510 * \ref py_mcumesh_renumberNodesInConn "Here is a Python example".
2513 void MEDCouplingUMesh::renumberNodesInConn(const mcIdType *newNodeNumbersO2N)
2515 checkConnectivityFullyDefined();
2516 mcIdType *conn=getNodalConnectivity()->getPointer();
2517 const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2518 mcIdType nbOfCells=getNumberOfCells();
2519 for(mcIdType i=0;i<nbOfCells;i++)
2520 for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2522 mcIdType& node=conn[iconn];
2523 if(node>=0)//avoid polyhedron separator
2525 node=newNodeNumbersO2N[node];
2528 _nodal_connec->declareAsNew();
2533 * This method renumbers nodes \b in \b connectivity \b only \b without \b any \b reference \b to \b coords.
2534 * This method performs no check on the fact that new coordinate ids are valid. \b Use \b it \b with \b care !
2535 * This method is an specialization of \ref MEDCoupling::MEDCouplingUMesh::renumberNodesInConn "renumberNodesInConn method".
2537 * \param [in] delta specifies the shift size applied to nodeId in nodal connectivity in \b this.
2539 void MEDCouplingUMesh::shiftNodeNumbersInConn(mcIdType delta)
2541 checkConnectivityFullyDefined();
2542 mcIdType *conn=getNodalConnectivity()->getPointer();
2543 const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2544 mcIdType nbOfCells=getNumberOfCells();
2545 for(mcIdType i=0;i<nbOfCells;i++)
2546 for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2548 mcIdType& node=conn[iconn];
2549 if(node>=0)//avoid polyhedron separator
2554 _nodal_connec->declareAsNew();
2559 * This method operates a modification of the connectivity in \b this.
2560 * 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.
2561 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2562 * its ids will be modified to id offset+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2563 * 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
2564 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id offset+0, node id nodeIdsToDuplicateBg[1] will have id offset+1,
2565 * node id nodeIdsToDuplicateBg[2] will have id offset+2...
2567 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2568 * As an another consequense after the call of this method \b this can be transiently non cohrent.
2570 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2571 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2572 * \param [in] offset the offset applied to all node ids in connectivity that are in [ \a nodeIdsToDuplicateBg, \a nodeIdsToDuplicateEnd ).
2574 void MEDCouplingUMesh::duplicateNodesInConn(const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd, mcIdType offset)
2576 checkConnectivityFullyDefined();
2577 std::map<mcIdType,mcIdType> m;
2578 mcIdType val=offset;
2579 for(const mcIdType *work=nodeIdsToDuplicateBg;work!=nodeIdsToDuplicateEnd;work++,val++)
2581 mcIdType *conn=getNodalConnectivity()->getPointer();
2582 const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2583 mcIdType nbOfCells=getNumberOfCells();
2584 for(mcIdType i=0;i<nbOfCells;i++)
2585 for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2587 mcIdType& node=conn[iconn];
2588 if(node>=0)//avoid polyhedron separator
2590 std::map<mcIdType,mcIdType>::iterator it=m.find(node);
2599 * This method renumbers cells of \a this using the array specified by [old2NewBg;old2NewBg+getNumberOfCells())
2601 * Contrary to MEDCouplingPointSet::renumberNodes, this method makes a permutation without any fuse of cell.
2602 * After the call of this method the number of cells remains the same as before.
2604 * If 'check' equals true the method will check that any elements in [ \a old2NewBg; \a old2NewEnd ) is unique ; if not
2605 * an INTERP_KERNEL::Exception will be thrown. When 'check' equals true [ \a old2NewBg ; \a old2NewEnd ) is not expected to
2606 * be strictly in [0;this->getNumberOfCells()).
2608 * If 'check' equals false the method will not check the content of [ \a old2NewBg ; \a old2NewEnd ).
2609 * To avoid any throw of SIGSEGV when 'check' equals false, the elements in [ \a old2NewBg ; \a old2NewEnd ) should be unique and
2610 * should be contained in[0;this->getNumberOfCells()).
2612 * \param [in] old2NewBg is expected to be a dynamically allocated pointer of size at least equal to this->getNumberOfCells()
2615 void MEDCouplingUMesh::renumberCells(const mcIdType *old2NewBg, bool check)
2617 checkConnectivityFullyDefined();
2618 mcIdType nbCells=getNumberOfCells();
2619 const mcIdType *array=old2NewBg;
2621 array=DataArrayIdType::CheckAndPreparePermutation(old2NewBg,old2NewBg+nbCells);
2623 const mcIdType *conn=_nodal_connec->getConstPointer();
2624 const mcIdType *connI=_nodal_connec_index->getConstPointer();
2625 MCAuto<DataArrayIdType> o2n=DataArrayIdType::New(); o2n->useArray(array,false,DeallocType::C_DEALLOC,nbCells,1);
2626 MCAuto<DataArrayIdType> n2o=o2n->invertArrayO2N2N2O(nbCells);
2627 const mcIdType *n2oPtr=n2o->begin();
2628 MCAuto<DataArrayIdType> newConn=DataArrayIdType::New();
2629 newConn->alloc(_nodal_connec->getNumberOfTuples(),_nodal_connec->getNumberOfComponents());
2630 newConn->copyStringInfoFrom(*_nodal_connec);
2631 MCAuto<DataArrayIdType> newConnI=DataArrayIdType::New();
2632 newConnI->alloc(_nodal_connec_index->getNumberOfTuples(),_nodal_connec_index->getNumberOfComponents());
2633 newConnI->copyStringInfoFrom(*_nodal_connec_index);
2635 mcIdType *newC=newConn->getPointer();
2636 mcIdType *newCI=newConnI->getPointer();
2639 for(mcIdType i=0;i<nbCells;i++)
2641 mcIdType pos=n2oPtr[i];
2642 mcIdType nbOfElts=connI[pos+1]-connI[pos];
2643 newC=std::copy(conn+connI[pos],conn+connI[pos+1],newC);
2648 setConnectivity(newConn,newConnI);
2650 free(const_cast<mcIdType *>(array));
2654 * Finds cells whose bounding boxes intersect a given bounding box.
2655 * \param [in] bbox - an array defining the bounding box via coordinates of its
2656 * extremum points in "no interlace" mode, i.e. xMin, xMax, yMin, yMax, zMin,
2658 * \param [in] eps - a factor used to increase size of the bounding box of cell
2659 * before comparing it with \a bbox. This factor is multiplied by the maximal
2660 * extent of the bounding box of cell to produce an addition to this bounding box.
2661 * \return DataArrayIdType * - a new instance of DataArrayIdType holding ids for found
2662 * cells. The caller is to delete this array using decrRef() as it is no more
2664 * \throw If the coordinates array is not set.
2665 * \throw If the nodal connectivity of cells is not defined.
2667 * \if ENABLE_EXAMPLES
2668 * \ref cpp_mcumesh_getCellsInBoundingBox "Here is a C++ example".<br>
2669 * \ref py_mcumesh_getCellsInBoundingBox "Here is a Python example".
2672 DataArrayIdType *MEDCouplingUMesh::getCellsInBoundingBox(const double *bbox, double eps) const
2674 MCAuto<DataArrayIdType> elems=DataArrayIdType::New(); elems->alloc(0,1);
2675 if(getMeshDimension()==-1)
2677 elems->pushBackSilent(0);
2678 return elems.retn();
2680 int dim=getSpaceDimension();
2681 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2682 const mcIdType* conn = getNodalConnectivity()->getConstPointer();
2683 const mcIdType* conn_index= getNodalConnectivityIndex()->getConstPointer();
2684 const double* coords = getCoords()->getConstPointer();
2685 mcIdType nbOfCells=getNumberOfCells();
2686 for ( mcIdType ielem=0; ielem<nbOfCells;ielem++ )
2688 for (int i=0; i<dim; i++)
2690 elem_bb[i*2]=std::numeric_limits<double>::max();
2691 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2694 for (mcIdType inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2696 mcIdType node= conn[inode];
2697 if(node>=0)//avoid polyhedron separator
2699 for (int idim=0; idim<dim; idim++)
2701 if ( coords[node*dim+idim] < elem_bb[idim*2] )
2703 elem_bb[idim*2] = coords[node*dim+idim] ;
2705 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2707 elem_bb[idim*2+1] = coords[node*dim+idim] ;
2712 if (intersectsBoundingBox(elem_bb, bbox, dim, eps))
2713 elems->pushBackSilent(ielem);
2715 return elems.retn();
2719 * Given a boundary box 'bbox' returns elements 'elems' contained in this 'bbox' or touching 'bbox' (within 'eps' distance).
2720 * Warning 'elems' is incremented during the call so if elems is not empty before call returned elements will be
2721 * added in 'elems' parameter.
2723 DataArrayIdType *MEDCouplingUMesh::getCellsInBoundingBox(const INTERP_KERNEL::DirectedBoundingBox& bbox, double eps)
2725 MCAuto<DataArrayIdType> elems=DataArrayIdType::New(); elems->alloc(0,1);
2726 if(getMeshDimension()==-1)
2728 elems->pushBackSilent(0);
2729 return elems.retn();
2731 int dim=getSpaceDimension();
2732 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2733 const mcIdType* conn = getNodalConnectivity()->getConstPointer();
2734 const mcIdType* conn_index= getNodalConnectivityIndex()->getConstPointer();
2735 const double* coords = getCoords()->getConstPointer();
2736 mcIdType nbOfCells=getNumberOfCells();
2737 for ( mcIdType ielem=0; ielem<nbOfCells;ielem++ )
2739 for (int i=0; i<dim; i++)
2741 elem_bb[i*2]=std::numeric_limits<double>::max();
2742 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2745 for (mcIdType inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2747 mcIdType node= conn[inode];
2748 if(node>=0)//avoid polyhedron separator
2750 for (int idim=0; idim<dim; idim++)
2752 if ( coords[node*dim+idim] < elem_bb[idim*2] )
2754 elem_bb[idim*2] = coords[node*dim+idim] ;
2756 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2758 elem_bb[idim*2+1] = coords[node*dim+idim] ;
2763 if(intersectsBoundingBox(bbox, elem_bb, dim, eps))
2764 elems->pushBackSilent(ielem);
2766 return elems.retn();
2770 * Returns a type of a cell by its id.
2771 * \param [in] cellId - the id of the cell of interest.
2772 * \return INTERP_KERNEL::NormalizedCellType - enumeration item describing the cell type.
2773 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2775 INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::getTypeOfCell(mcIdType cellId) const
2777 const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
2778 if(cellId<_nodal_connec_index->getNbOfElems()-1)
2779 return (INTERP_KERNEL::NormalizedCellType) pt[ptI[cellId]];
2782 std::ostringstream oss; oss << "MEDCouplingUMesh::getTypeOfCell : Requesting type of cell #" << cellId << " but it should be in [0," << _nodal_connec_index->getNbOfElems()-1 << ") !";
2783 throw INTERP_KERNEL::Exception(oss.str());
2788 * This method returns a newly allocated array containing cell ids (ascendingly sorted) whose geometric type are equal to type.
2789 * This method does not throw exception if geometric type \a type is not in \a this.
2790 * This method throws an INTERP_KERNEL::Exception if meshdimension of \b this is not equal to those of \b type.
2791 * The coordinates array is not considered here.
2793 * \param [in] type the geometric type
2794 * \return cell ids in this having geometric type \a type.
2796 DataArrayIdType *MEDCouplingUMesh::giveCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2799 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
2801 checkConnectivityFullyDefined();
2802 mcIdType nbCells=getNumberOfCells();
2803 int mdim=getMeshDimension();
2804 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
2805 if(mdim!=ToIdType(cm.getDimension()))
2806 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::giveCellsWithType : Mismatch between mesh dimension and dimension of the cell !");
2807 const mcIdType *ptI=_nodal_connec_index->getConstPointer();
2808 const mcIdType *pt=_nodal_connec->getConstPointer();
2809 for(mcIdType i=0;i<nbCells;i++)
2811 if((INTERP_KERNEL::NormalizedCellType)pt[ptI[i]]==type)
2812 ret->pushBackSilent(i);
2818 * Returns nb of cells having the geometric type \a type. No throw if no cells in \a this has the geometric type \a type.
2820 mcIdType MEDCouplingUMesh::getNumberOfCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2822 const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
2823 mcIdType nbOfCells(getNumberOfCells()),ret(0);
2824 for(mcIdType i=0;i<nbOfCells;i++)
2825 if((INTERP_KERNEL::NormalizedCellType) pt[ptI[i]]==type)
2831 * Returns the nodal connectivity of a given cell.
2832 * The separator of faces within polyhedron connectivity (-1) is not returned, thus
2833 * all returned node ids can be used in getCoordinatesOfNode().
2834 * \param [in] cellId - an id of the cell of interest.
2835 * \param [in,out] conn - a vector where the node ids are appended. It is not
2836 * cleared before the appending.
2837 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2839 void MEDCouplingUMesh::getNodeIdsOfCell(mcIdType cellId, std::vector<mcIdType>& conn) const
2841 const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
2842 for(const mcIdType *w=pt+ptI[cellId]+1;w!=pt+ptI[cellId+1];w++)
2847 std::string MEDCouplingUMesh::simpleRepr() const
2849 static const char msg0[]="No coordinates specified !";
2850 std::ostringstream ret;
2851 ret << "Unstructured mesh with name : \"" << getName() << "\"\n";
2852 ret << "Description of mesh : \"" << getDescription() << "\"\n";
2854 double tt=getTime(tmpp1,tmpp2);
2855 ret << "Time attached to the mesh [unit] : " << tt << " [" << getTimeUnit() << "]\n";
2856 ret << "Iteration : " << tmpp1 << " Order : " << tmpp2 << "\n";
2858 { ret << "Mesh dimension : " << _mesh_dim << "\nSpace dimension : "; }
2860 { ret << " Mesh dimension has not been set or is invalid !"; }
2863 const int spaceDim=getSpaceDimension();
2864 ret << spaceDim << "\nInfo attached on space dimension : ";
2865 for(int i=0;i<spaceDim;i++)
2866 ret << "\"" << _coords->getInfoOnComponent(i) << "\" ";
2870 ret << msg0 << "\n";
2871 ret << "Number of nodes : ";
2873 ret << getNumberOfNodes() << "\n";
2875 ret << msg0 << "\n";
2876 ret << "Number of cells : ";
2877 if(_nodal_connec!=0 && _nodal_connec_index!=0)
2878 ret << getNumberOfCells() << "\n";
2880 ret << "No connectivity specified !" << "\n";
2881 ret << "Cell types present : ";
2882 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
2884 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter);
2885 ret << cm.getRepr() << " ";
2891 std::string MEDCouplingUMesh::advancedRepr() const
2893 std::ostringstream ret;
2894 ret << simpleRepr();
2895 ret << "\nCoordinates array : \n___________________\n\n";
2897 _coords->reprWithoutNameStream(ret);
2899 ret << "No array set !\n";
2900 ret << "\n\nConnectivity arrays : \n_____________________\n\n";
2901 reprConnectivityOfThisLL(ret);
2906 * This method returns a C++ code that is a dump of \a this.
2907 * This method will throw if this is not fully defined.
2909 std::string MEDCouplingUMesh::cppRepr() const
2911 static const char coordsName[]="coords";
2912 static const char connName[]="conn";
2913 static const char connIName[]="connI";
2914 checkFullyDefined();
2915 std::ostringstream ret; ret << "// coordinates" << std::endl;
2916 _coords->reprCppStream(coordsName,ret); ret << std::endl << "// connectivity" << std::endl;
2917 _nodal_connec->reprCppStream(connName,ret); ret << std::endl;
2918 _nodal_connec_index->reprCppStream(connIName,ret); ret << std::endl;
2919 ret << "MEDCouplingUMesh *mesh=MEDCouplingUMesh::New(\"" << getName() << "\"," << getMeshDimension() << ");" << std::endl;
2920 ret << "mesh->setCoords(" << coordsName << ");" << std::endl;
2921 ret << "mesh->setConnectivity(" << connName << "," << connIName << ",true);" << std::endl;
2922 ret << coordsName << "->decrRef(); " << connName << "->decrRef(); " << connIName << "->decrRef();" << std::endl;
2926 std::string MEDCouplingUMesh::reprConnectivityOfThis() const
2928 std::ostringstream ret;
2929 reprConnectivityOfThisLL(ret);
2934 * This method builds a newly allocated instance (with the same name than \a this) that the caller has the responsibility to deal with.
2935 * This method returns an instance with all arrays allocated (connectivity, connectivity index, coordinates)
2936 * but with length of these arrays set to 0. It allows to define an "empty" mesh (with nor cells nor nodes but compliant with
2939 * This method expects that \a this has a mesh dimension set and higher or equal to 0. If not an exception will be thrown.
2940 * 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
2941 * with number of tuples set to 0, if not the array is taken as this in the returned instance.
2943 MEDCouplingUMesh *MEDCouplingUMesh::buildSetInstanceFromThis(std::size_t spaceDim) const
2945 int mdim=getMeshDimension();
2947 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSetInstanceFromThis : invalid mesh dimension ! Should be >= 0 !");
2948 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
2949 MCAuto<DataArrayIdType> tmp1,tmp2;
2950 bool needToCpyCT=true;
2953 tmp1=DataArrayIdType::New(); tmp1->alloc(0,1);
2961 if(!_nodal_connec_index)
2963 tmp2=DataArrayIdType::New(); tmp2->alloc(1,1); tmp2->setIJ(0,0,0);
2968 tmp2=_nodal_connec_index;
2971 ret->setConnectivity(tmp1,tmp2,false);
2976 MCAuto<DataArrayDouble> coords=DataArrayDouble::New(); coords->alloc(0,spaceDim);
2977 ret->setCoords(coords);
2980 ret->setCoords(_coords);
2984 mcIdType MEDCouplingUMesh::getNumberOfNodesInCell(mcIdType cellId) const
2986 const mcIdType *ptI=_nodal_connec_index->getConstPointer();
2987 const mcIdType *pt=_nodal_connec->getConstPointer();
2988 if(pt[ptI[cellId]]!=INTERP_KERNEL::NORM_POLYHED)
2989 return ptI[cellId+1]-ptI[cellId]-1;
2991 return ToIdType(std::count_if(pt+ptI[cellId]+1,pt+ptI[cellId+1],std::bind2nd(std::not_equal_to<mcIdType>(),-1)));
2995 * Returns types of cells of the specified part of \a this mesh.
2996 * This method avoids computing sub-mesh explicitly to get its types.
2997 * \param [in] begin - an array of cell ids of interest.
2998 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
2999 * \return std::set<INTERP_KERNEL::NormalizedCellType> - a set of enumeration items
3000 * describing the cell types.
3001 * \throw If the coordinates array is not set.
3002 * \throw If the nodal connectivity of cells is not defined.
3003 * \sa getAllGeoTypes()
3005 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getTypesOfPart(const mcIdType *begin, const mcIdType *end) const
3007 checkFullyDefined();
3008 std::set<INTERP_KERNEL::NormalizedCellType> ret;
3009 const mcIdType *conn=_nodal_connec->getConstPointer();
3010 const mcIdType *connIndex=_nodal_connec_index->getConstPointer();
3011 for(const mcIdType *w=begin;w!=end;w++)
3012 ret.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]);
3017 * Defines the nodal connectivity using given connectivity arrays in \ref numbering-indirect format.
3018 * Optionally updates
3019 * a set of types of cells constituting \a this mesh.
3020 * This method is for advanced users having prepared their connectivity before. For
3021 * more info on using this method see \ref MEDCouplingUMeshAdvBuild.
3022 * \param [in] conn - the nodal connectivity array.
3023 * \param [in] connIndex - the nodal connectivity index array.
3024 * \param [in] isComputingTypes - if \c true, the set of types constituting \a this
3027 void MEDCouplingUMesh::setConnectivity(DataArrayIdType *conn, DataArrayIdType *connIndex, bool isComputingTypes)
3029 DataArrayIdType::SetArrayIn(conn,_nodal_connec);
3030 DataArrayIdType::SetArrayIn(connIndex,_nodal_connec_index);
3031 if(isComputingTypes)
3037 * Copy constructor. If 'deepCopy' is false \a this is a shallow copy of other.
3038 * If 'deeCpy' is true all arrays (coordinates and connectivities) are deeply copied.
3040 MEDCouplingUMesh::MEDCouplingUMesh(const MEDCouplingUMesh& other, bool deepCpy):MEDCouplingPointSet(other,deepCpy),_mesh_dim(other._mesh_dim),
3041 _nodal_connec(0),_nodal_connec_index(0),
3042 _types(other._types)
3044 if(other._nodal_connec)
3045 _nodal_connec=other._nodal_connec->performCopyOrIncrRef(deepCpy);
3046 if(other._nodal_connec_index)
3047 _nodal_connec_index=other._nodal_connec_index->performCopyOrIncrRef(deepCpy);
3050 MEDCouplingUMesh::~MEDCouplingUMesh()
3053 _nodal_connec->decrRef();
3054 if(_nodal_connec_index)
3055 _nodal_connec_index->decrRef();
3059 * Recomputes a set of cell types of \a this mesh. For more info see
3060 * \ref MEDCouplingUMeshNodalConnectivity.
3062 void MEDCouplingUMesh::computeTypes()
3064 ComputeAllTypesInternal(_types,_nodal_connec,_nodal_connec_index);
3069 * Returns a number of cells constituting \a this mesh.
3070 * \return mcIdType - the number of cells in \a this mesh.
3071 * \throw If the nodal connectivity of cells is not defined.
3073 mcIdType MEDCouplingUMesh::getNumberOfCells() const
3075 if(_nodal_connec_index)
3076 return _nodal_connec_index->getNumberOfTuples()-1;
3081 throw INTERP_KERNEL::Exception("Unable to get number of cells because no connectivity specified !");
3085 * Returns a dimension of \a this mesh, i.e. a dimension of cells constituting \a this
3086 * mesh. For more info see \ref meshes.
3087 * \return int - the dimension of \a this mesh.
3088 * \throw If the mesh dimension is not defined using setMeshDimension().
3090 int MEDCouplingUMesh::getMeshDimension() const
3093 throw INTERP_KERNEL::Exception("No mesh dimension specified !");
3098 * Returns a length of the nodal connectivity array.
3099 * This method is for test reason. Normally the integer returned is not useable by
3100 * user. For more info see \ref MEDCouplingUMeshNodalConnectivity.
3101 * \return mcIdType - the length of the nodal connectivity array.
3103 mcIdType MEDCouplingUMesh::getNodalConnectivityArrayLen() const
3105 return _nodal_connec->getNbOfElems();
3109 * First step of serialization process. Used by ParaMEDMEM and MEDCouplingCorba to transfert data between process.
3111 void MEDCouplingUMesh::getTinySerializationInformation(std::vector<double>& tinyInfoD, std::vector<mcIdType>& tinyInfo, std::vector<std::string>& littleStrings) const
3113 MEDCouplingPointSet::getTinySerializationInformation(tinyInfoD,tinyInfo,littleStrings);
3114 tinyInfo.push_back(ToIdType(getMeshDimension()));
3115 tinyInfo.push_back(getNumberOfCells());
3117 tinyInfo.push_back(getNodalConnectivityArrayLen());
3119 tinyInfo.push_back(-1);
3123 * First step of unserialization process.
3125 bool MEDCouplingUMesh::isEmptyMesh(const std::vector<mcIdType>& tinyInfo) const
3127 return tinyInfo[6]<=0;
3131 * Second step of serialization process.
3132 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3135 * \param littleStrings
3137 void MEDCouplingUMesh::resizeForUnserialization(const std::vector<mcIdType>& tinyInfo, DataArrayIdType *a1, DataArrayDouble *a2, std::vector<std::string>& littleStrings) const
3139 MEDCouplingPointSet::resizeForUnserialization(tinyInfo,a1,a2,littleStrings);
3141 a1->alloc(tinyInfo[7]+tinyInfo[6]+1,1);
3145 * Third and final step of serialization process.
3147 void MEDCouplingUMesh::serialize(DataArrayIdType *&a1, DataArrayDouble *&a2) const
3149 MEDCouplingPointSet::serialize(a1,a2);
3150 if(getMeshDimension()>-1)
3152 a1=DataArrayIdType::New();
3153 a1->alloc(getNodalConnectivityArrayLen()+getNumberOfCells()+1,1);
3154 mcIdType *ptA1=a1->getPointer();
3155 const mcIdType *conn=getNodalConnectivity()->getConstPointer();
3156 const mcIdType *index=getNodalConnectivityIndex()->getConstPointer();
3157 ptA1=std::copy(index,index+getNumberOfCells()+1,ptA1);
3158 std::copy(conn,conn+getNodalConnectivityArrayLen(),ptA1);
3165 * Second and final unserialization process.
3166 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3168 void MEDCouplingUMesh::unserialization(const std::vector<double>& tinyInfoD, const std::vector<mcIdType>& tinyInfo, const DataArrayIdType *a1, DataArrayDouble *a2, const std::vector<std::string>& littleStrings)
3170 MEDCouplingPointSet::unserialization(tinyInfoD,tinyInfo,a1,a2,littleStrings);
3171 setMeshDimension(FromIdType<int>(tinyInfo[5]));
3175 const mcIdType *recvBuffer=a1->getConstPointer();
3176 MCAuto<DataArrayIdType> myConnecIndex=DataArrayIdType::New();
3177 myConnecIndex->alloc(tinyInfo[6]+1,1);
3178 std::copy(recvBuffer,recvBuffer+tinyInfo[6]+1,myConnecIndex->getPointer());
3179 MCAuto<DataArrayIdType> myConnec=DataArrayIdType::New();
3180 myConnec->alloc(tinyInfo[7],1);
3181 std::copy(recvBuffer+tinyInfo[6]+1,recvBuffer+tinyInfo[6]+1+tinyInfo[7],myConnec->getPointer());
3182 setConnectivity(myConnec, myConnecIndex);
3189 * Returns a new MEDCouplingFieldDouble containing volumes of cells constituting \a this
3191 * For 1D cells, the returned field contains lengths.<br>
3192 * For 2D cells, the returned field contains areas.<br>
3193 * For 3D cells, the returned field contains volumes.
3194 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3195 * orientation, i.e. the volume is always positive.
3196 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on cells
3197 * and one time . The caller is to delete this field using decrRef() as it is no
3200 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureField(bool isAbs) const
3202 std::string name="MeasureOfMesh_";
3204 mcIdType nbelem=getNumberOfCells();
3205 MCAuto<MEDCouplingFieldDouble> field=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3206 field->setName(name);
3207 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3208 array->alloc(nbelem,1);
3209 double *area_vol=array->getPointer();
3210 field->setArray(array) ; array=0;
3211 field->setMesh(const_cast<MEDCouplingUMesh *>(this));
3212 field->synchronizeTimeWithMesh();
3213 if(getMeshDimension()!=-1)
3216 INTERP_KERNEL::NormalizedCellType type;
3217 int dim_space=getSpaceDimension();
3218 const double *coords=getCoords()->getConstPointer();
3219 const mcIdType *connec=getNodalConnectivity()->getConstPointer();
3220 const mcIdType *connec_index=getNodalConnectivityIndex()->getConstPointer();
3221 for(mcIdType iel=0;iel<nbelem;iel++)
3223 ipt=connec_index[iel];
3224 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3225 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);
3228 std::transform(area_vol,area_vol+nbelem,area_vol,std::ptr_fun<double,double>(fabs));
3232 area_vol[0]=std::numeric_limits<double>::max();
3234 return field.retn();
3238 * Returns a new DataArrayDouble containing volumes of specified cells of \a this
3240 * For 1D cells, the returned array contains lengths.<br>
3241 * For 2D cells, the returned array contains areas.<br>
3242 * For 3D cells, the returned array contains volumes.
3243 * This method avoids building explicitly a part of \a this mesh to perform the work.
3244 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3245 * orientation, i.e. the volume is always positive.
3246 * \param [in] begin - an array of cell ids of interest.
3247 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3248 * \return DataArrayDouble * - a new instance of DataArrayDouble. The caller is to
3249 * delete this array using decrRef() as it is no more needed.
3251 * \if ENABLE_EXAMPLES
3252 * \ref cpp_mcumesh_getPartMeasureField "Here is a C++ example".<br>
3253 * \ref py_mcumesh_getPartMeasureField "Here is a Python example".
3255 * \sa getMeasureField()
3257 DataArrayDouble *MEDCouplingUMesh::getPartMeasureField(bool isAbs, const mcIdType *begin, const mcIdType *end) const
3259 std::string name="PartMeasureOfMesh_";
3261 std::size_t nbelem=std::distance(begin,end);
3262 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3263 array->setName(name);
3264 array->alloc(nbelem,1);
3265 double *area_vol=array->getPointer();
3266 if(getMeshDimension()!=-1)
3269 INTERP_KERNEL::NormalizedCellType type;
3270 int dim_space=getSpaceDimension();
3271 const double *coords=getCoords()->getConstPointer();
3272 const mcIdType *connec=getNodalConnectivity()->getConstPointer();
3273 const mcIdType *connec_index=getNodalConnectivityIndex()->getConstPointer();
3274 for(const mcIdType *iel=begin;iel!=end;iel++)
3276 ipt=connec_index[*iel];
3277 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3278 *area_vol++=INTERP_KERNEL::computeVolSurfOfCell2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,connec+ipt+1,connec_index[*iel+1]-ipt-1,coords,dim_space);
3281 std::transform(array->getPointer(),area_vol,array->getPointer(),std::ptr_fun<double,double>(fabs));
3285 area_vol[0]=std::numeric_limits<double>::max();
3287 return array.retn();
3291 * Returns a new MEDCouplingFieldDouble containing volumes of cells of a dual mesh of
3292 * \a this one. The returned field contains the dual cell volume for each corresponding
3293 * node in \a this mesh. In other words, the field returns the getMeasureField() of
3294 * the dual mesh in P1 sens of \a this.<br>
3295 * For 1D cells, the returned field contains lengths.<br>
3296 * For 2D cells, the returned field contains areas.<br>
3297 * For 3D cells, the returned field contains volumes.
3298 * This method is useful to check "P1*" conservative interpolators.
3299 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3300 * orientation, i.e. the volume is always positive.
3301 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3302 * nodes and one time. The caller is to delete this array using decrRef() as
3303 * it is no more needed.
3305 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureFieldOnNode(bool isAbs) const
3307 MCAuto<MEDCouplingFieldDouble> tmp=getMeasureField(isAbs);
3308 std::string name="MeasureOnNodeOfMesh_";
3310 mcIdType nbNodes=getNumberOfNodes();
3311 MCAuto<DataArrayDouble> nnpc;
3313 MCAuto<DataArrayIdType> tmp(computeNbOfNodesPerCell());
3314 nnpc=tmp->convertToDblArr();
3316 std::for_each(nnpc->rwBegin(),nnpc->rwEnd(),[](double& v) { v=1./v; });
3317 const double *nnpcPtr(nnpc->begin());
3318 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_NODES);
3319 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3320 array->alloc(nbNodes,1);
3321 double *valsToFill=array->getPointer();
3322 std::fill(valsToFill,valsToFill+nbNodes,0.);
3323 const double *values=tmp->getArray()->getConstPointer();
3324 MCAuto<DataArrayIdType> da=DataArrayIdType::New();
3325 MCAuto<DataArrayIdType> daInd=DataArrayIdType::New();
3326 getReverseNodalConnectivity(da,daInd);
3327 const mcIdType *daPtr=da->getConstPointer();
3328 const mcIdType *daIPtr=daInd->getConstPointer();
3329 for(mcIdType i=0;i<nbNodes;i++)
3330 for(const mcIdType *cell=daPtr+daIPtr[i];cell!=daPtr+daIPtr[i+1];cell++)
3331 valsToFill[i]+=nnpcPtr[*cell]*values[*cell];
3333 ret->setArray(array);
3338 * Returns a new MEDCouplingFieldDouble holding normal vectors to cells of \a this
3339 * mesh. The returned normal vectors to each cell have a norm2 equal to 1.
3340 * The computed vectors have <em> this->getMeshDimension()+1 </em> components
3341 * and are normalized.
3342 * <br> \a this can be either
3343 * - a 2D mesh in 2D or 3D space or
3344 * - an 1D mesh in 2D space.
3346 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3347 * cells and one time. The caller is to delete this field using decrRef() as
3348 * it is no more needed.
3349 * \throw If the nodal connectivity of cells is not defined.
3350 * \throw If the coordinates array is not set.
3351 * \throw If the mesh dimension is not set.
3352 * \throw If the mesh and space dimension is not as specified above.
3354 MEDCouplingFieldDouble *MEDCouplingUMesh::buildOrthogonalField() const
3356 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3357 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3358 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3359 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3360 mcIdType nbOfCells=getNumberOfCells();
3361 int nbComp=getMeshDimension()+1;
3362 array->alloc(nbOfCells,nbComp);
3363 double *vals=array->getPointer();
3364 const mcIdType *connI=_nodal_connec_index->getConstPointer();
3365 const mcIdType *conn=_nodal_connec->getConstPointer();
3366 const double *coords=_coords->getConstPointer();
3367 if(getMeshDimension()==2)
3369 if(getSpaceDimension()==3)
3371 MCAuto<DataArrayDouble> loc=computeCellCenterOfMass();
3372 const double *locPtr=loc->getConstPointer();
3373 for(mcIdType i=0;i<nbOfCells;i++,vals+=3)
3375 mcIdType offset=connI[i];
3376 INTERP_KERNEL::crossprod<3>(locPtr+3*i,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3377 double n=INTERP_KERNEL::norm<3>(vals);
3378 std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3383 MCAuto<MEDCouplingFieldDouble> isAbs=getMeasureField(false);
3384 const double *isAbsPtr=isAbs->getArray()->begin();
3385 for(mcIdType i=0;i<nbOfCells;i++,isAbsPtr++)
3386 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=*isAbsPtr>0.?1.:-1.; }
3389 else//meshdimension==1
3392 for(mcIdType i=0;i<nbOfCells;i++)
3394 mcIdType offset=connI[i];
3395 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3396 double n=INTERP_KERNEL::norm<2>(tmp);
3397 std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3402 ret->setArray(array);
3404 ret->synchronizeTimeWithSupport();
3409 * Returns a new MEDCouplingFieldDouble holding normal vectors to specified cells of
3410 * \a this mesh. The computed vectors have <em> this->getMeshDimension()+1 </em> components
3411 * and are normalized.
3412 * <br> \a this can be either
3413 * - a 2D mesh in 2D or 3D space or
3414 * - an 1D mesh in 2D space.
3416 * This method avoids building explicitly a part of \a this mesh to perform the work.
3417 * \param [in] begin - an array of cell ids of interest.
3418 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3419 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3420 * cells and one time. The caller is to delete this field using decrRef() as
3421 * it is no more needed.
3422 * \throw If the nodal connectivity of cells is not defined.
3423 * \throw If the coordinates array is not set.
3424 * \throw If the mesh dimension is not set.
3425 * \throw If the mesh and space dimension is not as specified above.
3426 * \sa buildOrthogonalField()
3428 * \if ENABLE_EXAMPLES
3429 * \ref cpp_mcumesh_buildPartOrthogonalField "Here is a C++ example".<br>
3430 * \ref py_mcumesh_buildPartOrthogonalField "Here is a Python example".
3433 MEDCouplingFieldDouble *MEDCouplingUMesh::buildPartOrthogonalField(const mcIdType *begin, const mcIdType *end) const
3435 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3436 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3437 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3438 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3439 std::size_t nbelems=std::distance(begin,end);
3440 int nbComp=getMeshDimension()+1;
3441 array->alloc(nbelems,nbComp);
3442 double *vals=array->getPointer();
3443 const mcIdType *connI=_nodal_connec_index->getConstPointer();
3444 const mcIdType *conn=_nodal_connec->getConstPointer();
3445 const double *coords=_coords->getConstPointer();
3446 if(getMeshDimension()==2)
3448 if(getSpaceDimension()==3)
3450 MCAuto<DataArrayDouble> loc=getPartBarycenterAndOwner(begin,end);
3451 const double *locPtr=loc->getConstPointer();
3452 for(const mcIdType *i=begin;i!=end;i++,vals+=3,locPtr+=3)
3454 mcIdType offset=connI[*i];
3455 INTERP_KERNEL::crossprod<3>(locPtr,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3456 double n=INTERP_KERNEL::norm<3>(vals);
3457 std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3462 for(std::size_t i=0;i<nbelems;i++)
3463 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=1.; }
3466 else//meshdimension==1
3469 for(const mcIdType *i=begin;i!=end;i++)
3471 mcIdType offset=connI[*i];
3472 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3473 double n=INTERP_KERNEL::norm<2>(tmp);
3474 std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3479 ret->setArray(array);
3481 ret->synchronizeTimeWithSupport();
3486 * Returns a new MEDCouplingFieldDouble holding a direction vector for each SEG2 in \a
3487 * this 1D mesh. The computed vectors have <em> this->getSpaceDimension() </em> components
3488 * and are \b not normalized.
3489 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3490 * cells and one time. The caller is to delete this field using decrRef() as
3491 * it is no more needed.
3492 * \throw If the nodal connectivity of cells is not defined.
3493 * \throw If the coordinates array is not set.
3494 * \throw If \a this->getMeshDimension() != 1.
3495 * \throw If \a this mesh includes cells of type other than SEG2.
3497 MEDCouplingFieldDouble *MEDCouplingUMesh::buildDirectionVectorField() const
3499 if(getMeshDimension()!=1)
3500 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for buildDirectionVectorField !");
3501 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3502 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for buildDirectionVectorField !");
3503 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3504 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3505 mcIdType nbOfCells=getNumberOfCells();
3506 int spaceDim=getSpaceDimension();
3507 array->alloc(nbOfCells,spaceDim);
3508 double *pt=array->getPointer();
3509 const double *coo=getCoords()->getConstPointer();
3510 std::vector<mcIdType> conn;
3512 for(mcIdType i=0;i<nbOfCells;i++)
3515 getNodeIdsOfCell(i,conn);
3516 pt=std::transform(coo+conn[1]*spaceDim,coo+(conn[1]+1)*spaceDim,coo+conn[0]*spaceDim,pt,std::minus<double>());
3518 ret->setArray(array);
3520 ret->synchronizeTimeWithSupport();
3525 * Creates a 2D mesh by cutting \a this 3D mesh with a plane. In addition to the mesh,
3526 * returns a new DataArrayIdType, of length equal to the number of 2D cells in the result
3527 * mesh, holding, for each cell in the result mesh, an id of a 3D cell it comes
3528 * from. If a result face is shared by two 3D cells, then the face in included twice in
3530 * \param [in] origin - 3 components of a point defining location of the plane.
3531 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3532 * must be greater than 1e-6.
3533 * \param [in] eps - half-thickness of the plane.
3534 * \param [out] cellIds - a new instance of DataArrayIdType holding ids of 3D cells
3535 * producing correspondent 2D cells. The caller is to delete this array
3536 * using decrRef() as it is no more needed.
3537 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This mesh does
3538 * not share the node coordinates array with \a this mesh. The caller is to
3539 * delete this mesh using decrRef() as it is no more needed.
3540 * \throw If the coordinates array is not set.
3541 * \throw If the nodal connectivity of cells is not defined.
3542 * \throw If \a this->getMeshDimension() != 3 or \a this->getSpaceDimension() != 3.
3543 * \throw If magnitude of \a vec is less than 1e-6.
3544 * \throw If the plane does not intersect any 3D cell of \a this mesh.
3545 * \throw If \a this includes quadratic cells.
3547 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3D(const double *origin, const double *vec, double eps, DataArrayIdType *&cellIds) const
3549 checkFullyDefined();
3550 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3551 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3552 MCAuto<DataArrayIdType> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3553 if(candidates->empty())
3554 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane considering bounding boxes !");
3555 std::vector<mcIdType> nodes;
3556 DataArrayIdType *cellIds1D=0;
3557 MCAuto<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3558 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3559 MCAuto<DataArrayIdType> desc1=DataArrayIdType::New(),desc2=DataArrayIdType::New();
3560 MCAuto<DataArrayIdType> descIndx1=DataArrayIdType::New(),descIndx2=DataArrayIdType::New();
3561 MCAuto<DataArrayIdType> revDesc1=DataArrayIdType::New(),revDesc2=DataArrayIdType::New();
3562 MCAuto<DataArrayIdType> revDescIndx1=DataArrayIdType::New(),revDescIndx2=DataArrayIdType::New();
3563 MCAuto<MEDCouplingUMesh> mDesc2=subMesh->buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2);//meshDim==2 spaceDim==3
3564 revDesc2=0; revDescIndx2=0;
3565 MCAuto<MEDCouplingUMesh> mDesc1=mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3566 revDesc1=0; revDescIndx1=0;
3567 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3568 MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3570 std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3571 for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3573 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3574 std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(mDesc2->getNumberOfCells());
3575 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->getConstPointer(),mDesc2->getNodalConnectivityIndex()->getConstPointer(),
3576 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3577 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3578 MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New()),cellIds2(DataArrayIdType::New());
3579 connI->pushBackSilent(0); conn->alloc(0,1); cellIds2->alloc(0,1);
3580 subMesh->assemblyForSplitFrom3DSurf(cut3DSurf,desc2->getConstPointer(),descIndx2->getConstPointer(),conn,connI,cellIds2);
3581 if(cellIds2->empty())
3582 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3583 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3D",2);
3584 ret->setCoords(mDesc1->getCoords());
3585 ret->setConnectivity(conn,connI,true);
3586 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3591 * Creates an 1D mesh by cutting \a this 2D mesh in 3D space with a plane. In
3592 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
3593 from. If a result segment is shared by two 2D cells, then the segment in included twice in
3595 * \param [in] origin - 3 components of a point defining location of the plane.
3596 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3597 * must be greater than 1e-6.
3598 * \param [in] eps - half-thickness of the plane.
3599 * \param [out] cellIds - a new instance of DataArrayIdType holding ids of faces
3600 * producing correspondent segments. The caller is to delete this array
3601 * using decrRef() as it is no more needed.
3602 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This is an 1D
3603 * mesh in 3D space. This mesh does not share the node coordinates array with
3604 * \a this mesh. The caller is to delete this mesh using decrRef() as it is
3606 * \throw If the coordinates array is not set.
3607 * \throw If the nodal connectivity of cells is not defined.
3608 * \throw If \a this->getMeshDimension() != 2 or \a this->getSpaceDimension() != 3.
3609 * \throw If magnitude of \a vec is less than 1e-6.
3610 * \throw If the plane does not intersect any 2D cell of \a this mesh.
3611 * \throw If \a this includes quadratic cells.
3613 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3DSurf(const double *origin, const double *vec, double eps, DataArrayIdType *&cellIds) const
3615 checkFullyDefined();
3616 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
3617 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf works on umeshes with meshdim equal to 2 and spaceDim equal to 3 !");
3618 MCAuto<DataArrayIdType> candidates(getCellIdsCrossingPlane(origin,vec,eps));
3619 if(candidates->empty())
3620 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3D surf cells in this intercepts the specified plane considering bounding boxes !");
3621 std::vector<mcIdType> nodes;
3622 DataArrayIdType *cellIds1D(0);
3623 MCAuto<MEDCouplingUMesh> subMesh(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3624 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3625 MCAuto<DataArrayIdType> desc1(DataArrayIdType::New()),descIndx1(DataArrayIdType::New()),revDesc1(DataArrayIdType::New()),revDescIndx1(DataArrayIdType::New());
3626 MCAuto<MEDCouplingUMesh> mDesc1(subMesh->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3627 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3628 MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3630 std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3631 for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3633 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3634 mcIdType ncellsSub=subMesh->getNumberOfCells();
3635 std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(ncellsSub);
3636 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,subMesh->getNodalConnectivity()->getConstPointer(),subMesh->getNodalConnectivityIndex()->getConstPointer(),
3637 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3638 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3639 MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New()),cellIds2(DataArrayIdType::New()); connI->pushBackSilent(0);
3641 const mcIdType *nodal=subMesh->getNodalConnectivity()->getConstPointer();
3642 const mcIdType *nodalI=subMesh->getNodalConnectivityIndex()->getConstPointer();
3643 for(mcIdType i=0;i<ncellsSub;i++)
3645 if(cut3DSurf[i].first!=-1 && cut3DSurf[i].second!=-1)
3647 if(cut3DSurf[i].first!=-2)
3649 conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_SEG2)); conn->pushBackSilent(cut3DSurf[i].first); conn->pushBackSilent(cut3DSurf[i].second);
3650 connI->pushBackSilent(conn->getNumberOfTuples());
3651 cellIds2->pushBackSilent(i);
3655 mcIdType cellId3DSurf=cut3DSurf[i].second;
3656 mcIdType offset=nodalI[cellId3DSurf]+1;
3657 mcIdType nbOfEdges=nodalI[cellId3DSurf+1]-offset;
3658 for(mcIdType j=0;j<nbOfEdges;j++)
3660 conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_SEG2)); conn->pushBackSilent(nodal[offset+j]); conn->pushBackSilent(nodal[offset+(j+1)%nbOfEdges]);
3661 connI->pushBackSilent(conn->getNumberOfTuples());
3662 cellIds2->pushBackSilent(cellId3DSurf);
3667 if(cellIds2->empty())
3668 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3DSurf cells in this intercepts the specified plane !");
3669 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3DSurf",1);
3670 ret->setCoords(mDesc1->getCoords());
3671 ret->setConnectivity(conn,connI,true);
3672 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3676 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::clipSingle3DCellByPlane(const double origin[3], const double vec[3], double eps) const
3678 checkFullyDefined();
3679 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3680 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3681 if(getNumberOfCells()!=1)
3682 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works only on mesh containing exactly one cell !");
3684 std::vector<mcIdType> nodes;
3685 findNodesOnPlane(origin,vec,eps,nodes);
3686 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());
3687 MCAuto<MEDCouplingUMesh> mDesc2(buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2));//meshDim==2 spaceDim==3
3688 revDesc2=0; revDescIndx2=0;
3689 MCAuto<MEDCouplingUMesh> mDesc1(mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3690 revDesc1=0; revDescIndx1=0;
3691 DataArrayIdType *cellIds1D(0);
3692 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3693 MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3694 std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3695 for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3699 mcIdType oldNbNodes(mDesc1->getNumberOfNodes());
3700 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3701 sameNbNodes=(mDesc1->getNumberOfNodes()==oldNbNodes);
3703 std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(mDesc2->getNumberOfCells());
3704 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->begin(),mDesc2->getNodalConnectivityIndex()->begin(),
3705 mDesc1->getNodalConnectivity()->begin(),mDesc1->getNodalConnectivityIndex()->begin(),
3706 desc1->begin(),descIndx1->begin(),cut3DSurf);
3707 MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New());
3708 connI->pushBackSilent(0); conn->alloc(0,1);
3710 MCAuto<DataArrayIdType> cellIds2(DataArrayIdType::New()); cellIds2->alloc(0,1);
3711 assemblyForSplitFrom3DSurf(cut3DSurf,desc2->begin(),descIndx2->begin(),conn,connI,cellIds2);
3712 if(cellIds2->empty())
3713 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3715 std::vector<std::vector<mcIdType> > res;
3716 buildSubCellsFromCut(cut3DSurf,desc2->begin(),descIndx2->begin(),mDesc1->getCoords()->begin(),eps,res);
3717 std::size_t sz(res.size());
3718 if(ToIdType(res.size())==mDesc1->getNumberOfCells() && sameNbNodes)
3719 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane : cell is not clipped !");
3720 for(std::size_t i=0;i<sz;i++)
3722 conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYGON));
3723 conn->insertAtTheEnd(res[i].begin(),res[i].end());
3724 connI->pushBackSilent(conn->getNumberOfTuples());
3726 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
3727 ret->setCoords(mDesc1->getCoords());
3728 ret->setConnectivity(conn,connI,true);
3729 mcIdType nbCellsRet(ret->getNumberOfCells());
3731 MCAuto<DataArrayDouble> vec2(DataArrayDouble::New()); vec2->alloc(1,3); std::copy(vec,vec+3,vec2->getPointer());
3732 MCAuto<MEDCouplingFieldDouble> ortho(ret->buildOrthogonalField());
3733 MCAuto<DataArrayDouble> ortho2(ortho->getArray()->selectByTupleIdSafeSlice(0,1,1));
3734 MCAuto<DataArrayDouble> dott(DataArrayDouble::Dot(ortho2,vec2));
3735 MCAuto<DataArrayDouble> ccm(ret->computeCellCenterOfMass());
3736 MCAuto<DataArrayDouble> occm;
3738 MCAuto<DataArrayDouble> pt(DataArrayDouble::New()); pt->alloc(1,3); std::copy(origin,origin+3,pt->getPointer());
3739 occm=DataArrayDouble::Substract(ccm,pt);
3741 vec2=DataArrayDouble::New(); vec2->alloc(nbCellsRet,3);
3742 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);
3743 MCAuto<DataArrayDouble> dott2(DataArrayDouble::Dot(occm,vec2));
3745 const mcIdType *cPtr(ret->getNodalConnectivity()->begin()),*ciPtr(ret->getNodalConnectivityIndex()->begin());
3746 MCAuto<MEDCouplingUMesh> ret2(MEDCouplingUMesh::New("Clip3D",3));
3747 ret2->setCoords(mDesc1->getCoords());
3748 MCAuto<DataArrayIdType> conn2(DataArrayIdType::New()),conn2I(DataArrayIdType::New());
3749 conn2I->pushBackSilent(0); conn2->alloc(0,1);
3750 std::vector<mcIdType> cell0(1,ToIdType(INTERP_KERNEL::NORM_POLYHED));
3751 std::vector<mcIdType> cell1(1,ToIdType(INTERP_KERNEL::NORM_POLYHED));
3752 if(dott->getIJ(0,0)>0)
3754 cell0.insert(cell0.end(),cPtr+1,cPtr+ciPtr[1]);
3755 std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell1,cell1.end()));
3759 cell1.insert(cell1.end(),cPtr+1,cPtr+ciPtr[1]);
3760 std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell0,cell0.end()));
3762 for(mcIdType i=1;i<nbCellsRet;i++)
3764 if(dott2->getIJ(i,0)<0)
3766 if(ciPtr[i+1]-ciPtr[i]>=4)
3768 cell0.push_back(-1);
3769 cell0.insert(cell0.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
3774 if(ciPtr[i+1]-ciPtr[i]>=4)
3776 cell1.push_back(-1);
3777 cell1.insert(cell1.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
3781 conn2->insertAtTheEnd(cell0.begin(),cell0.end());
3782 conn2I->pushBackSilent(conn2->getNumberOfTuples());
3783 conn2->insertAtTheEnd(cell1.begin(),cell1.end());
3784 conn2I->pushBackSilent(conn2->getNumberOfTuples());
3785 ret2->setConnectivity(conn2,conn2I,true);
3786 ret2->checkConsistencyLight();
3787 ret2->orientCorrectlyPolyhedrons();
3792 * Finds cells whose bounding boxes intersect a given plane.
3793 * \param [in] origin - 3 components of a point defining location of the plane.
3794 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3795 * must be greater than 1e-6.
3796 * \param [in] eps - half-thickness of the plane.
3797 * \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of the found
3798 * cells. The caller is to delete this array using decrRef() as it is no more
3800 * \throw If the coordinates array is not set.
3801 * \throw If the nodal connectivity of cells is not defined.
3802 * \throw If \a this->getSpaceDimension() != 3.
3803 * \throw If magnitude of \a vec is less than 1e-6.
3804 * \sa buildSlice3D()
3806 DataArrayIdType *MEDCouplingUMesh::getCellIdsCrossingPlane(const double *origin, const double *vec, double eps) const
3808 checkFullyDefined();
3809 if(getSpaceDimension()!=3)
3810 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with spaceDim equal to 3 !");
3811 double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
3813 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellIdsCrossingPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
3815 vec2[0]=vec[1]; vec2[1]=-vec[0]; vec2[2]=0.;//vec2 is the result of cross product of vec with (0,0,1)
3816 double angle=acos(vec[2]/normm);
3817 MCAuto<DataArrayIdType> cellIds;
3821 MCAuto<DataArrayDouble> coo=_coords->deepCopy();
3822 double normm2(sqrt(vec2[0]*vec2[0]+vec2[1]*vec2[1]+vec2[2]*vec2[2]));
3823 if(normm2/normm>1e-6)
3824 DataArrayDouble::Rotate3DAlg(origin,vec2,angle,coo->getNumberOfTuples(),coo->getPointer(),coo->getPointer());
3825 MCAuto<MEDCouplingUMesh> mw=clone(false);//false -> shallow copy
3827 mw->getBoundingBox(bbox);
3828 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3829 cellIds=mw->getCellsInBoundingBox(bbox,eps);
3833 getBoundingBox(bbox);
3834 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3835 cellIds=getCellsInBoundingBox(bbox,eps);
3837 return cellIds.retn();
3841 * This method checks that \a this is a contiguous mesh. The user is expected to call this method on a mesh with meshdim==1.
3842 * If not an exception will thrown. If this is an empty mesh with no cell an exception will be thrown too.
3843 * No consideration of coordinate is done by this method.
3844 * 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)
3845 * If not false is returned. In case that false is returned a call to MEDCoupling::MEDCouplingUMesh::mergeNodes could be useful.
3847 bool MEDCouplingUMesh::isContiguous1D() const
3849 if(getMeshDimension()!=1)
3850 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense only for 1D mesh !");
3851 mcIdType nbCells=getNumberOfCells();
3853 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense for non empty mesh !");
3854 const mcIdType *connI(_nodal_connec_index->begin()),*conn(_nodal_connec->begin());
3855 mcIdType ref=conn[connI[0]+2];
3856 for(mcIdType i=1;i<nbCells;i++)
3858 if(conn[connI[i]+1]!=ref)
3860 ref=conn[connI[i]+2];
3866 * This method is only callable on mesh with meshdim == 1 containing only SEG2 and spaceDim==3.
3867 * This method projects this on the 3D line defined by (pt,v). This methods first checks that all SEG2 are along v vector.
3868 * \param pt reference point of the line
3869 * \param v normalized director vector of the line
3870 * \param eps max precision before throwing an exception
3871 * \param res output of size this->getNumberOfCells
3873 void MEDCouplingUMesh::project1D(const double *pt, const double *v, double eps, double *res) const
3875 if(getMeshDimension()!=1)
3876 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for project1D !");
3877 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3878 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for project1D !");
3879 if(getSpaceDimension()!=3)
3880 throw INTERP_KERNEL::Exception("Expected a umesh with spaceDim==3 for project1D !");
3881 MCAuto<MEDCouplingFieldDouble> f=buildDirectionVectorField();
3882 const double *fPtr=f->getArray()->getConstPointer();
3884 for(mcIdType i=0;i<getNumberOfCells();i++)
3886 const double *tmp1=fPtr+3*i;
3887 tmp[0]=tmp1[1]*v[2]-tmp1[2]*v[1];
3888 tmp[1]=tmp1[2]*v[0]-tmp1[0]*v[2];
3889 tmp[2]=tmp1[0]*v[1]-tmp1[1]*v[0];
3890 double n1=INTERP_KERNEL::norm<3>(tmp);
3891 n1/=INTERP_KERNEL::norm<3>(tmp1);
3893 throw INTERP_KERNEL::Exception("UMesh::Projection 1D failed !");
3895 const double *coo=getCoords()->getConstPointer();
3896 for(mcIdType i=0;i<getNumberOfNodes();i++)
3898 std::transform(coo+i*3,coo+i*3+3,pt,tmp,std::minus<double>());
3899 std::transform(tmp,tmp+3,v,tmp,std::multiplies<double>());
3900 res[i]=std::accumulate(tmp,tmp+3,0.);
3905 * 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.
3906 * \a this is expected to be a mesh so that its space dimension is equal to its
3907 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
3908 * 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).
3910 * 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
3911 * 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).
3912 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
3914 * So this method is more accurate (so, more costly) than simply searching for the closest point in \a this.
3915 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
3917 * \param [in] ptBg the start pointer (included) of the coordinates of the point
3918 * \param [in] ptEnd the end pointer (not included) of the coordinates of the point
3919 * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
3920 * \return the positive value of the distance.
3921 * \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
3923 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoints
3925 double MEDCouplingUMesh::distanceToPoint(const double *ptBg, const double *ptEnd, mcIdType& cellId) const
3927 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
3928 if(meshDim!=spaceDim-1)
3929 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint works only for spaceDim=meshDim+1 !");
3930 if(meshDim!=2 && meshDim!=1)
3931 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint : only mesh dimension 2 and 1 are implemented !");
3932 checkFullyDefined();
3933 if(ToIdType(std::distance(ptBg,ptEnd))!=spaceDim)
3934 { 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()); }
3935 DataArrayIdType *ret1=0;
3936 MCAuto<DataArrayDouble> pts=DataArrayDouble::New(); pts->useArray(ptBg,false,DeallocType::C_DEALLOC,1,spaceDim);
3937 MCAuto<DataArrayDouble> ret0=distanceToPoints(pts,ret1);
3938 MCAuto<DataArrayIdType> ret1Safe(ret1);
3939 cellId=*ret1Safe->begin();
3940 return *ret0->begin();
3944 * This method computes the distance from each point of points serie \a pts (stored in a DataArrayDouble in which each tuple represents a point)
3945 * to \a this and the first \a cellId in \a this corresponding to the returned distance.
3946 * 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
3947 * 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).
3948 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
3950 * \a this is expected to be a mesh so that its space dimension is equal to its
3951 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
3952 * 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).
3954 * So this method is more accurate (so, more costly) than simply searching for each point in \a pts the closest point in \a this.
3955 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
3957 * \param [in] pts the list of points in which each tuple represents a point
3958 * \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.
3959 * \return a newly allocated object to be dealed by the caller that tells for each point in \a pts the distance to \a this.
3960 * \throw if number of components of \a pts is not equal to the space dimension.
3961 * \throw if mesh dimension of \a this is not equal to space dimension - 1.
3962 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoint
3964 DataArrayDouble *MEDCouplingUMesh::distanceToPoints(const DataArrayDouble *pts, DataArrayIdType *& cellIds) const
3967 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : input points pointer is NULL !");
3968 pts->checkAllocated();
3969 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
3970 if(meshDim!=spaceDim-1)
3971 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints works only for spaceDim=meshDim+1 !");
3972 if(meshDim!=2 && meshDim!=1)
3973 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only mesh dimension 2 and 1 are implemented !");
3974 if(ToIdType(pts->getNumberOfComponents())!=spaceDim)
3976 std::ostringstream oss; oss << "MEDCouplingUMesh::distanceToPoints : input pts DataArrayDouble has " << pts->getNumberOfComponents() << " components whereas it should be equal to " << spaceDim << " (mesh spaceDimension) !";
3977 throw INTERP_KERNEL::Exception(oss.str());
3979 checkFullyDefined();
3980 mcIdType nbCells=getNumberOfCells();
3982 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : no cells in this !");
3983 mcIdType nbOfPts=pts->getNumberOfTuples();
3984 MCAuto<DataArrayDouble> ret0=DataArrayDouble::New(); ret0->alloc(nbOfPts,1);
3985 MCAuto<DataArrayIdType> ret1=DataArrayIdType::New(); ret1->alloc(nbOfPts,1);
3986 const mcIdType *nc=_nodal_connec->begin(),*ncI=_nodal_connec_index->begin(); const double *coords=_coords->begin();
3987 double *ret0Ptr=ret0->getPointer(); mcIdType *ret1Ptr=ret1->getPointer(); const double *ptsPtr=pts->begin();
3988 MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree());
3989 const double *bbox(bboxArr->begin());
3994 BBTreeDst<3> myTree(bbox,0,0,nbCells);
3995 for(mcIdType i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=3)
3997 double x=std::numeric_limits<double>::max();
3998 std::vector<mcIdType> elems;
3999 myTree.getMinDistanceOfMax(ptsPtr,x);
4000 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4001 DistanceToPoint3DSurfAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4007 BBTreeDst<2> myTree(bbox,0,0,nbCells);
4008 for(mcIdType i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=2)
4010 double x=std::numeric_limits<double>::max();
4011 std::vector<mcIdType> elems;
4012 myTree.getMinDistanceOfMax(ptsPtr,x);
4013 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4014 DistanceToPoint2DCurveAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4019 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only spacedim 2 and 3 supported !");
4021 cellIds=ret1.retn();
4030 * Finds cells in contact with a ball (i.e. a point with precision).
4031 * 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.
4032 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4034 * \warning This method is suitable if the caller intends to evaluate only one
4035 * point, for more points getCellsContainingPoints() is recommended as it is
4037 * \param [in] pos - array of coordinates of the ball central point.
4038 * \param [in] eps - ball radius.
4039 * \return mcIdType - a smallest id of cells being in contact with the ball, -1 in case
4040 * if there are no such cells.
4041 * \throw If the coordinates array is not set.
4042 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4044 mcIdType MEDCouplingUMesh::getCellContainingPoint(const double *pos, double eps) const
4046 std::vector<mcIdType> elts;
4047 getCellsContainingPoint(pos,eps,elts);
4050 return elts.front();
4054 * Finds cells in contact with a ball (i.e. a point with precision).
4055 * 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.
4056 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4057 * \warning This method is suitable if the caller intends to evaluate only one
4058 * point, for more points getCellsContainingPoints() is recommended as it is
4060 * \param [in] pos - array of coordinates of the ball central point.
4061 * \param [in] eps - ball radius.
4062 * \param [out] elts - vector returning ids of the found cells. It is cleared
4063 * before inserting ids.
4064 * \throw If the coordinates array is not set.
4065 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4067 * \if ENABLE_EXAMPLES
4068 * \ref cpp_mcumesh_getCellsContainingPoint "Here is a C++ example".<br>
4069 * \ref py_mcumesh_getCellsContainingPoint "Here is a Python example".
4072 void MEDCouplingUMesh::getCellsContainingPoint(const double *pos, double eps, std::vector<mcIdType>& elts) const
4074 MCAuto<DataArrayIdType> eltsUg,eltsIndexUg;
4075 getCellsContainingPoints(pos,1,eps,eltsUg,eltsIndexUg);
4076 elts.clear(); elts.insert(elts.end(),eltsUg->begin(),eltsUg->end());
4079 void MEDCouplingUMesh::getCellsContainingPointsZeAlg(const double *pos, mcIdType nbOfPoints, double eps,
4080 MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex,
4081 std::function<bool(INTERP_KERNEL::NormalizedCellType,mcIdType)> sensibilityTo2DQuadraticLinearCellsFunc) const
4083 int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
4088 const double *coords=_coords->getConstPointer();
4089 getCellsContainingPointsAlg<3>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4092 throw INTERP_KERNEL::Exception("For spaceDim==3 only meshDim==3 implemented for getelementscontainingpoints !");
4094 else if(spaceDim==2)
4098 const double *coords=_coords->getConstPointer();
4099 getCellsContainingPointsAlg<2>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4102 throw INTERP_KERNEL::Exception("For spaceDim==2 only meshDim==2 implemented for getelementscontainingpoints !");
4104 else if(spaceDim==1)
4108 const double *coords=_coords->getConstPointer();
4109 getCellsContainingPointsAlg<1>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4112 throw INTERP_KERNEL::Exception("For spaceDim==1 only meshDim==1 implemented for getelementscontainingpoints !");
4115 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPoints : not managed for mdim not in [1,2,3] !");
4119 * Finds cells in contact with several balls (i.e. points with precision).
4120 * This method is an extension of getCellContainingPoint() and
4121 * getCellsContainingPoint() for the case of multiple points.
4122 * 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.
4123 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4124 * \param [in] pos - an array of coordinates of points in full interlace mode :
4125 * X0,Y0,Z0,X1,Y1,Z1,... Size of the array must be \a
4126 * this->getSpaceDimension() * \a nbOfPoints
4127 * \param [in] nbOfPoints - number of points to locate within \a this mesh.
4128 * \param [in] eps - radius of balls (i.e. the precision).
4129 * \param [out] elts - vector returning ids of found cells.
4130 * \param [out] eltsIndex - an array, of length \a nbOfPoints + 1,
4131 * dividing cell ids in \a elts into groups each referring to one
4132 * point. Its every element (except the last one) is an index pointing to the
4133 * first id of a group of cells. For example cells in contact with the *i*-th
4134 * point are described by following range of indices:
4135 * [ \a eltsIndex[ *i* ], \a eltsIndex[ *i*+1 ] ) and the cell ids are
4136 * \a elts[ \a eltsIndex[ *i* ]], \a elts[ \a eltsIndex[ *i* ] + 1 ], ...
4137 * Number of cells in contact with the *i*-th point is
4138 * \a eltsIndex[ *i*+1 ] - \a eltsIndex[ *i* ].
4139 * \throw If the coordinates array is not set.
4140 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4142 * \if ENABLE_EXAMPLES
4143 * \ref cpp_mcumesh_getCellsContainingPoints "Here is a C++ example".<br>
4144 * \ref py_mcumesh_getCellsContainingPoints "Here is a Python example".
4147 void MEDCouplingUMesh::getCellsContainingPoints(const double *pos, mcIdType nbOfPoints, double eps,
4148 MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex) const
4150 auto yesImSensibleTo2DQuadraticLinearCellsFunc([](INTERP_KERNEL::NormalizedCellType ct, int mdim) { return INTERP_KERNEL::CellModel::GetCellModel(ct).isQuadratic() && mdim == 2; } );
4151 this->getCellsContainingPointsZeAlg(pos,nbOfPoints,eps,elts,eltsIndex,yesImSensibleTo2DQuadraticLinearCellsFunc);
4155 * Behaves like MEDCouplingMesh::getCellsContainingPoints for cells in \a this that are linear.
4156 * For quadratic cells in \a this, this method behaves by just considering linear part of cells.
4157 * This method is here only for backward compatibility (interpolation GaussPoints to GaussPoints).
4159 * \sa MEDCouplingUMesh::getCellsContainingPoints, MEDCouplingRemapper::prepareNotInterpKernelOnlyGaussGauss
4161 void MEDCouplingUMesh::getCellsContainingPointsLinearPartOnlyOnNonDynType(const double *pos, mcIdType nbOfPoints, double eps, MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex) const
4163 auto noImNotSensibleTo2DQuadraticLinearCellsFunc([](INTERP_KERNEL::NormalizedCellType,mcIdType) { return false; } );
4164 this->getCellsContainingPointsZeAlg(pos,nbOfPoints,eps,elts,eltsIndex,noImNotSensibleTo2DQuadraticLinearCellsFunc);
4168 * Finds butterfly cells in \a this mesh. A 2D cell is considered to be butterfly if at
4169 * least two its edges intersect each other anywhere except their extremities. An
4170 * INTERP_KERNEL::NORM_NORI3 cell can \b not be butterfly.
4171 * \param [in,out] cells - a vector returning ids of the found cells. It is not
4172 * cleared before filling in.
4173 * \param [in] eps - precision.
4174 * \throw If \a this->getMeshDimension() != 2.
4175 * \throw If \a this->getSpaceDimension() != 2 && \a this->getSpaceDimension() != 3.
4177 void MEDCouplingUMesh::checkButterflyCells(std::vector<mcIdType>& cells, double eps) const
4179 const char msg[]="Butterfly detection work only for 2D cells with spaceDim==2 or 3!";
4180 if(getMeshDimension()!=2)
4181 throw INTERP_KERNEL::Exception(msg);
4182 int spaceDim=getSpaceDimension();
4183 if(spaceDim!=2 && spaceDim!=3)
4184 throw INTERP_KERNEL::Exception(msg);
4185 const mcIdType *conn=_nodal_connec->getConstPointer();
4186 const mcIdType *connI=_nodal_connec_index->getConstPointer();
4187 mcIdType nbOfCells=getNumberOfCells();
4188 std::vector<double> cell2DinS2;
4189 for(mcIdType i=0;i<nbOfCells;i++)
4191 mcIdType offset=connI[i];
4192 mcIdType nbOfNodesForCell=connI[i+1]-offset-1;
4193 if(nbOfNodesForCell<=3)
4195 bool isQuad=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[offset]).isQuadratic();
4196 project2DCellOnXY(conn+offset+1,conn+connI[i+1],cell2DinS2);
4197 if(isButterfly2DCell(cell2DinS2,isQuad,eps))
4204 * This method is typically requested to unbutterfly 2D linear cells in \b this.
4206 * 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.
4207 * 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.
4209 * For each 2D linear cell in \b this, this method builds the convex envelop (or the convex hull) of the current cell.
4210 * This convex envelop is computed using Jarvis march algorithm.
4211 * The coordinates and the number of cells of \b this remain unchanged on invocation of this method.
4212 * 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)
4213 * 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.
4215 * \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.
4216 * \sa MEDCouplingUMesh::colinearize2D
4218 DataArrayIdType *MEDCouplingUMesh::convexEnvelop2D()
4220 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
4221 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convexEnvelop2D works only for meshDim=2 and spaceDim=2 !");
4222 checkFullyDefined();
4223 const double *coords=getCoords()->getConstPointer();
4224 mcIdType nbOfCells=getNumberOfCells();
4225 MCAuto<DataArrayIdType> nodalConnecIndexOut=DataArrayIdType::New();
4226 nodalConnecIndexOut->alloc(nbOfCells+1,1);
4227 MCAuto<DataArrayIdType> nodalConnecOut(DataArrayIdType::New());
4228 mcIdType *workIndexOut=nodalConnecIndexOut->getPointer();
4230 const mcIdType *nodalConnecIn=_nodal_connec->getConstPointer();
4231 const mcIdType *nodalConnecIndexIn=_nodal_connec_index->getConstPointer();
4232 std::set<INTERP_KERNEL::NormalizedCellType> types;
4233 MCAuto<DataArrayIdType> isChanged(DataArrayIdType::New());
4234 isChanged->alloc(0,1);
4235 for(mcIdType i=0;i<nbOfCells;i++,workIndexOut++)
4237 mcIdType pos=nodalConnecOut->getNumberOfTuples();
4238 if(BuildConvexEnvelopOf2DCellJarvis(coords,nodalConnecIn+nodalConnecIndexIn[i],nodalConnecIn+nodalConnecIndexIn[i+1],nodalConnecOut))
4239 isChanged->pushBackSilent(i);
4240 types.insert((INTERP_KERNEL::NormalizedCellType)nodalConnecOut->getIJ(pos,0));
4241 workIndexOut[1]=nodalConnecOut->getNumberOfTuples();
4243 if(isChanged->empty())
4245 setConnectivity(nodalConnecOut,nodalConnecIndexOut,false);
4247 return isChanged.retn();
4251 * This method is \b NOT const because it can modify \a this.
4252 * \a this is expected to be an unstructured mesh with meshDim==2 and spaceDim==3. If not an exception will be thrown.
4253 * \param mesh1D is an unstructured mesh with MeshDim==1 and spaceDim==3. If not an exception will be thrown.
4254 * \param policy specifies the type of extrusion chosen:
4255 * - \b 0 for translation only (most simple): the cells of the 1D mesh represent the vectors along which the 2D mesh
4256 * will be repeated to build each level
4257 * - \b 1 for translation and rotation: the translation is done as above. For each level, an arc of circle is fitted on
4258 * 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
4259 * 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
4261 * \return an unstructured mesh with meshDim==3 and spaceDim==3. The returned mesh has the same coords than \a this.
4263 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMesh(const MEDCouplingUMesh *mesh1D, int policy)
4265 checkFullyDefined();
4266 mesh1D->checkFullyDefined();
4267 if(!mesh1D->isContiguous1D())
4268 throw INTERP_KERNEL::Exception("buildExtrudedMesh : 1D mesh passed in parameter is not contiguous !");
4269 if(getSpaceDimension()!=mesh1D->getSpaceDimension())
4270 throw INTERP_KERNEL::Exception("Invalid call to buildExtrudedMesh this and mesh1D must have same space dimension !");
4271 if((getMeshDimension()!=2 || getSpaceDimension()!=3) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
4272 throw INTERP_KERNEL::Exception("Invalid 'this' for buildExtrudedMesh method : must be (meshDim==2 and spaceDim==3) or (meshDim==1 and spaceDim==2) !");
4273 if(mesh1D->getMeshDimension()!=1)
4274 throw INTERP_KERNEL::Exception("Invalid 'mesh1D' for buildExtrudedMesh method : must be meshDim==1 !");
4276 if(isPresenceOfQuadratic())
4278 if(mesh1D->isFullyQuadratic())
4281 throw INTERP_KERNEL::Exception("Invalid 2D mesh and 1D mesh because 2D mesh has quadratic cells and 1D is not fully quadratic !");
4283 mcIdType oldNbOfNodes(getNumberOfNodes());
4284 MCAuto<DataArrayDouble> newCoords;
4289 newCoords=fillExtCoordsUsingTranslation(mesh1D,isQuad);
4294 newCoords=fillExtCoordsUsingTranslAndAutoRotation(mesh1D,isQuad);
4298 throw INTERP_KERNEL::Exception("Not implemented extrusion policy : must be in (0) !");
4300 setCoords(newCoords);
4301 MCAuto<MEDCouplingUMesh> ret(buildExtrudedMeshFromThisLowLev(oldNbOfNodes,isQuad));
4308 * Checks if \a this mesh is constituted by only quadratic cells.
4309 * \return bool - \c true if there are only quadratic cells in \a this mesh.
4310 * \throw If the coordinates array is not set.
4311 * \throw If the nodal connectivity of cells is not defined.
4313 bool MEDCouplingUMesh::isFullyQuadratic() const
4315 checkFullyDefined();
4317 mcIdType nbOfCells=getNumberOfCells();
4318 for(mcIdType i=0;i<nbOfCells && ret;i++)
4320 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4321 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4322 ret=cm.isQuadratic();
4328 * Checks if \a this mesh includes any quadratic cell.
4329 * \return bool - \c true if there is at least one quadratic cells in \a this mesh.
4330 * \throw If the coordinates array is not set.
4331 * \throw If the nodal connectivity of cells is not defined.
4333 bool MEDCouplingUMesh::isPresenceOfQuadratic() const
4335 checkFullyDefined();
4337 mcIdType nbOfCells=getNumberOfCells();
4338 for(mcIdType i=0;i<nbOfCells && !ret;i++)
4340 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4341 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4342 ret=cm.isQuadratic();
4348 * Converts all quadratic cells to linear ones. If there are no quadratic cells in \a
4349 * this mesh, it remains unchanged.
4350 * \throw If the coordinates array is not set.
4351 * \throw If the nodal connectivity of cells is not defined.
4353 void MEDCouplingUMesh::convertQuadraticCellsToLinear()
4355 checkFullyDefined();
4356 mcIdType nbOfCells=getNumberOfCells();
4358 const mcIdType *iciptr=_nodal_connec_index->begin();
4359 for(mcIdType i=0;i<nbOfCells;i++)
4361 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4362 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4363 if(cm.isQuadratic())
4365 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4366 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4367 if(!cml.isDynamic())
4368 delta+=cm.getNumberOfNodes()-cml.getNumberOfNodes();
4370 delta+=(iciptr[i+1]-iciptr[i]-1)/2;
4375 MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()),newConnI(DataArrayIdType::New());
4376 const mcIdType *icptr(_nodal_connec->begin());
4377 newConn->alloc(getNodalConnectivityArrayLen()-delta,1);
4378 newConnI->alloc(nbOfCells+1,1);
4379 mcIdType *ocptr(newConn->getPointer()),*ociptr(newConnI->getPointer());
4382 for(mcIdType i=0;i<nbOfCells;i++,ociptr++)
4384 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)icptr[iciptr[i]];
4385 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4386 if(!cm.isQuadratic())
4388 _types.insert(type);
4389 ocptr=std::copy(icptr+iciptr[i],icptr+iciptr[i+1],ocptr);
4390 ociptr[1]=ociptr[0]+iciptr[i+1]-iciptr[i];
4394 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4395 _types.insert(typel);
4396 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4397 mcIdType newNbOfNodes=cml.getNumberOfNodes();
4399 newNbOfNodes=(iciptr[i+1]-iciptr[i]-1)/2;
4400 *ocptr++=ToIdType(typel);
4401 ocptr=std::copy(icptr+iciptr[i]+1,icptr+iciptr[i]+newNbOfNodes+1,ocptr);
4402 ociptr[1]=ociptr[0]+newNbOfNodes+1;
4405 setConnectivity(newConn,newConnI,false);
4409 * This method converts all linear cell in \a this to quadratic one.
4410 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, here it is needed to specify the target
4411 * 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)
4412 * 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.
4413 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, the coordinates in \a this can be become bigger. All created nodes will be put at the
4414 * end of the existing coordinates.
4416 * \param [in] conversionType specifies the type of conversion expected. Only 0 (default) and 1 are supported presently. 0 those that creates the 'most' simple
4417 * corresponding quadratic cells. 1 is those creating the 'most' complex.
4418 * \return a newly created DataArrayIdType instance that the caller should deal with containing cell ids of converted cells.
4420 * \throw if \a this is not fully defined. It throws too if \a conversionType is not in [0,1].
4422 * \sa MEDCouplingUMesh::convertQuadraticCellsToLinear
4424 DataArrayIdType *MEDCouplingUMesh::convertLinearCellsToQuadratic(int conversionType)
4426 DataArrayIdType *conn=0,*connI=0;
4427 DataArrayDouble *coords=0;
4428 std::set<INTERP_KERNEL::NormalizedCellType> types;
4429 checkFullyDefined();
4430 MCAuto<DataArrayIdType> ret,connSafe,connISafe;
4431 MCAuto<DataArrayDouble> coordsSafe;
4432 int meshDim=getMeshDimension();
4433 switch(conversionType)
4439 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);
4440 connSafe=conn; connISafe=connI; coordsSafe=coords;
4443 ret=convertLinearCellsToQuadratic2D0(conn,connI,coords,types);
4444 connSafe=conn; connISafe=connI; coordsSafe=coords;
4447 ret=convertLinearCellsToQuadratic3D0(conn,connI,coords,types);
4448 connSafe=conn; connISafe=connI; coordsSafe=coords;
4451 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 0 mesh dimensions available are [1,2,3] !");
4459 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);//it is not a bug. In 1D policy 0 and 1 are equals
4460 connSafe=conn; connISafe=connI; coordsSafe=coords;
4463 ret=convertLinearCellsToQuadratic2D1(conn,connI,coords,types);
4464 connSafe=conn; connISafe=connI; coordsSafe=coords;
4467 ret=convertLinearCellsToQuadratic3D1(conn,connI,coords,types);
4468 connSafe=conn; connISafe=connI; coordsSafe=coords;
4471 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 1 mesh dimensions available are [1,2,3] !");
4476 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion type available are 0 (default, the simplest) and 1 (the most complex) !");
4478 setConnectivity(connSafe,connISafe,false);
4480 setCoords(coordsSafe);
4485 * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
4486 * so that the number of cells remains the same. Quadratic faces are converted to
4487 * polygons. This method works only for 2D meshes in
4488 * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
4489 * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
4490 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
4491 * \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
4492 * a polylinized edge constituting the input polygon.
4493 * \throw If the coordinates array is not set.
4494 * \throw If the nodal connectivity of cells is not defined.
4495 * \throw If \a this->getMeshDimension() != 2.
4496 * \throw If \a this->getSpaceDimension() != 2.
4498 void MEDCouplingUMesh::tessellate2D(double eps)
4500 int meshDim(getMeshDimension()),spaceDim(getSpaceDimension());
4502 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : works only with space dimension equal to 2 !");
4506 return tessellate2DCurveInternal(eps);
4508 return tessellate2DInternal(eps);
4510 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : mesh dimension must be in [1,2] !");
4516 * This method only works if \a this has spaceDimension equal to 2 and meshDimension also equal to 2.
4517 * This method allows to modify connectivity of cells in \a this that shares some edges in \a edgeIdsToBeSplit.
4518 * The nodes to be added in those 2D cells are defined by the pair of \a nodeIdsToAdd and \a nodeIdsIndexToAdd.
4519 * Length of \a nodeIdsIndexToAdd is expected to equal to length of \a edgeIdsToBeSplit + 1.
4520 * The node ids in \a nodeIdsToAdd should be valid. Those nodes have to be sorted exactly following exactly the direction of the edge.
4521 * This method can be seen as the opposite method of colinearize2D.
4522 * 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
4523 * to avoid to modify the numbering of existing nodes.
4525 * \param [in] nodeIdsToAdd - the list of node ids to be added (\a nodeIdsIndexToAdd array allows to walk on this array)
4526 * \param [in] nodeIdsIndexToAdd - the entry point of \a nodeIdsToAdd to point to the corresponding nodes to be added.
4527 * \param [in] mesh1Desc - 1st output of buildDescendingConnectivity2 on \a this.
4528 * \param [in] desc - 2nd output of buildDescendingConnectivity2 on \a this.
4529 * \param [in] descI - 3rd output of buildDescendingConnectivity2 on \a this.
4530 * \param [in] revDesc - 4th output of buildDescendingConnectivity2 on \a this.
4531 * \param [in] revDescI - 5th output of buildDescendingConnectivity2 on \a this.
4533 * \sa buildDescendingConnectivity2
4535 void MEDCouplingUMesh::splitSomeEdgesOf2DMesh(const DataArrayIdType *nodeIdsToAdd, const DataArrayIdType *nodeIdsIndexToAdd, const DataArrayIdType *edgeIdsToBeSplit,
4536 const MEDCouplingUMesh *mesh1Desc, const DataArrayIdType *desc, const DataArrayIdType *descI, const DataArrayIdType *revDesc, const DataArrayIdType *revDescI)
4538 if(!nodeIdsToAdd || !nodeIdsIndexToAdd || !edgeIdsToBeSplit || !mesh1Desc || !desc || !descI || !revDesc || !revDescI)
4539 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : input pointers must be not NULL !");
4540 nodeIdsToAdd->checkAllocated(); nodeIdsIndexToAdd->checkAllocated(); edgeIdsToBeSplit->checkAllocated(); desc->checkAllocated(); descI->checkAllocated(); revDesc->checkAllocated(); revDescI->checkAllocated();
4541 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
4542 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : this must have spacedim=meshdim=2 !");
4543 if(mesh1Desc->getSpaceDimension()!=2 || mesh1Desc->getMeshDimension()!=1)
4544 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : mesh1Desc must be the explosion of this with spaceDim=2 and meshDim = 1 !");
4545 //DataArrayIdType *out0(0),*outi0(0);
4546 //MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
4547 //MCAuto<DataArrayIdType> out0s(out0),outi0s(outi0);
4548 //out0s=out0s->buildUnique(); out0s->sort(true);
4554 * Divides every cell of \a this mesh into simplices (triangles in 2D and tetrahedra in 3D).
4555 * In addition, returns an array mapping new cells to old ones. <br>
4556 * This method typically increases the number of cells in \a this mesh
4557 * but the number of nodes remains \b unchanged.
4558 * That's why the 3D splitting policies
4559 * INTERP_KERNEL::GENERAL_24 and INTERP_KERNEL::GENERAL_48 are not available here.
4560 * \param [in] policy - specifies a pattern used for splitting.
4561 * The semantic of \a policy is:
4562 * - 0 - to split QUAD4 by cutting it along 0-2 diagonal (for 2D mesh only).
4563 * - 1 - to split QUAD4 by cutting it along 1-3 diagonal (for 2D mesh only).
4564 * - INTERP_KERNEL::PLANAR_FACE_5 - to split HEXA8 into 5 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4565 * - INTERP_KERNEL::PLANAR_FACE_6 - to split HEXA8 into 6 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4568 * \return DataArrayIdType * - a new instance of DataArrayIdType holding, for each new cell,
4569 * an id of old cell producing it. The caller is to delete this array using
4570 * decrRef() as it is no more needed.
4572 * \throw If \a policy is 0 or 1 and \a this->getMeshDimension() != 2.
4573 * \throw If \a policy is INTERP_KERNEL::PLANAR_FACE_5 or INTERP_KERNEL::PLANAR_FACE_6
4574 * and \a this->getMeshDimension() != 3.
4575 * \throw If \a policy is not one of the four discussed above.
4576 * \throw If the nodal connectivity of cells is not defined.
4577 * \sa MEDCouplingUMesh::tetrahedrize, MEDCoupling1SGTUMesh::sortHexa8EachOther
4579 DataArrayIdType *MEDCouplingUMesh::simplexize(int policy)
4584 return simplexizePol0();
4586 return simplexizePol1();
4587 case INTERP_KERNEL::PLANAR_FACE_5:
4588 return simplexizePlanarFace5();
4589 case INTERP_KERNEL::PLANAR_FACE_6:
4590 return simplexizePlanarFace6();
4592 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)");
4597 * Checks if \a this mesh is constituted by simplex cells only. Simplex cells are:
4598 * - 1D: INTERP_KERNEL::NORM_SEG2
4599 * - 2D: INTERP_KERNEL::NORM_TRI3
4600 * - 3D: INTERP_KERNEL::NORM_TETRA4.
4602 * This method is useful for users that need to use P1 field services as
4603 * MEDCouplingFieldDouble::getValueOn(), MEDCouplingField::buildMeasureField() etc.
4604 * All these methods need mesh support containing only simplex cells.
4605 * \return bool - \c true if there are only simplex cells in \a this mesh.
4606 * \throw If the coordinates array is not set.
4607 * \throw If the nodal connectivity of cells is not defined.
4608 * \throw If \a this->getMeshDimension() < 1.
4610 bool MEDCouplingUMesh::areOnlySimplexCells() const
4612 checkFullyDefined();
4613 int mdim=getMeshDimension();
4614 if(mdim<1 || mdim>3)
4615 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::areOnlySimplexCells : only available with meshes having a meshdim 1, 2 or 3 !");
4616 mcIdType nbCells=getNumberOfCells();
4617 const mcIdType *conn=_nodal_connec->begin();
4618 const mcIdType *connI=_nodal_connec_index->begin();
4619 for(mcIdType i=0;i<nbCells;i++)
4621 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4631 * Converts degenerated 2D or 3D linear cells of \a this mesh into cells of simpler
4632 * type. For example an INTERP_KERNEL::NORM_QUAD4 cell having only three unique nodes in
4633 * its connectivity is transformed into an INTERP_KERNEL::NORM_TRI3 cell.
4634 * Quadratic cells in 2D are also handled. In those cells edges where start=end=midpoint are removed.
4635 * This method does \b not perform geometrical checks and checks only nodal connectivity of cells,
4636 * so it can be useful to call mergeNodes() before calling this method.
4637 * \throw If \a this->getMeshDimension() <= 1.
4638 * \throw If the coordinates array is not set.
4639 * \throw If the nodal connectivity of cells is not defined.
4641 void MEDCouplingUMesh::convertDegeneratedCells()
4643 checkFullyDefined();
4644 if(getMeshDimension()<=1)
4645 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4646 mcIdType nbOfCells=getNumberOfCells();
4649 mcIdType initMeshLgth=getNodalConnectivityArrayLen();
4650 mcIdType *conn=_nodal_connec->getPointer();
4651 mcIdType *index=_nodal_connec_index->getPointer();
4652 mcIdType posOfCurCell=0;
4654 mcIdType lgthOfCurCell;
4655 for(mcIdType i=0;i<nbOfCells;i++)
4657 lgthOfCurCell=index[i+1]-posOfCurCell;
4658 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4660 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
4661 conn+newPos+1,newLgth);
4662 conn[newPos]=newType;
4664 posOfCurCell=index[i+1];
4667 if(newPos!=initMeshLgth)
4668 _nodal_connec->reAlloc(newPos);
4673 * Same as MEDCouplingUMesh::convertDegeneratedCells() plus deletion of the flat cells.
4674 * A cell is flat in the following cases:
4675 * - for a linear cell, all points in the connectivity are equal
4676 * - for a quadratic cell, either the above, or a quadratic polygon with two (linear) points and two
4677 * identical quadratic points
4678 * \return a new instance of DataArrayIdType holding ids of removed cells. The caller is to delete
4679 * this array using decrRef() as it is no more needed.
4681 DataArrayIdType *MEDCouplingUMesh::convertDegeneratedCellsAndRemoveFlatOnes()
4683 checkFullyDefined();
4684 if(getMeshDimension()<=1)
4685 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4686 mcIdType nbOfCells=getNumberOfCells();
4687 MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(0,1);
4690 mcIdType initMeshLgth=getNodalConnectivityArrayLen();
4691 mcIdType *conn=_nodal_connec->getPointer();
4692 mcIdType *index=_nodal_connec_index->getPointer();
4693 mcIdType posOfCurCell=0;
4695 mcIdType lgthOfCurCell, nbDelCells(0);
4696 for(mcIdType i=0;i<nbOfCells;i++)
4698 lgthOfCurCell=index[i+1]-posOfCurCell;
4699 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4701 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
4702 conn+newPos+1,newLgth);
4703 // Shall we delete the cell if it is completely degenerated:
4704 bool delCell=INTERP_KERNEL::CellSimplify::isFlatCell(conn, newPos, newLgth, newType);
4708 ret->pushBackSilent(i);
4710 else //if the cell is to be deleted, simply stay at the same place
4712 conn[newPos]=newType;
4715 posOfCurCell=index[i+1];
4716 index[i+1-nbDelCells]=newPos;
4718 if(newPos!=initMeshLgth)
4719 _nodal_connec->reAlloc(newPos);
4720 const mcIdType nCellDel=ret->getNumberOfTuples();
4722 _nodal_connec_index->reAlloc(nbOfCells-nCellDel+1);
4728 * This method remove null 1D cells from \a this. A 1D cell is considered null if start node is equal to end node.
4729 * Only connectivity is considered here.
4731 bool MEDCouplingUMesh::removeDegenerated1DCells()
4733 checkConnectivityFullyDefined();
4734 if(getMeshDimension()!=1)
4735 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::removeDegenerated1DCells works on umeshes with meshdim equals to 1 !");
4736 std::size_t nbCells(getNumberOfCells()),newSize(0),newSize2(0);
4737 const mcIdType *conn(getNodalConnectivity()->begin()),*conni(getNodalConnectivityIndex()->begin());
4739 for(std::size_t i=0;i<nbCells;i++)
4741 INTERP_KERNEL::NormalizedCellType ct((INTERP_KERNEL::NormalizedCellType)conn[conni[i]]);
4742 if(ct==INTERP_KERNEL::NORM_SEG2 || ct==INTERP_KERNEL::NORM_SEG3)
4744 if(conn[conni[i]+1]!=conn[conni[i]+2])
4747 newSize2+=conni[i+1]-conni[i];
4752 std::ostringstream oss; oss << "MEDCouplingUMesh::removeDegenerated1DCells : cell #" << i << " in this is not of type SEG2/SEG3 !";
4753 throw INTERP_KERNEL::Exception(oss.str());
4757 if(newSize==nbCells)//no cells has been removed -> do nothing
4759 MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()),newConnI(DataArrayIdType::New()); newConnI->alloc(newSize+1,1); newConn->alloc(newSize2,1);
4760 mcIdType *newConnPtr(newConn->getPointer()),*newConnIPtr(newConnI->getPointer()); newConnIPtr[0]=0;
4761 for(std::size_t i=0;i<nbCells;i++)
4763 if(conn[conni[i]+1]!=conn[conni[i]+2])
4765 newConnIPtr[1]=newConnIPtr[0]+conni[i+1]-conni[i];
4766 newConnPtr=std::copy(conn+conni[i],conn+conni[i+1],newConnPtr);
4770 setConnectivity(newConn,newConnI,true);
4775 * Finds incorrectly oriented cells of this 2D mesh in 3D space.
4776 * A cell is considered to be oriented correctly if an angle between its
4777 * normal vector and a given vector is less than \c PI / \c 2.
4778 * \param [in] vec - 3 components of the vector specifying the correct orientation of
4780 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
4782 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
4783 * is not cleared before filling in.
4784 * \throw If \a this->getMeshDimension() != 2.
4785 * \throw If \a this->getSpaceDimension() != 3.
4787 * \if ENABLE_EXAMPLES
4788 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
4789 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
4792 void MEDCouplingUMesh::are2DCellsNotCorrectlyOriented(const double *vec, bool polyOnly, std::vector<mcIdType>& cells) const
4794 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
4795 throw INTERP_KERNEL::Exception("Invalid mesh to apply are2DCellsNotCorrectlyOriented on it : must be meshDim==2 and spaceDim==3 !");
4796 mcIdType nbOfCells=getNumberOfCells();
4797 const mcIdType *conn=_nodal_connec->begin();
4798 const mcIdType *connI=_nodal_connec_index->begin();
4799 const double *coordsPtr=_coords->begin();
4800 for(mcIdType i=0;i<nbOfCells;i++)
4802 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4803 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
4805 bool isQuadratic=INTERP_KERNEL::CellModel::GetCellModel(type).isQuadratic();
4806 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4813 * Reverse connectivity of 2D cells whose orientation is not correct. A cell is
4814 * considered to be oriented correctly if an angle between its normal vector and a
4815 * given vector is less than \c PI / \c 2.
4816 * \param [in] vec - 3 components of the vector specifying the correct orientation of
4818 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
4820 * \throw If \a this->getMeshDimension() != 2.
4821 * \throw If \a this->getSpaceDimension() != 3.
4823 * \if ENABLE_EXAMPLES
4824 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
4825 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
4828 * \sa changeOrientationOfCells
4830 void MEDCouplingUMesh::orientCorrectly2DCells(const double *vec, bool polyOnly)
4832 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
4833 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectly2DCells on it : must be meshDim==2 and spaceDim==3 !");
4834 mcIdType nbOfCells=getNumberOfCells();
4835 mcIdType *conn(_nodal_connec->getPointer());
4836 const mcIdType *connI(_nodal_connec_index->begin());
4837 const double *coordsPtr(_coords->begin());
4838 bool isModified(false);
4839 for(mcIdType i=0;i<nbOfCells;i++)
4841 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4842 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
4844 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
4845 bool isQuadratic(cm.isQuadratic());
4846 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4849 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
4854 _nodal_connec->declareAsNew();
4859 * This method change the orientation of cells in \a this without any consideration of coordinates. Only connectivity is impacted.
4861 * \sa orientCorrectly2DCells
4863 void MEDCouplingUMesh::changeOrientationOfCells()
4865 int mdim(getMeshDimension());
4866 if(mdim!=2 && mdim!=1)
4867 throw INTERP_KERNEL::Exception("Invalid mesh to apply changeOrientationOfCells on it : must be meshDim==2 or meshDim==1 !");
4868 mcIdType nbOfCells=getNumberOfCells();
4869 mcIdType *conn(_nodal_connec->getPointer());
4870 const mcIdType *connI(_nodal_connec_index->begin());
4873 for(mcIdType i=0;i<nbOfCells;i++)
4875 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4876 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
4877 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
4882 for(mcIdType i=0;i<nbOfCells;i++)
4884 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4885 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
4886 cm.changeOrientationOf1D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
4892 * Finds incorrectly oriented polyhedral cells, i.e. polyhedrons having correctly
4893 * oriented facets. The normal vector of the facet should point out of the cell.
4894 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
4895 * is not cleared before filling in.
4896 * \throw If \a this->getMeshDimension() != 3.
4897 * \throw If \a this->getSpaceDimension() != 3.
4898 * \throw If the coordinates array is not set.
4899 * \throw If the nodal connectivity of cells is not defined.
4901 * \if ENABLE_EXAMPLES
4902 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
4903 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
4906 void MEDCouplingUMesh::arePolyhedronsNotCorrectlyOriented(std::vector<mcIdType>& cells) const
4908 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
4909 throw INTERP_KERNEL::Exception("Invalid mesh to apply arePolyhedronsNotCorrectlyOriented on it : must be meshDim==3 and spaceDim==3 !");
4910 mcIdType nbOfCells=getNumberOfCells();
4911 const mcIdType *conn=_nodal_connec->begin();
4912 const mcIdType *connI=_nodal_connec_index->begin();
4913 const double *coordsPtr=_coords->begin();
4914 for(mcIdType i=0;i<nbOfCells;i++)
4916 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4917 if(type==INTERP_KERNEL::NORM_POLYHED)
4919 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4926 * Tries to fix connectivity of polyhedra, so that normal vector of all facets to point
4928 * \throw If \a this->getMeshDimension() != 3.
4929 * \throw If \a this->getSpaceDimension() != 3.
4930 * \throw If the coordinates array is not set.
4931 * \throw If the nodal connectivity of cells is not defined.
4932 * \throw If the reparation fails.
4934 * \if ENABLE_EXAMPLES
4935 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
4936 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
4938 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
4940 void MEDCouplingUMesh::orientCorrectlyPolyhedrons()
4942 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
4943 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectlyPolyhedrons on it : must be meshDim==3 and spaceDim==3 !");
4944 mcIdType nbOfCells=getNumberOfCells();
4945 mcIdType *conn=_nodal_connec->getPointer();
4946 const mcIdType *connI=_nodal_connec_index->begin();
4947 const double *coordsPtr=_coords->begin();
4948 for(mcIdType i=0;i<nbOfCells;i++)
4950 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4951 if(type==INTERP_KERNEL::NORM_POLYHED)
4955 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4956 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
4958 catch(INTERP_KERNEL::Exception& e)
4960 std::ostringstream oss; oss << "Something wrong in polyhedron #" << i << " : " << e.what();
4961 throw INTERP_KERNEL::Exception(oss.str());
4969 * This method invert orientation of all cells in \a this.
4970 * After calling this method the absolute value of measure of cells in \a this are the same than before calling.
4971 * This method only operates on the connectivity so coordinates are not touched at all.
4973 void MEDCouplingUMesh::invertOrientationOfAllCells()
4975 checkConnectivityFullyDefined();
4976 std::set<INTERP_KERNEL::NormalizedCellType> gts(getAllGeoTypes());
4977 mcIdType *conn(_nodal_connec->getPointer());
4978 const mcIdType *conni(_nodal_connec_index->begin());
4979 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator gt=gts.begin();gt!=gts.end();gt++)
4981 INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::OrientationInverter> oi(INTERP_KERNEL::OrientationInverter::BuildInstanceFrom(*gt));
4982 MCAuto<DataArrayIdType> cwt(giveCellsWithType(*gt));
4983 for(const mcIdType *it=cwt->begin();it!=cwt->end();it++)
4984 oi->operate(conn+conni[*it]+1,conn+conni[*it+1]);
4990 * Finds and fixes incorrectly oriented linear extruded volumes (INTERP_KERNEL::NORM_HEXA8,
4991 * INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXGP12 etc) to respect the MED convention
4992 * according to which the first facet of the cell should be oriented to have the normal vector
4993 * pointing out of cell.
4994 * \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of fixed
4995 * cells. The caller is to delete this array using decrRef() as it is no more
4997 * \throw If \a this->getMeshDimension() != 3.
4998 * \throw If \a this->getSpaceDimension() != 3.
4999 * \throw If the coordinates array is not set.
5000 * \throw If the nodal connectivity of cells is not defined.
5002 * \if ENABLE_EXAMPLES
5003 * \ref cpp_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a C++ example".<br>
5004 * \ref py_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a Python example".
5006 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
5008 DataArrayIdType *MEDCouplingUMesh::findAndCorrectBadOriented3DExtrudedCells()
5010 const char msg[]="check3DCellsWellOriented detection works only for 3D cells !";
5011 if(getMeshDimension()!=3)
5012 throw INTERP_KERNEL::Exception(msg);
5013 int spaceDim=getSpaceDimension();
5015 throw INTERP_KERNEL::Exception(msg);
5017 mcIdType nbOfCells=getNumberOfCells();
5018 mcIdType *conn=_nodal_connec->getPointer();
5019 const mcIdType *connI=_nodal_connec_index->begin();
5020 const double *coo=getCoords()->begin();
5021 MCAuto<DataArrayIdType> cells(DataArrayIdType::New()); cells->alloc(0,1);
5022 for(mcIdType i=0;i<nbOfCells;i++)
5024 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5025 if(cm.isExtruded() && !cm.isDynamic() && !cm.isQuadratic())
5027 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coo))
5029 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
5030 cells->pushBackSilent(i);
5034 return cells.retn();
5038 * This method is a faster method to correct orientation of all 3D cells in \a this.
5039 * 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.
5040 * This method makes the hypothesis that \a this a coherent that is to say MEDCouplingUMesh::checkConsistency should throw no exception.
5042 * \return a newly allocated mcIdType array with one components containing cell ids renumbered to fit the convention of MED (MED file and MEDCoupling)
5043 * \sa MEDCouplingUMesh::orientCorrectlyPolyhedrons,
5045 DataArrayIdType *MEDCouplingUMesh::findAndCorrectBadOriented3DCells()
5047 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
5048 throw INTERP_KERNEL::Exception("Invalid mesh to apply findAndCorrectBadOriented3DCells on it : must be meshDim==3 and spaceDim==3 !");
5049 mcIdType nbOfCells=getNumberOfCells();
5050 mcIdType *conn=_nodal_connec->getPointer();
5051 const mcIdType *connI=_nodal_connec_index->begin();
5052 const double *coordsPtr=_coords->begin();
5053 MCAuto<DataArrayIdType> ret=DataArrayIdType::New(); ret->alloc(0,1);
5054 for(mcIdType i=0;i<nbOfCells;i++)
5056 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5059 case INTERP_KERNEL::NORM_TETRA4:
5061 if(!IsTetra4WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5063 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+3));
5064 ret->pushBackSilent(i);
5068 case INTERP_KERNEL::NORM_PYRA5:
5070 if(!IsPyra5WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5072 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+4));
5073 ret->pushBackSilent(i);
5077 case INTERP_KERNEL::NORM_PENTA6:
5078 case INTERP_KERNEL::NORM_HEXA8:
5079 case INTERP_KERNEL::NORM_HEXGP12:
5081 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5083 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
5084 ret->pushBackSilent(i);
5088 case INTERP_KERNEL::NORM_POLYHED:
5090 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5092 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
5093 ret->pushBackSilent(i);
5098 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 !");
5106 * This method has a sense for meshes with spaceDim==3 and meshDim==2.
5107 * If it is not the case an exception will be thrown.
5108 * This method is fast because the first cell of \a this is used to compute the plane.
5109 * \param vec output of size at least 3 used to store the normal vector (with norm equal to Area ) of searched plane.
5110 * \param pos output of size at least 3 used to store a point owned of searched plane.
5112 void MEDCouplingUMesh::getFastAveragePlaneOfThis(double *vec, double *pos) const
5114 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
5115 throw INTERP_KERNEL::Exception("Invalid mesh to apply getFastAveragePlaneOfThis on it : must be meshDim==2 and spaceDim==3 !");
5116 const mcIdType *conn=_nodal_connec->begin();
5117 const mcIdType *connI=_nodal_connec_index->begin();
5118 const double *coordsPtr=_coords->begin();
5119 INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(conn+1,connI[1]-connI[0]-1,coordsPtr,vec);
5120 std::copy(coordsPtr+3*conn[1],coordsPtr+3*conn[1]+3,pos);
5124 * Creates a new MEDCouplingFieldDouble holding Edge Ratio values of all
5125 * cells. Currently cells of the following types are treated:
5126 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5127 * For a cell of other type an exception is thrown.
5128 * Space dimension of a 2D mesh can be either 2 or 3.
5129 * The Edge Ratio of a cell \f$t\f$ is:
5130 * \f$\frac{|t|_\infty}{|t|_0}\f$,
5131 * where \f$|t|_\infty\f$ and \f$|t|_0\f$ respectively denote the greatest and
5132 * the smallest edge lengths of \f$t\f$.
5133 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5134 * cells and one time, lying on \a this mesh. The caller is to delete this
5135 * field using decrRef() as it is no more needed.
5136 * \throw If the coordinates array is not set.
5137 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5138 * \throw If the connectivity data array has more than one component.
5139 * \throw If the connectivity data array has a named component.
5140 * \throw If the connectivity index data array has more than one component.
5141 * \throw If the connectivity index data array has a named component.
5142 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
5143 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5144 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5146 MEDCouplingFieldDouble *MEDCouplingUMesh::getEdgeRatioField() const
5148 checkConsistencyLight();
5149 int spaceDim=getSpaceDimension();
5150 int meshDim=getMeshDimension();
5151 if(spaceDim!=2 && spaceDim!=3)
5152 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : SpaceDimension must be equal to 2 or 3 !");
5153 if(meshDim!=2 && meshDim!=3)
5154 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : MeshDimension must be equal to 2 or 3 !");
5155 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5157 mcIdType nbOfCells=getNumberOfCells();
5158 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5159 arr->alloc(nbOfCells,1);
5160 double *pt=arr->getPointer();
5161 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5162 const mcIdType *conn=_nodal_connec->begin();
5163 const mcIdType *connI=_nodal_connec_index->begin();
5164 const double *coo=_coords->begin();
5166 for(mcIdType i=0;i<nbOfCells;i++,pt++)
5168 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5171 case INTERP_KERNEL::NORM_TRI3:
5173 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5174 *pt=INTERP_KERNEL::triEdgeRatio(tmp);
5177 case INTERP_KERNEL::NORM_QUAD4:
5179 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5180 *pt=INTERP_KERNEL::quadEdgeRatio(tmp);
5183 case INTERP_KERNEL::NORM_TETRA4:
5185 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5186 *pt=INTERP_KERNEL::tetraEdgeRatio(tmp);
5190 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5192 conn+=connI[i+1]-connI[i];
5194 ret->setName("EdgeRatio");
5195 ret->synchronizeTimeWithSupport();
5200 * Creates a new MEDCouplingFieldDouble holding Aspect Ratio values of all
5201 * cells. Currently cells of the following types are treated:
5202 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5203 * For a cell of other type an exception is thrown.
5204 * Space dimension of a 2D mesh can be either 2 or 3.
5205 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5206 * cells and one time, lying on \a this mesh. The caller is to delete this
5207 * field using decrRef() as it is no more needed.
5208 * \throw If the coordinates array is not set.
5209 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5210 * \throw If the connectivity data array has more than one component.
5211 * \throw If the connectivity data array has a named component.
5212 * \throw If the connectivity index data array has more than one component.
5213 * \throw If the connectivity index data array has a named component.
5214 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
5215 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5216 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5218 MEDCouplingFieldDouble *MEDCouplingUMesh::getAspectRatioField() const
5220 checkConsistencyLight();
5221 int spaceDim=getSpaceDimension();
5222 int meshDim=getMeshDimension();
5223 if(spaceDim!=2 && spaceDim!=3)
5224 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : SpaceDimension must be equal to 2 or 3 !");
5225 if(meshDim!=2 && meshDim!=3)
5226 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : MeshDimension must be equal to 2 or 3 !");
5227 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5229 mcIdType nbOfCells=getNumberOfCells();
5230 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5231 arr->alloc(nbOfCells,1);
5232 double *pt=arr->getPointer();
5233 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5234 const mcIdType *conn=_nodal_connec->begin();
5235 const mcIdType *connI=_nodal_connec_index->begin();
5236 const double *coo=_coords->begin();
5238 for(mcIdType i=0;i<nbOfCells;i++,pt++)
5240 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5243 case INTERP_KERNEL::NORM_TRI3:
5245 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5246 *pt=INTERP_KERNEL::triAspectRatio(tmp);
5249 case INTERP_KERNEL::NORM_QUAD4:
5251 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5252 *pt=INTERP_KERNEL::quadAspectRatio(tmp);
5255 case INTERP_KERNEL::NORM_TETRA4:
5257 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5258 *pt=INTERP_KERNEL::tetraAspectRatio(tmp);
5262 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5264 conn+=connI[i+1]-connI[i];
5266 ret->setName("AspectRatio");
5267 ret->synchronizeTimeWithSupport();
5272 * Creates a new MEDCouplingFieldDouble holding Warping factor values of all
5273 * cells of \a this 2D mesh in 3D space. It is a measure of the "planarity" of 2D cell
5274 * in 3D space. Currently only cells of the following types are
5275 * treated: INTERP_KERNEL::NORM_QUAD4.
5276 * For a cell of other type an exception is thrown.
5277 * The warp field is computed as follows: let (a,b,c,d) be the points of the quad.
5279 * \f$t=\vec{da}\times\vec{ab}\f$,
5280 * \f$u=\vec{ab}\times\vec{bc}\f$
5281 * \f$v=\vec{bc}\times\vec{cd}\f$
5282 * \f$w=\vec{cd}\times\vec{da}\f$, the warp is defined as \f$W^3\f$ with
5284 * W=min(\frac{t}{|t|}\cdot\frac{v}{|v|}, \frac{u}{|u|}\cdot\frac{w}{|w|})
5286 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5287 * cells and one time, lying on \a this mesh. The caller is to delete this
5288 * field using decrRef() as it is no more needed.
5289 * \throw If the coordinates array is not set.
5290 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5291 * \throw If the connectivity data array has more than one component.
5292 * \throw If the connectivity data array has a named component.
5293 * \throw If the connectivity index data array has more than one component.
5294 * \throw If the connectivity index data array has a named component.
5295 * \throw If \a this->getMeshDimension() != 2.
5296 * \throw If \a this->getSpaceDimension() != 3.
5297 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5299 MEDCouplingFieldDouble *MEDCouplingUMesh::getWarpField() const
5301 checkConsistencyLight();
5302 int spaceDim=getSpaceDimension();
5303 int meshDim=getMeshDimension();
5305 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : SpaceDimension must be equal to 3 !");
5307 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : MeshDimension must be equal to 2 !");
5308 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5310 mcIdType nbOfCells=getNumberOfCells();
5311 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5312 arr->alloc(nbOfCells,1);
5313 double *pt=arr->getPointer();
5314 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5315 const mcIdType *conn=_nodal_connec->begin();
5316 const mcIdType *connI=_nodal_connec_index->begin();
5317 const double *coo=_coords->begin();
5319 for(mcIdType i=0;i<nbOfCells;i++,pt++)
5321 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5324 case INTERP_KERNEL::NORM_QUAD4:
5326 FillInCompact3DMode(3,4,conn+1,coo,tmp);
5327 *pt=INTERP_KERNEL::quadWarp(tmp);
5331 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : A cell with not manged type (NORM_QUAD4) has been detected !");
5333 conn+=connI[i+1]-connI[i];
5335 ret->setName("Warp");
5336 ret->synchronizeTimeWithSupport();
5342 * Creates a new MEDCouplingFieldDouble holding Skew factor values of all
5343 * cells of \a this 2D mesh in 3D space. Currently cells of the following types are
5344 * treated: INTERP_KERNEL::NORM_QUAD4.
5345 * The skew is computed as follow for a quad with points (a,b,c,d): let
5346 * \f$u=\vec{ab}+\vec{dc}\f$ and \f$v=\vec{ac}+\vec{bd}\f$
5347 * then the skew is computed as:
5349 * s=\frac{u}{|u|}\cdot\frac{v}{|v|}
5352 * For a cell of other type an exception is thrown.
5353 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5354 * cells and one time, lying on \a this mesh. The caller is to delete this
5355 * field using decrRef() as it is no more needed.
5356 * \throw If the coordinates array is not set.
5357 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5358 * \throw If the connectivity data array has more than one component.
5359 * \throw If the connectivity data array has a named component.
5360 * \throw If the connectivity index data array has more than one component.
5361 * \throw If the connectivity index data array has a named component.
5362 * \throw If \a this->getMeshDimension() != 2.
5363 * \throw If \a this->getSpaceDimension() != 3.
5364 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5366 MEDCouplingFieldDouble *MEDCouplingUMesh::getSkewField() const
5368 checkConsistencyLight();
5369 int spaceDim=getSpaceDimension();
5370 int meshDim=getMeshDimension();
5372 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : SpaceDimension must be equal to 3 !");
5374 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : MeshDimension must be equal to 2 !");
5375 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5377 mcIdType nbOfCells=getNumberOfCells();
5378 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5379 arr->alloc(nbOfCells,1);
5380 double *pt=arr->getPointer();
5381 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5382 const mcIdType *conn=_nodal_connec->begin();
5383 const mcIdType *connI=_nodal_connec_index->begin();
5384 const double *coo=_coords->begin();
5386 for(mcIdType i=0;i<nbOfCells;i++,pt++)
5388 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5391 case INTERP_KERNEL::NORM_QUAD4:
5393 FillInCompact3DMode(3,4,conn+1,coo,tmp);
5394 *pt=INTERP_KERNEL::quadSkew(tmp);
5398 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : A cell with not manged type (NORM_QUAD4) has been detected !");
5400 conn+=connI[i+1]-connI[i];
5402 ret->setName("Skew");
5403 ret->synchronizeTimeWithSupport();
5408 * 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.
5410 * \return a new instance of field containing the result. The returned instance has to be deallocated by the caller.
5412 * \sa getSkewField, getWarpField, getAspectRatioField, getEdgeRatioField
5414 MEDCouplingFieldDouble *MEDCouplingUMesh::computeDiameterField() const
5416 checkConsistencyLight();
5417 MCAuto<MEDCouplingFieldDouble> ret(MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME));
5419 std::set<INTERP_KERNEL::NormalizedCellType> types;
5420 ComputeAllTypesInternal(types,_nodal_connec,_nodal_connec_index);
5421 int spaceDim(getSpaceDimension());
5422 mcIdType nbCells(getNumberOfCells());
5423 MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
5424 arr->alloc(nbCells,1);
5425 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++)
5427 INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::DiameterCalculator> dc(INTERP_KERNEL::CellModel::GetCellModel(*it).buildInstanceOfDiameterCalulator(spaceDim));
5428 MCAuto<DataArrayIdType> cellIds(giveCellsWithType(*it));
5429 dc->computeForListOfCellIdsUMeshFrmt(cellIds->begin(),cellIds->end(),_nodal_connec_index->begin(),_nodal_connec->begin(),getCoords()->begin(),arr->getPointer());
5432 ret->setName("Diameter");
5437 * This method aggregate the bbox of each cell and put it into bbox parameter (xmin,xmax,ymin,ymax,zmin,zmax).
5439 * \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)
5440 * For all other cases this input parameter is ignored.
5441 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5443 * \throw If \a this is not fully set (coordinates and connectivity).
5444 * \throw If a cell in \a this has no valid nodeId.
5445 * \sa MEDCouplingUMesh::getBoundingBoxForBBTreeFast, MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5447 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree(double arcDetEps) const
5449 int mDim(getMeshDimension()),sDim(getSpaceDimension());
5450 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.
5451 return getBoundingBoxForBBTreeFast();
5452 if((mDim==2 && sDim==2) || (mDim==1 && sDim==2))
5454 bool presenceOfQuadratic(false);
5455 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=_types.begin();it!=_types.end();it++)
5457 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(*it));
5458 if(cm.isQuadratic())
5459 presenceOfQuadratic=true;
5461 if(!presenceOfQuadratic)
5462 return getBoundingBoxForBBTreeFast();
5463 if(mDim==2 && sDim==2)
5464 return getBoundingBoxForBBTree2DQuadratic(arcDetEps);
5466 return getBoundingBoxForBBTree1DQuadratic(arcDetEps);
5468 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) !");
5472 * This method aggregate the bbox of each cell only considering the nodes constituting each cell and put it into bbox parameter.
5473 * So meshes having quadratic cells the computed bounding boxes can be invalid !
5475 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5477 * \throw If \a this is not fully set (coordinates and connectivity).
5478 * \throw If a cell in \a this has no valid nodeId.
5480 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTreeFast() const
5482 checkFullyDefined();
5483 int spaceDim(getSpaceDimension());
5484 mcIdType nbOfCells(getNumberOfCells()), nbOfNodes(getNumberOfNodes());
5485 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5486 double *bbox(ret->getPointer());
5487 for(mcIdType i=0;i<nbOfCells*spaceDim;i++)
5489 bbox[2*i]=std::numeric_limits<double>::max();
5490 bbox[2*i+1]=-std::numeric_limits<double>::max();
5492 const double *coordsPtr(_coords->begin());
5493 const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5494 for(mcIdType i=0;i<nbOfCells;i++)
5496 mcIdType offset=connI[i]+1;
5497 mcIdType nbOfNodesForCell(connI[i+1]-offset),kk(0);
5498 for(mcIdType j=0;j<nbOfNodesForCell;j++)
5500 mcIdType nodeId=conn[offset+j];
5501 if(nodeId>=0 && nodeId<nbOfNodes)
5503 for(int k=0;k<spaceDim;k++)
5505 bbox[2*spaceDim*i+2*k]=std::min(bbox[2*spaceDim*i+2*k],coordsPtr[spaceDim*nodeId+k]);
5506 bbox[2*spaceDim*i+2*k+1]=std::max(bbox[2*spaceDim*i+2*k+1],coordsPtr[spaceDim*nodeId+k]);
5513 std::ostringstream oss; oss << "MEDCouplingUMesh::getBoundingBoxForBBTree : cell #" << i << " contains no valid nodeId !";
5514 throw INTERP_KERNEL::Exception(oss.str());
5521 * This method aggregates the bbox of each 2D cell in \a this considering the whole shape. This method is particularly
5522 * useful for 2D meshes having quadratic cells
5523 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5524 * the two extremities of the arc of circle).
5526 * \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)
5527 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5528 * \throw If \a this is not fully defined.
5529 * \throw If \a this is not a mesh with meshDimension equal to 2.
5530 * \throw If \a this is not a mesh with spaceDimension equal to 2.
5531 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic
5533 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic(double arcDetEps) const
5535 checkFullyDefined();
5536 INTERP_KERNEL::QuadraticPlanarPrecision arcPrec(arcDetEps);
5538 int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
5539 mcIdType nbOfCells=getNumberOfCells();
5540 if(spaceDim!=2 || mDim!=2)
5541 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!");
5542 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5543 double *bbox(ret->getPointer());
5544 const double *coords(_coords->begin());
5545 const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5546 for(mcIdType i=0;i<nbOfCells;i++,bbox+=4,connI++)
5548 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5549 mcIdType sz(connI[1]-connI[0]-1);
5550 std::vector<INTERP_KERNEL::Node *> nodes(sz);
5551 INTERP_KERNEL::QuadraticPolygon *pol(0);
5552 for(mcIdType j=0;j<sz;j++)
5554 mcIdType nodeId(conn[*connI+1+j]);
5555 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5557 if(!cm.isQuadratic())
5558 pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
5560 pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
5561 INTERP_KERNEL::Bounds b; b.prepareForAggregation(); pol->fillBounds(b); delete pol;
5562 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax();
5568 * This method aggregates the bbox of each 1D cell in \a this considering the whole shape. This method is particularly
5569 * useful for 2D meshes having quadratic cells
5570 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5571 * the two extremities of the arc of circle).
5573 * \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)
5574 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5575 * \throw If \a this is not fully defined.
5576 * \throw If \a this is not a mesh with meshDimension equal to 1.
5577 * \throw If \a this is not a mesh with spaceDimension equal to 2.
5578 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5580 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic(double arcDetEps) const
5582 checkFullyDefined();
5583 int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
5584 mcIdType nbOfCells=getNumberOfCells();
5585 if(spaceDim!=2 || mDim!=1)
5586 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!");
5587 INTERP_KERNEL::QuadraticPlanarPrecision arcPrec(arcDetEps);
5588 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5589 double *bbox(ret->getPointer());
5590 const double *coords(_coords->begin());
5591 const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5592 for(mcIdType i=0;i<nbOfCells;i++,bbox+=4,connI++)
5594 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5595 mcIdType sz(connI[1]-connI[0]-1);
5596 std::vector<INTERP_KERNEL::Node *> nodes(sz);
5597 INTERP_KERNEL::Edge *edge(0);
5598 for(mcIdType j=0;j<sz;j++)
5600 mcIdType nodeId(conn[*connI+1+j]);
5601 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5603 if(!cm.isQuadratic())
5604 edge=INTERP_KERNEL::QuadraticPolygon::BuildLinearEdge(nodes);
5606 edge=INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(nodes);
5607 const INTERP_KERNEL::Bounds& b(edge->getBounds());
5608 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax(); edge->decrRef();
5615 namespace MEDCouplingImpl
5620 ConnReader(const mcIdType *c, mcIdType val):_conn(c),_val(val) { }
5621 bool operator() (const mcIdType& pos) { return _conn[pos]!=_val; }
5623 const mcIdType *_conn;
5630 ConnReader2(const mcIdType *c, mcIdType val):_conn(c),_val(val) { }
5631 bool operator() (const mcIdType& pos) { return _conn[pos]==_val; }
5633 const mcIdType *_conn;
5641 * This method expects that \a this is sorted by types. If not an exception will be thrown.
5642 * This method returns in the same format as code (see MEDCouplingUMesh::checkTypeConsistencyAndContig or MEDCouplingUMesh::splitProfilePerType) how
5643 * \a this is composed in cell types.
5644 * The returned array is of size 3*n where n is the number of different types present in \a this.
5645 * For every k in [0,n] ret[3*k+2]==-1 because it has no sense here.
5646 * This parameter is kept only for compatibility with other method listed above.
5648 std::vector<mcIdType> MEDCouplingUMesh::getDistributionOfTypes() const
5650 checkConnectivityFullyDefined();
5651 const mcIdType *conn=_nodal_connec->begin();
5652 const mcIdType *connI=_nodal_connec_index->begin();
5653 const mcIdType *work=connI;
5654 mcIdType nbOfCells=getNumberOfCells();
5655 std::size_t n=getAllGeoTypes().size();
5656 std::vector<mcIdType> ret(3*n,-1); //ret[3*k+2]==-1 because it has no sense here
5657 std::set<INTERP_KERNEL::NormalizedCellType> types;
5658 for(std::size_t i=0;work!=connI+nbOfCells;i++)
5660 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn[*work];
5661 if(types.find(typ)!=types.end())
5663 std::ostringstream oss; oss << "MEDCouplingUMesh::getDistributionOfTypes : Type " << INTERP_KERNEL::CellModel::GetCellModel(typ).getRepr();
5664 oss << " is not contiguous !";
5665 throw INTERP_KERNEL::Exception(oss.str());
5669 const mcIdType *work2=std::find_if(work+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,typ));
5670 ret[3*i+1]=ToIdType(std::distance(work,work2));
5677 * This method is used to check that this has contiguous cell type in same order than described in \a code.
5678 * only for types cell, type node is not managed.
5679 * Format of \a code is the following. \a code should be of size 3*n and non empty. If not an exception is thrown.
5680 * foreach k in [0,n) on 3*k pos represent the geometric type and 3*k+1 number of elements of type 3*k.
5681 * 3*k+2 refers if different from -1 the pos in 'idsPerType' to get the corresponding array.
5682 * If 2 or more same geometric type is in \a code and exception is thrown too.
5684 * This method firstly checks
5685 * If it exists k so that 3*k geometric type is not in geometric types of this an exception will be thrown.
5686 * If it exists k so that 3*k geometric type exists but the number of consecutive cell types does not match,
5687 * an exception is thrown too.
5689 * If all geometric types in \a code are exactly those in \a this null pointer is returned.
5690 * If it exists a geometric type in \a this \b not in \a code \b no exception is thrown
5691 * and a DataArrayIdType instance is returned that the user has the responsibility to deallocate.
5693 DataArrayIdType *MEDCouplingUMesh::checkTypeConsistencyAndContig(const std::vector<mcIdType>& code, const std::vector<const DataArrayIdType *>& idsPerType) const
5696 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code is empty, should not !");
5697 std::size_t sz=code.size();
5700 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code size is NOT %3 !");
5701 std::vector<INTERP_KERNEL::NormalizedCellType> types;
5703 bool isNoPflUsed=true;
5704 for(std::size_t i=0;i<n;i++)
5705 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)code[3*i])==types.end())
5707 types.push_back((INTERP_KERNEL::NormalizedCellType)code[3*i]);
5709 if(_types.find((INTERP_KERNEL::NormalizedCellType)code[3*i])==_types.end())
5710 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : expected geo types not in this !");
5711 isNoPflUsed=isNoPflUsed && (code[3*i+2]==-1);
5714 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code contains duplication of types in unstructured mesh !");
5717 if(!checkConsecutiveCellTypesAndOrder(&types[0],&types[0]+types.size()))
5718 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : non contiguous type !");
5719 if(types.size()==_types.size())
5722 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
5724 mcIdType *retPtr=ret->getPointer();
5725 const mcIdType *connI=_nodal_connec_index->begin();
5726 const mcIdType *conn=_nodal_connec->begin();
5727 mcIdType nbOfCells=getNumberOfCells();
5728 const mcIdType *i=connI;
5730 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++,kk++)
5732 i=std::find_if(i,connI+nbOfCells,MEDCouplingImpl::ConnReader2(conn,ToIdType((*it))));
5733 mcIdType offset=ToIdType(std::distance(connI,i));
5734 const mcIdType *j=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType((*it))));
5735 mcIdType nbOfCellsOfCurType=ToIdType(std::distance(i,j));
5736 if(code[3*kk+2]==-1)
5737 for(mcIdType k=0;k<nbOfCellsOfCurType;k++)
5741 mcIdType idInIdsPerType=code[3*kk+2];
5742 if(idInIdsPerType>=0 && idInIdsPerType<ToIdType(idsPerType.size()))
5744 const DataArrayIdType *zePfl=idsPerType[idInIdsPerType];
5747 zePfl->checkAllocated();
5748 if(zePfl->getNumberOfComponents()==1)
5750 for(const mcIdType *k=zePfl->begin();k!=zePfl->end();k++,retPtr++)
5752 if(*k>=0 && *k<nbOfCellsOfCurType)
5753 *retPtr=(*k)+offset;
5756 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : the section " << kk << " points to the profile #" << idInIdsPerType;
5757 oss << ", and this profile contains a value " << *k << " should be in [0," << nbOfCellsOfCurType << ") !";
5758 throw INTERP_KERNEL::Exception(oss.str());
5763 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of a profile with nb of compo != 1 !");
5766 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of null profile !");
5770 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : at section " << kk << " of code it points to the array #" << idInIdsPerType;
5771 oss << " should be in [0," << idsPerType.size() << ") !";
5772 throw INTERP_KERNEL::Exception(oss.str());
5781 * This method makes the hypothesis that \a this is sorted by type. If not an exception will be thrown.
5782 * 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.
5783 * 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.
5784 * This method has 1 input \a profile and 3 outputs \a code \a idsInPflPerType and \a idsPerType.
5786 * \param [in] profile
5787 * \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.
5788 * \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,
5789 * \a idsInPflPerType[i] stores the tuple ids in \a profile that correspond to the geometric type code[3*i+0]
5790 * \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.
5791 * This vector can be empty in case of all geometric type cells are fully covered in ascending in the given input \a profile.
5792 * \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
5794 void MEDCouplingUMesh::splitProfilePerType(const DataArrayIdType *profile, std::vector<mcIdType>& code, std::vector<DataArrayIdType *>& idsInPflPerType, std::vector<DataArrayIdType *>& idsPerType, bool smartPflKiller) const
5797 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile is NULL !");
5798 if(profile->getNumberOfComponents()!=1)
5799 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile should have exactly one component !");
5800 checkConnectivityFullyDefined();
5801 const mcIdType *conn=_nodal_connec->begin();
5802 const mcIdType *connI=_nodal_connec_index->begin();
5803 mcIdType nbOfCells=getNumberOfCells();
5804 std::vector<INTERP_KERNEL::NormalizedCellType> types;
5805 std::vector<mcIdType> typeRangeVals(1);
5806 for(const mcIdType *i=connI;i!=connI+nbOfCells;)
5808 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5809 if(std::find(types.begin(),types.end(),curType)!=types.end())
5811 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : current mesh is not sorted by type !");
5813 types.push_back(curType);
5814 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
5815 typeRangeVals.push_back(ToIdType(std::distance(connI,i)));
5818 DataArrayIdType *castArr=0,*rankInsideCast=0,*castsPresent=0;
5819 profile->splitByValueRange(&typeRangeVals[0],&typeRangeVals[0]+typeRangeVals.size(),castArr,rankInsideCast,castsPresent);
5820 MCAuto<DataArrayIdType> tmp0=castArr;
5821 MCAuto<DataArrayIdType> tmp1=rankInsideCast;
5822 MCAuto<DataArrayIdType> tmp2=castsPresent;
5824 mcIdType nbOfCastsFinal=castsPresent->getNumberOfTuples();
5825 code.resize(3*nbOfCastsFinal);
5826 std::vector< MCAuto<DataArrayIdType> > idsInPflPerType2;
5827 std::vector< MCAuto<DataArrayIdType> > idsPerType2;
5828 for(mcIdType i=0;i<nbOfCastsFinal;i++)
5830 mcIdType castId=castsPresent->getIJ(i,0);
5831 MCAuto<DataArrayIdType> tmp3=castArr->findIdsEqual(castId);
5832 idsInPflPerType2.push_back(tmp3);
5833 code[3*i]=ToIdType(types[castId]);
5834 code[3*i+1]=tmp3->getNumberOfTuples();
5835 MCAuto<DataArrayIdType> tmp4=rankInsideCast->selectByTupleId(tmp3->begin(),tmp3->begin()+tmp3->getNumberOfTuples());
5836 if(!smartPflKiller || !tmp4->isIota(typeRangeVals[castId+1]-typeRangeVals[castId]))
5838 tmp4->copyStringInfoFrom(*profile);
5839 idsPerType2.push_back(tmp4);
5840 code[3*i+2]=ToIdType(idsPerType2.size())-1;
5847 std::size_t sz2=idsInPflPerType2.size();
5848 idsInPflPerType.resize(sz2);
5849 for(std::size_t i=0;i<sz2;i++)
5851 DataArrayIdType *locDa=idsInPflPerType2[i];
5853 idsInPflPerType[i]=locDa;
5855 std::size_t sz=idsPerType2.size();
5856 idsPerType.resize(sz);
5857 for(std::size_t i=0;i<sz;i++)
5859 DataArrayIdType *locDa=idsPerType2[i];
5861 idsPerType[i]=locDa;
5866 * This method is here too emulate the MEDMEM behaviour on BDC (buildDescendingConnectivity). Hoping this method becomes deprecated very soon.
5867 * This method make the assumption that \a this and 'nM1LevMesh' mesh lyies on same coords (same pointer) as MED and MEDMEM does.
5868 * The following equality should be verified 'nM1LevMesh->getMeshDimension()==this->getMeshDimension()-1'
5869 * 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.
5871 MEDCouplingUMesh *MEDCouplingUMesh::emulateMEDMEMBDC(const MEDCouplingUMesh *nM1LevMesh, DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *&revDesc, DataArrayIdType *&revDescIndx, DataArrayIdType *& nM1LevMeshIds, DataArrayIdType *&meshnM1Old2New) const
5873 checkFullyDefined();
5874 nM1LevMesh->checkFullyDefined();
5875 if(getMeshDimension()-1!=nM1LevMesh->getMeshDimension())
5876 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : The mesh passed as first argument should have a meshDim equal to this->getMeshDimension()-1 !" );
5877 if(_coords!=nM1LevMesh->getCoords())
5878 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : 'this' and mesh in first argument should share the same coords : Use tryToShareSameCoords method !");
5879 MCAuto<DataArrayIdType> tmp0=DataArrayIdType::New();
5880 MCAuto<DataArrayIdType> tmp1=DataArrayIdType::New();
5881 MCAuto<MEDCouplingUMesh> ret1=buildDescendingConnectivity(desc,descIndx,tmp0,tmp1);
5882 MCAuto<DataArrayIdType> ret0=ret1->sortCellsInMEDFileFrmt();
5883 desc->transformWithIndArr(ret0->begin(),ret0->begin()+ret0->getNbOfElems());
5884 MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
5885 tmp->setConnectivity(tmp0,tmp1);
5886 tmp->renumberCells(ret0->begin(),false);
5887 revDesc=tmp->getNodalConnectivity();
5888 revDescIndx=tmp->getNodalConnectivityIndex();
5889 DataArrayIdType *ret=0;
5890 if(!ret1->areCellsIncludedIn(nM1LevMesh,2,ret))
5893 ret->getMaxValue(tmp2);
5895 std::ostringstream oss; oss << "MEDCouplingUMesh::emulateMEDMEMBDC : input N-1 mesh present a cell not in descending mesh ... Id of cell is " << tmp2 << " !";
5896 throw INTERP_KERNEL::Exception(oss.str());
5901 revDescIndx->incrRef();
5904 meshnM1Old2New=ret0;
5909 * Permutes the nodal connectivity arrays so that the cells are sorted by type, which is
5910 * necessary for writing the mesh to MED file. Additionally returns a permutation array
5911 * in "Old to New" mode.
5912 * \return DataArrayIdType * - a new instance of DataArrayIdType. The caller is to delete
5913 * this array using decrRef() as it is no more needed.
5914 * \throw If the nodal connectivity of cells is not defined.
5916 DataArrayIdType *MEDCouplingUMesh::sortCellsInMEDFileFrmt()
5918 checkConnectivityFullyDefined();
5919 MCAuto<DataArrayIdType> ret=getRenumArrForMEDFileFrmt();
5920 renumberCells(ret->begin(),false);
5925 * This methods checks that cells are sorted by their types.
5926 * This method makes asumption (no check) that connectivity is correctly set before calling.
5928 bool MEDCouplingUMesh::checkConsecutiveCellTypes() const
5930 checkFullyDefined();
5931 const mcIdType *conn=_nodal_connec->begin();
5932 const mcIdType *connI=_nodal_connec_index->begin();
5933 mcIdType nbOfCells=getNumberOfCells();
5934 std::set<INTERP_KERNEL::NormalizedCellType> types;
5935 for(const mcIdType *i=connI;i!=connI+nbOfCells;)
5937 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5938 if(types.find(curType)!=types.end())
5940 types.insert(curType);
5941 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
5947 * This method is a specialization of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method that is called here.
5948 * The geometric type order is specified by MED file.
5950 * \sa MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder
5952 bool MEDCouplingUMesh::checkConsecutiveCellTypesForMEDFileFrmt() const
5954 return checkConsecutiveCellTypesAndOrder(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
5958 * This method performs the same job as checkConsecutiveCellTypes except that the order of types sequence is analyzed to check
5959 * that the order is specified in array defined by [ \a orderBg , \a orderEnd ).
5960 * If there is some geo types in \a this \b NOT in [ \a orderBg, \a orderEnd ) it is OK (return true) if contiguous.
5961 * If there is some geo types in [ \a orderBg, \a orderEnd ) \b NOT in \a this it is OK too (return true) if contiguous.
5963 bool MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
5965 checkFullyDefined();
5966 const mcIdType *conn=_nodal_connec->begin();
5967 const mcIdType *connI=_nodal_connec_index->begin();
5968 mcIdType nbOfCells=getNumberOfCells();
5971 mcIdType lastPos=-1;
5972 std::set<INTERP_KERNEL::NormalizedCellType> sg;
5973 for(const mcIdType *i=connI;i!=connI+nbOfCells;)
5975 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5976 const INTERP_KERNEL::NormalizedCellType *isTypeExists=std::find(orderBg,orderEnd,curType);
5977 if(isTypeExists!=orderEnd)
5979 mcIdType pos=ToIdType(std::distance(orderBg,isTypeExists));
5983 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
5987 if(sg.find(curType)==sg.end())
5989 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6000 * This method returns 2 newly allocated DataArrayIdType instances. The first is an array of size 'this->getNumberOfCells()' with one component,
6001 * 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
6002 * 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'.
6004 DataArrayIdType *MEDCouplingUMesh::getLevArrPerCellTypes(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd, DataArrayIdType *&nbPerType) const
6006 checkConnectivityFullyDefined();
6007 mcIdType nbOfCells=getNumberOfCells();
6008 const mcIdType *conn=_nodal_connec->begin();
6009 const mcIdType *connI=_nodal_connec_index->begin();
6010 MCAuto<DataArrayIdType> tmpa=DataArrayIdType::New();
6011 MCAuto<DataArrayIdType> tmpb=DataArrayIdType::New();
6012 tmpa->alloc(nbOfCells,1);
6013 tmpb->alloc(std::distance(orderBg,orderEnd),1);
6014 tmpb->fillWithZero();
6015 mcIdType *tmp=tmpa->getPointer();
6016 mcIdType *tmp2=tmpb->getPointer();
6017 for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6019 const INTERP_KERNEL::NormalizedCellType *where=std::find(orderBg,orderEnd,(INTERP_KERNEL::NormalizedCellType)conn[*i]);
6022 mcIdType pos=ToIdType(std::distance(orderBg,where));
6024 tmp[std::distance(connI,i)]=pos;
6028 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*i]);
6029 std::ostringstream oss; oss << "MEDCouplingUMesh::getLevArrPerCellTypes : Cell #" << std::distance(connI,i);
6030 oss << " has a type " << cm.getRepr() << " not in input array of type !";
6031 throw INTERP_KERNEL::Exception(oss.str());
6034 nbPerType=tmpb.retn();
6039 * This method behaves exactly as MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec but the order is those defined in MED file spec.
6041 * \return a new object containing the old to new correspondence.
6043 * \sa MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec, MEDCouplingUMesh::sortCellsInMEDFileFrmt.
6045 DataArrayIdType *MEDCouplingUMesh::getRenumArrForMEDFileFrmt() const
6047 return getRenumArrForConsecutiveCellTypesSpec(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
6051 * 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.
6052 * This method returns an array of size getNumberOfCells() that gives a renumber array old2New that can be used as input of MEDCouplingMesh::renumberCells.
6053 * The mesh after this call to MEDCouplingMesh::renumberCells will pass the test of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder with the same inputs.
6054 * The returned array minimizes the permutations that is to say the order of cells inside same geometric type remains the same.
6056 DataArrayIdType *MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
6058 DataArrayIdType *nbPerType=0;
6059 MCAuto<DataArrayIdType> tmpa=getLevArrPerCellTypes(orderBg,orderEnd,nbPerType);
6060 nbPerType->decrRef();
6061 return tmpa->buildPermArrPerLevel();
6065 * This method reorganize the cells of \a this so that the cells with same geometric types are put together.
6066 * The number of cells remains unchanged after the call of this method.
6067 * This method tries to minimizes the number of needed permutations. So, this method behaves not exactly as
6068 * MEDCouplingUMesh::sortCellsInMEDFileFrmt.
6070 * \return the array giving the correspondence old to new.
6072 DataArrayIdType *MEDCouplingUMesh::rearrange2ConsecutiveCellTypes()
6074 checkFullyDefined();
6076 const mcIdType *conn=_nodal_connec->begin();
6077 const mcIdType *connI=_nodal_connec_index->begin();
6078 mcIdType nbOfCells=getNumberOfCells();
6079 std::vector<INTERP_KERNEL::NormalizedCellType> types;
6080 for(const mcIdType *i=connI;i!=connI+nbOfCells && (types.size()!=_types.size());)
6081 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)conn[*i])==types.end())
6083 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6084 types.push_back(curType);
6085 for(i++;i!=connI+nbOfCells && (INTERP_KERNEL::NormalizedCellType)conn[*i]==curType;i++);
6087 DataArrayIdType *ret=DataArrayIdType::New();
6088 ret->alloc(nbOfCells,1);
6089 mcIdType *retPtr=ret->getPointer();
6090 std::fill(retPtr,retPtr+nbOfCells,-1);
6091 mcIdType newCellId=0;
6092 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
6094 for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6095 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
6096 retPtr[std::distance(connI,i)]=newCellId++;
6098 renumberCells(retPtr,false);
6103 * This method splits \a this into as mush as untructured meshes that consecutive set of same type cells.
6104 * So this method has typically a sense if MEDCouplingUMesh::checkConsecutiveCellTypes has a sense.
6105 * This method makes asumption that connectivity is correctly set before calling.
6107 std::vector<MEDCouplingUMesh *> MEDCouplingUMesh::splitByType() const
6109 checkConnectivityFullyDefined();
6110 const mcIdType *conn=_nodal_connec->begin();
6111 const mcIdType *connI=_nodal_connec_index->begin();
6112 mcIdType nbOfCells=getNumberOfCells();
6113 std::vector<MEDCouplingUMesh *> ret;
6114 for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6116 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6117 mcIdType beginCellId=ToIdType(std::distance(connI,i));
6118 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6119 mcIdType endCellId=ToIdType(std::distance(connI,i));
6120 mcIdType sz=endCellId-beginCellId;
6121 mcIdType *cells=new mcIdType[sz];
6122 for(mcIdType j=0;j<sz;j++)
6123 cells[j]=beginCellId+j;
6124 MEDCouplingUMesh *m=(MEDCouplingUMesh *)buildPartOfMySelf(cells,cells+sz,true);
6132 * This method performs the opposite operation than those in MEDCoupling1SGTUMesh::buildUnstructured.
6133 * If \a this is a single geometric type unstructured mesh, it will be converted into a more compact data structure,
6134 * MEDCoupling1GTUMesh instance. The returned instance will aggregate the same DataArrayDouble instance of coordinates than \a this.
6136 * \return a newly allocated instance, that the caller must manage.
6137 * \throw If \a this contains more than one geometric type.
6138 * \throw If the nodal connectivity of \a this is not fully defined.
6139 * \throw If the internal data is not coherent.
6141 MEDCoupling1GTUMesh *MEDCouplingUMesh::convertIntoSingleGeoTypeMesh() const
6143 checkConnectivityFullyDefined();
6144 if(_types.size()!=1)
6145 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6146 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6147 MCAuto<MEDCoupling1GTUMesh> ret=MEDCoupling1GTUMesh::New(getName(),typ);
6148 ret->setCoords(getCoords());
6149 MEDCoupling1SGTUMesh *retC=dynamic_cast<MEDCoupling1SGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6152 MCAuto<DataArrayIdType> c=convertNodalConnectivityToStaticGeoTypeMesh();
6153 retC->setNodalConnectivity(c);
6157 MEDCoupling1DGTUMesh *retD=dynamic_cast<MEDCoupling1DGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6159 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : Internal error !");
6160 DataArrayIdType *c=0,*ci=0;
6161 convertNodalConnectivityToDynamicGeoTypeMesh(c,ci);
6162 MCAuto<DataArrayIdType> cs(c),cis(ci);
6163 retD->setNodalConnectivity(cs,cis);
6168 DataArrayIdType *MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh() const
6170 checkConnectivityFullyDefined();
6171 if(_types.size()!=1)
6172 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6173 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6174 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6177 std::ostringstream oss; oss << "MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : this contains a single geo type (" << cm.getRepr() << ") but ";
6178 oss << "this type is dynamic ! Only static geometric type is possible for that type ! call convertNodalConnectivityToDynamicGeoTypeMesh instead !";
6179 throw INTERP_KERNEL::Exception(oss.str());
6181 mcIdType nbCells=getNumberOfCells();
6182 mcIdType typi=ToIdType(typ);
6183 mcIdType nbNodesPerCell=ToIdType(cm.getNumberOfNodes());
6184 MCAuto<DataArrayIdType> connOut=DataArrayIdType::New(); connOut->alloc(nbCells*nbNodesPerCell,1);
6185 mcIdType *outPtr=connOut->getPointer();
6186 const mcIdType *conn=_nodal_connec->begin();
6187 const mcIdType *connI=_nodal_connec_index->begin();
6189 for(mcIdType i=0;i<nbCells;i++,connI++)
6191 if(conn[connI[0]]==typi && connI[1]-connI[0]==nbNodesPerCell)
6192 outPtr=std::copy(conn+connI[0]+1,conn+connI[1],outPtr);
6195 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 << ") !";
6196 throw INTERP_KERNEL::Exception(oss.str());
6199 return connOut.retn();
6203 * Convert the nodal connectivity of the mesh so that all the cells are of dynamic types (polygon or quadratic
6204 * polygon). This returns the corresponding new nodal connectivity in \ref numbering-indirect format.
6208 void MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh(DataArrayIdType *&nodalConn, DataArrayIdType *&nodalConnIndex) const
6210 static const char msg0[]="MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : nodal connectivity in this are invalid ! Call checkConsistency !";
6211 checkConnectivityFullyDefined();
6212 if(_types.size()!=1)
6213 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6214 mcIdType nbCells=getNumberOfCells(),
6215 lgth=_nodal_connec->getNumberOfTuples();
6217 throw INTERP_KERNEL::Exception(msg0);
6218 MCAuto<DataArrayIdType> c(DataArrayIdType::New()),ci(DataArrayIdType::New());
6219 c->alloc(lgth-nbCells,1); ci->alloc(nbCells+1,1);
6220 mcIdType *cp(c->getPointer()),*cip(ci->getPointer());
6221 const mcIdType *incp(_nodal_connec->begin()),*incip(_nodal_connec_index->begin());
6223 for(mcIdType i=0;i<nbCells;i++,cip++,incip++)
6225 mcIdType strt(incip[0]+1),stop(incip[1]);//+1 to skip geo type
6226 mcIdType delta(stop-strt);
6229 if((strt>=0 && strt<lgth) && (stop>=0 && stop<=lgth))
6230 cp=std::copy(incp+strt,incp+stop,cp);
6232 throw INTERP_KERNEL::Exception(msg0);
6235 throw INTERP_KERNEL::Exception(msg0);
6236 cip[1]=cip[0]+delta;
6238 nodalConn=c.retn(); nodalConnIndex=ci.retn();
6242 * This method takes in input a vector of MEDCouplingUMesh instances lying on the same coordinates with same mesh dimensions.
6243 * Each mesh in \b ms must be sorted by type with the same order (typically using MEDCouplingUMesh::sortCellsInMEDFileFrmt).
6244 * This method is particularly useful for MED file interaction. It allows to aggregate several meshes and keeping the type sorting
6245 * and the track of the permutation by chunk of same geotype cells to retrieve it. The traditional formats old2new and new2old
6246 * are not used here to avoid the build of big permutation array.
6248 * \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
6249 * those specified in MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6250 * \param [out] szOfCellGrpOfSameType is a newly allocated DataArrayIdType instance whose number of tuples is equal to the number of chunks of same geotype
6251 * in all meshes in \b ms. The accumulation of all values of this array is equal to the number of cells of returned mesh.
6252 * \param [out] idInMsOfCellGrpOfSameType is a newly allocated DataArrayIdType instance having the same size than \b szOfCellGrpOfSameType. This
6253 * output array gives for each chunck of same type the corresponding mesh id in \b ms.
6254 * \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
6255 * is sorted by type following the geo cell types order of MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6257 MEDCouplingUMesh *MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& ms,
6258 DataArrayIdType *&szOfCellGrpOfSameType,
6259 DataArrayIdType *&idInMsOfCellGrpOfSameType)
6261 std::vector<const MEDCouplingUMesh *> ms2;
6262 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms.begin();it!=ms.end();it++)
6265 (*it)->checkConnectivityFullyDefined();
6269 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : input vector is empty !");
6270 const DataArrayDouble *refCoo=ms2[0]->getCoords();
6271 int meshDim=ms2[0]->getMeshDimension();
6272 std::vector<const MEDCouplingUMesh *> m1ssm;
6273 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmAuto;
6275 std::vector<const MEDCouplingUMesh *> m1ssmSingle;
6276 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmSingleAuto;
6277 mcIdType fake=0,rk=0;
6278 MCAuto<DataArrayIdType> ret1(DataArrayIdType::New()),ret2(DataArrayIdType::New());
6279 ret1->alloc(0,1); ret2->alloc(0,1);
6280 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms2.begin();it!=ms2.end();it++,rk++)
6282 if(meshDim!=(*it)->getMeshDimension())
6283 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshdims mismatch !");
6284 if(refCoo!=(*it)->getCoords())
6285 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshes are not shared by a single coordinates coords !");
6286 std::vector<MEDCouplingUMesh *> sp=(*it)->splitByType();
6287 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<const MEDCouplingUMesh *> >(m1ssm));
6288 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<MCAuto<MEDCouplingUMesh> > >(m1ssmAuto));
6289 for(std::vector<MEDCouplingUMesh *>::const_iterator it2=sp.begin();it2!=sp.end();it2++)
6291 MEDCouplingUMesh *singleCell=static_cast<MEDCouplingUMesh *>((*it2)->buildPartOfMySelf(&fake,&fake+1,true));
6292 m1ssmSingleAuto.push_back(singleCell);
6293 m1ssmSingle.push_back(singleCell);
6294 ret1->pushBackSilent((*it2)->getNumberOfCells()); ret2->pushBackSilent(rk);
6297 MCAuto<MEDCouplingUMesh> m1ssmSingle2=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmSingle);
6298 MCAuto<DataArrayIdType> renum=m1ssmSingle2->sortCellsInMEDFileFrmt();
6299 std::vector<const MEDCouplingUMesh *> m1ssmfinal(m1ssm.size());
6300 for(mcIdType i=0;i<ToIdType(m1ssm.size());i++)
6301 m1ssmfinal[renum->getIJ(i,0)]=m1ssm[i];
6302 MCAuto<MEDCouplingUMesh> ret0=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmfinal);
6303 szOfCellGrpOfSameType=ret1->renumber(renum->begin());
6304 idInMsOfCellGrpOfSameType=ret2->renumber(renum->begin());
6309 * This method returns a newly created DataArrayIdType instance.
6310 * This method retrieves cell ids in [ \a begin, \a end ) that have the type \a type.
6312 DataArrayIdType *MEDCouplingUMesh::keepCellIdsByType(INTERP_KERNEL::NormalizedCellType type, const mcIdType *begin, const mcIdType *end) const
6314 checkFullyDefined();
6315 const mcIdType *conn=_nodal_connec->begin();
6316 const mcIdType *connIndex=_nodal_connec_index->begin();
6317 MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(0,1);
6318 for(const mcIdType *w=begin;w!=end;w++)
6319 if((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]==type)
6320 ret->pushBackSilent(*w);
6325 * This method makes the assumption that da->getNumberOfTuples()<this->getNumberOfCells(). This method makes the assumption that ids contained in 'da'
6326 * are in [0:getNumberOfCells())
6328 DataArrayIdType *MEDCouplingUMesh::convertCellArrayPerGeoType(const DataArrayIdType *da) const
6330 checkFullyDefined();
6331 const mcIdType *conn=_nodal_connec->begin();
6332 const mcIdType *connI=_nodal_connec_index->begin();
6333 mcIdType nbOfCells=getNumberOfCells();
6334 std::set<INTERP_KERNEL::NormalizedCellType> types(getAllGeoTypes());
6335 mcIdType *tmp=new mcIdType[nbOfCells];
6336 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
6339 for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6340 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
6341 tmp[std::distance(connI,i)]=j++;
6343 DataArrayIdType *ret=DataArrayIdType::New();
6344 ret->alloc(da->getNumberOfTuples(),da->getNumberOfComponents());
6345 ret->copyStringInfoFrom(*da);
6346 mcIdType *retPtr=ret->getPointer();
6347 const mcIdType *daPtr=da->begin();
6348 mcIdType nbOfElems=da->getNbOfElems();
6349 for(mcIdType k=0;k<nbOfElems;k++)
6350 retPtr[k]=tmp[daPtr[k]];
6356 * This method reduced number of cells of this by keeping cells whose type is different from 'type' and if type=='type'
6357 * This method \b works \b for mesh sorted by type.
6358 * cells whose ids is in 'idsPerGeoType' array.
6359 * This method conserves coords and name of mesh.
6361 MEDCouplingUMesh *MEDCouplingUMesh::keepSpecifiedCells(INTERP_KERNEL::NormalizedCellType type, const mcIdType *idsPerGeoTypeBg, const mcIdType *idsPerGeoTypeEnd) const
6363 std::vector<mcIdType> code=getDistributionOfTypes();
6364 std::size_t nOfTypesInThis=code.size()/3;
6365 mcIdType sz=0,szOfType=0;
6366 for(std::size_t i=0;i<nOfTypesInThis;i++)
6371 szOfType=code[3*i+1];
6373 for(const mcIdType *work=idsPerGeoTypeBg;work!=idsPerGeoTypeEnd;work++)
6374 if(*work<0 || *work>=szOfType)
6376 std::ostringstream oss; oss << "MEDCouplingUMesh::keepSpecifiedCells : Request on type " << type << " at place #" << std::distance(idsPerGeoTypeBg,work) << " value " << *work;
6377 oss << ". It should be in [0," << szOfType << ") !";
6378 throw INTERP_KERNEL::Exception(oss.str());
6380 MCAuto<DataArrayIdType> idsTokeep=DataArrayIdType::New(); idsTokeep->alloc(sz+std::distance(idsPerGeoTypeBg,idsPerGeoTypeEnd),1);
6381 mcIdType *idsPtr=idsTokeep->getPointer();
6383 for(std::size_t i=0;i<nOfTypesInThis;i++)
6386 for(mcIdType j=0;j<code[3*i+1];j++)
6389 idsPtr=std::transform(idsPerGeoTypeBg,idsPerGeoTypeEnd,idsPtr,std::bind2nd(std::plus<mcIdType>(),offset));
6390 offset+=code[3*i+1];
6392 MCAuto<MEDCouplingUMesh> ret=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(idsTokeep->begin(),idsTokeep->end(),true));
6393 ret->copyTinyInfoFrom(this);
6398 * This method returns a vector of size 'this->getNumberOfCells()'.
6399 * This method retrieves for each cell in \a this if it is linear (false) or quadratic(true).
6401 std::vector<bool> MEDCouplingUMesh::getQuadraticStatus() const
6403 mcIdType ncell=getNumberOfCells();
6404 std::vector<bool> ret(ncell);
6405 const mcIdType *cI=getNodalConnectivityIndex()->begin();
6406 const mcIdType *c=getNodalConnectivity()->begin();
6407 for(mcIdType i=0;i<ncell;i++)
6409 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[i]];
6410 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6411 ret[i]=cm.isQuadratic();
6417 * Returns a newly created mesh (with ref count ==1) that contains merge of \a this and \a other.
6419 MEDCouplingMesh *MEDCouplingUMesh::mergeMyselfWith(const MEDCouplingMesh *other) const
6421 if(other->getType()!=UNSTRUCTURED)
6422 throw INTERP_KERNEL::Exception("Merge of umesh only available with umesh each other !");
6423 const MEDCouplingUMesh *otherC=static_cast<const MEDCouplingUMesh *>(other);
6424 return MergeUMeshes(this,otherC);
6428 * Returns a new DataArrayDouble holding barycenters of all cells. The barycenter is
6429 * computed by averaging coordinates of cell nodes, so this method is not a right
6430 * choice for degenerated meshes (not well oriented, cells with measure close to zero).
6431 * Beware also that for quadratic meshes, degenerated arc of circles are turned into linear edges for the computation.
6432 * This happens with a default detection precision of eps=1.0e-14. If you need control over this use computeCellCenterOfMassWithPrecision().
6433 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
6434 * this->getNumberOfCells() tuples per \a this->getSpaceDimension()
6435 * components. The caller is to delete this array using decrRef() as it is
6437 * \throw If the coordinates array is not set.
6438 * \throw If the nodal connectivity of cells is not defined.
6439 * \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
6440 * \sa MEDCouplingUMesh::computeCellCenterOfMassWithPrecision
6442 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMass() const
6444 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6445 int spaceDim=getSpaceDimension();
6446 mcIdType nbOfCells=getNumberOfCells();
6447 ret->alloc(nbOfCells,spaceDim);
6448 ret->copyStringInfoFrom(*getCoords());
6449 double *ptToFill=ret->getPointer();
6450 const mcIdType *nodal=_nodal_connec->begin();
6451 const mcIdType *nodalI=_nodal_connec_index->begin();
6452 const double *coor=_coords->begin();
6453 for(mcIdType i=0;i<nbOfCells;i++)
6455 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6456 INTERP_KERNEL::computeBarycenter2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[i]+1,nodalI[i+1]-nodalI[i]-1,coor,spaceDim,ptToFill);
6464 * See computeCellCenterOfMass().
6465 * \param eps a precision for the detection of degenerated arc of circles.
6466 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
6467 * this->getNumberOfCells() tuples per \a this->getSpaceDimension()
6468 * components. The caller is to delete this array using decrRef() as it is
6470 * \throw If the coordinates array is not set.
6471 * \throw If the nodal connectivity of cells is not defined.
6472 * \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
6473 * \sa MEDCouplingUMesh::computeCellCenterOfMassWithPrecision
6475 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMassWithPrecision(double eps) const
6477 INTERP_KERNEL::QuadraticPlanarPrecision prec(eps);
6478 MCAuto<DataArrayDouble> ret = computeCellCenterOfMass();
6484 * This method computes for each cell in \a this, the location of the iso barycenter of nodes constituting
6485 * the cell. Contrary to badly named MEDCouplingUMesh::computeCellCenterOfMass method that returns the center of inertia of the
6487 * \return a newly allocated DataArrayDouble instance that the caller has to deal with. The returned
6488 * DataArrayDouble instance will have \c this->getNumberOfCells() tuples and \c this->getSpaceDimension() components.
6490 * \sa MEDCouplingUMesh::computeCellCenterOfMass
6491 * \throw If \a this is not fully defined (coordinates and connectivity)
6492 * \throw If there is presence in nodal connectivity in \a this of node ids not in [0, \c this->getNumberOfNodes() )
6494 DataArrayDouble *MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell() const
6496 checkFullyDefined();
6497 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6498 int spaceDim=getSpaceDimension();
6499 mcIdType nbOfCells=getNumberOfCells();
6500 mcIdType nbOfNodes=getNumberOfNodes();
6501 ret->alloc(nbOfCells,spaceDim);
6502 double *ptToFill=ret->getPointer();
6503 const mcIdType *nodal=_nodal_connec->begin();
6504 const mcIdType *nodalI=_nodal_connec_index->begin();
6505 const double *coor=_coords->begin();
6506 for(mcIdType i=0;i<nbOfCells;i++,ptToFill+=spaceDim)
6508 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6509 std::fill(ptToFill,ptToFill+spaceDim,0.);
6510 if(type!=INTERP_KERNEL::NORM_POLYHED)
6512 for(const mcIdType *conn=nodal+nodalI[i]+1;conn!=nodal+nodalI[i+1];conn++)
6514 if(*conn>=0 && *conn<nbOfNodes)
6515 std::transform(coor+spaceDim*conn[0],coor+spaceDim*(conn[0]+1),ptToFill,ptToFill,std::plus<double>());
6518 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of nodeId #" << *conn << " should be in [0," << nbOfNodes << ") !";
6519 throw INTERP_KERNEL::Exception(oss.str());
6522 mcIdType nbOfNodesInCell=nodalI[i+1]-nodalI[i]-1;
6523 if(nbOfNodesInCell>0)
6524 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies<double>(),1./(double)nbOfNodesInCell));
6527 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of cell with no nodes !";
6528 throw INTERP_KERNEL::Exception(oss.str());
6533 std::set<mcIdType> s(nodal+nodalI[i]+1,nodal+nodalI[i+1]);
6535 for(std::set<mcIdType>::const_iterator it=s.begin();it!=s.end();it++)
6537 if(*it>=0 && *it<nbOfNodes)
6538 std::transform(coor+spaceDim*(*it),coor+spaceDim*((*it)+1),ptToFill,ptToFill,std::plus<double>());
6541 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell polyhedron cell #" << i << " presence of nodeId #" << *it << " should be in [0," << nbOfNodes << ") !";
6542 throw INTERP_KERNEL::Exception(oss.str());
6546 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies<double>(),1./(double)s.size()));
6549 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on polyhedron cell #" << i << " there are no nodes !";
6550 throw INTERP_KERNEL::Exception(oss.str());
6558 * Returns a new DataArrayDouble holding barycenters of specified cells. The
6559 * barycenter is computed by averaging coordinates of cell nodes. The cells to treat
6560 * are specified via an array of cell ids.
6561 * \warning Validity of the specified cell ids is not checked!
6562 * Valid range is [ 0, \a this->getNumberOfCells() ).
6563 * \param [in] begin - an array of cell ids of interest.
6564 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
6565 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size ( \a
6566 * end - \a begin ) tuples per \a this->getSpaceDimension() components. The
6567 * caller is to delete this array using decrRef() as it is no more needed.
6568 * \throw If the coordinates array is not set.
6569 * \throw If the nodal connectivity of cells is not defined.
6571 * \if ENABLE_EXAMPLES
6572 * \ref cpp_mcumesh_getPartBarycenterAndOwner "Here is a C++ example".<br>
6573 * \ref py_mcumesh_getPartBarycenterAndOwner "Here is a Python example".
6576 DataArrayDouble *MEDCouplingUMesh::getPartBarycenterAndOwner(const mcIdType *begin, const mcIdType *end) const
6578 DataArrayDouble *ret=DataArrayDouble::New();
6579 int spaceDim=getSpaceDimension();
6580 std::size_t nbOfTuple=std::distance(begin,end);
6581 ret->alloc(nbOfTuple,spaceDim);
6582 double *ptToFill=ret->getPointer();
6583 double *tmp=new double[spaceDim];
6584 const mcIdType *nodal=_nodal_connec->begin();
6585 const mcIdType *nodalI=_nodal_connec_index->begin();
6586 const double *coor=_coords->begin();
6587 for(const mcIdType *w=begin;w!=end;w++)
6589 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[*w]];
6590 INTERP_KERNEL::computeBarycenter2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[*w]+1,nodalI[*w+1]-nodalI[*w]-1,coor,spaceDim,ptToFill);
6598 * 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".
6599 * So the returned instance will have 4 components and \c this->getNumberOfCells() tuples.
6600 * So this method expects that \a this has a spaceDimension equal to 3 and meshDimension equal to 2.
6601 * The computation of the plane equation is done using each time the 3 first nodes of 2D cells.
6602 * This method is useful to detect 2D cells in 3D space that are not coplanar.
6604 * \return DataArrayDouble * - a new instance of DataArrayDouble having 4 components and a number of tuples equal to number of cells in \a this.
6605 * \throw If spaceDim!=3 or meshDim!=2.
6606 * \throw If connectivity of \a this is invalid.
6607 * \throw If connectivity of a cell in \a this points to an invalid node.
6609 DataArrayDouble *MEDCouplingUMesh::computePlaneEquationOf3DFaces() const
6611 MCAuto<DataArrayDouble> ret(DataArrayDouble::New());
6612 mcIdType nbOfCells=getNumberOfCells();
6613 mcIdType nbOfNodes(getNumberOfNodes());
6614 if(getSpaceDimension()!=3 || getMeshDimension()!=2)
6615 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computePlaneEquationOf3DFaces : This method must be applied on a mesh having meshDimension equal 2 and a spaceDimension equal to 3 !");
6616 ret->alloc(nbOfCells,4);
6617 double *retPtr(ret->getPointer());
6618 const mcIdType *nodal(_nodal_connec->begin()),*nodalI(_nodal_connec_index->begin());
6619 const double *coor(_coords->begin());
6620 for(mcIdType i=0;i<nbOfCells;i++,nodalI++,retPtr+=4)
6622 double matrix[16]={0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,0},matrix2[16];
6623 if(nodalI[1]-nodalI[0]>=4)
6625 double aa[3]={coor[nodal[nodalI[0]+1+1]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6626 coor[nodal[nodalI[0]+1+1]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6627 coor[nodal[nodalI[0]+1+1]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]}
6628 ,bb[3]={coor[nodal[nodalI[0]+1+2]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6629 coor[nodal[nodalI[0]+1+2]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6630 coor[nodal[nodalI[0]+1+2]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]};
6631 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]};
6632 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]));
6633 for(int j=0;j<3;j++)
6635 mcIdType nodeId(nodal[nodalI[0]+1+j]);
6636 if(nodeId>=0 && nodeId<nbOfNodes)
6637 std::copy(coor+nodeId*3,coor+(nodeId+1)*3,matrix+4*j);
6640 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! This cell points to an invalid nodeId : " << nodeId << " !";
6641 throw INTERP_KERNEL::Exception(oss.str());
6644 if(sqrt(cc[0]*cc[0]+cc[1]*cc[1]+cc[2]*cc[2])>(1e-3*aa_norm*bb_norm))
6646 INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6647 retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6651 if(nodalI[1]-nodalI[0]==4)
6653 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : cell" << i << " : Presence of The 3 colinear points !";
6654 throw INTERP_KERNEL::Exception(oss.str());
6657 double dd[3]={0.,0.,0.};
6658 for(mcIdType offset=nodalI[0]+1;offset<nodalI[1];offset++)
6659 std::transform(coor+3*nodal[offset],coor+3*(nodal[offset]+1),dd,dd,std::plus<double>());
6660 mcIdType nbOfNodesInCell(nodalI[1]-nodalI[0]-1);
6661 std::transform(dd,dd+3,dd,std::bind2nd(std::multiplies<double>(),1./(double)nbOfNodesInCell));
6662 std::copy(dd,dd+3,matrix+4*2);
6663 INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6664 retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6669 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! Must be constitued by more than 3 nodes !";
6670 throw INTERP_KERNEL::Exception(oss.str());
6677 * This method expects as input a DataArrayDouble non nul instance 'da' that should be allocated. If not an exception is thrown.
6680 MEDCouplingUMesh *MEDCouplingUMesh::Build0DMeshFromCoords(DataArrayDouble *da)
6683 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build0DMeshFromCoords : instance of DataArrayDouble must be not null !");
6684 da->checkAllocated();
6685 std::string name(da->getName());
6686 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New(name,0));
6688 ret->setName("Mesh");
6690 mcIdType nbOfTuples(da->getNumberOfTuples());
6691 MCAuto<DataArrayIdType> c(DataArrayIdType::New()),cI(DataArrayIdType::New());
6692 c->alloc(2*nbOfTuples,1);
6693 cI->alloc(nbOfTuples+1,1);
6694 mcIdType *cp(c->getPointer()),*cip(cI->getPointer());
6696 for(mcIdType i=0;i<nbOfTuples;i++)
6698 *cp++=INTERP_KERNEL::NORM_POINT1;
6702 ret->setConnectivity(c,cI,true);
6706 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::Build1DMeshFromCoords(DataArrayDouble *da)
6709 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build01MeshFromCoords : instance of DataArrayDouble must be not null !");
6710 da->checkAllocated();
6711 std::string name(da->getName());
6712 MCAuto<MEDCouplingUMesh> ret;
6714 MCAuto<MEDCouplingCMesh> tmp(MEDCouplingCMesh::New());
6715 MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
6716 arr->alloc(da->getNumberOfTuples());
6717 tmp->setCoordsAt(0,arr);
6718 ret=tmp->buildUnstructured();
6722 ret->setName("Mesh");
6729 * Creates a new MEDCouplingUMesh by concatenating two given meshes of the same dimension.
6730 * Cells and nodes of
6731 * the first mesh precede cells and nodes of the second mesh within the result mesh.
6732 * \param [in] mesh1 - the first mesh.
6733 * \param [in] mesh2 - the second mesh.
6734 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6735 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6736 * is no more needed.
6737 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
6738 * \throw If the coordinates array is not set in none of the meshes.
6739 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
6740 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
6742 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
6744 std::vector<const MEDCouplingUMesh *> tmp(2);
6745 tmp[0]=const_cast<MEDCouplingUMesh *>(mesh1); tmp[1]=const_cast<MEDCouplingUMesh *>(mesh2);
6746 return MergeUMeshes(tmp);
6750 * Creates a new MEDCouplingUMesh by concatenating all given meshes of the same dimension.
6751 * Cells and nodes of
6752 * the *i*-th mesh precede cells and nodes of the (*i*+1)-th mesh within the result mesh.
6753 * \param [in] a - a vector of meshes (MEDCouplingUMesh) to concatenate.
6754 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6755 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6756 * is no more needed.
6757 * \throw If \a a.size() == 0.
6758 * \throw If \a a[ *i* ] == NULL.
6759 * \throw If the coordinates array is not set in none of the meshes.
6760 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
6761 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
6763 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const std::vector<const MEDCouplingUMesh *>& a)
6765 std::size_t sz=a.size();
6767 return MergeUMeshesLL(a);
6768 for(std::size_t ii=0;ii<sz;ii++)
6771 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshes : item #" << ii << " in input array of size "<< sz << " is empty !";
6772 throw INTERP_KERNEL::Exception(oss.str());
6774 std::vector< MCAuto<MEDCouplingUMesh> > bb(sz);
6775 std::vector< const MEDCouplingUMesh * > aa(sz);
6777 for(std::size_t i=0;i<sz && spaceDim==-3;i++)
6779 const MEDCouplingUMesh *cur=a[i];
6780 const DataArrayDouble *coo=cur->getCoords();
6782 spaceDim=int(coo->getNumberOfComponents());
6785 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : no spaceDim specified ! unable to perform merge !");
6786 for(std::size_t i=0;i<sz;i++)
6788 bb[i]=a[i]->buildSetInstanceFromThis(spaceDim);
6791 return MergeUMeshesLL(aa);
6795 * Creates a new MEDCouplingUMesh by concatenating cells of two given meshes of same
6796 * dimension and sharing the node coordinates array.
6797 * All cells of the first mesh precede all cells of the second mesh
6798 * within the result mesh.
6799 * \param [in] mesh1 - the first mesh.
6800 * \param [in] mesh2 - the second mesh.
6801 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6802 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6803 * is no more needed.
6804 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
6805 * \throw If the meshes do not share the node coordinates array.
6806 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
6807 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
6809 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
6811 std::vector<const MEDCouplingUMesh *> tmp(2);
6812 tmp[0]=mesh1; tmp[1]=mesh2;
6813 return MergeUMeshesOnSameCoords(tmp);
6817 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
6818 * dimension and sharing the node coordinates array.
6819 * All cells of the *i*-th mesh precede all cells of the
6820 * (*i*+1)-th mesh within the result mesh.
6821 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
6822 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6823 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6824 * is no more needed.
6825 * \throw If \a a.size() == 0.
6826 * \throw If \a a[ *i* ] == NULL.
6827 * \throw If the meshes do not share the node coordinates array.
6828 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
6829 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
6831 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes)
6834 throw INTERP_KERNEL::Exception("meshes input parameter is expected to be non empty.");
6835 for(std::size_t ii=0;ii<meshes.size();ii++)
6838 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshesOnSameCoords : item #" << ii << " in input array of size "<< meshes.size() << " is empty !";
6839 throw INTERP_KERNEL::Exception(oss.str());
6841 const DataArrayDouble *coords=meshes.front()->getCoords();
6842 int meshDim=meshes.front()->getMeshDimension();
6843 std::vector<const MEDCouplingUMesh *>::const_iterator iter=meshes.begin();
6844 mcIdType meshLgth=0;
6845 mcIdType meshIndexLgth=0;
6846 for(;iter!=meshes.end();iter++)
6848 if(coords!=(*iter)->getCoords())
6849 throw INTERP_KERNEL::Exception("meshes does not share the same coords ! Try using tryToShareSameCoords method !");
6850 if(meshDim!=(*iter)->getMeshDimension())
6851 throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, FuseUMeshesOnSameCoords impossible !");
6852 meshLgth+=(*iter)->getNodalConnectivityArrayLen();
6853 meshIndexLgth+=(*iter)->getNumberOfCells();
6855 MCAuto<DataArrayIdType> nodal=DataArrayIdType::New();
6856 nodal->alloc(meshLgth,1);
6857 mcIdType *nodalPtr=nodal->getPointer();
6858 MCAuto<DataArrayIdType> nodalIndex=DataArrayIdType::New();
6859 nodalIndex->alloc(meshIndexLgth+1,1);
6860 mcIdType *nodalIndexPtr=nodalIndex->getPointer();
6862 for(iter=meshes.begin();iter!=meshes.end();iter++)
6864 const mcIdType *nod=(*iter)->getNodalConnectivity()->begin();
6865 const mcIdType *index=(*iter)->getNodalConnectivityIndex()->begin();
6866 mcIdType nbOfCells=(*iter)->getNumberOfCells();
6867 mcIdType meshLgth2=(*iter)->getNodalConnectivityArrayLen();
6868 nodalPtr=std::copy(nod,nod+meshLgth2,nodalPtr);
6869 if(iter!=meshes.begin())
6870 nodalIndexPtr=std::transform(index+1,index+nbOfCells+1,nodalIndexPtr,std::bind2nd(std::plus<mcIdType>(),offset));
6872 nodalIndexPtr=std::copy(index,index+nbOfCells+1,nodalIndexPtr);
6875 MEDCouplingUMesh *ret=MEDCouplingUMesh::New();
6876 ret->setName("merge");
6877 ret->setMeshDimension(meshDim);
6878 ret->setConnectivity(nodal,nodalIndex,true);
6879 ret->setCoords(coords);
6884 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
6885 * dimension and sharing the node coordinates array. Cells of the *i*-th mesh precede
6886 * cells of the (*i*+1)-th mesh within the result mesh. Duplicates of cells are
6887 * removed from \a this mesh and arrays mapping between new and old cell ids in "Old to
6888 * New" mode are returned for each input mesh.
6889 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
6890 * \param [in] compType - specifies a cell comparison technique. For meaning of its
6891 * valid values [0,1,2], see zipConnectivityTraducer().
6892 * \param [in,out] corr - an array of DataArrayIdType, of the same size as \a
6893 * meshes. The *i*-th array describes cell ids mapping for \a meshes[ *i* ]
6894 * mesh. The caller is to delete each of the arrays using decrRef() as it is
6896 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6897 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6898 * is no more needed.
6899 * \throw If \a meshes.size() == 0.
6900 * \throw If \a meshes[ *i* ] == NULL.
6901 * \throw If the meshes do not share the node coordinates array.
6902 * \throw If \a meshes[ *i* ]->getMeshDimension() < 0.
6903 * \throw If the \a meshes are of different dimension (getMeshDimension()).
6904 * \throw If the nodal connectivity of cells of any of \a meshes is not defined.
6905 * \throw If the nodal connectivity any of \a meshes includes an invalid id.
6907 MEDCouplingUMesh *MEDCouplingUMesh::FuseUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes, int compType, std::vector<DataArrayIdType *>& corr)
6909 //All checks are delegated to MergeUMeshesOnSameCoords
6910 MCAuto<MEDCouplingUMesh> ret=MergeUMeshesOnSameCoords(meshes);
6911 MCAuto<DataArrayIdType> o2n=ret->zipConnectivityTraducer(compType);
6912 corr.resize(meshes.size());
6913 std::size_t nbOfMeshes=meshes.size();
6915 const mcIdType *o2nPtr=o2n->begin();
6916 for(std::size_t i=0;i<nbOfMeshes;i++)
6918 DataArrayIdType *tmp=DataArrayIdType::New();
6919 mcIdType curNbOfCells=meshes[i]->getNumberOfCells();
6920 tmp->alloc(curNbOfCells,1);
6921 std::copy(o2nPtr+offset,o2nPtr+offset+curNbOfCells,tmp->getPointer());
6922 offset+=curNbOfCells;
6923 tmp->setName(meshes[i]->getName());
6930 * Makes all given meshes share the nodal connectivity array. The common connectivity
6931 * array is created by concatenating the connectivity arrays of all given meshes. All
6932 * the given meshes must be of the same space dimension but dimension of cells **can
6933 * differ**. This method is particularly useful in MEDLoader context to build a \ref
6934 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
6935 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
6936 * \param [in,out] meshes - a vector of meshes to update.
6937 * \throw If any of \a meshes is NULL.
6938 * \throw If the coordinates array is not set in any of \a meshes.
6939 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
6940 * \throw If \a meshes are of different space dimension.
6942 void MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords(const std::vector<MEDCouplingUMesh *>& meshes)
6944 std::size_t sz=meshes.size();
6947 std::vector< const DataArrayDouble * > coords(meshes.size());
6948 std::vector< const DataArrayDouble * >::iterator it2=coords.begin();
6949 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++,it2++)
6953 (*it)->checkConnectivityFullyDefined();
6954 const DataArrayDouble *coo=(*it)->getCoords();
6959 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
6960 oss << " has no coordinate array defined !";
6961 throw INTERP_KERNEL::Exception(oss.str());
6966 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
6967 oss << " is null !";
6968 throw INTERP_KERNEL::Exception(oss.str());
6971 MCAuto<DataArrayDouble> res=DataArrayDouble::Aggregate(coords);
6972 std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();
6973 mcIdType offset=(*it)->getNumberOfNodes();
6974 (*it++)->setCoords(res);
6975 for(;it!=meshes.end();it++)
6977 mcIdType oldNumberOfNodes=(*it)->getNumberOfNodes();
6978 (*it)->setCoords(res);
6979 (*it)->shiftNodeNumbersInConn(offset);
6980 offset+=oldNumberOfNodes;
6985 * Merges nodes coincident with a given precision within all given meshes that share
6986 * the nodal connectivity array. The given meshes **can be of different** mesh
6987 * dimension. This method is particularly useful in MEDLoader context to build a \ref
6988 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
6989 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
6990 * \param [in,out] meshes - a vector of meshes to update.
6991 * \param [in] eps - the precision used to detect coincident nodes (infinite norm).
6992 * \throw If any of \a meshes is NULL.
6993 * \throw If the \a meshes do not share the same node coordinates array.
6994 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
6996 void MEDCouplingUMesh::MergeNodesOnUMeshesSharingSameCoords(const std::vector<MEDCouplingUMesh *>& meshes, double eps)
7000 std::set<const DataArrayDouble *> s;
7001 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
7004 s.insert((*it)->getCoords());
7007 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 !";
7008 throw INTERP_KERNEL::Exception(oss.str());
7013 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 !";
7014 throw INTERP_KERNEL::Exception(oss.str());
7016 const DataArrayDouble *coo=*(s.begin());
7020 DataArrayIdType *comm,*commI;
7021 coo->findCommonTuples(eps,-1,comm,commI);
7022 MCAuto<DataArrayIdType> tmp1(comm),tmp2(commI);
7023 mcIdType oldNbOfNodes=coo->getNumberOfTuples();
7024 mcIdType newNbOfNodes;
7025 MCAuto<DataArrayIdType> o2n=DataArrayIdType::ConvertIndexArrayToO2N(oldNbOfNodes,comm->begin(),commI->begin(),commI->end(),newNbOfNodes);
7026 if(oldNbOfNodes==newNbOfNodes)
7028 MCAuto<DataArrayDouble> newCoords=coo->renumberAndReduce(o2n->begin(),newNbOfNodes);
7029 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
7031 (*it)->renumberNodesInConn(o2n->begin());
7032 (*it)->setCoords(newCoords);
7038 * This static operates only for coords in 3D. The polygon is specified by its connectivity nodes in [ \a begin , \a end ).
7040 bool MEDCouplingUMesh::IsPolygonWellOriented(bool isQuadratic, const double *vec, const mcIdType *begin, const mcIdType *end, const double *coords)
7043 double v[3]={0.,0.,0.};
7044 std::size_t sz=std::distance(begin,end);
7048 // Algorithm: sum in v the cross products of (e1, e2) where e_i it the vector between (0,0,0) and point i
7049 // and e2 is linear point directly following e1 in the connectivity. All points are used.
7050 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];
7051 v[1]+=coords[3*begin[i]+2]*coords[3*begin[(i+1)%sz]]-coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+2];
7052 v[2]+=coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+1]-coords[3*begin[i]+1]*coords[3*begin[(i+1)%sz]];
7056 // Same algorithm as above but also using intermediate quadratic points.
7057 // (taking only linear points might lead to issues if the linearized version of the
7058 // polygon is not convex or self-intersecting ... see testCellOrientation4)
7059 std::size_t hsz = sz/2;
7060 for(std::size_t j=0;j<sz;j++)
7062 if (j%2) // current point i is quadratic, next point i+1 is standard
7065 ip1 = ((j-1)/2 + 1)%hsz; // ip1 means "i+1", i.e. next point
7067 else // current point i is standard, next point i+1 is quadratic
7072 v[0]+=coords[3*begin[i]+1]*coords[3*begin[ip1]+2]-coords[3*begin[i]+2]*coords[3*begin[ip1]+1];
7073 v[1]+=coords[3*begin[i]+2]*coords[3*begin[ip1]]-coords[3*begin[i]]*coords[3*begin[ip1]+2];
7074 v[2]+=coords[3*begin[i]]*coords[3*begin[ip1]+1]-coords[3*begin[i]+1]*coords[3*begin[ip1]];
7077 double ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
7082 * The polyhedron is specified by its connectivity nodes in [ \a begin , \a end ).
7084 bool MEDCouplingUMesh::IsPolyhedronWellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7086 std::vector<std::pair<mcIdType,mcIdType> > edges;
7087 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
7088 const mcIdType *bgFace=begin;
7089 for(std::size_t i=0;i<nbOfFaces;i++)
7091 const mcIdType *endFace=std::find(bgFace+1,end,-1);
7092 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
7093 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7095 std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7096 if(std::find(edges.begin(),edges.end(),p1)!=edges.end())
7098 edges.push_back(p1);
7102 return INTERP_KERNEL::calculateVolumeForPolyh2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,ToIdType(std::distance(begin,end)),coords)>-EPS_FOR_POLYH_ORIENTATION;
7106 * The 3D extruded static cell (PENTA6,HEXA8,HEXAGP12...) its connectivity nodes in [ \a begin , \a end ).
7108 bool MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7110 double vec0[3],vec1[3];
7111 std::size_t sz=std::distance(begin,end);
7113 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented : the length of nodal connectivity of extruded cell is not even !");
7114 mcIdType nbOfNodes=ToIdType(sz/2);
7115 INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,nbOfNodes,coords,vec0);
7116 const double *pt0=coords+3*begin[0];
7117 const double *pt1=coords+3*begin[nbOfNodes];
7118 vec1[0]=pt1[0]-pt0[0]; vec1[1]=pt1[1]-pt0[1]; vec1[2]=pt1[2]-pt0[2];
7119 return (vec0[0]*vec1[0]+vec0[1]*vec1[1]+vec0[2]*vec1[2])<0.;
7122 void MEDCouplingUMesh::CorrectExtrudedStaticCell(mcIdType *begin, mcIdType *end)
7124 std::size_t sz=std::distance(begin,end);
7125 INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz];
7126 std::size_t nbOfNodes(sz/2);
7127 std::copy(begin,end,(mcIdType *)tmp);
7128 for(std::size_t j=1;j<nbOfNodes;j++)
7130 begin[j]=tmp[nbOfNodes-j];
7131 begin[j+nbOfNodes]=tmp[nbOfNodes+nbOfNodes-j];
7135 bool MEDCouplingUMesh::IsTetra4WellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7137 std::size_t sz=std::distance(begin,end);
7139 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsTetra4WellOriented : Tetra4 cell with not 4 nodes ! Call checkConsistency !");
7140 double vec0[3],vec1[3];
7141 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[1],*pt2=coords+3*begin[2],*pt3=coords+3*begin[3];
7142 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];
7143 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;
7146 bool MEDCouplingUMesh::IsPyra5WellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7148 std::size_t sz=std::distance(begin,end);
7150 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsPyra5WellOriented : Pyra5 cell with not 5 nodes ! Call checkConsistency !");
7152 INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,4,coords,vec0);
7153 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[4];
7154 return (vec0[0]*(pt1[0]-pt0[0])+vec0[1]*(pt1[1]-pt0[1])+vec0[2]*(pt1[2]-pt0[2]))<0.;
7158 * 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 )
7159 * 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
7162 * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not.
7163 * \param [in] coords the coordinates with nb of components exactly equal to 3
7164 * \param [in] begin begin of the nodal connectivity (geometric type included) of a single polyhedron cell
7165 * \param [in] end end of nodal connectivity of a single polyhedron cell (excluded)
7166 * \param [out] res the result is put at the end of the vector without any alteration of the data.
7168 void MEDCouplingUMesh::SimplifyPolyhedronCell(double eps, const DataArrayDouble *coords, mcIdType index, DataArrayIdType *res, MEDCouplingUMesh *faces,
7169 DataArrayIdType *E_Fi, DataArrayIdType *E_F, DataArrayIdType *F_Ei, DataArrayIdType *F_E)
7171 mcIdType nbFaces = E_Fi->getIJ(index + 1, 0) - E_Fi->getIJ(index, 0);
7172 MCAuto<DataArrayDouble> v=DataArrayDouble::New(); v->alloc(nbFaces,3);
7173 double *vPtr=v->getPointer();
7174 MCAuto<DataArrayDouble> p=DataArrayDouble::New(); p->alloc(nbFaces,2);
7175 double *pPtr=p->getPointer();
7176 mcIdType *e_fi = E_Fi->getPointer(), *e_f = E_F->getPointer(), *f_ei = F_Ei->getPointer(), *f_e = F_E->getPointer();
7177 const mcIdType *f_idx = faces->getNodalConnectivityIndex()->getPointer(), *f_cnn = faces->getNodalConnectivity()->getPointer();
7178 for(mcIdType i=0;i<nbFaces;i++,vPtr+=3,pPtr++)
7180 mcIdType face = e_f[e_fi[index] + i];
7181 ComputeVecAndPtOfFace(eps, coords->begin(), f_cnn + f_idx[face] + 1, f_cnn + f_idx[face + 1], vPtr, pPtr);
7182 // to differentiate faces going to different cells:
7184 for (mcIdType j = f_ei[face]; j < f_ei[face + 1]; j++)
7185 *pPtr += FromIdType<double>(f_e[j]);
7187 pPtr=p->getPointer(); vPtr=v->getPointer();
7188 DataArrayIdType *comm1=0,*commI1=0;
7189 v->findCommonTuples(eps,-1,comm1,commI1);
7190 for (mcIdType i = 0; i < nbFaces; i++)
7191 if (comm1->findIdFirstEqual(i) < 0)
7193 comm1->pushBackSilent(i);
7194 commI1->pushBackSilent(comm1->getNumberOfTuples());
7196 MCAuto<DataArrayIdType> comm1Auto(comm1),commI1Auto(commI1);
7197 const mcIdType *comm1Ptr=comm1->begin();
7198 const mcIdType *commI1Ptr=commI1->begin();
7199 mcIdType nbOfGrps1=commI1Auto->getNumberOfTuples()-1;
7200 res->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYHED));
7202 for(mcIdType i=0;i<nbOfGrps1;i++)
7204 mcIdType vecId=comm1Ptr[commI1Ptr[i]];
7205 MCAuto<DataArrayDouble> tmpgrp2=p->selectByTupleId(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7206 DataArrayIdType *comm2=0,*commI2=0;
7207 tmpgrp2->findCommonTuples(eps,-1,comm2,commI2);
7208 for (mcIdType j = 0; j < commI1Ptr[i+1] - commI1Ptr[i]; j++)
7209 if (comm2->findIdFirstEqual(j) < 0)
7211 comm2->pushBackSilent(j);
7212 commI2->pushBackSilent(comm2->getNumberOfTuples());
7214 MCAuto<DataArrayIdType> comm2Auto(comm2),commI2Auto(commI2);
7215 const mcIdType *comm2Ptr=comm2->begin();
7216 const mcIdType *commI2Ptr=commI2->begin();
7217 mcIdType nbOfGrps2=commI2Auto->getNumberOfTuples()-1;
7218 for(mcIdType j=0;j<nbOfGrps2;j++)
7220 if(commI2Ptr[j+1] == commI2Ptr[j] + 1)
7222 mcIdType face = e_f[e_fi[index] + comm1Ptr[commI1Ptr[i] + comm2Ptr[commI2Ptr[j]]]]; //hmmm
7223 res->insertAtTheEnd(f_cnn + f_idx[face] + 1, f_cnn + f_idx[face + 1]);
7224 res->pushBackSilent(-1);
7228 mcIdType pointId=comm1Ptr[commI1Ptr[i]+comm2Ptr[commI2Ptr[j]]];
7229 MCAuto<DataArrayIdType> ids2=comm2->selectByTupleIdSafeSlice(commI2Ptr[j],commI2Ptr[j+1],1);
7230 ids2->transformWithIndArr(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7231 ids2->transformWithIndArr(e_f + e_fi[index], e_f + e_fi[index + 1]);
7232 MCAuto<MEDCouplingUMesh> mm3=static_cast<MEDCouplingUMesh *>(faces->buildPartOfMySelf(ids2->begin(),ids2->end(),true));
7233 MCAuto<DataArrayIdType> idsNodeTmp=mm3->zipCoordsTraducer();
7234 MCAuto<DataArrayIdType> idsNode=idsNodeTmp->invertArrayO2N2N2O(mm3->getNumberOfNodes());
7235 const mcIdType *idsNodePtr=idsNode->begin();
7236 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];
7237 double vec[3]; vec[0]=vPtr[3*vecId+1]; vec[1]=-vPtr[3*vecId]; vec[2]=0.;
7238 double norm=vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2];
7239 if(std::abs(norm)>eps)
7241 double angle=INTERP_KERNEL::EdgeArcCircle::SafeAsin(norm);
7242 mm3->rotate(center,vec,angle);
7244 mm3->changeSpaceDimension(2);
7245 MCAuto<MEDCouplingUMesh> mm4=mm3->buildSpreadZonesWithPoly();
7246 const mcIdType *conn4=mm4->getNodalConnectivity()->begin();
7247 const mcIdType *connI4=mm4->getNodalConnectivityIndex()->begin();
7248 mcIdType nbOfCells=mm4->getNumberOfCells();
7249 for(mcIdType k=0;k<nbOfCells;k++)
7252 for(const mcIdType *work=conn4+connI4[k]+1;work!=conn4+connI4[k+1];work++,l++)
7253 res->pushBackSilent(idsNodePtr[*work]);
7254 res->pushBackSilent(-1);
7259 res->popBackSilent();
7263 * 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
7264 * through origin. The plane is defined by its nodal connectivity [ \b begin, \b end ).
7266 * \param [in] eps below that value the dot product of 2 vectors is considered as colinears
7267 * \param [in] coords coordinates expected to have 3 components.
7268 * \param [in] begin start of the nodal connectivity of the face.
7269 * \param [in] end end of the nodal connectivity (excluded) of the face.
7270 * \param [out] v the normalized vector of size 3
7271 * \param [out] p the pos of plane
7273 void MEDCouplingUMesh::ComputeVecAndPtOfFace(double eps, const double *coords, const mcIdType *begin, const mcIdType *end, double *v, double *p)
7275 std::size_t nbPoints=std::distance(begin,end);
7277 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeVecAndPtOfFace : < of 3 points in face ! not able to find a plane on that face !");
7278 double vec[3]={0.,0.,0.};
7280 bool refFound=false;
7281 for(;j<nbPoints-1 && !refFound;j++)
7283 vec[0]=coords[3*begin[j+1]]-coords[3*begin[j]];
7284 vec[1]=coords[3*begin[j+1]+1]-coords[3*begin[j]+1];
7285 vec[2]=coords[3*begin[j+1]+2]-coords[3*begin[j]+2];
7286 double norm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
7290 vec[0]/=norm; vec[1]/=norm; vec[2]/=norm;
7293 for(std::size_t i=j;i<nbPoints-1;i++)
7296 curVec[0]=coords[3*begin[i+1]]-coords[3*begin[i]];
7297 curVec[1]=coords[3*begin[i+1]+1]-coords[3*begin[i]+1];
7298 curVec[2]=coords[3*begin[i+1]+2]-coords[3*begin[i]+2];
7299 double norm=sqrt(curVec[0]*curVec[0]+curVec[1]*curVec[1]+curVec[2]*curVec[2]);
7302 curVec[0]/=norm; curVec[1]/=norm; curVec[2]/=norm;
7303 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];
7304 norm=sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
7307 v[0]/=norm; v[1]/=norm; v[2]/=norm;
7308 *p=v[0]*coords[3*begin[i]]+v[1]*coords[3*begin[i]+1]+v[2]*coords[3*begin[i]+2];
7312 throw INTERP_KERNEL::Exception("Not able to find a normal vector of that 3D face !");
7316 * This method tries to obtain a well oriented polyhedron.
7317 * If the algorithm fails, an exception will be thrown.
7319 void MEDCouplingUMesh::TryToCorrectPolyhedronOrientation(mcIdType *begin, mcIdType *end, const double *coords)
7321 std::list< std::pair<mcIdType,mcIdType> > edgesOK,edgesFinished;
7322 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
7323 std::vector<bool> isPerm(nbOfFaces,false);//field on faces False: I don't know, True : oriented
7325 mcIdType *bgFace=begin,*endFace=std::find(begin+1,end,-1);
7326 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
7327 for(std::size_t l=0;l<nbOfEdgesInFace;l++) { std::pair<mcIdType,mcIdType> p1(bgFace[l],bgFace[(l+1)%nbOfEdgesInFace]); edgesOK.push_back(p1); }
7329 while(std::find(isPerm.begin(),isPerm.end(),false)!=isPerm.end())
7332 std::size_t smthChanged=0;
7333 for(std::size_t i=0;i<nbOfFaces;i++)
7335 endFace=std::find(bgFace+1,end,-1);
7336 nbOfEdgesInFace=std::distance(bgFace,endFace);
7340 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7342 std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7343 std::pair<mcIdType,mcIdType> p2(p1.second,p1.first);
7344 bool b1=std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end();
7345 bool b2=std::find(edgesOK.begin(),edgesOK.end(),p2)!=edgesOK.end();
7346 if(b1 || b2) { b=b2; isPerm[i]=true; smthChanged++; break; }
7351 std::reverse(bgFace+1,endFace);
7352 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7354 std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7355 std::pair<mcIdType,mcIdType> p2(p1.second,p1.first);
7356 if(std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end())
7357 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7358 if(std::find(edgesFinished.begin(),edgesFinished.end(),p1)!=edgesFinished.end() || std::find(edgesFinished.begin(),edgesFinished.end(),p2)!=edgesFinished.end())
7359 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7360 std::list< std::pair<mcIdType,mcIdType> >::iterator it=std::find(edgesOK.begin(),edgesOK.end(),p2);
7361 if(it!=edgesOK.end())
7364 edgesFinished.push_back(p1);
7367 edgesOK.push_back(p1);
7374 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired !"); }
7376 if(!edgesOK.empty())
7377 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired : Some edges are shared only once !"); }
7378 if(INTERP_KERNEL::calculateVolumeForPolyh2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,ToIdType(std::distance(begin,end)),coords)<-EPS_FOR_POLYH_ORIENTATION)
7379 {//not lucky ! The first face was not correctly oriented : reorient all faces...
7381 for(std::size_t i=0;i<nbOfFaces;i++)
7383 endFace=std::find(bgFace+1,end,-1);
7384 std::reverse(bgFace+1,endFace);
7392 * This method makes the assumption spacedimension == meshdimension == 2.
7393 * This method works only for linear cells.
7395 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYGON in pos#0)
7397 DataArrayIdType *MEDCouplingUMesh::buildUnionOf2DMesh() const
7399 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
7400 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : meshdimension, spacedimension must be equal to 2 !");
7401 MCAuto<MEDCouplingUMesh> skin(computeSkin());
7402 mcIdType oldNbOfNodes(skin->getNumberOfNodes());
7403 MCAuto<DataArrayIdType> o2n(skin->zipCoordsTraducer());
7404 mcIdType nbOfNodesExpected(skin->getNumberOfNodes());
7405 MCAuto<DataArrayIdType> n2o(o2n->invertArrayO2N2N2O(oldNbOfNodes));
7406 mcIdType nbCells=skin->getNumberOfCells();
7407 if(nbCells==nbOfNodesExpected)
7408 return buildUnionOf2DMeshLinear(skin,n2o);
7409 else if(2*nbCells==nbOfNodesExpected)
7410 return buildUnionOf2DMeshQuadratic(skin,n2o);
7412 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : the mesh 2D in input appears to be not in a single part of a 2D mesh !");
7416 * This method makes the assumption spacedimension == meshdimension == 3.
7417 * This method works only for linear cells.
7419 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYHED in pos#0)
7421 DataArrayIdType *MEDCouplingUMesh::buildUnionOf3DMesh() const
7423 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
7424 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf3DMesh : meshdimension, spacedimension must be equal to 2 !");
7425 MCAuto<MEDCouplingUMesh> m=computeSkin();
7426 const mcIdType *conn=m->getNodalConnectivity()->begin();
7427 const mcIdType *connI=m->getNodalConnectivityIndex()->begin();
7428 mcIdType nbOfCells=m->getNumberOfCells();
7429 MCAuto<DataArrayIdType> ret=DataArrayIdType::New(); ret->alloc(m->getNodalConnectivity()->getNumberOfTuples(),1);
7430 mcIdType *work=ret->getPointer(); *work++=INTERP_KERNEL::NORM_POLYHED;
7433 work=std::copy(conn+connI[0]+1,conn+connI[1],work);
7434 for(mcIdType i=1;i<nbOfCells;i++)
7437 work=std::copy(conn+connI[i]+1,conn+connI[i+1],work);
7443 * \brief Creates a graph of cell neighbors
7444 * \return MEDCouplingSkyLineArray * - an sky line array the user should delete.
7445 * In the sky line array, graph arcs are stored in terms of (index,value) notation.
7447 * - index: 0 3 5 6 6
7448 * - value: 1 2 3 2 3 3
7449 * means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7450 * Arcs are not doubled but reflexive (1,1) arcs are present for each cell
7452 MEDCouplingSkyLineArray* MEDCouplingUMesh::generateGraph() const
7454 checkConnectivityFullyDefined();
7456 int meshDim = this->getMeshDimension();
7457 MEDCoupling::DataArrayIdType* indexr=MEDCoupling::DataArrayIdType::New();
7458 MEDCoupling::DataArrayIdType* revConn=MEDCoupling::DataArrayIdType::New();
7459 this->getReverseNodalConnectivity(revConn,indexr);
7460 const mcIdType* indexr_ptr=indexr->begin();
7461 const mcIdType* revConn_ptr=revConn->begin();
7463 const MEDCoupling::DataArrayIdType* index;
7464 const MEDCoupling::DataArrayIdType* conn;
7465 conn=this->getNodalConnectivity(); // it includes a type as the 1st element!!!
7466 index=this->getNodalConnectivityIndex();
7467 mcIdType nbCells=this->getNumberOfCells();
7468 const mcIdType* index_ptr=index->begin();
7469 const mcIdType* conn_ptr=conn->begin();
7471 //creating graph arcs (cell to cell relations)
7472 //arcs are stored in terms of (index,value) notation
7475 // means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7476 // in present version arcs are not doubled but reflexive (1,1) arcs are present for each cell
7478 //warning here one node have less than or equal effective number of cell with it
7479 //but cell could have more than effective nodes
7480 //because other equals nodes in other domain (with other global inode)
7481 std::vector <mcIdType> cell2cell_index(nbCells+1,0);
7482 std::vector <mcIdType> cell2cell;
7483 cell2cell.reserve(3*nbCells);
7485 for (mcIdType icell=0; icell<nbCells;icell++)
7487 std::map<mcIdType,mcIdType > counter;
7488 for (mcIdType iconn=index_ptr[icell]+1; iconn<index_ptr[icell+1];iconn++)
7490 mcIdType inode=conn_ptr[iconn];
7491 for (mcIdType iconnr=indexr_ptr[inode]; iconnr<indexr_ptr[inode+1];iconnr++)
7493 mcIdType icell2=revConn_ptr[iconnr];
7494 std::map<mcIdType,mcIdType>::iterator iter=counter.find(icell2);
7495 if (iter!=counter.end()) (iter->second)++;
7496 else counter.insert(std::make_pair(icell2,1));
7499 for (std::map<mcIdType,mcIdType>::const_iterator iter=counter.begin();
7500 iter!=counter.end(); iter++)
7501 if (iter->second >= meshDim)
7503 cell2cell_index[icell+1]++;
7504 cell2cell.push_back(iter->first);
7509 cell2cell_index[0]=0;
7510 for (mcIdType icell=0; icell<nbCells;icell++)
7511 cell2cell_index[icell+1]=cell2cell_index[icell]+cell2cell_index[icell+1];
7513 //filling up index and value to create skylinearray structure
7514 MEDCouplingSkyLineArray * array(MEDCouplingSkyLineArray::New(cell2cell_index,cell2cell));
7519 void MEDCouplingUMesh::writeVTKLL(std::ostream& ofs, const std::string& cellData, const std::string& pointData, DataArrayByte *byteData) const
7521 mcIdType nbOfCells=getNumberOfCells();
7523 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::writeVTK : the unstructured mesh has no cells !");
7524 ofs << " <" << getVTKDataSetType() << ">\n";
7525 ofs << " <Piece NumberOfPoints=\"" << getNumberOfNodes() << "\" NumberOfCells=\"" << nbOfCells << "\">\n";
7526 ofs << " <PointData>\n" << pointData << std::endl;
7527 ofs << " </PointData>\n";
7528 ofs << " <CellData>\n" << cellData << std::endl;
7529 ofs << " </CellData>\n";
7530 ofs << " <Points>\n";
7531 if(getSpaceDimension()==3)
7532 _coords->writeVTK(ofs,8,"Points",byteData);
7535 MCAuto<DataArrayDouble> coo=_coords->changeNbOfComponents(3,0.);
7536 coo->writeVTK(ofs,8,"Points",byteData);
7538 ofs << " </Points>\n";
7539 ofs << " <Cells>\n";
7540 const mcIdType *cPtr=_nodal_connec->begin();
7541 const mcIdType *cIPtr=_nodal_connec_index->begin();
7542 MCAuto<DataArrayIdType> faceoffsets=DataArrayIdType::New(); faceoffsets->alloc(nbOfCells,1);
7543 MCAuto<DataArrayIdType> types=DataArrayIdType::New(); types->alloc(nbOfCells,1);
7544 MCAuto<DataArrayIdType> offsets=DataArrayIdType::New(); offsets->alloc(nbOfCells,1);
7545 MCAuto<DataArrayIdType> connectivity=DataArrayIdType::New(); connectivity->alloc(_nodal_connec->getNumberOfTuples()-nbOfCells,1);
7546 mcIdType *w1=faceoffsets->getPointer(),*w2=types->getPointer(),*w3=offsets->getPointer(),*w4=connectivity->getPointer();
7547 mcIdType szFaceOffsets=0,szConn=0;
7548 for(mcIdType i=0;i<nbOfCells;i++,w1++,w2++,w3++)
7551 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]!=INTERP_KERNEL::NORM_POLYHED)
7554 *w3=szConn+cIPtr[i+1]-cIPtr[i]-1; szConn+=cIPtr[i+1]-cIPtr[i]-1;
7555 w4=std::copy(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],w4);
7559 mcIdType deltaFaceOffset=cIPtr[i+1]-cIPtr[i]+1;
7560 *w1=szFaceOffsets+deltaFaceOffset; szFaceOffsets+=deltaFaceOffset;
7561 std::set<mcIdType> c(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1]); c.erase(-1);
7562 *w3=szConn+ToIdType(c.size()); szConn+=ToIdType(c.size());
7563 w4=std::copy(c.begin(),c.end(),w4);
7566 std::unique_ptr<mcIdType[]> medcoupling2vtkTypeTraducer_mcIdType(new mcIdType[MEDCOUPLING2VTKTYPETRADUCER_LGTH]);
7567 for(auto ii = 0; ii<MEDCOUPLING2VTKTYPETRADUCER_LGTH ; ++ii)
7568 medcoupling2vtkTypeTraducer_mcIdType[ii] = MEDCOUPLING2VTKTYPETRADUCER[ii]!=MEDCOUPLING2VTKTYPETRADUCER_NONE?MEDCOUPLING2VTKTYPETRADUCER[ii] : -1;
7569 types->transformWithIndArr(medcoupling2vtkTypeTraducer_mcIdType.get(),medcoupling2vtkTypeTraducer_mcIdType.get()+MEDCOUPLING2VTKTYPETRADUCER_LGTH);
7570 types->writeVTK(ofs,8,"UInt8","types",byteData);
7571 std::string vtkTypeName = Traits<mcIdType>::VTKReprStr;
7572 offsets->writeVTK(ofs,8,vtkTypeName,"offsets",byteData);
7573 if(szFaceOffsets!=0)
7574 {//presence of Polyhedra
7575 connectivity->reAlloc(szConn);
7576 faceoffsets->writeVTK(ofs,8,vtkTypeName,"faceoffsets",byteData);
7577 MCAuto<DataArrayIdType> faces=DataArrayIdType::New(); faces->alloc(szFaceOffsets,1);
7578 w1=faces->getPointer();
7579 for(mcIdType i=0;i<nbOfCells;i++)
7580 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]==INTERP_KERNEL::NORM_POLYHED)
7582 mcIdType nbFaces=ToIdType(std::count(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],-1))+1;
7584 const mcIdType *w6=cPtr+cIPtr[i]+1,*w5=0;
7585 for(mcIdType j=0;j<nbFaces;j++)
7587 w5=std::find(w6,cPtr+cIPtr[i+1],-1);
7588 *w1++=ToIdType(std::distance(w6,w5));
7589 w1=std::copy(w6,w5,w1);
7593 faces->writeVTK(ofs,8,vtkTypeName,"faces",byteData);
7595 connectivity->writeVTK(ofs,8,vtkTypeName,"connectivity",byteData);
7596 ofs << " </Cells>\n";
7597 ofs << " </Piece>\n";
7598 ofs << " </" << getVTKDataSetType() << ">\n";
7601 void MEDCouplingUMesh::reprQuickOverview(std::ostream& stream) const
7603 stream << "MEDCouplingUMesh C++ instance at " << this << ". Name : \"" << getName() << "\".";
7605 { stream << " Not set !"; return ; }
7606 stream << " Mesh dimension : " << _mesh_dim << ".";
7610 { stream << " No coordinates set !"; return ; }
7611 if(!_coords->isAllocated())
7612 { stream << " Coordinates set but not allocated !"; return ; }
7613 stream << " Space dimension : " << _coords->getNumberOfComponents() << "." << std::endl;
7614 stream << "Number of nodes : " << _coords->getNumberOfTuples() << ".";
7615 if(!_nodal_connec_index)
7616 { stream << std::endl << "Nodal connectivity NOT set !"; return ; }
7617 if(!_nodal_connec_index->isAllocated())
7618 { stream << std::endl << "Nodal connectivity set but not allocated !"; return ; }
7619 mcIdType lgth=_nodal_connec_index->getNumberOfTuples();
7620 std::size_t cpt=_nodal_connec_index->getNumberOfComponents();
7621 if(cpt!=1 || lgth<1)
7623 stream << std::endl << "Number of cells : " << lgth-1 << ".";
7626 std::string MEDCouplingUMesh::getVTKDataSetType() const
7628 return std::string("UnstructuredGrid");
7631 std::string MEDCouplingUMesh::getVTKFileExtension() const
7633 return std::string("vtu");
7639 * Provides a renumbering of the cells of this (which has to be a piecewise connected 1D line), so that
7640 * the segments of the line are indexed in consecutive order (i.e. cells \a i and \a i+1 are neighbors).
7641 * This doesn't modify the mesh. This method only works using nodal connectivity consideration. Coordinates of nodes are ignored here.
7642 * The caller is to deal with the resulting DataArrayIdType.
7643 * \throw If the coordinate array is not set.
7644 * \throw If the nodal connectivity of the cells is not defined.
7645 * \throw If m1 is not a mesh of dimension 2, or m1 is not a mesh of dimension 1
7646 * \throw If m2 is not a (piecewise) line (i.e. if a point has more than 2 adjacent segments)
7648 * \sa DataArrayIdType::sortEachPairToMakeALinkedList
7650 DataArrayIdType *MEDCouplingUMesh::orderConsecutiveCells1D() const
7652 checkFullyDefined();
7653 if(getMeshDimension()!=1)
7654 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D works on unstructured mesh with meshdim = 1 !");
7656 // Check that this is a line (and not a more complex 1D mesh) - each point is used at most by 2 segments:
7657 MCAuto<DataArrayIdType> _d(DataArrayIdType::New()),_dI(DataArrayIdType::New());
7658 MCAuto<DataArrayIdType> _rD(DataArrayIdType::New()),_rDI(DataArrayIdType::New());
7659 MCAuto<MEDCouplingUMesh> m_points(buildDescendingConnectivity(_d, _dI, _rD, _rDI));
7660 const mcIdType *d(_d->begin()), *dI(_dI->begin());
7661 const mcIdType *rD(_rD->begin()), *rDI(_rDI->begin());
7662 MCAuto<DataArrayIdType> _dsi(_rDI->deltaShiftIndex());
7663 const mcIdType * dsi(_dsi->begin());
7664 MCAuto<DataArrayIdType> dsii = _dsi->findIdsNotInRange(0,3);
7666 if (dsii->getNumberOfTuples())
7667 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D only work with a mesh being a (piecewise) connected line!");
7669 mcIdType nc=getNumberOfCells();
7670 MCAuto<DataArrayIdType> result(DataArrayIdType::New());
7671 result->alloc(nc,1);
7673 // set of edges not used so far
7674 std::set<mcIdType> edgeSet;
7675 for (mcIdType i=0; i<nc; edgeSet.insert(i), i++);
7677 mcIdType startSeg=0;
7679 // while we have points with only one neighbor segments
7682 std::list<mcIdType> linePiece;
7683 // fills a list of consecutive segment linked to startSeg. This can go forward or backward.
7684 for (int direction=0;direction<2;direction++) // direction=0 --> forward, direction=1 --> backward
7686 // Fill the list forward (resp. backward) from the start segment:
7687 mcIdType activeSeg = startSeg;
7688 mcIdType prevPointId = -20;
7690 while (!edgeSet.empty())
7692 if (!(direction == 1 && prevPointId==-20)) // prevent adding twice startSeg
7695 linePiece.push_back(activeSeg);
7697 linePiece.push_front(activeSeg);
7698 edgeSet.erase(activeSeg);
7701 mcIdType ptId1 = d[dI[activeSeg]], ptId2 = d[dI[activeSeg]+1];
7702 ptId = direction ? (ptId1 == prevPointId ? ptId2 : ptId1) : (ptId2 == prevPointId ? ptId1 : ptId2);
7703 if (dsi[ptId] == 1) // hitting the end of the line
7706 mcIdType seg1 = rD[rDI[ptId]], seg2 = rD[rDI[ptId]+1];
7707 activeSeg = (seg1 == activeSeg) ? seg2 : seg1;
7710 // Done, save final piece into DA:
7711 std::copy(linePiece.begin(), linePiece.end(), result->getPointer()+newIdx);
7712 newIdx += ToIdType(linePiece.size());
7714 // identify next valid start segment (one which is not consumed)
7715 if(!edgeSet.empty())
7716 startSeg = *(edgeSet.begin());
7718 while (!edgeSet.empty());
7719 return result.retn();
7723 * This method split some of edges of 2D cells in \a this. The edges to be split are specified in \a subNodesInSeg
7724 * and in \a subNodesInSegI using \ref numbering-indirect storage mode.
7725 * To do the work this method can optionally needs information about middle of subedges for quadratic cases if
7726 * a minimal creation of new nodes is wanted.
7727 * So this method try to reduce at most the number of new nodes. The only case that can lead this method to add
7728 * nodes if a SEG3 is split without information of middle.
7729 * \b WARNING : is returned value is different from 0 a call to MEDCouplingUMesh::mergeNodes is necessary to
7730 * avoid to have a non conform mesh.
7732 * \return mcIdType - the number of new nodes created (in most of cases 0).
7734 * \throw If \a this is not coherent.
7735 * \throw If \a this has not spaceDim equal to 2.
7736 * \throw If \a this has not meshDim equal to 2.
7737 * \throw If some subcells needed to be split are orphan.
7738 * \sa MEDCouplingUMesh::conformize2D
7740 mcIdType MEDCouplingUMesh::split2DCells(const DataArrayIdType *desc, const DataArrayIdType *descI, const DataArrayIdType *subNodesInSeg, const DataArrayIdType *subNodesInSegI, const DataArrayIdType *midOpt, const DataArrayIdType *midOptI)
7742 if(!desc || !descI || !subNodesInSeg || !subNodesInSegI)
7743 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : the 4 first arrays must be not null !");
7744 desc->checkAllocated(); descI->checkAllocated(); subNodesInSeg->checkAllocated(); subNodesInSegI->checkAllocated();
7745 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
7746 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : This method only works for meshes with spaceDim=2 and meshDim=2 !");
7747 if(midOpt==0 && midOptI==0)
7749 split2DCellsLinear(desc,descI,subNodesInSeg,subNodesInSegI);
7752 else if(midOpt!=0 && midOptI!=0)
7753 return split2DCellsQuadratic(desc,descI,subNodesInSeg,subNodesInSegI,midOpt,midOptI);
7755 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : middle parameters must be set to null for all or not null for all.");
7759 * 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
7760 * 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
7761 * the geometric cell type set to INTERP_KERNEL::NORM_POLYGON.
7762 * 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
7763 * 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.
7765 * \return false if the input connectivity represents already the convex hull, true if the input cell needs to be reordered.
7767 bool MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis(const double *coords, const mcIdType *nodalConnBg, const mcIdType *nodalConnEnd, DataArrayIdType *nodalConnecOut)
7769 std::size_t sz=std::distance(nodalConnBg,nodalConnEnd);
7772 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)*nodalConnBg);
7773 if(cm.getDimension()==2)
7775 const mcIdType *node=nodalConnBg+1;
7776 mcIdType startNode=*node++;
7777 double refX=coords[2*startNode];
7778 for(;node!=nodalConnEnd;node++)
7780 if(coords[2*(*node)]<refX)
7783 refX=coords[2*startNode];
7786 std::vector<mcIdType> tmpOut; tmpOut.reserve(sz); tmpOut.push_back(startNode);
7790 double angle0=-M_PI/2;
7792 mcIdType nextNode=-1;
7793 mcIdType prevNode=-1;
7795 double angleNext=0.;
7796 while(nextNode!=startNode)
7800 for(node=nodalConnBg+1;node!=nodalConnEnd;node++)
7802 if(*node!=tmpOut.back() && *node!=prevNode)
7804 tmp2[0]=coords[2*(*node)]-coords[2*tmpOut.back()]; tmp2[1]=coords[2*(*node)+1]-coords[2*tmpOut.back()+1];
7805 double angleM=INTERP_KERNEL::EdgeArcCircle::GetAbsoluteAngle(tmp2,tmp1);
7810 res=angle0-angleM+2.*M_PI;
7819 if(nextNode!=startNode)
7821 angle0=angleNext-M_PI;
7824 prevNode=tmpOut.back();
7825 tmpOut.push_back(nextNode);
7828 std::vector<mcIdType> tmp3(2*(sz-1));
7829 std::vector<mcIdType>::iterator it=std::copy(nodalConnBg+1,nodalConnEnd,tmp3.begin());
7830 std::copy(nodalConnBg+1,nodalConnEnd,it);
7831 if(std::search(tmp3.begin(),tmp3.end(),tmpOut.begin(),tmpOut.end())!=tmp3.end())
7833 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
7836 if(std::search(tmp3.rbegin(),tmp3.rend(),tmpOut.begin(),tmpOut.end())!=tmp3.rend())
7838 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
7843 nodalConnecOut->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYGON));
7844 nodalConnecOut->insertAtTheEnd(tmpOut.begin(),tmpOut.end());
7849 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
7852 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
7856 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
7857 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
7858 * 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]].
7859 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
7860 * A negative value in \b arrIn means that it is ignored.
7861 * 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.
7863 * \param [in] arrIn arr origin array from which the extraction will be done.
7864 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7865 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
7866 * \sa MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed, MEDCouplingUMesh::partitionBySpreadZone
7868 DataArrayIdType *MEDCouplingUMesh::ComputeSpreadZoneGradually(const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn)
7870 mcIdType seed=0,nbOfDepthPeelingPerformed=0;
7871 return ComputeSpreadZoneGraduallyFromSeed(&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfDepthPeelingPerformed);
7875 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
7876 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
7877 * 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]].
7878 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
7879 * A negative value in \b arrIn means that it is ignored.
7880 * 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.
7881 * \param [in] seedBg the begin pointer (included) of an array containing the seed of the search zone
7882 * \param [in] seedEnd the end pointer (not included) of an array containing the seed of the search zone
7883 * \param [in] arrIn arr origin array from which the extraction will be done.
7884 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7885 * \param [in] nbOfDepthPeeling the max number of peels requested in search. By default -1, that is to say, no limit.
7886 * \param [out] nbOfDepthPeelingPerformed the number of peels effectively performed. May be different from \a nbOfDepthPeeling
7887 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
7888 * \sa MEDCouplingUMesh::partitionBySpreadZone
7890 DataArrayIdType *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(const mcIdType *seedBg, const mcIdType *seedEnd, const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn, mcIdType nbOfDepthPeeling, mcIdType& nbOfDepthPeelingPerformed)
7892 nbOfDepthPeelingPerformed=0;
7894 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed : arrIndxIn input pointer is NULL !");
7895 mcIdType nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
7898 DataArrayIdType *ret=DataArrayIdType::New(); ret->alloc(0,1);
7902 std::vector<bool> fetched(nbOfTuples,false);
7903 return ComputeSpreadZoneGraduallyFromSeedAlg(fetched,seedBg,seedEnd,arrIn,arrIndxIn,nbOfDepthPeeling,nbOfDepthPeelingPerformed);
7909 * \b this is expected to be a mesh fully defined whose spaceDim==meshDim.
7910 * It returns a new allocated mesh having the same mesh dimension and lying on same coordinates.
7911 * The returned mesh contains as poly cells as number of contiguous zone (regarding connectivity).
7912 * A spread contiguous zone is built using poly cells (polyhedra in 3D, polygons in 2D and polyline in 1D).
7913 * The sum of measure field of returned mesh is equal to the sum of measure field of this.
7915 * \return a newly allocated mesh lying on the same coords than \b this with same meshdimension than \b this.
7917 MEDCouplingUMesh *MEDCouplingUMesh::buildSpreadZonesWithPoly() const
7919 checkFullyDefined();
7920 int mdim=getMeshDimension();
7921 int spaceDim=getSpaceDimension();
7923 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension and spacedimension do not match !");
7924 std::vector<DataArrayIdType *> partition=partitionBySpreadZone();
7925 std::vector< MCAuto<DataArrayIdType> > partitionAuto; partitionAuto.reserve(partition.size());
7926 std::copy(partition.begin(),partition.end(),std::back_insert_iterator<std::vector< MCAuto<DataArrayIdType> > >(partitionAuto));
7927 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
7928 ret->setCoords(getCoords());
7929 ret->allocateCells(ToIdType(partition.size()));
7931 for(std::vector<DataArrayIdType *>::const_iterator it=partition.begin();it!=partition.end();it++)
7933 MCAuto<MEDCouplingUMesh> tmp=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf((*it)->begin(),(*it)->end(),true));
7934 MCAuto<DataArrayIdType> cell;
7938 cell=tmp->buildUnionOf2DMesh();
7941 cell=tmp->buildUnionOf3DMesh();
7944 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension supported are [2,3] ! Not implemented yet for others !");
7947 ret->insertNextCell((INTERP_KERNEL::NormalizedCellType)cell->getIJSafe(0,0),cell->getNumberOfTuples()-1,cell->begin()+1);
7950 ret->finishInsertingCells();
7955 * This method partitions \b this into contiguous zone.
7956 * This method only needs a well defined connectivity. Coordinates are not considered here.
7957 * This method returns a vector of \b newly allocated arrays that the caller has to deal with.
7959 std::vector<DataArrayIdType *> MEDCouplingUMesh::partitionBySpreadZone() const
7961 DataArrayIdType *neigh=0,*neighI=0;
7962 computeNeighborsOfCells(neigh,neighI);
7963 MCAuto<DataArrayIdType> neighAuto(neigh),neighIAuto(neighI);
7964 return PartitionBySpreadZone(neighAuto,neighIAuto);
7967 std::vector<DataArrayIdType *> MEDCouplingUMesh::PartitionBySpreadZone(const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn)
7969 if(!arrIn || !arrIndxIn)
7970 throw INTERP_KERNEL::Exception("PartitionBySpreadZone : null input pointers !");
7971 arrIn->checkAllocated(); arrIndxIn->checkAllocated();
7972 mcIdType nbOfTuples(arrIndxIn->getNumberOfTuples());
7973 if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1 || nbOfTuples<1)
7974 throw INTERP_KERNEL::Exception("PartitionBySpreadZone : invalid arrays in input !");
7975 mcIdType nbOfCellsCur(nbOfTuples-1);
7976 std::vector<DataArrayIdType *> ret;
7979 std::vector<bool> fetchedCells(nbOfCellsCur,false);
7980 std::vector< MCAuto<DataArrayIdType> > ret2;
7982 while(seed<nbOfCellsCur)
7984 mcIdType nbOfPeelPerformed=0;
7985 ret2.push_back(ComputeSpreadZoneGraduallyFromSeedAlg(fetchedCells,&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfPeelPerformed));
7986 seed=ToIdType(std::distance(fetchedCells.begin(),std::find(fetchedCells.begin()+seed,fetchedCells.end(),false)));
7988 for(std::vector< MCAuto<DataArrayIdType> >::iterator it=ret2.begin();it!=ret2.end();it++)
7989 ret.push_back((*it).retn());
7994 * This method returns given a distribution of cell type (returned for example by MEDCouplingUMesh::getDistributionOfTypes method and customized after) a
7995 * newly allocated DataArrayIdType instance with 2 components ready to be interpreted as input of DataArrayIdType::findRangeIdForEachTuple method.
7997 * \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.
7998 * \return a newly allocated DataArrayIdType to be managed by the caller.
7999 * \throw In case of \a code has not the right format (typically of size 3*n)
8001 DataArrayIdType *MEDCouplingUMesh::ComputeRangesFromTypeDistribution(const std::vector<mcIdType>& code)
8003 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
8004 std::size_t nb=code.size()/3;
8005 if(code.size()%3!=0)
8006 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeRangesFromTypeDistribution : invalid input code !");
8008 mcIdType *retPtr=ret->getPointer();
8009 for(std::size_t i=0;i<nb;i++,retPtr+=2)
8011 retPtr[0]=code[3*i+2];
8012 retPtr[1]=code[3*i+2]+code[3*i+1];
8018 * This method expects that \a this a 3D mesh (spaceDim=3 and meshDim=3) with all coordinates and connectivities set.
8019 * All cells in \a this are expected to be linear 3D cells.
8020 * This method will split **all** 3D cells in \a this into INTERP_KERNEL::NORM_TETRA4 cells and put them in the returned mesh.
8021 * It leads to an increase to number of cells.
8022 * This method contrary to MEDCouplingUMesh::simplexize can append coordinates in \a this to perform its work.
8023 * The \a nbOfAdditionalPoints returned value informs about it. If > 0, the coordinates array in returned mesh will have \a nbOfAdditionalPoints
8024 * more tuples (nodes) than in \a this. Anyway, all the nodes in \a this (with the same order) will be in the returned mesh.
8026 * \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.
8027 * For all other cells, the splitting policy will be ignored. See INTERP_KERNEL::SplittingPolicy for the images.
8028 * \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.
8029 * \param [out] n2oCells - A new instance of DataArrayIdType holding, for each new cell,
8030 * an id of old cell producing it. The caller is to delete this array using
8031 * decrRef() as it is no more needed.
8032 * \return MEDCoupling1SGTUMesh * - the mesh containing only INTERP_KERNEL::NORM_TETRA4 cells.
8034 * \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
8035 * the policy PLANAR_FACE_6 should be used on a mesh sorted with MEDCoupling1SGTUMesh::sortHexa8EachOther.
8037 * \throw If \a this is not a 3D mesh (spaceDim==3 and meshDim==3).
8038 * \throw If \a this is not fully constituted with linear 3D cells.
8039 * \sa MEDCouplingUMesh::simplexize, MEDCoupling1SGTUMesh::sortHexa8EachOther
8041 MEDCoupling1SGTUMesh *MEDCouplingUMesh::tetrahedrize(int policy, DataArrayIdType *& n2oCells, mcIdType& nbOfAdditionalPoints) const
8043 INTERP_KERNEL::SplittingPolicy pol((INTERP_KERNEL::SplittingPolicy)policy);
8044 checkConnectivityFullyDefined();
8045 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
8046 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tetrahedrize : only available for mesh with meshdim == 3 and spacedim == 3 !");
8047 mcIdType nbOfCells=getNumberOfCells();
8048 mcIdType nbNodes(getNumberOfNodes());
8049 MCAuto<MEDCoupling1SGTUMesh> ret0(MEDCoupling1SGTUMesh::New(getName(),INTERP_KERNEL::NORM_TETRA4));
8050 MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(nbOfCells,1);
8051 mcIdType *retPt(ret->getPointer());
8052 MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()); newConn->alloc(0,1);
8053 MCAuto<DataArrayDouble> addPts(DataArrayDouble::New()); addPts->alloc(0,1);
8054 const mcIdType *oldc(_nodal_connec->begin());
8055 const mcIdType *oldci(_nodal_connec_index->begin());
8056 const double *coords(_coords->begin());
8057 for(mcIdType i=0;i<nbOfCells;i++,oldci++,retPt++)
8059 std::vector<mcIdType> a; std::vector<double> b;
8060 INTERP_KERNEL::SplitIntoTetras(pol,(INTERP_KERNEL::NormalizedCellType)oldc[oldci[0]],oldc+oldci[0]+1,oldc+oldci[1],coords,a,b);
8061 std::size_t nbOfTet(a.size()/4); *retPt=ToIdType(nbOfTet);
8062 const mcIdType *aa(&a[0]);
8065 for(std::vector<mcIdType>::iterator it=a.begin();it!=a.end();it++)
8067 *it=(-(*(it))-1+nbNodes);
8068 addPts->insertAtTheEnd(b.begin(),b.end());
8069 nbNodes+=ToIdType(b.size()/3);
8071 for(std::size_t j=0;j<nbOfTet;j++,aa+=4)
8072 newConn->insertAtTheEnd(aa,aa+4);
8074 if(!addPts->empty())
8076 addPts->rearrange(3);
8077 nbOfAdditionalPoints=addPts->getNumberOfTuples();
8078 addPts=DataArrayDouble::Aggregate(getCoords(),addPts);
8079 ret0->setCoords(addPts);
8083 nbOfAdditionalPoints=0;
8084 ret0->setCoords(getCoords());
8086 ret0->setNodalConnectivity(newConn);
8088 ret->computeOffsetsFull();
8089 n2oCells=ret->buildExplicitArrOfSliceOnScaledArr(0,nbOfCells,1);
8093 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),
8094 _own_cell(true),_cell_id(-1),_nb_cell(0)
8099 _nb_cell=mesh->getNumberOfCells();
8103 MEDCouplingUMeshCellIterator::~MEDCouplingUMeshCellIterator()
8111 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh, MEDCouplingUMeshCell *itc, mcIdType bg, mcIdType end):_mesh(mesh),_cell(itc),
8112 _own_cell(false),_cell_id(bg-1),
8119 MEDCouplingUMeshCell *MEDCouplingUMeshCellIterator::nextt()
8122 if(_cell_id<_nb_cell)
8131 MEDCouplingUMeshCellByTypeEntry::MEDCouplingUMeshCellByTypeEntry(MEDCouplingUMesh *mesh):_mesh(mesh)
8137 MEDCouplingUMeshCellByTypeIterator *MEDCouplingUMeshCellByTypeEntry::iterator()
8139 return new MEDCouplingUMeshCellByTypeIterator(_mesh);
8142 MEDCouplingUMeshCellByTypeEntry::~MEDCouplingUMeshCellByTypeEntry()
8148 MEDCouplingUMeshCellEntry::MEDCouplingUMeshCellEntry(MEDCouplingUMesh *mesh, INTERP_KERNEL::NormalizedCellType type, MEDCouplingUMeshCell *itc, mcIdType bg, mcIdType end):_mesh(mesh),_type(type),
8156 MEDCouplingUMeshCellEntry::~MEDCouplingUMeshCellEntry()
8162 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCellEntry::getType() const
8167 mcIdType MEDCouplingUMeshCellEntry::getNumberOfElems() const
8172 MEDCouplingUMeshCellIterator *MEDCouplingUMeshCellEntry::iterator()
8174 return new MEDCouplingUMeshCellIterator(_mesh,_itc,_bg,_end);
8177 MEDCouplingUMeshCellByTypeIterator::MEDCouplingUMeshCellByTypeIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),_cell_id(0),_nb_cell(0)
8182 _nb_cell=mesh->getNumberOfCells();
8186 MEDCouplingUMeshCellByTypeIterator::~MEDCouplingUMeshCellByTypeIterator()
8193 MEDCouplingUMeshCellEntry *MEDCouplingUMeshCellByTypeIterator::nextt()
8195 const mcIdType *c=_mesh->getNodalConnectivity()->begin();
8196 const mcIdType *ci=_mesh->getNodalConnectivityIndex()->begin();
8197 if(_cell_id<_nb_cell)
8199 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[_cell_id]];
8200 mcIdType nbOfElems=ToIdType(std::distance(ci+_cell_id,std::find_if(ci+_cell_id,ci+_nb_cell,MEDCouplingImpl::ConnReader(c,type))));
8201 mcIdType startId=_cell_id;
8202 _cell_id+=nbOfElems;
8203 return new MEDCouplingUMeshCellEntry(_mesh,type,_cell,startId,_cell_id);
8209 MEDCouplingUMeshCell::MEDCouplingUMeshCell(MEDCouplingUMesh *mesh):_conn(0),_conn_indx(0),_conn_lgth(NOTICABLE_FIRST_VAL)
8213 _conn=mesh->getNodalConnectivity()->getPointer();
8214 _conn_indx=mesh->getNodalConnectivityIndex()->getPointer();
8218 void MEDCouplingUMeshCell::next()
8220 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8225 _conn_lgth=_conn_indx[1]-_conn_indx[0];
8228 std::string MEDCouplingUMeshCell::repr() const
8230 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8232 std::ostringstream oss; oss << "Cell Type " << INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)_conn[0]).getRepr();
8234 std::copy(_conn+1,_conn+_conn_lgth,std::ostream_iterator<mcIdType>(oss," "));
8238 return std::string("MEDCouplingUMeshCell::repr : Invalid pos");
8241 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCell::getType() const
8243 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8244 return (INTERP_KERNEL::NormalizedCellType)_conn[0];
8246 return INTERP_KERNEL::NORM_ERROR;
8249 const mcIdType *MEDCouplingUMeshCell::getAllConn(mcIdType& lgth) const
8252 if(_conn_lgth!=NOTICABLE_FIRST_VAL)