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 by \a compType (see zipConnectivityTraducer).
1699 * This method keeps the coordinates of \a this. The comparison starts at rank \a startCellId cell id (included).
1700 * If \a startCellId is equal to 0 algorithm starts at cell #0 and for each cell candidates being searched have cell id higher than current cellId.
1701 * If \a startCellId is greater than 0 algorithm starts at cell #startCellId but for each cell all candidates are considered.
1702 * This method is time consuming.
1704 * \param [in] compType input specifying the technique used to compare cells each other.
1705 * - 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.
1706 * - 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)
1707 * and their type equal. For 1D mesh the policy 1 is equivalent to 0.
1708 * - 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
1709 * can be used for users not sensitive to orientation of cell
1710 * \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.
1711 * \param [out] commonCellsArr common cells ids (\ref numbering-indirect)
1712 * \param [out] commonCellsIArr common cells ids (\ref numbering-indirect)
1713 * \return the correspondence array old to new in a newly allocated array.
1716 void MEDCouplingUMesh::findCommonCells(int compType, mcIdType startCellId, DataArrayIdType *& commonCellsArr, DataArrayIdType *& commonCellsIArr) const
1718 MCAuto<DataArrayIdType> revNodal=DataArrayIdType::New(),revNodalI=DataArrayIdType::New();
1719 getReverseNodalConnectivity(revNodal,revNodalI);
1720 FindCommonCellsAlg(compType,startCellId,_nodal_connec,_nodal_connec_index,revNodal,revNodalI,commonCellsArr,commonCellsIArr);
1723 void MEDCouplingUMesh::FindCommonCellsAlg(int compType, mcIdType startCellId, const DataArrayIdType *nodal, const DataArrayIdType *nodalI, const DataArrayIdType *revNodal, const DataArrayIdType *revNodalI,
1724 DataArrayIdType *& commonCellsArr, DataArrayIdType *& commonCellsIArr)
1726 MCAuto<DataArrayIdType> commonCells=DataArrayIdType::New(),commonCellsI=DataArrayIdType::New(); commonCells->alloc(0,1);
1727 mcIdType nbOfCells=nodalI->getNumberOfTuples()-1;
1728 commonCellsI->reserve(1); commonCellsI->pushBackSilent(0);
1729 const mcIdType *revNodalPtr=revNodal->getConstPointer(),*revNodalIPtr=revNodalI->getConstPointer();
1730 const mcIdType *connPtr=nodal->getConstPointer(),*connIPtr=nodalI->getConstPointer();
1731 std::vector<bool> isFetched(nbOfCells,false);
1734 for(mcIdType i=startCellId;i<nbOfCells;i++)
1738 const mcIdType *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind2nd(std::not_equal_to<mcIdType>(),-1));
1739 std::vector<mcIdType> v,v2;
1740 if(connOfNode!=connPtr+connIPtr[i+1])
1742 const mcIdType *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1743 v2.insert(v2.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1]);
1746 for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1750 const mcIdType *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1751 std::vector<mcIdType>::iterator it=std::set_intersection(v.begin(),v.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1752 v2.resize(std::distance(v2.begin(),it));
1756 if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1758 mcIdType pos=commonCellsI->back();
1759 commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1760 for(const mcIdType *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1761 isFetched[*it]=true;
1769 for(mcIdType i=startCellId;i<nbOfCells;i++)
1773 const mcIdType *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind2nd(std::not_equal_to<mcIdType>(),-1));
1774 // v2 contains the result of successive intersections using rev nodal on on each node of cell #i
1775 std::vector<mcIdType> v,v2;
1776 if(connOfNode!=connPtr+connIPtr[i+1])
1778 v2.insert(v2.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1]);
1781 for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1785 std::vector<mcIdType>::iterator it=std::set_intersection(v.begin(),v.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1786 v2.resize(std::distance(v2.begin(),it));
1788 // v2 contains now candidates. Problem candidates are sorted using id rank.
1793 auto it(std::find(v2.begin(),v2.end(),i));
1794 std::swap(*v2.begin(),*it);
1796 if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1798 mcIdType newPos(commonCells->getNumberOfTuples());
1799 mcIdType pos(commonCellsI->back());
1800 std::sort(commonCells->getPointer()+pos,commonCells->getPointer()+newPos);
1801 commonCellsI->pushBackSilent(newPos);
1802 for(const mcIdType *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1803 isFetched[*it]=true;
1809 commonCellsArr=commonCells.retn();
1810 commonCellsIArr=commonCellsI.retn();
1814 * Checks if \a this mesh includes all cells of an \a other mesh, and returns an array
1815 * giving for each cell of the \a other an id of a cell in \a this mesh. A value larger
1816 * than \a this->getNumberOfCells() in the returned array means that there is no
1817 * corresponding cell in \a this mesh.
1818 * It is expected that \a this and \a other meshes share the same node coordinates
1819 * array, if it is not so an exception is thrown.
1820 * \param [in] other - the mesh to compare with.
1821 * \param [in] compType - specifies a cell comparison technique. For meaning of its
1822 * valid values [0,1,2], see zipConnectivityTraducer().
1823 * \param [out] arr - a new instance of DataArrayIdType returning correspondence
1824 * between cells of the two meshes. It contains \a other->getNumberOfCells()
1825 * values. The caller is to delete this array using
1826 * decrRef() as it is no more needed.
1827 * \return bool - \c true if all cells of \a other mesh are present in the \a this
1830 * \if ENABLE_EXAMPLES
1831 * \ref cpp_mcumesh_areCellsIncludedIn "Here is a C++ example".<br>
1832 * \ref py_mcumesh_areCellsIncludedIn "Here is a Python example".
1834 * \sa checkDeepEquivalOnSameNodesWith()
1835 * \sa checkGeoEquivalWith()
1837 bool MEDCouplingUMesh::areCellsIncludedIn(const MEDCouplingUMesh *other, int compType, DataArrayIdType *& arr) const
1839 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1840 mcIdType nbOfCells=getNumberOfCells();
1841 static const int possibleCompType[]={0,1,2};
1842 if(std::find(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),compType)==possibleCompType+sizeof(possibleCompType)/sizeof(int))
1844 std::ostringstream oss; oss << "MEDCouplingUMesh::areCellsIncludedIn : only following policies are possible : ";
1845 std::copy(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),std::ostream_iterator<int>(oss," "));
1847 throw INTERP_KERNEL::Exception(oss.str());
1849 MCAuto<DataArrayIdType> o2n=mesh->zipConnectivityTraducer(compType,nbOfCells);
1850 arr=o2n->subArray(nbOfCells);
1851 arr->setName(other->getName());
1853 if(other->getNumberOfCells()==0)
1855 return arr->getMaxValue(tmp)<nbOfCells;
1859 * This method makes the assumption that \a this and \a other share the same coords. If not an exception will be thrown !
1860 * This method tries to determine if \b other is fully included in \b this.
1861 * The main difference is that this method is not expected to throw exception.
1862 * This method has two outputs :
1864 * \param other other mesh
1865 * \param arr is an output parameter that returns a \b newly created instance. This array is of size 'other->getNumberOfCells()'.
1866 * \return If \a other is fully included in 'this 'true is returned. If not false is returned.
1868 bool MEDCouplingUMesh::areCellsIncludedInPolicy7(const MEDCouplingUMesh *other, DataArrayIdType *& arr) const
1870 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1871 DataArrayIdType *commonCells=0,*commonCellsI=0;
1872 mcIdType thisNbCells=getNumberOfCells();
1873 mesh->findCommonCells(7,thisNbCells,commonCells,commonCellsI);
1874 MCAuto<DataArrayIdType> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1875 const mcIdType *commonCellsPtr=commonCells->getConstPointer(),*commonCellsIPtr=commonCellsI->getConstPointer();
1876 mcIdType otherNbCells=other->getNumberOfCells();
1877 MCAuto<DataArrayIdType> arr2=DataArrayIdType::New();
1878 arr2->alloc(otherNbCells,1);
1879 arr2->fillWithZero();
1880 mcIdType *arr2Ptr=arr2->getPointer();
1881 mcIdType nbOfCommon=commonCellsI->getNumberOfTuples()-1;
1882 for(mcIdType i=0;i<nbOfCommon;i++)
1884 mcIdType start=commonCellsPtr[commonCellsIPtr[i]];
1885 if(start<thisNbCells)
1887 for(mcIdType j=commonCellsIPtr[i]+1;j!=commonCellsIPtr[i+1];j++)
1889 mcIdType sig=commonCellsPtr[j]>0?1:-1;
1890 mcIdType val=std::abs(commonCellsPtr[j])-1;
1891 if(val>=thisNbCells)
1892 arr2Ptr[val-thisNbCells]=sig*(start+1);
1896 arr2->setName(other->getName());
1897 if(arr2->presenceOfValue(0))
1903 MEDCouplingUMesh *MEDCouplingUMesh::mergeMyselfWithOnSameCoords(const MEDCouplingPointSet *other) const
1906 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : input other is null !");
1907 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
1909 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : the input other mesh is not of type unstructured !");
1910 std::vector<const MEDCouplingUMesh *> ms(2);
1913 return MergeUMeshesOnSameCoords(ms);
1917 * Build a sub part of \b this lying or not on the same coordinates than \b this (regarding value of \b keepCoords).
1918 * By default coordinates are kept. This method is close to MEDCouplingUMesh::buildPartOfMySelf except that here input
1919 * cellIds is not given explicitly but by a range python like.
1924 * \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.
1925 * \return a newly allocated
1927 * \warning This method modifies can generate an unstructured mesh whose cells are not sorted by geometric type order.
1928 * In view of the MED file writing, a renumbering of cells of returned unstructured mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
1930 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfSlice(mcIdType start, mcIdType end, mcIdType step, bool keepCoords) const
1932 if(getMeshDimension()!=-1)
1933 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelfSlice(start,end,step,keepCoords));
1936 mcIdType newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfSlice for -1 dimension mesh ");
1938 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
1940 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
1942 return const_cast<MEDCouplingUMesh *>(this);
1947 * Creates a new MEDCouplingUMesh containing specified cells of \a this mesh.
1948 * The result mesh shares or not the node coordinates array with \a this mesh depending
1949 * on \a keepCoords parameter.
1950 * \warning Cells of the result mesh can be \b not sorted by geometric type, hence,
1951 * to write this mesh to the MED file, its cells must be sorted using
1952 * sortCellsInMEDFileFrmt().
1953 * \param [in] begin - an array of cell ids to include to the new mesh.
1954 * \param [in] end - a pointer to last-plus-one-th element of \a begin.
1955 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
1956 * array of \a this mesh, else "free" nodes are removed from the result mesh
1957 * by calling zipCoords().
1958 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
1959 * to delete this mesh using decrRef() as it is no more needed.
1960 * \throw If the coordinates array is not set.
1961 * \throw If the nodal connectivity of cells is not defined.
1962 * \throw If any cell id in the array \a begin is not valid.
1964 * \if ENABLE_EXAMPLES
1965 * \ref cpp_mcumesh_buildPartOfMySelf "Here is a C++ example".<br>
1966 * \ref py_mcumesh_buildPartOfMySelf "Here is a Python example".
1969 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelf(const mcIdType *begin, const mcIdType *end, bool keepCoords) const
1971 if(getMeshDimension()!=-1)
1972 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelf(begin,end,keepCoords));
1976 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
1978 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
1980 return const_cast<MEDCouplingUMesh *>(this);
1985 * This method operates only on nodal connectivity on \b this. Coordinates of \b this is completely ignored here.
1987 * 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.
1988 * Size of [ \b cellIdsBg, \b cellIdsEnd ) ) must be equal to the number of cells of otherOnSameCoordsThanThis.
1989 * The number of cells of \b this will remain the same with this method.
1991 * \param [in] cellIdsBg begin of cell ids (included) of cells in this to assign
1992 * \param [in] cellIdsEnd end of cell ids (excluded) of cells in this to assign
1993 * \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 ).
1994 * Coordinate pointer of \b this and those of \b otherOnSameCoordsThanThis must be the same
1996 void MEDCouplingUMesh::setPartOfMySelf(const mcIdType *cellIdsBg, const mcIdType *cellIdsEnd, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
1998 checkConnectivityFullyDefined();
1999 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2000 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2001 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelf : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2002 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2004 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2005 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2006 throw INTERP_KERNEL::Exception(oss.str());
2008 mcIdType nbOfCellsToModify( ToIdType((std::distance(cellIdsBg,cellIdsEnd))));
2009 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2011 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2012 throw INTERP_KERNEL::Exception(oss.str());
2014 mcIdType nbOfCells(getNumberOfCells());
2015 bool easyAssign(true);
2016 const mcIdType *connI(_nodal_connec_index->begin());
2017 const mcIdType *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->begin();
2018 for(const mcIdType *it=cellIdsBg;it!=cellIdsEnd && easyAssign;it++,connIOther++)
2020 if(*it>=0 && *it<nbOfCells)
2022 easyAssign=(connIOther[1]-connIOther[0])==(connI[*it+1]-connI[*it]);
2026 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : On pos #" << std::distance(cellIdsBg,it) << " id is equal to " << *it << " which is not in [0," << nbOfCells << ") !";
2027 throw INTERP_KERNEL::Exception(oss.str());
2032 DataArrayIdType::SetPartOfIndexedArraysSameIdx(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2037 DataArrayIdType *arrOut=0,*arrIOut=0;
2038 DataArrayIdType::SetPartOfIndexedArrays(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2040 MCAuto<DataArrayIdType> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2041 setConnectivity(arrOut,arrIOut,true);
2045 void MEDCouplingUMesh::setPartOfMySelfSlice(mcIdType start, mcIdType end, mcIdType step, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2047 checkConnectivityFullyDefined();
2048 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2049 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2050 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelfSlice : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2051 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2053 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2054 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2055 throw INTERP_KERNEL::Exception(oss.str());
2057 mcIdType nbOfCellsToModify=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::setPartOfMySelfSlice : ");
2058 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2060 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2061 throw INTERP_KERNEL::Exception(oss.str());
2063 mcIdType nbOfCells=getNumberOfCells();
2064 bool easyAssign=true;
2065 const mcIdType *connI=_nodal_connec_index->getConstPointer();
2066 const mcIdType *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2068 for(mcIdType i=0;i<nbOfCellsToModify && easyAssign;i++,it+=step,connIOther++)
2070 if(it>=0 && it<nbOfCells)
2072 easyAssign=(connIOther[1]-connIOther[0])==(connI[it+1]-connI[it]);
2076 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : On pos #" << i << " id is equal to " << it << " which is not in [0," << nbOfCells << ") !";
2077 throw INTERP_KERNEL::Exception(oss.str());
2082 DataArrayIdType::SetPartOfIndexedArraysSameIdxSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2087 DataArrayIdType *arrOut=0,*arrIOut=0;
2088 DataArrayIdType::SetPartOfIndexedArraysSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2090 MCAuto<DataArrayIdType> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2091 setConnectivity(arrOut,arrIOut,true);
2097 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2098 * this->getMeshDimension(), that bound some cells of \a this mesh.
2099 * The cells of lower dimension to include to the result mesh are selected basing on
2100 * specified node ids and the value of \a fullyIn parameter. If \a fullyIn ==\c true, a
2101 * cell is copied if its all nodes are in the array \a begin of node ids. If \a fullyIn
2102 * ==\c false, a cell is copied if any its node is in the array of node ids. The
2103 * created mesh shares the node coordinates array with \a this mesh.
2104 * \param [in] begin - the array of node ids.
2105 * \param [in] end - a pointer to the (last+1)-th element of \a begin.
2106 * \param [in] fullyIn - if \c true, then cells whose all nodes are in the
2107 * array \a begin are added, else cells whose any node is in the
2108 * array \a begin are added.
2109 * \return MEDCouplingUMesh * - new instance of MEDCouplingUMesh. The caller is
2110 * to delete this mesh using decrRef() as it is no more needed.
2111 * \throw If the coordinates array is not set.
2112 * \throw If the nodal connectivity of cells is not defined.
2113 * \throw If any node id in \a begin is not valid.
2115 * \if ENABLE_EXAMPLES
2116 * \ref cpp_mcumesh_buildFacePartOfMySelfNode "Here is a C++ example".<br>
2117 * \ref py_mcumesh_buildFacePartOfMySelfNode "Here is a Python example".
2120 MEDCouplingUMesh *MEDCouplingUMesh::buildFacePartOfMySelfNode(const mcIdType *begin, const mcIdType *end, bool fullyIn) const
2122 MCAuto<DataArrayIdType> desc,descIndx,revDesc,revDescIndx;
2123 desc=DataArrayIdType::New(); descIndx=DataArrayIdType::New(); revDesc=DataArrayIdType::New(); revDescIndx=DataArrayIdType::New();
2124 MCAuto<MEDCouplingUMesh> subMesh=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2125 desc=0; descIndx=0; revDesc=0; revDescIndx=0;
2126 return static_cast<MEDCouplingUMesh*>(subMesh->buildPartOfMySelfNode(begin,end,fullyIn));
2130 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2131 * this->getMeshDimension(), which bound only one cell of \a this mesh.
2132 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2133 * array of \a this mesh, else "free" nodes are removed from the result mesh
2134 * by calling zipCoords().
2135 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2136 * to delete this mesh using decrRef() as it is no more needed.
2137 * \throw If the coordinates array is not set.
2138 * \throw If the nodal connectivity of cells is not defined.
2140 * \if ENABLE_EXAMPLES
2141 * \ref cpp_mcumesh_buildBoundaryMesh "Here is a C++ example".<br>
2142 * \ref py_mcumesh_buildBoundaryMesh "Here is a Python example".
2145 MEDCouplingUMesh *MEDCouplingUMesh::buildBoundaryMesh(bool keepCoords) const
2147 DataArrayIdType *desc=DataArrayIdType::New();
2148 DataArrayIdType *descIndx=DataArrayIdType::New();
2149 DataArrayIdType *revDesc=DataArrayIdType::New();
2150 DataArrayIdType *revDescIndx=DataArrayIdType::New();
2152 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2155 descIndx->decrRef();
2156 mcIdType nbOfCells=meshDM1->getNumberOfCells();
2157 const mcIdType *revDescIndxC=revDescIndx->getConstPointer();
2158 std::vector<mcIdType> boundaryCells;
2159 for(mcIdType i=0;i<nbOfCells;i++)
2160 if(revDescIndxC[i+1]-revDescIndxC[i]==1)
2161 boundaryCells.push_back(i);
2162 revDescIndx->decrRef();
2163 MEDCouplingUMesh *ret=meshDM1->buildPartOfMySelf(&boundaryCells[0],&boundaryCells[0]+boundaryCells.size(),keepCoords);
2168 * This method returns a newly created DataArrayIdType instance containing ids of cells located in boundary.
2169 * A cell is detected to be on boundary if it contains one or more than one face having only one father.
2170 * This method makes the assumption that \a this is fully defined (coords,connectivity). If not an exception will be thrown.
2172 DataArrayIdType *MEDCouplingUMesh::findCellIdsOnBoundary() const
2174 checkFullyDefined();
2175 MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
2176 MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
2177 MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
2178 MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
2180 buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx)->decrRef();
2181 desc=(DataArrayIdType*)0; descIndx=(DataArrayIdType*)0;
2183 MCAuto<DataArrayIdType> tmp=revDescIndx->deltaShiftIndex();
2184 MCAuto<DataArrayIdType> faceIds=tmp->findIdsEqual(1); tmp=(DataArrayIdType*)0;
2185 const mcIdType *revDescPtr=revDesc->getConstPointer();
2186 const mcIdType *revDescIndxPtr=revDescIndx->getConstPointer();
2187 mcIdType nbOfCells=getNumberOfCells();
2188 std::vector<bool> ret1(nbOfCells,false);
2190 for(const mcIdType *pt=faceIds->begin();pt!=faceIds->end();pt++)
2191 if(!ret1[revDescPtr[revDescIndxPtr[*pt]]])
2192 { ret1[revDescPtr[revDescIndxPtr[*pt]]]=true; sz++; }
2194 DataArrayIdType *ret2=DataArrayIdType::New();
2196 mcIdType *ret2Ptr=ret2->getPointer();
2198 for(std::vector<bool>::const_iterator it=ret1.begin();it!=ret1.end();it++,sz++)
2201 ret2->setName("BoundaryCells");
2206 * This method finds in \b this the cell ids that lie on mesh \b otherDimM1OnSameCoords.
2207 * \b this and \b otherDimM1OnSameCoords have to lie on the same coordinate array pointer. The coherency of that coords array with connectivity
2208 * of \b this and \b otherDimM1OnSameCoords is not important here because this method works only on connectivity.
2209 * this->getMeshDimension() - 1 must be equal to otherDimM1OnSameCoords.getMeshDimension()
2211 * s0 is the cell ids set in \b this lying on at least one node in the fetched nodes in \b otherDimM1OnSameCoords.
2212 * 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
2213 * equals a cell in \b otherDimM1OnSameCoords.
2215 * \throw if \b otherDimM1OnSameCoords is not part of constituent of \b this, or if coordinate pointer of \b this and \b otherDimM1OnSameCoords
2216 * are not same, or if this->getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension()
2218 * \param [in] otherDimM1OnSameCoords
2219 * \param [out] cellIdsRk0 a newly allocated array containing the cell ids of s0 (which are cell ids of \b this) in the above algorithm.
2220 * \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
2221 * cellIdsRk1->transformWithIndArr(cellIdsRk0->begin(),cellIdsRk0->end());
2223 void MEDCouplingUMesh::findCellIdsLyingOn(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayIdType *&cellIdsRk0, DataArrayIdType *&cellIdsRk1) const
2225 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2226 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : coordinates pointer are not the same ! Use tryToShareSameCoords method !");
2227 checkConnectivityFullyDefined();
2228 otherDimM1OnSameCoords.checkConnectivityFullyDefined();
2229 if(getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension())
2230 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : invalid mesh dimension of input mesh regarding meshdimesion of this !");
2231 MCAuto<DataArrayIdType> fetchedNodeIds1=otherDimM1OnSameCoords.computeFetchedNodeIds();
2232 MCAuto<DataArrayIdType> s0arr=getCellIdsLyingOnNodes(fetchedNodeIds1->begin(),fetchedNodeIds1->end(),false);
2233 MCAuto<MEDCouplingUMesh> thisPart=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(s0arr->begin(),s0arr->end(),true));
2234 MCAuto<DataArrayIdType> descThisPart=DataArrayIdType::New(),descIThisPart=DataArrayIdType::New(),revDescThisPart=DataArrayIdType::New(),revDescIThisPart=DataArrayIdType::New();
2235 MCAuto<MEDCouplingUMesh> thisPartConsti=thisPart->buildDescendingConnectivity(descThisPart,descIThisPart,revDescThisPart,revDescIThisPart);
2236 const mcIdType *revDescThisPartPtr=revDescThisPart->getConstPointer(),*revDescIThisPartPtr=revDescIThisPart->getConstPointer();
2237 DataArrayIdType *idsOtherInConsti=0;
2238 bool b=thisPartConsti->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsOtherInConsti);
2239 MCAuto<DataArrayIdType> idsOtherInConstiAuto(idsOtherInConsti);
2241 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : the given mdim-1 mesh in other is not a constituent of this !");
2242 std::set<mcIdType> s1;
2243 for(const mcIdType *idOther=idsOtherInConsti->begin();idOther!=idsOtherInConsti->end();idOther++)
2244 s1.insert(revDescThisPartPtr+revDescIThisPartPtr[*idOther],revDescThisPartPtr+revDescIThisPartPtr[*idOther+1]);
2245 MCAuto<DataArrayIdType> s1arr_renum1=DataArrayIdType::New(); s1arr_renum1->alloc(s1.size(),1); std::copy(s1.begin(),s1.end(),s1arr_renum1->getPointer());
2246 s1arr_renum1->sort();
2247 cellIdsRk0=s0arr.retn();
2248 //cellIdsRk1=s_renum1.retn();
2249 cellIdsRk1=s1arr_renum1.retn();
2253 * 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
2254 * returned. This subpart of meshdim-1 mesh is built using meshdim-1 cells in it shared only one cell in \b this.
2256 * \return a newly allocated mesh lying on the same coordinates than \b this. The caller has to deal with returned mesh.
2258 MEDCouplingUMesh *MEDCouplingUMesh::computeSkin() const
2260 MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
2261 MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
2262 MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
2263 MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
2265 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2266 revDesc=0; desc=0; descIndx=0;
2267 MCAuto<DataArrayIdType> revDescIndx2=revDescIndx->deltaShiftIndex();
2268 MCAuto<DataArrayIdType> part=revDescIndx2->findIdsEqual(1);
2269 return static_cast<MEDCouplingUMesh *>(meshDM1->buildPartOfMySelf(part->begin(),part->end(),true));
2273 * Finds nodes lying on the boundary of \a this mesh.
2274 * \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of found
2275 * nodes. The caller is to delete this array using decrRef() as it is no
2277 * \throw If the coordinates array is not set.
2278 * \throw If the nodal connectivity of cells is node defined.
2280 * \if ENABLE_EXAMPLES
2281 * \ref cpp_mcumesh_findBoundaryNodes "Here is a C++ example".<br>
2282 * \ref py_mcumesh_findBoundaryNodes "Here is a Python example".
2285 DataArrayIdType *MEDCouplingUMesh::findBoundaryNodes() const
2287 MCAuto<MEDCouplingUMesh> skin=computeSkin();
2288 return skin->computeFetchedNodeIds();
2291 MEDCouplingUMesh *MEDCouplingUMesh::buildUnstructured() const
2294 return const_cast<MEDCouplingUMesh *>(this);
2298 * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2299 * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2300 * 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.
2301 * 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.
2302 * 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.
2304 * \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
2305 * parameter is altered during the call.
2306 * \param [out] nodeIdsToDuplicate node ids needed to be duplicated following the algorithm explain above.
2307 * \param [out] cellIdsNeededToBeRenum cell ids in \b this in which the renumber of nodes should be performed.
2308 * \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.
2310 * \warning This method modifies param \b otherDimM1OnSameCoords (for speed reasons).
2312 void MEDCouplingUMesh::findNodesToDuplicate(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayIdType *& nodeIdsToDuplicate,
2313 DataArrayIdType *& cellIdsNeededToBeRenum, DataArrayIdType *& cellIdsNotModified) const
2315 typedef MCAuto<DataArrayIdType> DAInt;
2316 typedef MCAuto<MEDCouplingUMesh> MCUMesh;
2318 checkFullyDefined();
2319 otherDimM1OnSameCoords.checkFullyDefined();
2320 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2321 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : meshes do not share the same coords array !");
2322 if(otherDimM1OnSameCoords.getMeshDimension()!=getMeshDimension()-1)
2323 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the mesh given in other parameter must have this->getMeshDimension()-1 !");
2325 // Checking star-shaped M1 group:
2326 DAInt dt0=DataArrayIdType::New(),dit0=DataArrayIdType::New(),rdt0=DataArrayIdType::New(),rdit0=DataArrayIdType::New();
2327 MCUMesh meshM2 = otherDimM1OnSameCoords.buildDescendingConnectivity(dt0, dit0, rdt0, rdit0);
2328 DAInt dsi = rdit0->deltaShiftIndex();
2329 DAInt idsTmp0 = dsi->findIdsNotInRange(-1, 3);
2330 if(idsTmp0->getNumberOfTuples())
2331 throw INTERP_KERNEL::Exception("MEDFileUMesh::buildInnerBoundaryAlongM1Group: group is too complex: some points (or edges) have more than two connected segments (or faces)!");
2332 dt0=0; dit0=0; rdt0=0; rdit0=0; idsTmp0=0;
2334 // Get extreme nodes from the group (they won't be duplicated), ie nodes belonging to boundary cells of M1
2335 DAInt xtremIdsM2 = dsi->findIdsEqual(1); dsi = 0;
2336 MCUMesh meshM2Part = static_cast<MEDCouplingUMesh *>(meshM2->buildPartOfMySelf(xtremIdsM2->begin(), xtremIdsM2->end(),true));
2337 DAInt xtrem = meshM2Part->computeFetchedNodeIds();
2338 // Remove from the list points on the boundary of the M0 mesh (those need duplication!)
2339 dt0=DataArrayIdType::New(),dit0=DataArrayIdType::New(),rdt0=DataArrayIdType::New(),rdit0=DataArrayIdType::New();
2340 MCUMesh m0desc = buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); dt0=0; dit0=0; rdt0=0;
2341 dsi = rdit0->deltaShiftIndex();
2342 DAInt boundSegs = dsi->findIdsEqual(1); // boundary segs/faces of the M0 mesh
2343 MCUMesh m0descSkin = static_cast<MEDCouplingUMesh *>(m0desc->buildPartOfMySelf(boundSegs->begin(),boundSegs->end(), true));
2344 DAInt fNodes = m0descSkin->computeFetchedNodeIds();
2345 // In 3D, some points on the boundary of M0 still need duplication:
2347 if (getMeshDimension() == 3)
2349 DAInt dnu1=DataArrayIdType::New(), dnu2=DataArrayIdType::New(), dnu3=DataArrayIdType::New(), dnu4=DataArrayIdType::New();
2350 MCUMesh m0descSkinDesc = m0descSkin->buildDescendingConnectivity(dnu1, dnu2, dnu3, dnu4);
2351 dnu1=0;dnu2=0;dnu3=0;dnu4=0;
2352 DataArrayIdType * corresp=0;
2353 meshM2->areCellsIncludedIn(m0descSkinDesc,2,corresp);
2354 DAInt validIds = corresp->findIdsInRange(0, meshM2->getNumberOfCells());
2356 if (validIds->getNumberOfTuples())
2358 MCUMesh m1IntersecSkin = static_cast<MEDCouplingUMesh *>(m0descSkinDesc->buildPartOfMySelf(validIds->begin(), validIds->end(), true));
2359 DAInt notDuplSkin = m1IntersecSkin->findBoundaryNodes();
2360 DAInt fNodes1 = fNodes->buildSubstraction(notDuplSkin);
2361 notDup = xtrem->buildSubstraction(fNodes1);
2364 notDup = xtrem->buildSubstraction(fNodes);
2367 notDup = xtrem->buildSubstraction(fNodes);
2369 // Now compute cells around group (i.e. cells where we will do the propagation to identify the two sub-sets delimited by the group)
2370 DAInt m1Nodes = otherDimM1OnSameCoords.computeFetchedNodeIds();
2371 DAInt dupl = m1Nodes->buildSubstraction(notDup);
2372 DAInt cellsAroundGroup = getCellIdsLyingOnNodes(dupl->begin(), dupl->end(), false); // false= take cell in, even if not all nodes are in notDup
2375 MCUMesh m0Part2=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(cellsAroundGroup->begin(),cellsAroundGroup->end(),true));
2376 mcIdType nCells2 = m0Part2->getNumberOfCells();
2377 DAInt desc00=DataArrayIdType::New(),descI00=DataArrayIdType::New(),revDesc00=DataArrayIdType::New(),revDescI00=DataArrayIdType::New();
2378 MCUMesh m01=m0Part2->buildDescendingConnectivity(desc00,descI00,revDesc00,revDescI00);
2380 // Neighbor information of the mesh without considering the crack (serves to count how many connex pieces it is made of)
2381 DataArrayIdType *tmp00=0,*tmp11=0;
2382 MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00, tmp00, tmp11);
2383 DAInt neighInit00(tmp00);
2384 DAInt neighIInit00(tmp11);
2385 // Neighbor information of the mesh WITH the crack (some neighbors are removed):
2386 DataArrayIdType *idsTmp=0;
2387 m01->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsTmp);
2389 // In the neighbor information remove the connection between high dimension cells and its low level constituents which are part
2390 // of the frontier given in parameter (i.e. the cells of low dimension from the group delimiting the crack):
2391 DataArrayIdType::RemoveIdsFromIndexedArrays(ids->begin(),ids->end(),desc00,descI00);
2392 DataArrayIdType *tmp0=0,*tmp1=0;
2393 // Compute the neighbor of each cell in m0Part2, taking into account the broken link above. Two
2394 // cells on either side of the crack (defined by the mesh of low dimension) are not neighbor anymore.
2395 ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00,tmp0,tmp1);
2396 DAInt neigh00(tmp0);
2397 DAInt neighI00(tmp1);
2399 // For each initial connex part of the sub-mesh (or said differently for each independent crack):
2400 mcIdType seed = 0, nIter = 0;
2401 mcIdType nIterMax = nCells2+1; // Safety net for the loop
2402 DAInt hitCells = DataArrayIdType::New(); hitCells->alloc(nCells2);
2403 hitCells->fillWithValue(-1);
2404 DAInt cellsToModifyConn0_torenum = DataArrayIdType::New();
2405 cellsToModifyConn0_torenum->alloc(0,1);
2406 while (nIter < nIterMax)
2408 DAInt t = hitCells->findIdsEqual(-1);
2409 if (!t->getNumberOfTuples())
2411 // Connex zone without the crack (to compute the next seed really)
2413 DAInt connexCheck = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neighInit00,neighIInit00, -1, dnu);
2415 for (mcIdType * ptr = connexCheck->getPointer(); cnt < connexCheck->getNumberOfTuples(); ptr++, cnt++)
2416 hitCells->setIJ(*ptr,0,1);
2417 // Connex zone WITH the crack (to identify cells lying on either part of the crack)
2418 DAInt spreadZone = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neigh00,neighI00, -1, dnu);
2419 cellsToModifyConn0_torenum = DataArrayIdType::Aggregate(cellsToModifyConn0_torenum, spreadZone, 0);
2420 // Compute next seed, i.e. a cell in another connex part, which was not covered by the previous iterations
2421 DAInt comple = cellsToModifyConn0_torenum->buildComplement(nCells2);
2422 DAInt nonHitCells = hitCells->findIdsEqual(-1);
2423 DAInt intersec = nonHitCells->buildIntersection(comple);
2424 if (intersec->getNumberOfTuples())
2425 { seed = intersec->getIJ(0,0); }
2430 if (nIter >= nIterMax)
2431 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate(): internal error - too many iterations.");
2433 DAInt cellsToModifyConn1_torenum=cellsToModifyConn0_torenum->buildComplement(neighI00->getNumberOfTuples()-1);
2434 cellsToModifyConn0_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2435 cellsToModifyConn1_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2437 cellIdsNeededToBeRenum=cellsToModifyConn0_torenum.retn();
2438 cellIdsNotModified=cellsToModifyConn1_torenum.retn();
2439 nodeIdsToDuplicate=dupl.retn();
2443 * This method operates a modification of the connectivity and coords in \b this.
2444 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2445 * its ids will be modified to id this->getNumberOfNodes()+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2446 * 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
2447 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id this->getNumberOfNodes()+0, node id nodeIdsToDuplicateBg[1] will have id this->getNumberOfNodes()+1,
2448 * node id nodeIdsToDuplicateBg[2] will have id this->getNumberOfNodes()+2...
2450 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2452 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2453 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2455 void MEDCouplingUMesh::duplicateNodes(const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd)
2457 mcIdType nbOfNodes=getNumberOfNodes();
2458 duplicateNodesInCoords(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd);
2459 duplicateNodesInConn(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,nbOfNodes);
2463 * This method renumbers only nodal connectivity in \a this. The renumbering is only an offset applied. So this method is a specialization of
2464 * \a renumberNodesInConn. \b WARNING, this method does not check that the resulting node ids in the nodal connectivity is in a valid range !
2466 * \param [in] offset - specifies the offset to be applied on each element of connectivity.
2468 * \sa renumberNodesInConn
2470 void MEDCouplingUMesh::renumberNodesWithOffsetInConn(mcIdType offset)
2472 checkConnectivityFullyDefined();
2473 mcIdType *conn(getNodalConnectivity()->getPointer());
2474 const mcIdType *connIndex(getNodalConnectivityIndex()->getConstPointer());
2475 mcIdType nbOfCells=getNumberOfCells();
2476 for(mcIdType i=0;i<nbOfCells;i++)
2477 for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2479 mcIdType& node=conn[iconn];
2480 if(node>=0)//avoid polyhedron separator
2485 _nodal_connec->declareAsNew();
2490 * Same than renumberNodesInConn(const mcIdType *) except that here the format of old-to-new traducer is using map instead
2491 * 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
2494 void MEDCouplingUMesh::renumberNodesInConn(const INTERP_KERNEL::HashMap<mcIdType,mcIdType>& newNodeNumbersO2N)
2496 this->renumberNodesInConnT< INTERP_KERNEL::HashMap<mcIdType,mcIdType> >(newNodeNumbersO2N);
2500 * Same than renumberNodesInConn(const mcIdType *) except that here the format of old-to-new traducer is using map instead
2501 * 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
2504 void MEDCouplingUMesh::renumberNodesInConn(const std::map<mcIdType,mcIdType>& newNodeNumbersO2N)
2506 this->renumberNodesInConnT< std::map<mcIdType,mcIdType> >(newNodeNumbersO2N);
2510 * Changes ids of nodes within the nodal connectivity arrays according to a permutation
2511 * array in "Old to New" mode. The node coordinates array is \b not changed by this method.
2512 * This method is a generalization of shiftNodeNumbersInConn().
2513 * \warning This method performs no check of validity of new ids. **Use it with care !**
2514 * \param [in] newNodeNumbersO2N - a permutation array, of length \a
2515 * this->getNumberOfNodes(), in "Old to New" mode.
2516 * See \ref numbering for more info on renumbering modes.
2517 * \throw If the nodal connectivity of cells is not defined.
2519 * \if ENABLE_EXAMPLES
2520 * \ref cpp_mcumesh_renumberNodesInConn "Here is a C++ example".<br>
2521 * \ref py_mcumesh_renumberNodesInConn "Here is a Python example".
2524 void MEDCouplingUMesh::renumberNodesInConn(const mcIdType *newNodeNumbersO2N)
2526 checkConnectivityFullyDefined();
2527 mcIdType *conn=getNodalConnectivity()->getPointer();
2528 const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2529 mcIdType nbOfCells=getNumberOfCells();
2530 for(mcIdType i=0;i<nbOfCells;i++)
2531 for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2533 mcIdType& node=conn[iconn];
2534 if(node>=0)//avoid polyhedron separator
2536 node=newNodeNumbersO2N[node];
2539 _nodal_connec->declareAsNew();
2544 * This method renumbers nodes \b in \b connectivity \b only \b without \b any \b reference \b to \b coords.
2545 * This method performs no check on the fact that new coordinate ids are valid. \b Use \b it \b with \b care !
2546 * This method is an specialization of \ref MEDCoupling::MEDCouplingUMesh::renumberNodesInConn "renumberNodesInConn method".
2548 * \param [in] delta specifies the shift size applied to nodeId in nodal connectivity in \b this.
2550 void MEDCouplingUMesh::shiftNodeNumbersInConn(mcIdType delta)
2552 checkConnectivityFullyDefined();
2553 mcIdType *conn=getNodalConnectivity()->getPointer();
2554 const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2555 mcIdType nbOfCells=getNumberOfCells();
2556 for(mcIdType i=0;i<nbOfCells;i++)
2557 for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2559 mcIdType& node=conn[iconn];
2560 if(node>=0)//avoid polyhedron separator
2565 _nodal_connec->declareAsNew();
2570 * This method operates a modification of the connectivity in \b this.
2571 * 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.
2572 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2573 * its ids will be modified to id offset+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2574 * 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
2575 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id offset+0, node id nodeIdsToDuplicateBg[1] will have id offset+1,
2576 * node id nodeIdsToDuplicateBg[2] will have id offset+2...
2578 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2579 * As an another consequense after the call of this method \b this can be transiently non cohrent.
2581 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2582 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2583 * \param [in] offset the offset applied to all node ids in connectivity that are in [ \a nodeIdsToDuplicateBg, \a nodeIdsToDuplicateEnd ).
2585 void MEDCouplingUMesh::duplicateNodesInConn(const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd, mcIdType offset)
2587 checkConnectivityFullyDefined();
2588 std::map<mcIdType,mcIdType> m;
2589 mcIdType val=offset;
2590 for(const mcIdType *work=nodeIdsToDuplicateBg;work!=nodeIdsToDuplicateEnd;work++,val++)
2592 mcIdType *conn=getNodalConnectivity()->getPointer();
2593 const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2594 mcIdType nbOfCells=getNumberOfCells();
2595 for(mcIdType i=0;i<nbOfCells;i++)
2596 for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2598 mcIdType& node=conn[iconn];
2599 if(node>=0)//avoid polyhedron separator
2601 std::map<mcIdType,mcIdType>::iterator it=m.find(node);
2610 * This method renumbers cells of \a this using the array specified by [old2NewBg;old2NewBg+getNumberOfCells())
2612 * Contrary to MEDCouplingPointSet::renumberNodes, this method makes a permutation without any fuse of cell.
2613 * After the call of this method the number of cells remains the same as before.
2615 * If 'check' equals true the method will check that any elements in [ \a old2NewBg; \a old2NewEnd ) is unique ; if not
2616 * an INTERP_KERNEL::Exception will be thrown. When 'check' equals true [ \a old2NewBg ; \a old2NewEnd ) is not expected to
2617 * be strictly in [0;this->getNumberOfCells()).
2619 * If 'check' equals false the method will not check the content of [ \a old2NewBg ; \a old2NewEnd ).
2620 * To avoid any throw of SIGSEGV when 'check' equals false, the elements in [ \a old2NewBg ; \a old2NewEnd ) should be unique and
2621 * should be contained in[0;this->getNumberOfCells()).
2623 * \param [in] old2NewBg is expected to be a dynamically allocated pointer of size at least equal to this->getNumberOfCells()
2626 void MEDCouplingUMesh::renumberCells(const mcIdType *old2NewBg, bool check)
2628 checkConnectivityFullyDefined();
2629 mcIdType nbCells=getNumberOfCells();
2630 const mcIdType *array=old2NewBg;
2632 array=DataArrayIdType::CheckAndPreparePermutation(old2NewBg,old2NewBg+nbCells);
2634 const mcIdType *conn=_nodal_connec->getConstPointer();
2635 const mcIdType *connI=_nodal_connec_index->getConstPointer();
2636 MCAuto<DataArrayIdType> o2n=DataArrayIdType::New(); o2n->useArray(array,false,DeallocType::C_DEALLOC,nbCells,1);
2637 MCAuto<DataArrayIdType> n2o=o2n->invertArrayO2N2N2O(nbCells);
2638 const mcIdType *n2oPtr=n2o->begin();
2639 MCAuto<DataArrayIdType> newConn=DataArrayIdType::New();
2640 newConn->alloc(_nodal_connec->getNumberOfTuples(),_nodal_connec->getNumberOfComponents());
2641 newConn->copyStringInfoFrom(*_nodal_connec);
2642 MCAuto<DataArrayIdType> newConnI=DataArrayIdType::New();
2643 newConnI->alloc(_nodal_connec_index->getNumberOfTuples(),_nodal_connec_index->getNumberOfComponents());
2644 newConnI->copyStringInfoFrom(*_nodal_connec_index);
2646 mcIdType *newC=newConn->getPointer();
2647 mcIdType *newCI=newConnI->getPointer();
2650 for(mcIdType i=0;i<nbCells;i++)
2652 mcIdType pos=n2oPtr[i];
2653 mcIdType nbOfElts=connI[pos+1]-connI[pos];
2654 newC=std::copy(conn+connI[pos],conn+connI[pos+1],newC);
2659 setConnectivity(newConn,newConnI);
2661 free(const_cast<mcIdType *>(array));
2665 * Finds cells whose bounding boxes intersect a given bounding box.
2666 * \param [in] bbox - an array defining the bounding box via coordinates of its
2667 * extremum points in "no interlace" mode, i.e. xMin, xMax, yMin, yMax, zMin,
2669 * \param [in] eps - a factor used to increase size of the bounding box of cell
2670 * before comparing it with \a bbox. This factor is multiplied by the maximal
2671 * extent of the bounding box of cell to produce an addition to this bounding box.
2672 * \return DataArrayIdType * - a new instance of DataArrayIdType holding ids for found
2673 * cells. The caller is to delete this array using decrRef() as it is no more
2675 * \throw If the coordinates array is not set.
2676 * \throw If the nodal connectivity of cells is not defined.
2678 * \if ENABLE_EXAMPLES
2679 * \ref cpp_mcumesh_getCellsInBoundingBox "Here is a C++ example".<br>
2680 * \ref py_mcumesh_getCellsInBoundingBox "Here is a Python example".
2683 DataArrayIdType *MEDCouplingUMesh::getCellsInBoundingBox(const double *bbox, double eps) const
2685 MCAuto<DataArrayIdType> elems=DataArrayIdType::New(); elems->alloc(0,1);
2686 if(getMeshDimension()==-1)
2688 elems->pushBackSilent(0);
2689 return elems.retn();
2691 int dim=getSpaceDimension();
2692 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2693 const mcIdType* conn = getNodalConnectivity()->getConstPointer();
2694 const mcIdType* conn_index= getNodalConnectivityIndex()->getConstPointer();
2695 const double* coords = getCoords()->getConstPointer();
2696 mcIdType nbOfCells=getNumberOfCells();
2697 for ( mcIdType ielem=0; ielem<nbOfCells;ielem++ )
2699 for (int i=0; i<dim; i++)
2701 elem_bb[i*2]=std::numeric_limits<double>::max();
2702 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2705 for (mcIdType inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2707 mcIdType node= conn[inode];
2708 if(node>=0)//avoid polyhedron separator
2710 for (int idim=0; idim<dim; idim++)
2712 if ( coords[node*dim+idim] < elem_bb[idim*2] )
2714 elem_bb[idim*2] = coords[node*dim+idim] ;
2716 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2718 elem_bb[idim*2+1] = coords[node*dim+idim] ;
2723 if (intersectsBoundingBox(elem_bb, bbox, dim, eps))
2724 elems->pushBackSilent(ielem);
2726 return elems.retn();
2730 * Given a boundary box 'bbox' returns elements 'elems' contained in this 'bbox' or touching 'bbox' (within 'eps' distance).
2731 * Warning 'elems' is incremented during the call so if elems is not empty before call returned elements will be
2732 * added in 'elems' parameter.
2734 DataArrayIdType *MEDCouplingUMesh::getCellsInBoundingBox(const INTERP_KERNEL::DirectedBoundingBox& bbox, double eps)
2736 MCAuto<DataArrayIdType> elems=DataArrayIdType::New(); elems->alloc(0,1);
2737 if(getMeshDimension()==-1)
2739 elems->pushBackSilent(0);
2740 return elems.retn();
2742 int dim=getSpaceDimension();
2743 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2744 const mcIdType* conn = getNodalConnectivity()->getConstPointer();
2745 const mcIdType* conn_index= getNodalConnectivityIndex()->getConstPointer();
2746 const double* coords = getCoords()->getConstPointer();
2747 mcIdType nbOfCells=getNumberOfCells();
2748 for ( mcIdType ielem=0; ielem<nbOfCells;ielem++ )
2750 for (int i=0; i<dim; i++)
2752 elem_bb[i*2]=std::numeric_limits<double>::max();
2753 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2756 for (mcIdType inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2758 mcIdType node= conn[inode];
2759 if(node>=0)//avoid polyhedron separator
2761 for (int idim=0; idim<dim; idim++)
2763 if ( coords[node*dim+idim] < elem_bb[idim*2] )
2765 elem_bb[idim*2] = coords[node*dim+idim] ;
2767 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2769 elem_bb[idim*2+1] = coords[node*dim+idim] ;
2774 if(intersectsBoundingBox(bbox, elem_bb, dim, eps))
2775 elems->pushBackSilent(ielem);
2777 return elems.retn();
2781 * Returns a type of a cell by its id.
2782 * \param [in] cellId - the id of the cell of interest.
2783 * \return INTERP_KERNEL::NormalizedCellType - enumeration item describing the cell type.
2784 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2786 INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::getTypeOfCell(mcIdType cellId) const
2788 const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
2789 if(cellId<_nodal_connec_index->getNbOfElems()-1)
2790 return (INTERP_KERNEL::NormalizedCellType) pt[ptI[cellId]];
2793 std::ostringstream oss; oss << "MEDCouplingUMesh::getTypeOfCell : Requesting type of cell #" << cellId << " but it should be in [0," << _nodal_connec_index->getNbOfElems()-1 << ") !";
2794 throw INTERP_KERNEL::Exception(oss.str());
2799 * This method returns a newly allocated array containing cell ids (ascendingly sorted) whose geometric type are equal to type.
2800 * This method does not throw exception if geometric type \a type is not in \a this.
2801 * This method throws an INTERP_KERNEL::Exception if meshdimension of \b this is not equal to those of \b type.
2802 * The coordinates array is not considered here.
2804 * \param [in] type the geometric type
2805 * \return cell ids in this having geometric type \a type.
2807 DataArrayIdType *MEDCouplingUMesh::giveCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2810 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
2812 checkConnectivityFullyDefined();
2813 mcIdType nbCells=getNumberOfCells();
2814 int mdim=getMeshDimension();
2815 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
2816 if(mdim!=ToIdType(cm.getDimension()))
2817 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::giveCellsWithType : Mismatch between mesh dimension and dimension of the cell !");
2818 const mcIdType *ptI=_nodal_connec_index->getConstPointer();
2819 const mcIdType *pt=_nodal_connec->getConstPointer();
2820 for(mcIdType i=0;i<nbCells;i++)
2822 if((INTERP_KERNEL::NormalizedCellType)pt[ptI[i]]==type)
2823 ret->pushBackSilent(i);
2829 * Returns nb of cells having the geometric type \a type. No throw if no cells in \a this has the geometric type \a type.
2831 mcIdType MEDCouplingUMesh::getNumberOfCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2833 const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
2834 mcIdType nbOfCells(getNumberOfCells()),ret(0);
2835 for(mcIdType i=0;i<nbOfCells;i++)
2836 if((INTERP_KERNEL::NormalizedCellType) pt[ptI[i]]==type)
2842 * Returns the nodal connectivity of a given cell.
2843 * The separator of faces within polyhedron connectivity (-1) is not returned, thus
2844 * all returned node ids can be used in getCoordinatesOfNode().
2845 * \param [in] cellId - an id of the cell of interest.
2846 * \param [in,out] conn - a vector where the node ids are appended. It is not
2847 * cleared before the appending.
2848 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2850 void MEDCouplingUMesh::getNodeIdsOfCell(mcIdType cellId, std::vector<mcIdType>& conn) const
2852 const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
2853 for(const mcIdType *w=pt+ptI[cellId]+1;w!=pt+ptI[cellId+1];w++)
2858 std::string MEDCouplingUMesh::simpleRepr() const
2860 static const char msg0[]="No coordinates specified !";
2861 std::ostringstream ret;
2862 ret << "Unstructured mesh with name : \"" << getName() << "\"\n";
2863 ret << "Description of mesh : \"" << getDescription() << "\"\n";
2865 double tt=getTime(tmpp1,tmpp2);
2866 ret << "Time attached to the mesh [unit] : " << tt << " [" << getTimeUnit() << "]\n";
2867 ret << "Iteration : " << tmpp1 << " Order : " << tmpp2 << "\n";
2869 { ret << "Mesh dimension : " << _mesh_dim << "\nSpace dimension : "; }
2871 { ret << " Mesh dimension has not been set or is invalid !"; }
2874 const int spaceDim=getSpaceDimension();
2875 ret << spaceDim << "\nInfo attached on space dimension : ";
2876 for(int i=0;i<spaceDim;i++)
2877 ret << "\"" << _coords->getInfoOnComponent(i) << "\" ";
2881 ret << msg0 << "\n";
2882 ret << "Number of nodes : ";
2884 ret << getNumberOfNodes() << "\n";
2886 ret << msg0 << "\n";
2887 ret << "Number of cells : ";
2888 if(_nodal_connec!=0 && _nodal_connec_index!=0)
2889 ret << getNumberOfCells() << "\n";
2891 ret << "No connectivity specified !" << "\n";
2892 ret << "Cell types present : ";
2893 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
2895 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter);
2896 ret << cm.getRepr() << " ";
2902 std::string MEDCouplingUMesh::advancedRepr() const
2904 std::ostringstream ret;
2905 ret << simpleRepr();
2906 ret << "\nCoordinates array : \n___________________\n\n";
2908 _coords->reprWithoutNameStream(ret);
2910 ret << "No array set !\n";
2911 ret << "\n\nConnectivity arrays : \n_____________________\n\n";
2912 reprConnectivityOfThisLL(ret);
2917 * This method returns a C++ code that is a dump of \a this.
2918 * This method will throw if this is not fully defined.
2920 std::string MEDCouplingUMesh::cppRepr() const
2922 static const char coordsName[]="coords";
2923 static const char connName[]="conn";
2924 static const char connIName[]="connI";
2925 checkFullyDefined();
2926 std::ostringstream ret; ret << "// coordinates" << std::endl;
2927 _coords->reprCppStream(coordsName,ret); ret << std::endl << "// connectivity" << std::endl;
2928 _nodal_connec->reprCppStream(connName,ret); ret << std::endl;
2929 _nodal_connec_index->reprCppStream(connIName,ret); ret << std::endl;
2930 ret << "MEDCouplingUMesh *mesh=MEDCouplingUMesh::New(\"" << getName() << "\"," << getMeshDimension() << ");" << std::endl;
2931 ret << "mesh->setCoords(" << coordsName << ");" << std::endl;
2932 ret << "mesh->setConnectivity(" << connName << "," << connIName << ",true);" << std::endl;
2933 ret << coordsName << "->decrRef(); " << connName << "->decrRef(); " << connIName << "->decrRef();" << std::endl;
2937 std::string MEDCouplingUMesh::reprConnectivityOfThis() const
2939 std::ostringstream ret;
2940 reprConnectivityOfThisLL(ret);
2945 * This method builds a newly allocated instance (with the same name than \a this) that the caller has the responsibility to deal with.
2946 * This method returns an instance with all arrays allocated (connectivity, connectivity index, coordinates)
2947 * but with length of these arrays set to 0. It allows to define an "empty" mesh (with nor cells nor nodes but compliant with
2950 * This method expects that \a this has a mesh dimension set and higher or equal to 0. If not an exception will be thrown.
2951 * 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
2952 * with number of tuples set to 0, if not the array is taken as this in the returned instance.
2954 MEDCouplingUMesh *MEDCouplingUMesh::buildSetInstanceFromThis(std::size_t spaceDim) const
2956 int mdim=getMeshDimension();
2958 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSetInstanceFromThis : invalid mesh dimension ! Should be >= 0 !");
2959 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
2960 MCAuto<DataArrayIdType> tmp1,tmp2;
2961 bool needToCpyCT=true;
2964 tmp1=DataArrayIdType::New(); tmp1->alloc(0,1);
2972 if(!_nodal_connec_index)
2974 tmp2=DataArrayIdType::New(); tmp2->alloc(1,1); tmp2->setIJ(0,0,0);
2979 tmp2=_nodal_connec_index;
2982 ret->setConnectivity(tmp1,tmp2,false);
2987 MCAuto<DataArrayDouble> coords=DataArrayDouble::New(); coords->alloc(0,spaceDim);
2988 ret->setCoords(coords);
2991 ret->setCoords(_coords);
2995 mcIdType MEDCouplingUMesh::getNumberOfNodesInCell(mcIdType cellId) const
2997 const mcIdType *ptI=_nodal_connec_index->getConstPointer();
2998 const mcIdType *pt=_nodal_connec->getConstPointer();
2999 if(pt[ptI[cellId]]!=INTERP_KERNEL::NORM_POLYHED)
3000 return ptI[cellId+1]-ptI[cellId]-1;
3002 return ToIdType(std::count_if(pt+ptI[cellId]+1,pt+ptI[cellId+1],std::bind2nd(std::not_equal_to<mcIdType>(),-1)));
3006 * Returns types of cells of the specified part of \a this mesh.
3007 * This method avoids computing sub-mesh explicitly to get its types.
3008 * \param [in] begin - an array of cell ids of interest.
3009 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3010 * \return std::set<INTERP_KERNEL::NormalizedCellType> - a set of enumeration items
3011 * describing the cell types.
3012 * \throw If the coordinates array is not set.
3013 * \throw If the nodal connectivity of cells is not defined.
3014 * \sa getAllGeoTypes()
3016 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getTypesOfPart(const mcIdType *begin, const mcIdType *end) const
3018 checkFullyDefined();
3019 std::set<INTERP_KERNEL::NormalizedCellType> ret;
3020 const mcIdType *conn=_nodal_connec->getConstPointer();
3021 const mcIdType *connIndex=_nodal_connec_index->getConstPointer();
3022 for(const mcIdType *w=begin;w!=end;w++)
3023 ret.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]);
3028 * Defines the nodal connectivity using given connectivity arrays in \ref numbering-indirect format.
3029 * Optionally updates
3030 * a set of types of cells constituting \a this mesh.
3031 * This method is for advanced users having prepared their connectivity before. For
3032 * more info on using this method see \ref MEDCouplingUMeshAdvBuild.
3033 * \param [in] conn - the nodal connectivity array.
3034 * \param [in] connIndex - the nodal connectivity index array.
3035 * \param [in] isComputingTypes - if \c true, the set of types constituting \a this
3038 void MEDCouplingUMesh::setConnectivity(DataArrayIdType *conn, DataArrayIdType *connIndex, bool isComputingTypes)
3040 DataArrayIdType::SetArrayIn(conn,_nodal_connec);
3041 DataArrayIdType::SetArrayIn(connIndex,_nodal_connec_index);
3042 if(isComputingTypes)
3048 * Copy constructor. If 'deepCopy' is false \a this is a shallow copy of other.
3049 * If 'deeCpy' is true all arrays (coordinates and connectivities) are deeply copied.
3051 MEDCouplingUMesh::MEDCouplingUMesh(const MEDCouplingUMesh& other, bool deepCpy):MEDCouplingPointSet(other,deepCpy),_mesh_dim(other._mesh_dim),
3052 _nodal_connec(0),_nodal_connec_index(0),
3053 _types(other._types)
3055 if(other._nodal_connec)
3056 _nodal_connec=other._nodal_connec->performCopyOrIncrRef(deepCpy);
3057 if(other._nodal_connec_index)
3058 _nodal_connec_index=other._nodal_connec_index->performCopyOrIncrRef(deepCpy);
3061 MEDCouplingUMesh::~MEDCouplingUMesh()
3064 _nodal_connec->decrRef();
3065 if(_nodal_connec_index)
3066 _nodal_connec_index->decrRef();
3070 * Recomputes a set of cell types of \a this mesh. For more info see
3071 * \ref MEDCouplingUMeshNodalConnectivity.
3073 void MEDCouplingUMesh::computeTypes()
3075 ComputeAllTypesInternal(_types,_nodal_connec,_nodal_connec_index);
3080 * Returns a number of cells constituting \a this mesh.
3081 * \return mcIdType - the number of cells in \a this mesh.
3082 * \throw If the nodal connectivity of cells is not defined.
3084 mcIdType MEDCouplingUMesh::getNumberOfCells() const
3086 if(_nodal_connec_index)
3087 return _nodal_connec_index->getNumberOfTuples()-1;
3092 throw INTERP_KERNEL::Exception("Unable to get number of cells because no connectivity specified !");
3096 * Returns a dimension of \a this mesh, i.e. a dimension of cells constituting \a this
3097 * mesh. For more info see \ref meshes.
3098 * \return int - the dimension of \a this mesh.
3099 * \throw If the mesh dimension is not defined using setMeshDimension().
3101 int MEDCouplingUMesh::getMeshDimension() const
3104 throw INTERP_KERNEL::Exception("No mesh dimension specified !");
3109 * Returns a length of the nodal connectivity array.
3110 * This method is for test reason. Normally the integer returned is not useable by
3111 * user. For more info see \ref MEDCouplingUMeshNodalConnectivity.
3112 * \return mcIdType - the length of the nodal connectivity array.
3114 mcIdType MEDCouplingUMesh::getNodalConnectivityArrayLen() const
3116 return _nodal_connec->getNbOfElems();
3120 * First step of serialization process. Used by ParaMEDMEM and MEDCouplingCorba to transfert data between process.
3122 void MEDCouplingUMesh::getTinySerializationInformation(std::vector<double>& tinyInfoD, std::vector<mcIdType>& tinyInfo, std::vector<std::string>& littleStrings) const
3124 MEDCouplingPointSet::getTinySerializationInformation(tinyInfoD,tinyInfo,littleStrings);
3125 tinyInfo.push_back(ToIdType(getMeshDimension()));
3126 tinyInfo.push_back(getNumberOfCells());
3128 tinyInfo.push_back(getNodalConnectivityArrayLen());
3130 tinyInfo.push_back(-1);
3134 * First step of unserialization process.
3136 bool MEDCouplingUMesh::isEmptyMesh(const std::vector<mcIdType>& tinyInfo) const
3138 return tinyInfo[6]<=0;
3142 * Second step of serialization process.
3143 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3146 * \param littleStrings
3148 void MEDCouplingUMesh::resizeForUnserialization(const std::vector<mcIdType>& tinyInfo, DataArrayIdType *a1, DataArrayDouble *a2, std::vector<std::string>& littleStrings) const
3150 MEDCouplingPointSet::resizeForUnserialization(tinyInfo,a1,a2,littleStrings);
3152 a1->alloc(tinyInfo[7]+tinyInfo[6]+1,1);
3156 * Third and final step of serialization process.
3158 void MEDCouplingUMesh::serialize(DataArrayIdType *&a1, DataArrayDouble *&a2) const
3160 MEDCouplingPointSet::serialize(a1,a2);
3161 if(getMeshDimension()>-1)
3163 a1=DataArrayIdType::New();
3164 a1->alloc(getNodalConnectivityArrayLen()+getNumberOfCells()+1,1);
3165 mcIdType *ptA1=a1->getPointer();
3166 const mcIdType *conn=getNodalConnectivity()->getConstPointer();
3167 const mcIdType *index=getNodalConnectivityIndex()->getConstPointer();
3168 ptA1=std::copy(index,index+getNumberOfCells()+1,ptA1);
3169 std::copy(conn,conn+getNodalConnectivityArrayLen(),ptA1);
3176 * Second and final unserialization process.
3177 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3179 void MEDCouplingUMesh::unserialization(const std::vector<double>& tinyInfoD, const std::vector<mcIdType>& tinyInfo, const DataArrayIdType *a1, DataArrayDouble *a2, const std::vector<std::string>& littleStrings)
3181 MEDCouplingPointSet::unserialization(tinyInfoD,tinyInfo,a1,a2,littleStrings);
3182 setMeshDimension(FromIdType<int>(tinyInfo[5]));
3186 const mcIdType *recvBuffer=a1->getConstPointer();
3187 MCAuto<DataArrayIdType> myConnecIndex=DataArrayIdType::New();
3188 myConnecIndex->alloc(tinyInfo[6]+1,1);
3189 std::copy(recvBuffer,recvBuffer+tinyInfo[6]+1,myConnecIndex->getPointer());
3190 MCAuto<DataArrayIdType> myConnec=DataArrayIdType::New();
3191 myConnec->alloc(tinyInfo[7],1);
3192 std::copy(recvBuffer+tinyInfo[6]+1,recvBuffer+tinyInfo[6]+1+tinyInfo[7],myConnec->getPointer());
3193 setConnectivity(myConnec, myConnecIndex);
3200 * Returns a new MEDCouplingFieldDouble containing volumes of cells constituting \a this
3202 * For 1D cells, the returned field contains lengths.<br>
3203 * For 2D cells, the returned field contains areas.<br>
3204 * For 3D cells, the returned field contains volumes.
3205 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3206 * orientation, i.e. the volume is always positive.
3207 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on cells
3208 * and one time . The caller is to delete this field using decrRef() as it is no
3211 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureField(bool isAbs) const
3213 std::string name="MeasureOfMesh_";
3215 mcIdType nbelem=getNumberOfCells();
3216 MCAuto<MEDCouplingFieldDouble> field=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3217 field->setName(name);
3218 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3219 array->alloc(nbelem,1);
3220 double *area_vol=array->getPointer();
3221 field->setArray(array) ; array=0;
3222 field->setMesh(const_cast<MEDCouplingUMesh *>(this));
3223 field->synchronizeTimeWithMesh();
3224 if(getMeshDimension()!=-1)
3227 INTERP_KERNEL::NormalizedCellType type;
3228 int dim_space=getSpaceDimension();
3229 const double *coords=getCoords()->getConstPointer();
3230 const mcIdType *connec=getNodalConnectivity()->getConstPointer();
3231 const mcIdType *connec_index=getNodalConnectivityIndex()->getConstPointer();
3232 for(mcIdType iel=0;iel<nbelem;iel++)
3234 ipt=connec_index[iel];
3235 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3236 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);
3239 std::transform(area_vol,area_vol+nbelem,area_vol,std::ptr_fun<double,double>(fabs));
3243 area_vol[0]=std::numeric_limits<double>::max();
3245 return field.retn();
3249 * Returns a new DataArrayDouble containing volumes of specified cells of \a this
3251 * For 1D cells, the returned array contains lengths.<br>
3252 * For 2D cells, the returned array contains areas.<br>
3253 * For 3D cells, the returned array contains volumes.
3254 * This method avoids building explicitly a part of \a this mesh to perform the work.
3255 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3256 * orientation, i.e. the volume is always positive.
3257 * \param [in] begin - an array of cell ids of interest.
3258 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3259 * \return DataArrayDouble * - a new instance of DataArrayDouble. The caller is to
3260 * delete this array using decrRef() as it is no more needed.
3262 * \if ENABLE_EXAMPLES
3263 * \ref cpp_mcumesh_getPartMeasureField "Here is a C++ example".<br>
3264 * \ref py_mcumesh_getPartMeasureField "Here is a Python example".
3266 * \sa getMeasureField()
3268 DataArrayDouble *MEDCouplingUMesh::getPartMeasureField(bool isAbs, const mcIdType *begin, const mcIdType *end) const
3270 std::string name="PartMeasureOfMesh_";
3272 std::size_t nbelem=std::distance(begin,end);
3273 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3274 array->setName(name);
3275 array->alloc(nbelem,1);
3276 double *area_vol=array->getPointer();
3277 if(getMeshDimension()!=-1)
3280 INTERP_KERNEL::NormalizedCellType type;
3281 int dim_space=getSpaceDimension();
3282 const double *coords=getCoords()->getConstPointer();
3283 const mcIdType *connec=getNodalConnectivity()->getConstPointer();
3284 const mcIdType *connec_index=getNodalConnectivityIndex()->getConstPointer();
3285 for(const mcIdType *iel=begin;iel!=end;iel++)
3287 ipt=connec_index[*iel];
3288 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3289 *area_vol++=INTERP_KERNEL::computeVolSurfOfCell2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,connec+ipt+1,connec_index[*iel+1]-ipt-1,coords,dim_space);
3292 std::transform(array->getPointer(),area_vol,array->getPointer(),std::ptr_fun<double,double>(fabs));
3296 area_vol[0]=std::numeric_limits<double>::max();
3298 return array.retn();
3302 * Returns a new MEDCouplingFieldDouble containing volumes of cells of a dual mesh of
3303 * \a this one. The returned field contains the dual cell volume for each corresponding
3304 * node in \a this mesh. In other words, the field returns the getMeasureField() of
3305 * the dual mesh in P1 sens of \a this.<br>
3306 * For 1D cells, the returned field contains lengths.<br>
3307 * For 2D cells, the returned field contains areas.<br>
3308 * For 3D cells, the returned field contains volumes.
3309 * This method is useful to check "P1*" conservative interpolators.
3310 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3311 * orientation, i.e. the volume is always positive.
3312 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3313 * nodes and one time. The caller is to delete this array using decrRef() as
3314 * it is no more needed.
3316 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureFieldOnNode(bool isAbs) const
3318 MCAuto<MEDCouplingFieldDouble> tmp=getMeasureField(isAbs);
3319 std::string name="MeasureOnNodeOfMesh_";
3321 mcIdType nbNodes=getNumberOfNodes();
3322 MCAuto<DataArrayDouble> nnpc;
3324 MCAuto<DataArrayIdType> tmp(computeNbOfNodesPerCell());
3325 nnpc=tmp->convertToDblArr();
3327 std::for_each(nnpc->rwBegin(),nnpc->rwEnd(),[](double& v) { v=1./v; });
3328 const double *nnpcPtr(nnpc->begin());
3329 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_NODES);
3330 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3331 array->alloc(nbNodes,1);
3332 double *valsToFill=array->getPointer();
3333 std::fill(valsToFill,valsToFill+nbNodes,0.);
3334 const double *values=tmp->getArray()->getConstPointer();
3335 MCAuto<DataArrayIdType> da=DataArrayIdType::New();
3336 MCAuto<DataArrayIdType> daInd=DataArrayIdType::New();
3337 getReverseNodalConnectivity(da,daInd);
3338 const mcIdType *daPtr=da->getConstPointer();
3339 const mcIdType *daIPtr=daInd->getConstPointer();
3340 for(mcIdType i=0;i<nbNodes;i++)
3341 for(const mcIdType *cell=daPtr+daIPtr[i];cell!=daPtr+daIPtr[i+1];cell++)
3342 valsToFill[i]+=nnpcPtr[*cell]*values[*cell];
3344 ret->setArray(array);
3349 * Returns a new MEDCouplingFieldDouble holding normal vectors to cells of \a this
3350 * mesh. The returned normal vectors to each cell have a norm2 equal to 1.
3351 * The computed vectors have <em> this->getMeshDimension()+1 </em> components
3352 * and are normalized.
3353 * <br> \a this can be either
3354 * - a 2D mesh in 2D or 3D space or
3355 * - an 1D mesh in 2D space.
3357 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3358 * cells and one time. The caller is to delete this field using decrRef() as
3359 * it is no more needed.
3360 * \throw If the nodal connectivity of cells is not defined.
3361 * \throw If the coordinates array is not set.
3362 * \throw If the mesh dimension is not set.
3363 * \throw If the mesh and space dimension is not as specified above.
3365 MEDCouplingFieldDouble *MEDCouplingUMesh::buildOrthogonalField() const
3367 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3368 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3369 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3370 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3371 mcIdType nbOfCells=getNumberOfCells();
3372 int nbComp=getMeshDimension()+1;
3373 array->alloc(nbOfCells,nbComp);
3374 double *vals=array->getPointer();
3375 const mcIdType *connI=_nodal_connec_index->getConstPointer();
3376 const mcIdType *conn=_nodal_connec->getConstPointer();
3377 const double *coords=_coords->getConstPointer();
3378 if(getMeshDimension()==2)
3380 if(getSpaceDimension()==3)
3382 MCAuto<DataArrayDouble> loc=computeCellCenterOfMass();
3383 const double *locPtr=loc->getConstPointer();
3384 for(mcIdType i=0;i<nbOfCells;i++,vals+=3)
3386 mcIdType offset=connI[i];
3387 INTERP_KERNEL::crossprod<3>(locPtr+3*i,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3388 double n=INTERP_KERNEL::norm<3>(vals);
3389 std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3394 MCAuto<MEDCouplingFieldDouble> isAbs=getMeasureField(false);
3395 const double *isAbsPtr=isAbs->getArray()->begin();
3396 for(mcIdType i=0;i<nbOfCells;i++,isAbsPtr++)
3397 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=*isAbsPtr>0.?1.:-1.; }
3400 else//meshdimension==1
3403 for(mcIdType i=0;i<nbOfCells;i++)
3405 mcIdType offset=connI[i];
3406 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3407 double n=INTERP_KERNEL::norm<2>(tmp);
3408 std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3413 ret->setArray(array);
3415 ret->synchronizeTimeWithSupport();
3420 * Returns a new MEDCouplingFieldDouble holding normal vectors to specified cells of
3421 * \a this mesh. The computed vectors have <em> this->getMeshDimension()+1 </em> components
3422 * and are normalized.
3423 * <br> \a this can be either
3424 * - a 2D mesh in 2D or 3D space or
3425 * - an 1D mesh in 2D space.
3427 * This method avoids building explicitly a part of \a this mesh to perform the work.
3428 * \param [in] begin - an array of cell ids of interest.
3429 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3430 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3431 * cells and one time. The caller is to delete this field using decrRef() as
3432 * it is no more needed.
3433 * \throw If the nodal connectivity of cells is not defined.
3434 * \throw If the coordinates array is not set.
3435 * \throw If the mesh dimension is not set.
3436 * \throw If the mesh and space dimension is not as specified above.
3437 * \sa buildOrthogonalField()
3439 * \if ENABLE_EXAMPLES
3440 * \ref cpp_mcumesh_buildPartOrthogonalField "Here is a C++ example".<br>
3441 * \ref py_mcumesh_buildPartOrthogonalField "Here is a Python example".
3444 MEDCouplingFieldDouble *MEDCouplingUMesh::buildPartOrthogonalField(const mcIdType *begin, const mcIdType *end) const
3446 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3447 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3448 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3449 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3450 std::size_t nbelems=std::distance(begin,end);
3451 int nbComp=getMeshDimension()+1;
3452 array->alloc(nbelems,nbComp);
3453 double *vals=array->getPointer();
3454 const mcIdType *connI=_nodal_connec_index->getConstPointer();
3455 const mcIdType *conn=_nodal_connec->getConstPointer();
3456 const double *coords=_coords->getConstPointer();
3457 if(getMeshDimension()==2)
3459 if(getSpaceDimension()==3)
3461 MCAuto<DataArrayDouble> loc=getPartBarycenterAndOwner(begin,end);
3462 const double *locPtr=loc->getConstPointer();
3463 for(const mcIdType *i=begin;i!=end;i++,vals+=3,locPtr+=3)
3465 mcIdType offset=connI[*i];
3466 INTERP_KERNEL::crossprod<3>(locPtr,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3467 double n=INTERP_KERNEL::norm<3>(vals);
3468 std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3473 for(std::size_t i=0;i<nbelems;i++)
3474 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=1.; }
3477 else//meshdimension==1
3480 for(const mcIdType *i=begin;i!=end;i++)
3482 mcIdType offset=connI[*i];
3483 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3484 double n=INTERP_KERNEL::norm<2>(tmp);
3485 std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3490 ret->setArray(array);
3492 ret->synchronizeTimeWithSupport();
3497 * Returns a new MEDCouplingFieldDouble holding a direction vector for each SEG2 in \a
3498 * this 1D mesh. The computed vectors have <em> this->getSpaceDimension() </em> components
3499 * and are \b not normalized.
3500 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3501 * cells and one time. The caller is to delete this field using decrRef() as
3502 * it is no more needed.
3503 * \throw If the nodal connectivity of cells is not defined.
3504 * \throw If the coordinates array is not set.
3505 * \throw If \a this->getMeshDimension() != 1.
3506 * \throw If \a this mesh includes cells of type other than SEG2.
3508 MEDCouplingFieldDouble *MEDCouplingUMesh::buildDirectionVectorField() const
3510 if(getMeshDimension()!=1)
3511 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for buildDirectionVectorField !");
3512 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3513 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for buildDirectionVectorField !");
3514 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3515 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3516 mcIdType nbOfCells=getNumberOfCells();
3517 int spaceDim=getSpaceDimension();
3518 array->alloc(nbOfCells,spaceDim);
3519 double *pt=array->getPointer();
3520 const double *coo=getCoords()->getConstPointer();
3521 std::vector<mcIdType> conn;
3523 for(mcIdType i=0;i<nbOfCells;i++)
3526 getNodeIdsOfCell(i,conn);
3527 pt=std::transform(coo+conn[1]*spaceDim,coo+(conn[1]+1)*spaceDim,coo+conn[0]*spaceDim,pt,std::minus<double>());
3529 ret->setArray(array);
3531 ret->synchronizeTimeWithSupport();
3536 * Creates a 2D mesh by cutting \a this 3D mesh with a plane. In addition to the mesh,
3537 * returns a new DataArrayIdType, of length equal to the number of 2D cells in the result
3538 * mesh, holding, for each cell in the result mesh, an id of a 3D cell it comes
3539 * from. If a result face is shared by two 3D cells, then the face in included twice in
3541 * \param [in] origin - 3 components of a point defining location of the plane.
3542 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3543 * must be greater than 1e-6.
3544 * \param [in] eps - half-thickness of the plane.
3545 * \param [out] cellIds - a new instance of DataArrayIdType holding ids of 3D cells
3546 * producing correspondent 2D cells. The caller is to delete this array
3547 * using decrRef() as it is no more needed.
3548 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This mesh does
3549 * not share the node coordinates array with \a this mesh. The caller is to
3550 * delete this mesh using decrRef() as it is no more needed.
3551 * \throw If the coordinates array is not set.
3552 * \throw If the nodal connectivity of cells is not defined.
3553 * \throw If \a this->getMeshDimension() != 3 or \a this->getSpaceDimension() != 3.
3554 * \throw If magnitude of \a vec is less than 1e-6.
3555 * \throw If the plane does not intersect any 3D cell of \a this mesh.
3556 * \throw If \a this includes quadratic cells.
3558 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3D(const double *origin, const double *vec, double eps, DataArrayIdType *&cellIds) const
3560 checkFullyDefined();
3561 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3562 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3563 MCAuto<DataArrayIdType> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3564 if(candidates->empty())
3565 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane considering bounding boxes !");
3566 std::vector<mcIdType> nodes;
3567 DataArrayIdType *cellIds1D=0;
3568 MCAuto<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3569 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3570 MCAuto<DataArrayIdType> desc1=DataArrayIdType::New(),desc2=DataArrayIdType::New();
3571 MCAuto<DataArrayIdType> descIndx1=DataArrayIdType::New(),descIndx2=DataArrayIdType::New();
3572 MCAuto<DataArrayIdType> revDesc1=DataArrayIdType::New(),revDesc2=DataArrayIdType::New();
3573 MCAuto<DataArrayIdType> revDescIndx1=DataArrayIdType::New(),revDescIndx2=DataArrayIdType::New();
3574 MCAuto<MEDCouplingUMesh> mDesc2=subMesh->buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2);//meshDim==2 spaceDim==3
3575 revDesc2=0; revDescIndx2=0;
3576 MCAuto<MEDCouplingUMesh> mDesc1=mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3577 revDesc1=0; revDescIndx1=0;
3578 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3579 MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3581 std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3582 for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3584 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3585 std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(mDesc2->getNumberOfCells());
3586 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->getConstPointer(),mDesc2->getNodalConnectivityIndex()->getConstPointer(),
3587 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3588 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3589 MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New()),cellIds2(DataArrayIdType::New());
3590 connI->pushBackSilent(0); conn->alloc(0,1); cellIds2->alloc(0,1);
3591 subMesh->assemblyForSplitFrom3DSurf(cut3DSurf,desc2->getConstPointer(),descIndx2->getConstPointer(),conn,connI,cellIds2);
3592 if(cellIds2->empty())
3593 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3594 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3D",2);
3595 ret->setCoords(mDesc1->getCoords());
3596 ret->setConnectivity(conn,connI,true);
3597 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3602 * Creates an 1D mesh by cutting \a this 2D mesh in 3D space with a plane. In
3603 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
3604 from. If a result segment is shared by two 2D cells, then the segment in included twice in
3606 * \param [in] origin - 3 components of a point defining location of the plane.
3607 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3608 * must be greater than 1e-6.
3609 * \param [in] eps - half-thickness of the plane.
3610 * \param [out] cellIds - a new instance of DataArrayIdType holding ids of faces
3611 * producing correspondent segments. The caller is to delete this array
3612 * using decrRef() as it is no more needed.
3613 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This is an 1D
3614 * mesh in 3D space. This mesh does not share the node coordinates array with
3615 * \a this mesh. The caller is to delete this mesh using decrRef() as it is
3617 * \throw If the coordinates array is not set.
3618 * \throw If the nodal connectivity of cells is not defined.
3619 * \throw If \a this->getMeshDimension() != 2 or \a this->getSpaceDimension() != 3.
3620 * \throw If magnitude of \a vec is less than 1e-6.
3621 * \throw If the plane does not intersect any 2D cell of \a this mesh.
3622 * \throw If \a this includes quadratic cells.
3624 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3DSurf(const double *origin, const double *vec, double eps, DataArrayIdType *&cellIds) const
3626 checkFullyDefined();
3627 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
3628 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf works on umeshes with meshdim equal to 2 and spaceDim equal to 3 !");
3629 MCAuto<DataArrayIdType> candidates(getCellIdsCrossingPlane(origin,vec,eps));
3630 if(candidates->empty())
3631 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3D surf cells in this intercepts the specified plane considering bounding boxes !");
3632 std::vector<mcIdType> nodes;
3633 DataArrayIdType *cellIds1D(0);
3634 MCAuto<MEDCouplingUMesh> subMesh(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3635 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3636 MCAuto<DataArrayIdType> desc1(DataArrayIdType::New()),descIndx1(DataArrayIdType::New()),revDesc1(DataArrayIdType::New()),revDescIndx1(DataArrayIdType::New());
3637 MCAuto<MEDCouplingUMesh> mDesc1(subMesh->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3638 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3639 MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3641 std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3642 for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3644 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3645 mcIdType ncellsSub=subMesh->getNumberOfCells();
3646 std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(ncellsSub);
3647 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,subMesh->getNodalConnectivity()->getConstPointer(),subMesh->getNodalConnectivityIndex()->getConstPointer(),
3648 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3649 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3650 MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New()),cellIds2(DataArrayIdType::New()); connI->pushBackSilent(0);
3652 const mcIdType *nodal=subMesh->getNodalConnectivity()->getConstPointer();
3653 const mcIdType *nodalI=subMesh->getNodalConnectivityIndex()->getConstPointer();
3654 for(mcIdType i=0;i<ncellsSub;i++)
3656 if(cut3DSurf[i].first!=-1 && cut3DSurf[i].second!=-1)
3658 if(cut3DSurf[i].first!=-2)
3660 conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_SEG2)); conn->pushBackSilent(cut3DSurf[i].first); conn->pushBackSilent(cut3DSurf[i].second);
3661 connI->pushBackSilent(conn->getNumberOfTuples());
3662 cellIds2->pushBackSilent(i);
3666 mcIdType cellId3DSurf=cut3DSurf[i].second;
3667 mcIdType offset=nodalI[cellId3DSurf]+1;
3668 mcIdType nbOfEdges=nodalI[cellId3DSurf+1]-offset;
3669 for(mcIdType j=0;j<nbOfEdges;j++)
3671 conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_SEG2)); conn->pushBackSilent(nodal[offset+j]); conn->pushBackSilent(nodal[offset+(j+1)%nbOfEdges]);
3672 connI->pushBackSilent(conn->getNumberOfTuples());
3673 cellIds2->pushBackSilent(cellId3DSurf);
3678 if(cellIds2->empty())
3679 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3DSurf cells in this intercepts the specified plane !");
3680 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3DSurf",1);
3681 ret->setCoords(mDesc1->getCoords());
3682 ret->setConnectivity(conn,connI,true);
3683 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3687 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::clipSingle3DCellByPlane(const double origin[3], const double vec[3], double eps) const
3689 checkFullyDefined();
3690 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3691 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3692 if(getNumberOfCells()!=1)
3693 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works only on mesh containing exactly one cell !");
3695 std::vector<mcIdType> nodes;
3696 findNodesOnPlane(origin,vec,eps,nodes);
3697 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());
3698 MCAuto<MEDCouplingUMesh> mDesc2(buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2));//meshDim==2 spaceDim==3
3699 revDesc2=0; revDescIndx2=0;
3700 MCAuto<MEDCouplingUMesh> mDesc1(mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3701 revDesc1=0; revDescIndx1=0;
3702 DataArrayIdType *cellIds1D(0);
3703 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3704 MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3705 std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3706 for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3710 mcIdType oldNbNodes(mDesc1->getNumberOfNodes());
3711 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3712 sameNbNodes=(mDesc1->getNumberOfNodes()==oldNbNodes);
3714 std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(mDesc2->getNumberOfCells());
3715 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->begin(),mDesc2->getNodalConnectivityIndex()->begin(),
3716 mDesc1->getNodalConnectivity()->begin(),mDesc1->getNodalConnectivityIndex()->begin(),
3717 desc1->begin(),descIndx1->begin(),cut3DSurf);
3718 MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New());
3719 connI->pushBackSilent(0); conn->alloc(0,1);
3721 MCAuto<DataArrayIdType> cellIds2(DataArrayIdType::New()); cellIds2->alloc(0,1);
3722 assemblyForSplitFrom3DSurf(cut3DSurf,desc2->begin(),descIndx2->begin(),conn,connI,cellIds2);
3723 if(cellIds2->empty())
3724 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3726 std::vector<std::vector<mcIdType> > res;
3727 buildSubCellsFromCut(cut3DSurf,desc2->begin(),descIndx2->begin(),mDesc1->getCoords()->begin(),eps,res);
3728 std::size_t sz(res.size());
3729 if(ToIdType(res.size())==mDesc1->getNumberOfCells() && sameNbNodes)
3730 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane : cell is not clipped !");
3731 for(std::size_t i=0;i<sz;i++)
3733 conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYGON));
3734 conn->insertAtTheEnd(res[i].begin(),res[i].end());
3735 connI->pushBackSilent(conn->getNumberOfTuples());
3737 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
3738 ret->setCoords(mDesc1->getCoords());
3739 ret->setConnectivity(conn,connI,true);
3740 mcIdType nbCellsRet(ret->getNumberOfCells());
3742 MCAuto<DataArrayDouble> vec2(DataArrayDouble::New()); vec2->alloc(1,3); std::copy(vec,vec+3,vec2->getPointer());
3743 MCAuto<MEDCouplingFieldDouble> ortho(ret->buildOrthogonalField());
3744 MCAuto<DataArrayDouble> ortho2(ortho->getArray()->selectByTupleIdSafeSlice(0,1,1));
3745 MCAuto<DataArrayDouble> dott(DataArrayDouble::Dot(ortho2,vec2));
3746 MCAuto<DataArrayDouble> ccm(ret->computeCellCenterOfMass());
3747 MCAuto<DataArrayDouble> occm;
3749 MCAuto<DataArrayDouble> pt(DataArrayDouble::New()); pt->alloc(1,3); std::copy(origin,origin+3,pt->getPointer());
3750 occm=DataArrayDouble::Substract(ccm,pt);
3752 vec2=DataArrayDouble::New(); vec2->alloc(nbCellsRet,3);
3753 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);
3754 MCAuto<DataArrayDouble> dott2(DataArrayDouble::Dot(occm,vec2));
3756 const mcIdType *cPtr(ret->getNodalConnectivity()->begin()),*ciPtr(ret->getNodalConnectivityIndex()->begin());
3757 MCAuto<MEDCouplingUMesh> ret2(MEDCouplingUMesh::New("Clip3D",3));
3758 ret2->setCoords(mDesc1->getCoords());
3759 MCAuto<DataArrayIdType> conn2(DataArrayIdType::New()),conn2I(DataArrayIdType::New());
3760 conn2I->pushBackSilent(0); conn2->alloc(0,1);
3761 std::vector<mcIdType> cell0(1,ToIdType(INTERP_KERNEL::NORM_POLYHED));
3762 std::vector<mcIdType> cell1(1,ToIdType(INTERP_KERNEL::NORM_POLYHED));
3763 if(dott->getIJ(0,0)>0)
3765 cell0.insert(cell0.end(),cPtr+1,cPtr+ciPtr[1]);
3766 std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell1,cell1.end()));
3770 cell1.insert(cell1.end(),cPtr+1,cPtr+ciPtr[1]);
3771 std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell0,cell0.end()));
3773 for(mcIdType i=1;i<nbCellsRet;i++)
3775 if(dott2->getIJ(i,0)<0)
3777 if(ciPtr[i+1]-ciPtr[i]>=4)
3779 cell0.push_back(-1);
3780 cell0.insert(cell0.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
3785 if(ciPtr[i+1]-ciPtr[i]>=4)
3787 cell1.push_back(-1);
3788 cell1.insert(cell1.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
3792 conn2->insertAtTheEnd(cell0.begin(),cell0.end());
3793 conn2I->pushBackSilent(conn2->getNumberOfTuples());
3794 conn2->insertAtTheEnd(cell1.begin(),cell1.end());
3795 conn2I->pushBackSilent(conn2->getNumberOfTuples());
3796 ret2->setConnectivity(conn2,conn2I,true);
3797 ret2->checkConsistencyLight();
3798 ret2->orientCorrectlyPolyhedrons();
3803 * Finds cells whose bounding boxes intersect a given plane.
3804 * \param [in] origin - 3 components of a point defining location of the plane.
3805 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3806 * must be greater than 1e-6.
3807 * \param [in] eps - half-thickness of the plane.
3808 * \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of the found
3809 * cells. The caller is to delete this array using decrRef() as it is no more
3811 * \throw If the coordinates array is not set.
3812 * \throw If the nodal connectivity of cells is not defined.
3813 * \throw If \a this->getSpaceDimension() != 3.
3814 * \throw If magnitude of \a vec is less than 1e-6.
3815 * \sa buildSlice3D()
3817 DataArrayIdType *MEDCouplingUMesh::getCellIdsCrossingPlane(const double *origin, const double *vec, double eps) const
3819 checkFullyDefined();
3820 if(getSpaceDimension()!=3)
3821 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with spaceDim equal to 3 !");
3822 double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
3824 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellIdsCrossingPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
3826 vec2[0]=vec[1]; vec2[1]=-vec[0]; vec2[2]=0.;//vec2 is the result of cross product of vec with (0,0,1)
3827 double angle=acos(vec[2]/normm);
3828 MCAuto<DataArrayIdType> cellIds;
3832 MCAuto<DataArrayDouble> coo=_coords->deepCopy();
3833 double normm2(sqrt(vec2[0]*vec2[0]+vec2[1]*vec2[1]+vec2[2]*vec2[2]));
3834 if(normm2/normm>1e-6)
3835 DataArrayDouble::Rotate3DAlg(origin,vec2,angle,coo->getNumberOfTuples(),coo->getPointer(),coo->getPointer());
3836 MCAuto<MEDCouplingUMesh> mw=clone(false);//false -> shallow copy
3838 mw->getBoundingBox(bbox);
3839 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3840 cellIds=mw->getCellsInBoundingBox(bbox,eps);
3844 getBoundingBox(bbox);
3845 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3846 cellIds=getCellsInBoundingBox(bbox,eps);
3848 return cellIds.retn();
3852 * This method checks that \a this is a contiguous mesh. The user is expected to call this method on a mesh with meshdim==1.
3853 * If not an exception will thrown. If this is an empty mesh with no cell an exception will be thrown too.
3854 * No consideration of coordinate is done by this method.
3855 * 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)
3856 * If not false is returned. In case that false is returned a call to MEDCoupling::MEDCouplingUMesh::mergeNodes could be useful.
3858 bool MEDCouplingUMesh::isContiguous1D() const
3860 if(getMeshDimension()!=1)
3861 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense only for 1D mesh !");
3862 mcIdType nbCells=getNumberOfCells();
3864 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense for non empty mesh !");
3865 const mcIdType *connI(_nodal_connec_index->begin()),*conn(_nodal_connec->begin());
3866 mcIdType ref=conn[connI[0]+2];
3867 for(mcIdType i=1;i<nbCells;i++)
3869 if(conn[connI[i]+1]!=ref)
3871 ref=conn[connI[i]+2];
3877 * This method is only callable on mesh with meshdim == 1 containing only SEG2 and spaceDim==3.
3878 * This method projects this on the 3D line defined by (pt,v). This methods first checks that all SEG2 are along v vector.
3879 * \param pt reference point of the line
3880 * \param v normalized director vector of the line
3881 * \param eps max precision before throwing an exception
3882 * \param res output of size this->getNumberOfCells
3884 void MEDCouplingUMesh::project1D(const double *pt, const double *v, double eps, double *res) const
3886 if(getMeshDimension()!=1)
3887 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for project1D !");
3888 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3889 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for project1D !");
3890 if(getSpaceDimension()!=3)
3891 throw INTERP_KERNEL::Exception("Expected a umesh with spaceDim==3 for project1D !");
3892 MCAuto<MEDCouplingFieldDouble> f=buildDirectionVectorField();
3893 const double *fPtr=f->getArray()->getConstPointer();
3895 for(mcIdType i=0;i<getNumberOfCells();i++)
3897 const double *tmp1=fPtr+3*i;
3898 tmp[0]=tmp1[1]*v[2]-tmp1[2]*v[1];
3899 tmp[1]=tmp1[2]*v[0]-tmp1[0]*v[2];
3900 tmp[2]=tmp1[0]*v[1]-tmp1[1]*v[0];
3901 double n1=INTERP_KERNEL::norm<3>(tmp);
3902 n1/=INTERP_KERNEL::norm<3>(tmp1);
3904 throw INTERP_KERNEL::Exception("UMesh::Projection 1D failed !");
3906 const double *coo=getCoords()->getConstPointer();
3907 for(mcIdType i=0;i<getNumberOfNodes();i++)
3909 std::transform(coo+i*3,coo+i*3+3,pt,tmp,std::minus<double>());
3910 std::transform(tmp,tmp+3,v,tmp,std::multiplies<double>());
3911 res[i]=std::accumulate(tmp,tmp+3,0.);
3916 * 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.
3917 * \a this is expected to be a mesh so that its space dimension is equal to its
3918 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
3919 * 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).
3921 * 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
3922 * 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).
3923 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
3925 * So this method is more accurate (so, more costly) than simply searching for the closest point in \a this.
3926 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
3928 * \param [in] ptBg the start pointer (included) of the coordinates of the point
3929 * \param [in] ptEnd the end pointer (not included) of the coordinates of the point
3930 * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
3931 * \return the positive value of the distance.
3932 * \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
3934 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoints
3936 double MEDCouplingUMesh::distanceToPoint(const double *ptBg, const double *ptEnd, mcIdType& cellId) const
3938 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
3939 if(meshDim!=spaceDim-1)
3940 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint works only for spaceDim=meshDim+1 !");
3941 if(meshDim!=2 && meshDim!=1)
3942 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint : only mesh dimension 2 and 1 are implemented !");
3943 checkFullyDefined();
3944 if(ToIdType(std::distance(ptBg,ptEnd))!=spaceDim)
3945 { 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()); }
3946 DataArrayIdType *ret1=0;
3947 MCAuto<DataArrayDouble> pts=DataArrayDouble::New(); pts->useArray(ptBg,false,DeallocType::C_DEALLOC,1,spaceDim);
3948 MCAuto<DataArrayDouble> ret0=distanceToPoints(pts,ret1);
3949 MCAuto<DataArrayIdType> ret1Safe(ret1);
3950 cellId=*ret1Safe->begin();
3951 return *ret0->begin();
3955 * This method computes the distance from each point of points serie \a pts (stored in a DataArrayDouble in which each tuple represents a point)
3956 * to \a this and the first \a cellId in \a this corresponding to the returned distance.
3957 * 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
3958 * 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).
3959 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
3961 * \a this is expected to be a mesh so that its space dimension is equal to its
3962 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
3963 * 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).
3965 * So this method is more accurate (so, more costly) than simply searching for each point in \a pts the closest point in \a this.
3966 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
3968 * \param [in] pts the list of points in which each tuple represents a point
3969 * \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.
3970 * \return a newly allocated object to be dealed by the caller that tells for each point in \a pts the distance to \a this.
3971 * \throw if number of components of \a pts is not equal to the space dimension.
3972 * \throw if mesh dimension of \a this is not equal to space dimension - 1.
3973 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoint
3975 DataArrayDouble *MEDCouplingUMesh::distanceToPoints(const DataArrayDouble *pts, DataArrayIdType *& cellIds) const
3978 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : input points pointer is NULL !");
3979 pts->checkAllocated();
3980 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
3981 if(meshDim!=spaceDim-1)
3982 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints works only for spaceDim=meshDim+1 !");
3983 if(meshDim!=2 && meshDim!=1)
3984 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only mesh dimension 2 and 1 are implemented !");
3985 if(ToIdType(pts->getNumberOfComponents())!=spaceDim)
3987 std::ostringstream oss; oss << "MEDCouplingUMesh::distanceToPoints : input pts DataArrayDouble has " << pts->getNumberOfComponents() << " components whereas it should be equal to " << spaceDim << " (mesh spaceDimension) !";
3988 throw INTERP_KERNEL::Exception(oss.str());
3990 checkFullyDefined();
3991 mcIdType nbCells=getNumberOfCells();
3993 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : no cells in this !");
3994 mcIdType nbOfPts=pts->getNumberOfTuples();
3995 MCAuto<DataArrayDouble> ret0=DataArrayDouble::New(); ret0->alloc(nbOfPts,1);
3996 MCAuto<DataArrayIdType> ret1=DataArrayIdType::New(); ret1->alloc(nbOfPts,1);
3997 const mcIdType *nc=_nodal_connec->begin(),*ncI=_nodal_connec_index->begin(); const double *coords=_coords->begin();
3998 double *ret0Ptr=ret0->getPointer(); mcIdType *ret1Ptr=ret1->getPointer(); const double *ptsPtr=pts->begin();
3999 MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree());
4000 const double *bbox(bboxArr->begin());
4005 BBTreeDst<3> myTree(bbox,0,0,nbCells);
4006 for(mcIdType i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=3)
4008 double x=std::numeric_limits<double>::max();
4009 std::vector<mcIdType> elems;
4010 myTree.getMinDistanceOfMax(ptsPtr,x);
4011 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4012 DistanceToPoint3DSurfAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4018 BBTreeDst<2> myTree(bbox,0,0,nbCells);
4019 for(mcIdType i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=2)
4021 double x=std::numeric_limits<double>::max();
4022 std::vector<mcIdType> elems;
4023 myTree.getMinDistanceOfMax(ptsPtr,x);
4024 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4025 DistanceToPoint2DCurveAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4030 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only spacedim 2 and 3 supported !");
4032 cellIds=ret1.retn();
4041 * Finds cells in contact with a ball (i.e. a point with precision).
4042 * 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.
4043 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4045 * \warning This method is suitable if the caller intends to evaluate only one
4046 * point, for more points getCellsContainingPoints() is recommended as it is
4048 * \param [in] pos - array of coordinates of the ball central point.
4049 * \param [in] eps - ball radius.
4050 * \return mcIdType - a smallest id of cells being in contact with the ball, -1 in case
4051 * if there are no such cells.
4052 * \throw If the coordinates array is not set.
4053 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4055 mcIdType MEDCouplingUMesh::getCellContainingPoint(const double *pos, double eps) const
4057 std::vector<mcIdType> elts;
4058 getCellsContainingPoint(pos,eps,elts);
4061 return elts.front();
4065 * Finds cells in contact with a ball (i.e. a point with precision).
4066 * 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.
4067 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4068 * \warning This method is suitable if the caller intends to evaluate only one
4069 * point, for more points getCellsContainingPoints() is recommended as it is
4071 * \param [in] pos - array of coordinates of the ball central point.
4072 * \param [in] eps - ball radius.
4073 * \param [out] elts - vector returning ids of the found cells. It is cleared
4074 * before inserting ids.
4075 * \throw If the coordinates array is not set.
4076 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4078 * \if ENABLE_EXAMPLES
4079 * \ref cpp_mcumesh_getCellsContainingPoint "Here is a C++ example".<br>
4080 * \ref py_mcumesh_getCellsContainingPoint "Here is a Python example".
4083 void MEDCouplingUMesh::getCellsContainingPoint(const double *pos, double eps, std::vector<mcIdType>& elts) const
4085 MCAuto<DataArrayIdType> eltsUg,eltsIndexUg;
4086 getCellsContainingPoints(pos,1,eps,eltsUg,eltsIndexUg);
4087 elts.clear(); elts.insert(elts.end(),eltsUg->begin(),eltsUg->end());
4090 void MEDCouplingUMesh::getCellsContainingPointsZeAlg(const double *pos, mcIdType nbOfPoints, double eps,
4091 MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex,
4092 std::function<bool(INTERP_KERNEL::NormalizedCellType,mcIdType)> sensibilityTo2DQuadraticLinearCellsFunc) const
4094 int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
4099 const double *coords=_coords->getConstPointer();
4100 getCellsContainingPointsAlg<3>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4103 throw INTERP_KERNEL::Exception("For spaceDim==3 only meshDim==3 implemented for getelementscontainingpoints !");
4105 else if(spaceDim==2)
4109 const double *coords=_coords->getConstPointer();
4110 getCellsContainingPointsAlg<2>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4113 throw INTERP_KERNEL::Exception("For spaceDim==2 only meshDim==2 implemented for getelementscontainingpoints !");
4115 else if(spaceDim==1)
4119 const double *coords=_coords->getConstPointer();
4120 getCellsContainingPointsAlg<1>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4123 throw INTERP_KERNEL::Exception("For spaceDim==1 only meshDim==1 implemented for getelementscontainingpoints !");
4126 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPoints : not managed for mdim not in [1,2,3] !");
4130 * Finds cells in contact with several balls (i.e. points with precision).
4131 * This method is an extension of getCellContainingPoint() and
4132 * getCellsContainingPoint() for the case of multiple points.
4133 * 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.
4134 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4135 * \param [in] pos - an array of coordinates of points in full interlace mode :
4136 * X0,Y0,Z0,X1,Y1,Z1,... Size of the array must be \a
4137 * this->getSpaceDimension() * \a nbOfPoints
4138 * \param [in] nbOfPoints - number of points to locate within \a this mesh.
4139 * \param [in] eps - radius of balls (i.e. the precision).
4140 * \param [out] elts - vector returning ids of found cells.
4141 * \param [out] eltsIndex - an array, of length \a nbOfPoints + 1,
4142 * dividing cell ids in \a elts into groups each referring to one
4143 * point. Its every element (except the last one) is an index pointing to the
4144 * first id of a group of cells. For example cells in contact with the *i*-th
4145 * point are described by following range of indices:
4146 * [ \a eltsIndex[ *i* ], \a eltsIndex[ *i*+1 ] ) and the cell ids are
4147 * \a elts[ \a eltsIndex[ *i* ]], \a elts[ \a eltsIndex[ *i* ] + 1 ], ...
4148 * Number of cells in contact with the *i*-th point is
4149 * \a eltsIndex[ *i*+1 ] - \a eltsIndex[ *i* ].
4150 * \throw If the coordinates array is not set.
4151 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4153 * \if ENABLE_EXAMPLES
4154 * \ref cpp_mcumesh_getCellsContainingPoints "Here is a C++ example".<br>
4155 * \ref py_mcumesh_getCellsContainingPoints "Here is a Python example".
4158 void MEDCouplingUMesh::getCellsContainingPoints(const double *pos, mcIdType nbOfPoints, double eps,
4159 MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex) const
4161 auto yesImSensibleTo2DQuadraticLinearCellsFunc([](INTERP_KERNEL::NormalizedCellType ct, int mdim) { return INTERP_KERNEL::CellModel::GetCellModel(ct).isQuadratic() && mdim == 2; } );
4162 this->getCellsContainingPointsZeAlg(pos,nbOfPoints,eps,elts,eltsIndex,yesImSensibleTo2DQuadraticLinearCellsFunc);
4166 * Behaves like MEDCouplingMesh::getCellsContainingPoints for cells in \a this that are linear.
4167 * For quadratic cells in \a this, this method behaves by just considering linear part of cells.
4168 * This method is here only for backward compatibility (interpolation GaussPoints to GaussPoints).
4170 * \sa MEDCouplingUMesh::getCellsContainingPoints, MEDCouplingRemapper::prepareNotInterpKernelOnlyGaussGauss
4172 void MEDCouplingUMesh::getCellsContainingPointsLinearPartOnlyOnNonDynType(const double *pos, mcIdType nbOfPoints, double eps, MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex) const
4174 auto noImNotSensibleTo2DQuadraticLinearCellsFunc([](INTERP_KERNEL::NormalizedCellType,mcIdType) { return false; } );
4175 this->getCellsContainingPointsZeAlg(pos,nbOfPoints,eps,elts,eltsIndex,noImNotSensibleTo2DQuadraticLinearCellsFunc);
4179 * Finds butterfly cells in \a this mesh. A 2D cell is considered to be butterfly if at
4180 * least two its edges intersect each other anywhere except their extremities. An
4181 * INTERP_KERNEL::NORM_NORI3 cell can \b not be butterfly.
4182 * \param [in,out] cells - a vector returning ids of the found cells. It is not
4183 * cleared before filling in.
4184 * \param [in] eps - precision.
4185 * \throw If \a this->getMeshDimension() != 2.
4186 * \throw If \a this->getSpaceDimension() != 2 && \a this->getSpaceDimension() != 3.
4188 void MEDCouplingUMesh::checkButterflyCells(std::vector<mcIdType>& cells, double eps) const
4190 const char msg[]="Butterfly detection work only for 2D cells with spaceDim==2 or 3!";
4191 if(getMeshDimension()!=2)
4192 throw INTERP_KERNEL::Exception(msg);
4193 int spaceDim=getSpaceDimension();
4194 if(spaceDim!=2 && spaceDim!=3)
4195 throw INTERP_KERNEL::Exception(msg);
4196 const mcIdType *conn=_nodal_connec->getConstPointer();
4197 const mcIdType *connI=_nodal_connec_index->getConstPointer();
4198 mcIdType nbOfCells=getNumberOfCells();
4199 std::vector<double> cell2DinS2;
4200 for(mcIdType i=0;i<nbOfCells;i++)
4202 mcIdType offset=connI[i];
4203 mcIdType nbOfNodesForCell=connI[i+1]-offset-1;
4204 if(nbOfNodesForCell<=3)
4206 bool isQuad=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[offset]).isQuadratic();
4207 project2DCellOnXY(conn+offset+1,conn+connI[i+1],cell2DinS2);
4208 if(isButterfly2DCell(cell2DinS2,isQuad,eps))
4215 * This method is typically requested to unbutterfly 2D linear cells in \b this.
4217 * 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.
4218 * 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.
4220 * For each 2D linear cell in \b this, this method builds the convex envelop (or the convex hull) of the current cell.
4221 * This convex envelop is computed using Jarvis march algorithm.
4222 * The coordinates and the number of cells of \b this remain unchanged on invocation of this method.
4223 * 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)
4224 * 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.
4226 * \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.
4227 * \sa MEDCouplingUMesh::colinearize2D
4229 DataArrayIdType *MEDCouplingUMesh::convexEnvelop2D()
4231 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
4232 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convexEnvelop2D works only for meshDim=2 and spaceDim=2 !");
4233 checkFullyDefined();
4234 const double *coords=getCoords()->getConstPointer();
4235 mcIdType nbOfCells=getNumberOfCells();
4236 MCAuto<DataArrayIdType> nodalConnecIndexOut=DataArrayIdType::New();
4237 nodalConnecIndexOut->alloc(nbOfCells+1,1);
4238 MCAuto<DataArrayIdType> nodalConnecOut(DataArrayIdType::New());
4239 mcIdType *workIndexOut=nodalConnecIndexOut->getPointer();
4241 const mcIdType *nodalConnecIn=_nodal_connec->getConstPointer();
4242 const mcIdType *nodalConnecIndexIn=_nodal_connec_index->getConstPointer();
4243 std::set<INTERP_KERNEL::NormalizedCellType> types;
4244 MCAuto<DataArrayIdType> isChanged(DataArrayIdType::New());
4245 isChanged->alloc(0,1);
4246 for(mcIdType i=0;i<nbOfCells;i++,workIndexOut++)
4248 mcIdType pos=nodalConnecOut->getNumberOfTuples();
4249 if(BuildConvexEnvelopOf2DCellJarvis(coords,nodalConnecIn+nodalConnecIndexIn[i],nodalConnecIn+nodalConnecIndexIn[i+1],nodalConnecOut))
4250 isChanged->pushBackSilent(i);
4251 types.insert((INTERP_KERNEL::NormalizedCellType)nodalConnecOut->getIJ(pos,0));
4252 workIndexOut[1]=nodalConnecOut->getNumberOfTuples();
4254 if(isChanged->empty())
4256 setConnectivity(nodalConnecOut,nodalConnecIndexOut,false);
4258 return isChanged.retn();
4262 * This method is \b NOT const because it can modify \a this.
4263 * \a this is expected to be an unstructured mesh with meshDim==2 and spaceDim==3. If not an exception will be thrown.
4264 * \param mesh1D is an unstructured mesh with MeshDim==1 and spaceDim==3. If not an exception will be thrown.
4265 * \param policy specifies the type of extrusion chosen:
4266 * - \b 0 for translation only (most simple): the cells of the 1D mesh represent the vectors along which the 2D mesh
4267 * will be repeated to build each level
4268 * - \b 1 for translation and rotation: the translation is done as above. For each level, an arc of circle is fitted on
4269 * 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
4270 * 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
4272 * \return an unstructured mesh with meshDim==3 and spaceDim==3. The returned mesh has the same coords than \a this.
4274 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMesh(const MEDCouplingUMesh *mesh1D, int policy)
4276 checkFullyDefined();
4277 mesh1D->checkFullyDefined();
4278 if(!mesh1D->isContiguous1D())
4279 throw INTERP_KERNEL::Exception("buildExtrudedMesh : 1D mesh passed in parameter is not contiguous !");
4280 if(getSpaceDimension()!=mesh1D->getSpaceDimension())
4281 throw INTERP_KERNEL::Exception("Invalid call to buildExtrudedMesh this and mesh1D must have same space dimension !");
4282 if((getMeshDimension()!=2 || getSpaceDimension()!=3) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
4283 throw INTERP_KERNEL::Exception("Invalid 'this' for buildExtrudedMesh method : must be (meshDim==2 and spaceDim==3) or (meshDim==1 and spaceDim==2) !");
4284 if(mesh1D->getMeshDimension()!=1)
4285 throw INTERP_KERNEL::Exception("Invalid 'mesh1D' for buildExtrudedMesh method : must be meshDim==1 !");
4287 if(isPresenceOfQuadratic())
4289 if(mesh1D->isFullyQuadratic())
4292 throw INTERP_KERNEL::Exception("Invalid 2D mesh and 1D mesh because 2D mesh has quadratic cells and 1D is not fully quadratic !");
4294 mcIdType oldNbOfNodes(getNumberOfNodes());
4295 MCAuto<DataArrayDouble> newCoords;
4300 newCoords=fillExtCoordsUsingTranslation(mesh1D,isQuad);
4305 newCoords=fillExtCoordsUsingTranslAndAutoRotation(mesh1D,isQuad);
4309 throw INTERP_KERNEL::Exception("Not implemented extrusion policy : must be in (0) !");
4311 setCoords(newCoords);
4312 MCAuto<MEDCouplingUMesh> ret(buildExtrudedMeshFromThisLowLev(oldNbOfNodes,isQuad));
4319 * Checks if \a this mesh is constituted by only quadratic cells.
4320 * \return bool - \c true if there are only quadratic cells in \a this mesh.
4321 * \throw If the coordinates array is not set.
4322 * \throw If the nodal connectivity of cells is not defined.
4324 bool MEDCouplingUMesh::isFullyQuadratic() const
4326 checkFullyDefined();
4328 mcIdType nbOfCells=getNumberOfCells();
4329 for(mcIdType i=0;i<nbOfCells && ret;i++)
4331 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4332 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4333 ret=cm.isQuadratic();
4339 * Checks if \a this mesh includes any quadratic cell.
4340 * \return bool - \c true if there is at least one quadratic cells in \a this mesh.
4341 * \throw If the coordinates array is not set.
4342 * \throw If the nodal connectivity of cells is not defined.
4344 bool MEDCouplingUMesh::isPresenceOfQuadratic() const
4346 checkFullyDefined();
4348 mcIdType nbOfCells=getNumberOfCells();
4349 for(mcIdType i=0;i<nbOfCells && !ret;i++)
4351 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4352 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4353 ret=cm.isQuadratic();
4359 * Converts all quadratic cells to linear ones. If there are no quadratic cells in \a
4360 * this mesh, it remains unchanged.
4361 * \throw If the coordinates array is not set.
4362 * \throw If the nodal connectivity of cells is not defined.
4364 void MEDCouplingUMesh::convertQuadraticCellsToLinear()
4366 checkFullyDefined();
4367 mcIdType nbOfCells=getNumberOfCells();
4369 const mcIdType *iciptr=_nodal_connec_index->begin();
4370 for(mcIdType i=0;i<nbOfCells;i++)
4372 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4373 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4374 if(cm.isQuadratic())
4376 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4377 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4378 if(!cml.isDynamic())
4379 delta+=cm.getNumberOfNodes()-cml.getNumberOfNodes();
4381 delta+=(iciptr[i+1]-iciptr[i]-1)/2;
4386 MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()),newConnI(DataArrayIdType::New());
4387 const mcIdType *icptr(_nodal_connec->begin());
4388 newConn->alloc(getNodalConnectivityArrayLen()-delta,1);
4389 newConnI->alloc(nbOfCells+1,1);
4390 mcIdType *ocptr(newConn->getPointer()),*ociptr(newConnI->getPointer());
4393 for(mcIdType i=0;i<nbOfCells;i++,ociptr++)
4395 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)icptr[iciptr[i]];
4396 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4397 if(!cm.isQuadratic())
4399 _types.insert(type);
4400 ocptr=std::copy(icptr+iciptr[i],icptr+iciptr[i+1],ocptr);
4401 ociptr[1]=ociptr[0]+iciptr[i+1]-iciptr[i];
4405 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4406 _types.insert(typel);
4407 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4408 mcIdType newNbOfNodes=cml.getNumberOfNodes();
4410 newNbOfNodes=(iciptr[i+1]-iciptr[i]-1)/2;
4411 *ocptr++=ToIdType(typel);
4412 ocptr=std::copy(icptr+iciptr[i]+1,icptr+iciptr[i]+newNbOfNodes+1,ocptr);
4413 ociptr[1]=ociptr[0]+newNbOfNodes+1;
4416 setConnectivity(newConn,newConnI,false);
4420 * This method converts all linear cell in \a this to quadratic one.
4421 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, here it is needed to specify the target
4422 * 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)
4423 * 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.
4424 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, the coordinates in \a this can be become bigger. All created nodes will be put at the
4425 * end of the existing coordinates.
4427 * \param [in] conversionType specifies the type of conversion expected. Only 0 (default) and 1 are supported presently. 0 those that creates the 'most' simple
4428 * corresponding quadratic cells. 1 is those creating the 'most' complex.
4429 * \return a newly created DataArrayIdType instance that the caller should deal with containing cell ids of converted cells.
4431 * \throw if \a this is not fully defined. It throws too if \a conversionType is not in [0,1].
4433 * \sa MEDCouplingUMesh::convertQuadraticCellsToLinear
4435 DataArrayIdType *MEDCouplingUMesh::convertLinearCellsToQuadratic(int conversionType)
4437 DataArrayIdType *conn=0,*connI=0;
4438 DataArrayDouble *coords=0;
4439 std::set<INTERP_KERNEL::NormalizedCellType> types;
4440 checkFullyDefined();
4441 MCAuto<DataArrayIdType> ret,connSafe,connISafe;
4442 MCAuto<DataArrayDouble> coordsSafe;
4443 int meshDim=getMeshDimension();
4444 switch(conversionType)
4450 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);
4451 connSafe=conn; connISafe=connI; coordsSafe=coords;
4454 ret=convertLinearCellsToQuadratic2D0(conn,connI,coords,types);
4455 connSafe=conn; connISafe=connI; coordsSafe=coords;
4458 ret=convertLinearCellsToQuadratic3D0(conn,connI,coords,types);
4459 connSafe=conn; connISafe=connI; coordsSafe=coords;
4462 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 0 mesh dimensions available are [1,2,3] !");
4470 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);//it is not a bug. In 1D policy 0 and 1 are equals
4471 connSafe=conn; connISafe=connI; coordsSafe=coords;
4474 ret=convertLinearCellsToQuadratic2D1(conn,connI,coords,types);
4475 connSafe=conn; connISafe=connI; coordsSafe=coords;
4478 ret=convertLinearCellsToQuadratic3D1(conn,connI,coords,types);
4479 connSafe=conn; connISafe=connI; coordsSafe=coords;
4482 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 1 mesh dimensions available are [1,2,3] !");
4487 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion type available are 0 (default, the simplest) and 1 (the most complex) !");
4489 setConnectivity(connSafe,connISafe,false);
4491 setCoords(coordsSafe);
4496 * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
4497 * so that the number of cells remains the same. Quadratic faces are converted to
4498 * polygons. This method works only for 2D meshes in
4499 * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
4500 * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
4501 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
4502 * \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
4503 * a polylinized edge constituting the input polygon.
4504 * \throw If the coordinates array is not set.
4505 * \throw If the nodal connectivity of cells is not defined.
4506 * \throw If \a this->getMeshDimension() != 2.
4507 * \throw If \a this->getSpaceDimension() != 2.
4509 void MEDCouplingUMesh::tessellate2D(double eps)
4511 int meshDim(getMeshDimension()),spaceDim(getSpaceDimension());
4513 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : works only with space dimension equal to 2 !");
4517 return tessellate2DCurveInternal(eps);
4519 return tessellate2DInternal(eps);
4521 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : mesh dimension must be in [1,2] !");
4527 * This method only works if \a this has spaceDimension equal to 2 and meshDimension also equal to 2.
4528 * This method allows to modify connectivity of cells in \a this that shares some edges in \a edgeIdsToBeSplit.
4529 * The nodes to be added in those 2D cells are defined by the pair of \a nodeIdsToAdd and \a nodeIdsIndexToAdd.
4530 * Length of \a nodeIdsIndexToAdd is expected to equal to length of \a edgeIdsToBeSplit + 1.
4531 * The node ids in \a nodeIdsToAdd should be valid. Those nodes have to be sorted exactly following exactly the direction of the edge.
4532 * This method can be seen as the opposite method of colinearize2D.
4533 * 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
4534 * to avoid to modify the numbering of existing nodes.
4536 * \param [in] nodeIdsToAdd - the list of node ids to be added (\a nodeIdsIndexToAdd array allows to walk on this array)
4537 * \param [in] nodeIdsIndexToAdd - the entry point of \a nodeIdsToAdd to point to the corresponding nodes to be added.
4538 * \param [in] mesh1Desc - 1st output of buildDescendingConnectivity2 on \a this.
4539 * \param [in] desc - 2nd output of buildDescendingConnectivity2 on \a this.
4540 * \param [in] descI - 3rd output of buildDescendingConnectivity2 on \a this.
4541 * \param [in] revDesc - 4th output of buildDescendingConnectivity2 on \a this.
4542 * \param [in] revDescI - 5th output of buildDescendingConnectivity2 on \a this.
4544 * \sa buildDescendingConnectivity2
4546 void MEDCouplingUMesh::splitSomeEdgesOf2DMesh(const DataArrayIdType *nodeIdsToAdd, const DataArrayIdType *nodeIdsIndexToAdd, const DataArrayIdType *edgeIdsToBeSplit,
4547 const MEDCouplingUMesh *mesh1Desc, const DataArrayIdType *desc, const DataArrayIdType *descI, const DataArrayIdType *revDesc, const DataArrayIdType *revDescI)
4549 if(!nodeIdsToAdd || !nodeIdsIndexToAdd || !edgeIdsToBeSplit || !mesh1Desc || !desc || !descI || !revDesc || !revDescI)
4550 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : input pointers must be not NULL !");
4551 nodeIdsToAdd->checkAllocated(); nodeIdsIndexToAdd->checkAllocated(); edgeIdsToBeSplit->checkAllocated(); desc->checkAllocated(); descI->checkAllocated(); revDesc->checkAllocated(); revDescI->checkAllocated();
4552 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
4553 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : this must have spacedim=meshdim=2 !");
4554 if(mesh1Desc->getSpaceDimension()!=2 || mesh1Desc->getMeshDimension()!=1)
4555 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : mesh1Desc must be the explosion of this with spaceDim=2 and meshDim = 1 !");
4556 //DataArrayIdType *out0(0),*outi0(0);
4557 //MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
4558 //MCAuto<DataArrayIdType> out0s(out0),outi0s(outi0);
4559 //out0s=out0s->buildUnique(); out0s->sort(true);
4565 * Divides every cell of \a this mesh into simplices (triangles in 2D and tetrahedra in 3D).
4566 * In addition, returns an array mapping new cells to old ones. <br>
4567 * This method typically increases the number of cells in \a this mesh
4568 * but the number of nodes remains \b unchanged.
4569 * That's why the 3D splitting policies
4570 * INTERP_KERNEL::GENERAL_24 and INTERP_KERNEL::GENERAL_48 are not available here.
4571 * \param [in] policy - specifies a pattern used for splitting.
4572 * The semantic of \a policy is:
4573 * - 0 - to split QUAD4 by cutting it along 0-2 diagonal (for 2D mesh only).
4574 * - 1 - to split QUAD4 by cutting it along 1-3 diagonal (for 2D mesh only).
4575 * - INTERP_KERNEL::PLANAR_FACE_5 - to split HEXA8 into 5 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4576 * - INTERP_KERNEL::PLANAR_FACE_6 - to split HEXA8 into 6 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4579 * \return DataArrayIdType * - a new instance of DataArrayIdType holding, for each new cell,
4580 * an id of old cell producing it. The caller is to delete this array using
4581 * decrRef() as it is no more needed.
4583 * \throw If \a policy is 0 or 1 and \a this->getMeshDimension() != 2.
4584 * \throw If \a policy is INTERP_KERNEL::PLANAR_FACE_5 or INTERP_KERNEL::PLANAR_FACE_6
4585 * and \a this->getMeshDimension() != 3.
4586 * \throw If \a policy is not one of the four discussed above.
4587 * \throw If the nodal connectivity of cells is not defined.
4588 * \sa MEDCouplingUMesh::tetrahedrize, MEDCoupling1SGTUMesh::sortHexa8EachOther
4590 DataArrayIdType *MEDCouplingUMesh::simplexize(int policy)
4595 return simplexizePol0();
4597 return simplexizePol1();
4598 case INTERP_KERNEL::PLANAR_FACE_5:
4599 return simplexizePlanarFace5();
4600 case INTERP_KERNEL::PLANAR_FACE_6:
4601 return simplexizePlanarFace6();
4603 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)");
4608 * Checks if \a this mesh is constituted by simplex cells only. Simplex cells are:
4609 * - 1D: INTERP_KERNEL::NORM_SEG2
4610 * - 2D: INTERP_KERNEL::NORM_TRI3
4611 * - 3D: INTERP_KERNEL::NORM_TETRA4.
4613 * This method is useful for users that need to use P1 field services as
4614 * MEDCouplingFieldDouble::getValueOn(), MEDCouplingField::buildMeasureField() etc.
4615 * All these methods need mesh support containing only simplex cells.
4616 * \return bool - \c true if there are only simplex cells in \a this mesh.
4617 * \throw If the coordinates array is not set.
4618 * \throw If the nodal connectivity of cells is not defined.
4619 * \throw If \a this->getMeshDimension() < 1.
4621 bool MEDCouplingUMesh::areOnlySimplexCells() const
4623 checkFullyDefined();
4624 int mdim=getMeshDimension();
4625 if(mdim<1 || mdim>3)
4626 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::areOnlySimplexCells : only available with meshes having a meshdim 1, 2 or 3 !");
4627 mcIdType nbCells=getNumberOfCells();
4628 const mcIdType *conn=_nodal_connec->begin();
4629 const mcIdType *connI=_nodal_connec_index->begin();
4630 for(mcIdType i=0;i<nbCells;i++)
4632 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4642 * Converts degenerated 2D or 3D linear cells of \a this mesh into cells of simpler
4643 * type. For example an INTERP_KERNEL::NORM_QUAD4 cell having only three unique nodes in
4644 * its connectivity is transformed into an INTERP_KERNEL::NORM_TRI3 cell.
4645 * Quadratic cells in 2D are also handled. In those cells edges where start=end=midpoint are removed.
4646 * This method does \b not perform geometrical checks and checks only nodal connectivity of cells,
4647 * so it can be useful to call mergeNodes() before calling this method.
4648 * \throw If \a this->getMeshDimension() <= 1.
4649 * \throw If the coordinates array is not set.
4650 * \throw If the nodal connectivity of cells is not defined.
4652 void MEDCouplingUMesh::convertDegeneratedCells()
4654 checkFullyDefined();
4655 if(getMeshDimension()<=1)
4656 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4657 mcIdType nbOfCells=getNumberOfCells();
4660 mcIdType initMeshLgth=getNodalConnectivityArrayLen();
4661 mcIdType *conn=_nodal_connec->getPointer();
4662 mcIdType *index=_nodal_connec_index->getPointer();
4663 mcIdType posOfCurCell=0;
4665 mcIdType lgthOfCurCell;
4666 for(mcIdType i=0;i<nbOfCells;i++)
4668 lgthOfCurCell=index[i+1]-posOfCurCell;
4669 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4671 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
4672 conn+newPos+1,newLgth);
4673 conn[newPos]=newType;
4675 posOfCurCell=index[i+1];
4678 if(newPos!=initMeshLgth)
4679 _nodal_connec->reAlloc(newPos);
4684 * Same as MEDCouplingUMesh::convertDegeneratedCells() plus deletion of the flat cells.
4685 * A cell is flat in the following cases:
4686 * - for a linear cell, all points in the connectivity are equal
4687 * - for a quadratic cell, either the above, or a quadratic polygon with two (linear) points and two
4688 * identical quadratic points
4689 * \return a new instance of DataArrayIdType holding ids of removed cells. The caller is to delete
4690 * this array using decrRef() as it is no more needed.
4692 DataArrayIdType *MEDCouplingUMesh::convertDegeneratedCellsAndRemoveFlatOnes()
4694 checkFullyDefined();
4695 if(getMeshDimension()<=1)
4696 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4697 mcIdType nbOfCells=getNumberOfCells();
4698 MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(0,1);
4701 mcIdType initMeshLgth=getNodalConnectivityArrayLen();
4702 mcIdType *conn=_nodal_connec->getPointer();
4703 mcIdType *index=_nodal_connec_index->getPointer();
4704 mcIdType posOfCurCell=0;
4706 mcIdType lgthOfCurCell, nbDelCells(0);
4707 for(mcIdType i=0;i<nbOfCells;i++)
4709 lgthOfCurCell=index[i+1]-posOfCurCell;
4710 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4712 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
4713 conn+newPos+1,newLgth);
4714 // Shall we delete the cell if it is completely degenerated:
4715 bool delCell=INTERP_KERNEL::CellSimplify::isFlatCell(conn, newPos, newLgth, newType);
4719 ret->pushBackSilent(i);
4721 else //if the cell is to be deleted, simply stay at the same place
4723 conn[newPos]=newType;
4726 posOfCurCell=index[i+1];
4727 index[i+1-nbDelCells]=newPos;
4729 if(newPos!=initMeshLgth)
4730 _nodal_connec->reAlloc(newPos);
4731 const mcIdType nCellDel=ret->getNumberOfTuples();
4733 _nodal_connec_index->reAlloc(nbOfCells-nCellDel+1);
4739 * This method remove null 1D cells from \a this. A 1D cell is considered null if start node is equal to end node.
4740 * Only connectivity is considered here.
4742 bool MEDCouplingUMesh::removeDegenerated1DCells()
4744 checkConnectivityFullyDefined();
4745 if(getMeshDimension()!=1)
4746 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::removeDegenerated1DCells works on umeshes with meshdim equals to 1 !");
4747 std::size_t nbCells(getNumberOfCells()),newSize(0),newSize2(0);
4748 const mcIdType *conn(getNodalConnectivity()->begin()),*conni(getNodalConnectivityIndex()->begin());
4750 for(std::size_t i=0;i<nbCells;i++)
4752 INTERP_KERNEL::NormalizedCellType ct((INTERP_KERNEL::NormalizedCellType)conn[conni[i]]);
4753 if(ct==INTERP_KERNEL::NORM_SEG2 || ct==INTERP_KERNEL::NORM_SEG3)
4755 if(conn[conni[i]+1]!=conn[conni[i]+2])
4758 newSize2+=conni[i+1]-conni[i];
4763 std::ostringstream oss; oss << "MEDCouplingUMesh::removeDegenerated1DCells : cell #" << i << " in this is not of type SEG2/SEG3 !";
4764 throw INTERP_KERNEL::Exception(oss.str());
4768 if(newSize==nbCells)//no cells has been removed -> do nothing
4770 MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()),newConnI(DataArrayIdType::New()); newConnI->alloc(newSize+1,1); newConn->alloc(newSize2,1);
4771 mcIdType *newConnPtr(newConn->getPointer()),*newConnIPtr(newConnI->getPointer()); newConnIPtr[0]=0;
4772 for(std::size_t i=0;i<nbCells;i++)
4774 if(conn[conni[i]+1]!=conn[conni[i]+2])
4776 newConnIPtr[1]=newConnIPtr[0]+conni[i+1]-conni[i];
4777 newConnPtr=std::copy(conn+conni[i],conn+conni[i+1],newConnPtr);
4781 setConnectivity(newConn,newConnI,true);
4786 * Finds incorrectly oriented cells of this 2D mesh in 3D space.
4787 * A cell is considered to be oriented correctly if an angle between its
4788 * normal vector and a given vector is less than \c PI / \c 2.
4789 * \param [in] vec - 3 components of the vector specifying the correct orientation of
4791 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
4793 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
4794 * is not cleared before filling in.
4795 * \throw If \a this->getMeshDimension() != 2.
4796 * \throw If \a this->getSpaceDimension() != 3.
4798 * \if ENABLE_EXAMPLES
4799 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
4800 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
4803 void MEDCouplingUMesh::are2DCellsNotCorrectlyOriented(const double *vec, bool polyOnly, std::vector<mcIdType>& cells) const
4805 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
4806 throw INTERP_KERNEL::Exception("Invalid mesh to apply are2DCellsNotCorrectlyOriented on it : must be meshDim==2 and spaceDim==3 !");
4807 mcIdType nbOfCells=getNumberOfCells();
4808 const mcIdType *conn=_nodal_connec->begin();
4809 const mcIdType *connI=_nodal_connec_index->begin();
4810 const double *coordsPtr=_coords->begin();
4811 for(mcIdType i=0;i<nbOfCells;i++)
4813 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4814 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
4816 bool isQuadratic=INTERP_KERNEL::CellModel::GetCellModel(type).isQuadratic();
4817 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4824 * Reverse connectivity of 2D cells whose orientation is not correct. A cell is
4825 * considered to be oriented correctly if an angle between its normal vector and a
4826 * given vector is less than \c PI / \c 2.
4827 * \param [in] vec - 3 components of the vector specifying the correct orientation of
4829 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
4831 * \throw If \a this->getMeshDimension() != 2.
4832 * \throw If \a this->getSpaceDimension() != 3.
4834 * \if ENABLE_EXAMPLES
4835 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
4836 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
4839 * \sa changeOrientationOfCells
4841 void MEDCouplingUMesh::orientCorrectly2DCells(const double *vec, bool polyOnly)
4843 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
4844 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectly2DCells on it : must be meshDim==2 and spaceDim==3 !");
4845 mcIdType nbOfCells=getNumberOfCells();
4846 mcIdType *conn(_nodal_connec->getPointer());
4847 const mcIdType *connI(_nodal_connec_index->begin());
4848 const double *coordsPtr(_coords->begin());
4849 bool isModified(false);
4850 for(mcIdType i=0;i<nbOfCells;i++)
4852 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4853 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
4855 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
4856 bool isQuadratic(cm.isQuadratic());
4857 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4860 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
4865 _nodal_connec->declareAsNew();
4870 * This method change the orientation of cells in \a this without any consideration of coordinates. Only connectivity is impacted.
4872 * \sa orientCorrectly2DCells
4874 void MEDCouplingUMesh::changeOrientationOfCells()
4876 int mdim(getMeshDimension());
4877 if(mdim!=2 && mdim!=1)
4878 throw INTERP_KERNEL::Exception("Invalid mesh to apply changeOrientationOfCells on it : must be meshDim==2 or meshDim==1 !");
4879 mcIdType nbOfCells=getNumberOfCells();
4880 mcIdType *conn(_nodal_connec->getPointer());
4881 const mcIdType *connI(_nodal_connec_index->begin());
4884 for(mcIdType i=0;i<nbOfCells;i++)
4886 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4887 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
4888 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
4893 for(mcIdType i=0;i<nbOfCells;i++)
4895 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4896 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
4897 cm.changeOrientationOf1D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
4903 * Finds incorrectly oriented polyhedral cells, i.e. polyhedrons having correctly
4904 * oriented facets. The normal vector of the facet should point out of the cell.
4905 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
4906 * is not cleared before filling in.
4907 * \throw If \a this->getMeshDimension() != 3.
4908 * \throw If \a this->getSpaceDimension() != 3.
4909 * \throw If the coordinates array is not set.
4910 * \throw If the nodal connectivity of cells is not defined.
4912 * \if ENABLE_EXAMPLES
4913 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
4914 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
4917 void MEDCouplingUMesh::arePolyhedronsNotCorrectlyOriented(std::vector<mcIdType>& cells) const
4919 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
4920 throw INTERP_KERNEL::Exception("Invalid mesh to apply arePolyhedronsNotCorrectlyOriented on it : must be meshDim==3 and spaceDim==3 !");
4921 mcIdType nbOfCells=getNumberOfCells();
4922 const mcIdType *conn=_nodal_connec->begin();
4923 const mcIdType *connI=_nodal_connec_index->begin();
4924 const double *coordsPtr=_coords->begin();
4925 for(mcIdType i=0;i<nbOfCells;i++)
4927 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4928 if(type==INTERP_KERNEL::NORM_POLYHED)
4930 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4937 * Tries to fix connectivity of polyhedra, so that normal vector of all facets to point
4939 * \throw If \a this->getMeshDimension() != 3.
4940 * \throw If \a this->getSpaceDimension() != 3.
4941 * \throw If the coordinates array is not set.
4942 * \throw If the nodal connectivity of cells is not defined.
4943 * \throw If the reparation fails.
4945 * \if ENABLE_EXAMPLES
4946 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
4947 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
4949 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
4951 void MEDCouplingUMesh::orientCorrectlyPolyhedrons()
4953 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
4954 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectlyPolyhedrons on it : must be meshDim==3 and spaceDim==3 !");
4955 mcIdType nbOfCells=getNumberOfCells();
4956 mcIdType *conn=_nodal_connec->getPointer();
4957 const mcIdType *connI=_nodal_connec_index->begin();
4958 const double *coordsPtr=_coords->begin();
4959 for(mcIdType i=0;i<nbOfCells;i++)
4961 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4962 if(type==INTERP_KERNEL::NORM_POLYHED)
4966 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4967 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
4969 catch(INTERP_KERNEL::Exception& e)
4971 std::ostringstream oss; oss << "Something wrong in polyhedron #" << i << " : " << e.what();
4972 throw INTERP_KERNEL::Exception(oss.str());
4980 * This method invert orientation of all cells in \a this.
4981 * After calling this method the absolute value of measure of cells in \a this are the same than before calling.
4982 * This method only operates on the connectivity so coordinates are not touched at all.
4984 void MEDCouplingUMesh::invertOrientationOfAllCells()
4986 checkConnectivityFullyDefined();
4987 std::set<INTERP_KERNEL::NormalizedCellType> gts(getAllGeoTypes());
4988 mcIdType *conn(_nodal_connec->getPointer());
4989 const mcIdType *conni(_nodal_connec_index->begin());
4990 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator gt=gts.begin();gt!=gts.end();gt++)
4992 INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::OrientationInverter> oi(INTERP_KERNEL::OrientationInverter::BuildInstanceFrom(*gt));
4993 MCAuto<DataArrayIdType> cwt(giveCellsWithType(*gt));
4994 for(const mcIdType *it=cwt->begin();it!=cwt->end();it++)
4995 oi->operate(conn+conni[*it]+1,conn+conni[*it+1]);
5001 * Finds and fixes incorrectly oriented linear extruded volumes (INTERP_KERNEL::NORM_HEXA8,
5002 * INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXGP12 etc) to respect the MED convention
5003 * according to which the first facet of the cell should be oriented to have the normal vector
5004 * pointing out of cell.
5005 * \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of fixed
5006 * cells. The caller is to delete this array using decrRef() as it is no more
5008 * \throw If \a this->getMeshDimension() != 3.
5009 * \throw If \a this->getSpaceDimension() != 3.
5010 * \throw If the coordinates array is not set.
5011 * \throw If the nodal connectivity of cells is not defined.
5013 * \if ENABLE_EXAMPLES
5014 * \ref cpp_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a C++ example".<br>
5015 * \ref py_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a Python example".
5017 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
5019 DataArrayIdType *MEDCouplingUMesh::findAndCorrectBadOriented3DExtrudedCells()
5021 const char msg[]="check3DCellsWellOriented detection works only for 3D cells !";
5022 if(getMeshDimension()!=3)
5023 throw INTERP_KERNEL::Exception(msg);
5024 int spaceDim=getSpaceDimension();
5026 throw INTERP_KERNEL::Exception(msg);
5028 mcIdType nbOfCells=getNumberOfCells();
5029 mcIdType *conn=_nodal_connec->getPointer();
5030 const mcIdType *connI=_nodal_connec_index->begin();
5031 const double *coo=getCoords()->begin();
5032 MCAuto<DataArrayIdType> cells(DataArrayIdType::New()); cells->alloc(0,1);
5033 for(mcIdType i=0;i<nbOfCells;i++)
5035 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5036 if(cm.isExtruded() && !cm.isDynamic() && !cm.isQuadratic())
5038 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coo))
5040 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
5041 cells->pushBackSilent(i);
5045 return cells.retn();
5049 * This method is a faster method to correct orientation of all 3D cells in \a this.
5050 * 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.
5051 * This method makes the hypothesis that \a this a coherent that is to say MEDCouplingUMesh::checkConsistency should throw no exception.
5053 * \return a newly allocated mcIdType array with one components containing cell ids renumbered to fit the convention of MED (MED file and MEDCoupling)
5054 * \sa MEDCouplingUMesh::orientCorrectlyPolyhedrons,
5056 DataArrayIdType *MEDCouplingUMesh::findAndCorrectBadOriented3DCells()
5058 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
5059 throw INTERP_KERNEL::Exception("Invalid mesh to apply findAndCorrectBadOriented3DCells on it : must be meshDim==3 and spaceDim==3 !");
5060 mcIdType nbOfCells=getNumberOfCells();
5061 mcIdType *conn=_nodal_connec->getPointer();
5062 const mcIdType *connI=_nodal_connec_index->begin();
5063 const double *coordsPtr=_coords->begin();
5064 MCAuto<DataArrayIdType> ret=DataArrayIdType::New(); ret->alloc(0,1);
5065 for(mcIdType i=0;i<nbOfCells;i++)
5067 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5070 case INTERP_KERNEL::NORM_TETRA4:
5072 if(!IsTetra4WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5074 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+3));
5075 ret->pushBackSilent(i);
5079 case INTERP_KERNEL::NORM_PYRA5:
5081 if(!IsPyra5WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5083 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+4));
5084 ret->pushBackSilent(i);
5088 case INTERP_KERNEL::NORM_PENTA6:
5089 case INTERP_KERNEL::NORM_HEXA8:
5090 case INTERP_KERNEL::NORM_HEXGP12:
5092 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5094 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
5095 ret->pushBackSilent(i);
5099 case INTERP_KERNEL::NORM_POLYHED:
5101 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5103 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
5104 ret->pushBackSilent(i);
5109 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 !");
5117 * This method has a sense for meshes with spaceDim==3 and meshDim==2.
5118 * If it is not the case an exception will be thrown.
5119 * This method is fast because the first cell of \a this is used to compute the plane.
5120 * \param vec output of size at least 3 used to store the normal vector (with norm equal to Area ) of searched plane.
5121 * \param pos output of size at least 3 used to store a point owned of searched plane.
5123 void MEDCouplingUMesh::getFastAveragePlaneOfThis(double *vec, double *pos) const
5125 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
5126 throw INTERP_KERNEL::Exception("Invalid mesh to apply getFastAveragePlaneOfThis on it : must be meshDim==2 and spaceDim==3 !");
5127 const mcIdType *conn=_nodal_connec->begin();
5128 const mcIdType *connI=_nodal_connec_index->begin();
5129 const double *coordsPtr=_coords->begin();
5130 INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(conn+1,connI[1]-connI[0]-1,coordsPtr,vec);
5131 std::copy(coordsPtr+3*conn[1],coordsPtr+3*conn[1]+3,pos);
5135 * Creates a new MEDCouplingFieldDouble holding Edge Ratio values of all
5136 * cells. Currently cells of the following types are treated:
5137 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5138 * For a cell of other type an exception is thrown.
5139 * Space dimension of a 2D mesh can be either 2 or 3.
5140 * The Edge Ratio of a cell \f$t\f$ is:
5141 * \f$\frac{|t|_\infty}{|t|_0}\f$,
5142 * where \f$|t|_\infty\f$ and \f$|t|_0\f$ respectively denote the greatest and
5143 * the smallest edge lengths of \f$t\f$.
5144 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5145 * cells and one time, lying on \a this mesh. The caller is to delete this
5146 * field using decrRef() as it is no more needed.
5147 * \throw If the coordinates array is not set.
5148 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5149 * \throw If the connectivity data array has more than one component.
5150 * \throw If the connectivity data array has a named component.
5151 * \throw If the connectivity index data array has more than one component.
5152 * \throw If the connectivity index data array has a named component.
5153 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
5154 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5155 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5157 MEDCouplingFieldDouble *MEDCouplingUMesh::getEdgeRatioField() const
5159 checkConsistencyLight();
5160 int spaceDim=getSpaceDimension();
5161 int meshDim=getMeshDimension();
5162 if(spaceDim!=2 && spaceDim!=3)
5163 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : SpaceDimension must be equal to 2 or 3 !");
5164 if(meshDim!=2 && meshDim!=3)
5165 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : MeshDimension must be equal to 2 or 3 !");
5166 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5168 mcIdType nbOfCells=getNumberOfCells();
5169 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5170 arr->alloc(nbOfCells,1);
5171 double *pt=arr->getPointer();
5172 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5173 const mcIdType *conn=_nodal_connec->begin();
5174 const mcIdType *connI=_nodal_connec_index->begin();
5175 const double *coo=_coords->begin();
5177 for(mcIdType i=0;i<nbOfCells;i++,pt++)
5179 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5182 case INTERP_KERNEL::NORM_TRI3:
5184 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5185 *pt=INTERP_KERNEL::triEdgeRatio(tmp);
5188 case INTERP_KERNEL::NORM_QUAD4:
5190 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5191 *pt=INTERP_KERNEL::quadEdgeRatio(tmp);
5194 case INTERP_KERNEL::NORM_TETRA4:
5196 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5197 *pt=INTERP_KERNEL::tetraEdgeRatio(tmp);
5201 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5203 conn+=connI[i+1]-connI[i];
5205 ret->setName("EdgeRatio");
5206 ret->synchronizeTimeWithSupport();
5211 * Creates a new MEDCouplingFieldDouble holding Aspect Ratio values of all
5212 * cells. Currently cells of the following types are treated:
5213 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5214 * For a cell of other type an exception is thrown.
5215 * Space dimension of a 2D mesh can be either 2 or 3.
5216 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5217 * cells and one time, lying on \a this mesh. The caller is to delete this
5218 * field using decrRef() as it is no more needed.
5219 * \throw If the coordinates array is not set.
5220 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5221 * \throw If the connectivity data array has more than one component.
5222 * \throw If the connectivity data array has a named component.
5223 * \throw If the connectivity index data array has more than one component.
5224 * \throw If the connectivity index data array has a named component.
5225 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
5226 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5227 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5229 MEDCouplingFieldDouble *MEDCouplingUMesh::getAspectRatioField() const
5231 checkConsistencyLight();
5232 int spaceDim=getSpaceDimension();
5233 int meshDim=getMeshDimension();
5234 if(spaceDim!=2 && spaceDim!=3)
5235 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : SpaceDimension must be equal to 2 or 3 !");
5236 if(meshDim!=2 && meshDim!=3)
5237 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : MeshDimension must be equal to 2 or 3 !");
5238 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5240 mcIdType nbOfCells=getNumberOfCells();
5241 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5242 arr->alloc(nbOfCells,1);
5243 double *pt=arr->getPointer();
5244 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5245 const mcIdType *conn=_nodal_connec->begin();
5246 const mcIdType *connI=_nodal_connec_index->begin();
5247 const double *coo=_coords->begin();
5249 for(mcIdType i=0;i<nbOfCells;i++,pt++)
5251 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5254 case INTERP_KERNEL::NORM_TRI3:
5256 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5257 *pt=INTERP_KERNEL::triAspectRatio(tmp);
5260 case INTERP_KERNEL::NORM_QUAD4:
5262 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5263 *pt=INTERP_KERNEL::quadAspectRatio(tmp);
5266 case INTERP_KERNEL::NORM_TETRA4:
5268 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5269 *pt=INTERP_KERNEL::tetraAspectRatio(tmp);
5273 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5275 conn+=connI[i+1]-connI[i];
5277 ret->setName("AspectRatio");
5278 ret->synchronizeTimeWithSupport();
5283 * Creates a new MEDCouplingFieldDouble holding Warping factor values of all
5284 * cells of \a this 2D mesh in 3D space. It is a measure of the "planarity" of 2D cell
5285 * in 3D space. Currently only cells of the following types are
5286 * treated: INTERP_KERNEL::NORM_QUAD4.
5287 * For a cell of other type an exception is thrown.
5288 * The warp field is computed as follows: let (a,b,c,d) be the points of the quad.
5290 * \f$t=\vec{da}\times\vec{ab}\f$,
5291 * \f$u=\vec{ab}\times\vec{bc}\f$
5292 * \f$v=\vec{bc}\times\vec{cd}\f$
5293 * \f$w=\vec{cd}\times\vec{da}\f$, the warp is defined as \f$W^3\f$ with
5295 * W=min(\frac{t}{|t|}\cdot\frac{v}{|v|}, \frac{u}{|u|}\cdot\frac{w}{|w|})
5297 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5298 * cells and one time, lying on \a this mesh. The caller is to delete this
5299 * field using decrRef() as it is no more needed.
5300 * \throw If the coordinates array is not set.
5301 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5302 * \throw If the connectivity data array has more than one component.
5303 * \throw If the connectivity data array has a named component.
5304 * \throw If the connectivity index data array has more than one component.
5305 * \throw If the connectivity index data array has a named component.
5306 * \throw If \a this->getMeshDimension() != 2.
5307 * \throw If \a this->getSpaceDimension() != 3.
5308 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5310 MEDCouplingFieldDouble *MEDCouplingUMesh::getWarpField() const
5312 checkConsistencyLight();
5313 int spaceDim=getSpaceDimension();
5314 int meshDim=getMeshDimension();
5316 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : SpaceDimension must be equal to 3 !");
5318 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : MeshDimension must be equal to 2 !");
5319 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5321 mcIdType nbOfCells=getNumberOfCells();
5322 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5323 arr->alloc(nbOfCells,1);
5324 double *pt=arr->getPointer();
5325 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5326 const mcIdType *conn=_nodal_connec->begin();
5327 const mcIdType *connI=_nodal_connec_index->begin();
5328 const double *coo=_coords->begin();
5330 for(mcIdType i=0;i<nbOfCells;i++,pt++)
5332 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5335 case INTERP_KERNEL::NORM_QUAD4:
5337 FillInCompact3DMode(3,4,conn+1,coo,tmp);
5338 *pt=INTERP_KERNEL::quadWarp(tmp);
5342 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : A cell with not manged type (NORM_QUAD4) has been detected !");
5344 conn+=connI[i+1]-connI[i];
5346 ret->setName("Warp");
5347 ret->synchronizeTimeWithSupport();
5353 * Creates a new MEDCouplingFieldDouble holding Skew factor values of all
5354 * cells of \a this 2D mesh in 3D space. Currently cells of the following types are
5355 * treated: INTERP_KERNEL::NORM_QUAD4.
5356 * The skew is computed as follow for a quad with points (a,b,c,d): let
5357 * \f$u=\vec{ab}+\vec{dc}\f$ and \f$v=\vec{ac}+\vec{bd}\f$
5358 * then the skew is computed as:
5360 * s=\frac{u}{|u|}\cdot\frac{v}{|v|}
5363 * For a cell of other type an exception is thrown.
5364 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5365 * cells and one time, lying on \a this mesh. The caller is to delete this
5366 * field using decrRef() as it is no more needed.
5367 * \throw If the coordinates array is not set.
5368 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5369 * \throw If the connectivity data array has more than one component.
5370 * \throw If the connectivity data array has a named component.
5371 * \throw If the connectivity index data array has more than one component.
5372 * \throw If the connectivity index data array has a named component.
5373 * \throw If \a this->getMeshDimension() != 2.
5374 * \throw If \a this->getSpaceDimension() != 3.
5375 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5377 MEDCouplingFieldDouble *MEDCouplingUMesh::getSkewField() const
5379 checkConsistencyLight();
5380 int spaceDim=getSpaceDimension();
5381 int meshDim=getMeshDimension();
5383 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : SpaceDimension must be equal to 3 !");
5385 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : MeshDimension must be equal to 2 !");
5386 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5388 mcIdType nbOfCells=getNumberOfCells();
5389 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5390 arr->alloc(nbOfCells,1);
5391 double *pt=arr->getPointer();
5392 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5393 const mcIdType *conn=_nodal_connec->begin();
5394 const mcIdType *connI=_nodal_connec_index->begin();
5395 const double *coo=_coords->begin();
5397 for(mcIdType i=0;i<nbOfCells;i++,pt++)
5399 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5402 case INTERP_KERNEL::NORM_QUAD4:
5404 FillInCompact3DMode(3,4,conn+1,coo,tmp);
5405 *pt=INTERP_KERNEL::quadSkew(tmp);
5409 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : A cell with not manged type (NORM_QUAD4) has been detected !");
5411 conn+=connI[i+1]-connI[i];
5413 ret->setName("Skew");
5414 ret->synchronizeTimeWithSupport();
5419 * 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.
5421 * \return a new instance of field containing the result. The returned instance has to be deallocated by the caller.
5423 * \sa getSkewField, getWarpField, getAspectRatioField, getEdgeRatioField
5425 MEDCouplingFieldDouble *MEDCouplingUMesh::computeDiameterField() const
5427 checkConsistencyLight();
5428 MCAuto<MEDCouplingFieldDouble> ret(MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME));
5430 std::set<INTERP_KERNEL::NormalizedCellType> types;
5431 ComputeAllTypesInternal(types,_nodal_connec,_nodal_connec_index);
5432 int spaceDim(getSpaceDimension());
5433 mcIdType nbCells(getNumberOfCells());
5434 MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
5435 arr->alloc(nbCells,1);
5436 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++)
5438 INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::DiameterCalculator> dc(INTERP_KERNEL::CellModel::GetCellModel(*it).buildInstanceOfDiameterCalulator(spaceDim));
5439 MCAuto<DataArrayIdType> cellIds(giveCellsWithType(*it));
5440 dc->computeForListOfCellIdsUMeshFrmt(cellIds->begin(),cellIds->end(),_nodal_connec_index->begin(),_nodal_connec->begin(),getCoords()->begin(),arr->getPointer());
5443 ret->setName("Diameter");
5448 * This method aggregate the bbox of each cell and put it into bbox parameter (xmin,xmax,ymin,ymax,zmin,zmax).
5450 * \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)
5451 * For all other cases this input parameter is ignored.
5452 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5454 * \throw If \a this is not fully set (coordinates and connectivity).
5455 * \throw If a cell in \a this has no valid nodeId.
5456 * \sa MEDCouplingUMesh::getBoundingBoxForBBTreeFast, MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5458 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree(double arcDetEps) const
5460 int mDim(getMeshDimension()),sDim(getSpaceDimension());
5461 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.
5462 return getBoundingBoxForBBTreeFast();
5463 if((mDim==2 && sDim==2) || (mDim==1 && sDim==2))
5465 bool presenceOfQuadratic(false);
5466 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=_types.begin();it!=_types.end();it++)
5468 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(*it));
5469 if(cm.isQuadratic())
5470 presenceOfQuadratic=true;
5472 if(!presenceOfQuadratic)
5473 return getBoundingBoxForBBTreeFast();
5474 if(mDim==2 && sDim==2)
5475 return getBoundingBoxForBBTree2DQuadratic(arcDetEps);
5477 return getBoundingBoxForBBTree1DQuadratic(arcDetEps);
5479 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) !");
5483 * This method aggregate the bbox of each cell only considering the nodes constituting each cell and put it into bbox parameter.
5484 * So meshes having quadratic cells the computed bounding boxes can be invalid !
5486 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5488 * \throw If \a this is not fully set (coordinates and connectivity).
5489 * \throw If a cell in \a this has no valid nodeId.
5491 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTreeFast() const
5493 checkFullyDefined();
5494 int spaceDim(getSpaceDimension());
5495 mcIdType nbOfCells(getNumberOfCells()), nbOfNodes(getNumberOfNodes());
5496 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5497 double *bbox(ret->getPointer());
5498 for(mcIdType i=0;i<nbOfCells*spaceDim;i++)
5500 bbox[2*i]=std::numeric_limits<double>::max();
5501 bbox[2*i+1]=-std::numeric_limits<double>::max();
5503 const double *coordsPtr(_coords->begin());
5504 const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5505 for(mcIdType i=0;i<nbOfCells;i++)
5507 mcIdType offset=connI[i]+1;
5508 mcIdType nbOfNodesForCell(connI[i+1]-offset),kk(0);
5509 for(mcIdType j=0;j<nbOfNodesForCell;j++)
5511 mcIdType nodeId=conn[offset+j];
5512 if(nodeId>=0 && nodeId<nbOfNodes)
5514 for(int k=0;k<spaceDim;k++)
5516 bbox[2*spaceDim*i+2*k]=std::min(bbox[2*spaceDim*i+2*k],coordsPtr[spaceDim*nodeId+k]);
5517 bbox[2*spaceDim*i+2*k+1]=std::max(bbox[2*spaceDim*i+2*k+1],coordsPtr[spaceDim*nodeId+k]);
5524 std::ostringstream oss; oss << "MEDCouplingUMesh::getBoundingBoxForBBTree : cell #" << i << " contains no valid nodeId !";
5525 throw INTERP_KERNEL::Exception(oss.str());
5532 * This method aggregates the bbox of each 2D cell in \a this considering the whole shape. This method is particularly
5533 * useful for 2D meshes having quadratic cells
5534 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5535 * the two extremities of the arc of circle).
5537 * \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)
5538 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5539 * \throw If \a this is not fully defined.
5540 * \throw If \a this is not a mesh with meshDimension equal to 2.
5541 * \throw If \a this is not a mesh with spaceDimension equal to 2.
5542 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic
5544 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic(double arcDetEps) const
5546 checkFullyDefined();
5547 INTERP_KERNEL::QuadraticPlanarPrecision arcPrec(arcDetEps);
5549 int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
5550 mcIdType nbOfCells=getNumberOfCells();
5551 if(spaceDim!=2 || mDim!=2)
5552 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!");
5553 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5554 double *bbox(ret->getPointer());
5555 const double *coords(_coords->begin());
5556 const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5557 for(mcIdType i=0;i<nbOfCells;i++,bbox+=4,connI++)
5559 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5560 mcIdType sz(connI[1]-connI[0]-1);
5561 std::vector<INTERP_KERNEL::Node *> nodes(sz);
5562 INTERP_KERNEL::QuadraticPolygon *pol(0);
5563 for(mcIdType j=0;j<sz;j++)
5565 mcIdType nodeId(conn[*connI+1+j]);
5566 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5568 if(!cm.isQuadratic())
5569 pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
5571 pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
5572 INTERP_KERNEL::Bounds b; b.prepareForAggregation(); pol->fillBounds(b); delete pol;
5573 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax();
5579 * This method aggregates the bbox of each 1D cell in \a this considering the whole shape. This method is particularly
5580 * useful for 2D meshes having quadratic cells
5581 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5582 * the two extremities of the arc of circle).
5584 * \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)
5585 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5586 * \throw If \a this is not fully defined.
5587 * \throw If \a this is not a mesh with meshDimension equal to 1.
5588 * \throw If \a this is not a mesh with spaceDimension equal to 2.
5589 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5591 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic(double arcDetEps) const
5593 checkFullyDefined();
5594 int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
5595 mcIdType nbOfCells=getNumberOfCells();
5596 if(spaceDim!=2 || mDim!=1)
5597 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!");
5598 INTERP_KERNEL::QuadraticPlanarPrecision arcPrec(arcDetEps);
5599 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5600 double *bbox(ret->getPointer());
5601 const double *coords(_coords->begin());
5602 const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5603 for(mcIdType i=0;i<nbOfCells;i++,bbox+=4,connI++)
5605 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5606 mcIdType sz(connI[1]-connI[0]-1);
5607 std::vector<INTERP_KERNEL::Node *> nodes(sz);
5608 INTERP_KERNEL::Edge *edge(0);
5609 for(mcIdType j=0;j<sz;j++)
5611 mcIdType nodeId(conn[*connI+1+j]);
5612 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5614 if(!cm.isQuadratic())
5615 edge=INTERP_KERNEL::QuadraticPolygon::BuildLinearEdge(nodes);
5617 edge=INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(nodes);
5618 const INTERP_KERNEL::Bounds& b(edge->getBounds());
5619 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax(); edge->decrRef();
5626 namespace MEDCouplingImpl
5631 ConnReader(const mcIdType *c, mcIdType val):_conn(c),_val(val) { }
5632 bool operator() (const mcIdType& pos) { return _conn[pos]!=_val; }
5634 const mcIdType *_conn;
5641 ConnReader2(const mcIdType *c, mcIdType val):_conn(c),_val(val) { }
5642 bool operator() (const mcIdType& pos) { return _conn[pos]==_val; }
5644 const mcIdType *_conn;
5652 * This method expects that \a this is sorted by types. If not an exception will be thrown.
5653 * This method returns in the same format as code (see MEDCouplingUMesh::checkTypeConsistencyAndContig or MEDCouplingUMesh::splitProfilePerType) how
5654 * \a this is composed in cell types.
5655 * The returned array is of size 3*n where n is the number of different types present in \a this.
5656 * For every k in [0,n] ret[3*k+2]==-1 because it has no sense here.
5657 * This parameter is kept only for compatibility with other method listed above.
5659 std::vector<mcIdType> MEDCouplingUMesh::getDistributionOfTypes() const
5661 checkConnectivityFullyDefined();
5662 const mcIdType *conn=_nodal_connec->begin();
5663 const mcIdType *connI=_nodal_connec_index->begin();
5664 const mcIdType *work=connI;
5665 mcIdType nbOfCells=getNumberOfCells();
5666 std::size_t n=getAllGeoTypes().size();
5667 std::vector<mcIdType> ret(3*n,-1); //ret[3*k+2]==-1 because it has no sense here
5668 std::set<INTERP_KERNEL::NormalizedCellType> types;
5669 for(std::size_t i=0;work!=connI+nbOfCells;i++)
5671 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn[*work];
5672 if(types.find(typ)!=types.end())
5674 std::ostringstream oss; oss << "MEDCouplingUMesh::getDistributionOfTypes : Type " << INTERP_KERNEL::CellModel::GetCellModel(typ).getRepr();
5675 oss << " is not contiguous !";
5676 throw INTERP_KERNEL::Exception(oss.str());
5680 const mcIdType *work2=std::find_if(work+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,typ));
5681 ret[3*i+1]=ToIdType(std::distance(work,work2));
5688 * This method is used to check that this has contiguous cell type in same order than described in \a code.
5689 * only for types cell, type node is not managed.
5690 * Format of \a code is the following. \a code should be of size 3*n and non empty. If not an exception is thrown.
5691 * foreach k in [0,n) on 3*k pos represent the geometric type and 3*k+1 number of elements of type 3*k.
5692 * 3*k+2 refers if different from -1 the pos in 'idsPerType' to get the corresponding array.
5693 * If 2 or more same geometric type is in \a code and exception is thrown too.
5695 * This method firstly checks
5696 * If it exists k so that 3*k geometric type is not in geometric types of this an exception will be thrown.
5697 * If it exists k so that 3*k geometric type exists but the number of consecutive cell types does not match,
5698 * an exception is thrown too.
5700 * If all geometric types in \a code are exactly those in \a this null pointer is returned.
5701 * If it exists a geometric type in \a this \b not in \a code \b no exception is thrown
5702 * and a DataArrayIdType instance is returned that the user has the responsibility to deallocate.
5704 DataArrayIdType *MEDCouplingUMesh::checkTypeConsistencyAndContig(const std::vector<mcIdType>& code, const std::vector<const DataArrayIdType *>& idsPerType) const
5707 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code is empty, should not !");
5708 std::size_t sz=code.size();
5711 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code size is NOT %3 !");
5712 std::vector<INTERP_KERNEL::NormalizedCellType> types;
5714 bool isNoPflUsed=true;
5715 for(std::size_t i=0;i<n;i++)
5716 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)code[3*i])==types.end())
5718 types.push_back((INTERP_KERNEL::NormalizedCellType)code[3*i]);
5720 if(_types.find((INTERP_KERNEL::NormalizedCellType)code[3*i])==_types.end())
5721 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : expected geo types not in this !");
5722 isNoPflUsed=isNoPflUsed && (code[3*i+2]==-1);
5725 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code contains duplication of types in unstructured mesh !");
5728 if(!checkConsecutiveCellTypesAndOrder(&types[0],&types[0]+types.size()))
5729 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : non contiguous type !");
5730 if(types.size()==_types.size())
5733 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
5735 mcIdType *retPtr=ret->getPointer();
5736 const mcIdType *connI=_nodal_connec_index->begin();
5737 const mcIdType *conn=_nodal_connec->begin();
5738 mcIdType nbOfCells=getNumberOfCells();
5739 const mcIdType *i=connI;
5741 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++,kk++)
5743 i=std::find_if(i,connI+nbOfCells,MEDCouplingImpl::ConnReader2(conn,ToIdType((*it))));
5744 mcIdType offset=ToIdType(std::distance(connI,i));
5745 const mcIdType *j=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType((*it))));
5746 mcIdType nbOfCellsOfCurType=ToIdType(std::distance(i,j));
5747 if(code[3*kk+2]==-1)
5748 for(mcIdType k=0;k<nbOfCellsOfCurType;k++)
5752 mcIdType idInIdsPerType=code[3*kk+2];
5753 if(idInIdsPerType>=0 && idInIdsPerType<ToIdType(idsPerType.size()))
5755 const DataArrayIdType *zePfl=idsPerType[idInIdsPerType];
5758 zePfl->checkAllocated();
5759 if(zePfl->getNumberOfComponents()==1)
5761 for(const mcIdType *k=zePfl->begin();k!=zePfl->end();k++,retPtr++)
5763 if(*k>=0 && *k<nbOfCellsOfCurType)
5764 *retPtr=(*k)+offset;
5767 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : the section " << kk << " points to the profile #" << idInIdsPerType;
5768 oss << ", and this profile contains a value " << *k << " should be in [0," << nbOfCellsOfCurType << ") !";
5769 throw INTERP_KERNEL::Exception(oss.str());
5774 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of a profile with nb of compo != 1 !");
5777 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of null profile !");
5781 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : at section " << kk << " of code it points to the array #" << idInIdsPerType;
5782 oss << " should be in [0," << idsPerType.size() << ") !";
5783 throw INTERP_KERNEL::Exception(oss.str());
5792 * This method makes the hypothesis that \a this is sorted by type. If not an exception will be thrown.
5793 * 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.
5794 * 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.
5795 * This method has 1 input \a profile and 3 outputs \a code \a idsInPflPerType and \a idsPerType.
5797 * \param [in] profile
5798 * \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.
5799 * \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,
5800 * \a idsInPflPerType[i] stores the tuple ids in \a profile that correspond to the geometric type code[3*i+0]
5801 * \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.
5802 * This vector can be empty in case of all geometric type cells are fully covered in ascending in the given input \a profile.
5803 * \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
5805 void MEDCouplingUMesh::splitProfilePerType(const DataArrayIdType *profile, std::vector<mcIdType>& code, std::vector<DataArrayIdType *>& idsInPflPerType, std::vector<DataArrayIdType *>& idsPerType, bool smartPflKiller) const
5808 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile is NULL !");
5809 if(profile->getNumberOfComponents()!=1)
5810 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile should have exactly one component !");
5811 checkConnectivityFullyDefined();
5812 const mcIdType *conn=_nodal_connec->begin();
5813 const mcIdType *connI=_nodal_connec_index->begin();
5814 mcIdType nbOfCells=getNumberOfCells();
5815 std::vector<INTERP_KERNEL::NormalizedCellType> types;
5816 std::vector<mcIdType> typeRangeVals(1);
5817 for(const mcIdType *i=connI;i!=connI+nbOfCells;)
5819 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5820 if(std::find(types.begin(),types.end(),curType)!=types.end())
5822 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : current mesh is not sorted by type !");
5824 types.push_back(curType);
5825 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
5826 typeRangeVals.push_back(ToIdType(std::distance(connI,i)));
5829 DataArrayIdType *castArr=0,*rankInsideCast=0,*castsPresent=0;
5830 profile->splitByValueRange(&typeRangeVals[0],&typeRangeVals[0]+typeRangeVals.size(),castArr,rankInsideCast,castsPresent);
5831 MCAuto<DataArrayIdType> tmp0=castArr;
5832 MCAuto<DataArrayIdType> tmp1=rankInsideCast;
5833 MCAuto<DataArrayIdType> tmp2=castsPresent;
5835 mcIdType nbOfCastsFinal=castsPresent->getNumberOfTuples();
5836 code.resize(3*nbOfCastsFinal);
5837 std::vector< MCAuto<DataArrayIdType> > idsInPflPerType2;
5838 std::vector< MCAuto<DataArrayIdType> > idsPerType2;
5839 for(mcIdType i=0;i<nbOfCastsFinal;i++)
5841 mcIdType castId=castsPresent->getIJ(i,0);
5842 MCAuto<DataArrayIdType> tmp3=castArr->findIdsEqual(castId);
5843 idsInPflPerType2.push_back(tmp3);
5844 code[3*i]=ToIdType(types[castId]);
5845 code[3*i+1]=tmp3->getNumberOfTuples();
5846 MCAuto<DataArrayIdType> tmp4=rankInsideCast->selectByTupleId(tmp3->begin(),tmp3->begin()+tmp3->getNumberOfTuples());
5847 if(!smartPflKiller || !tmp4->isIota(typeRangeVals[castId+1]-typeRangeVals[castId]))
5849 tmp4->copyStringInfoFrom(*profile);
5850 idsPerType2.push_back(tmp4);
5851 code[3*i+2]=ToIdType(idsPerType2.size())-1;
5858 std::size_t sz2=idsInPflPerType2.size();
5859 idsInPflPerType.resize(sz2);
5860 for(std::size_t i=0;i<sz2;i++)
5862 DataArrayIdType *locDa=idsInPflPerType2[i];
5864 idsInPflPerType[i]=locDa;
5866 std::size_t sz=idsPerType2.size();
5867 idsPerType.resize(sz);
5868 for(std::size_t i=0;i<sz;i++)
5870 DataArrayIdType *locDa=idsPerType2[i];
5872 idsPerType[i]=locDa;
5877 * This method is here too emulate the MEDMEM behaviour on BDC (buildDescendingConnectivity). Hoping this method becomes deprecated very soon.
5878 * This method make the assumption that \a this and 'nM1LevMesh' mesh lyies on same coords (same pointer) as MED and MEDMEM does.
5879 * The following equality should be verified 'nM1LevMesh->getMeshDimension()==this->getMeshDimension()-1'
5880 * 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.
5882 MEDCouplingUMesh *MEDCouplingUMesh::emulateMEDMEMBDC(const MEDCouplingUMesh *nM1LevMesh, DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *&revDesc, DataArrayIdType *&revDescIndx, DataArrayIdType *& nM1LevMeshIds, DataArrayIdType *&meshnM1Old2New) const
5884 checkFullyDefined();
5885 nM1LevMesh->checkFullyDefined();
5886 if(getMeshDimension()-1!=nM1LevMesh->getMeshDimension())
5887 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : The mesh passed as first argument should have a meshDim equal to this->getMeshDimension()-1 !" );
5888 if(_coords!=nM1LevMesh->getCoords())
5889 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : 'this' and mesh in first argument should share the same coords : Use tryToShareSameCoords method !");
5890 MCAuto<DataArrayIdType> tmp0=DataArrayIdType::New();
5891 MCAuto<DataArrayIdType> tmp1=DataArrayIdType::New();
5892 MCAuto<MEDCouplingUMesh> ret1=buildDescendingConnectivity(desc,descIndx,tmp0,tmp1);
5893 MCAuto<DataArrayIdType> ret0=ret1->sortCellsInMEDFileFrmt();
5894 desc->transformWithIndArr(ret0->begin(),ret0->begin()+ret0->getNbOfElems());
5895 MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
5896 tmp->setConnectivity(tmp0,tmp1);
5897 tmp->renumberCells(ret0->begin(),false);
5898 revDesc=tmp->getNodalConnectivity();
5899 revDescIndx=tmp->getNodalConnectivityIndex();
5900 DataArrayIdType *ret=0;
5901 if(!ret1->areCellsIncludedIn(nM1LevMesh,2,ret))
5904 ret->getMaxValue(tmp2);
5906 std::ostringstream oss; oss << "MEDCouplingUMesh::emulateMEDMEMBDC : input N-1 mesh present a cell not in descending mesh ... Id of cell is " << tmp2 << " !";
5907 throw INTERP_KERNEL::Exception(oss.str());
5912 revDescIndx->incrRef();
5915 meshnM1Old2New=ret0;
5920 * Permutes the nodal connectivity arrays so that the cells are sorted by type, which is
5921 * necessary for writing the mesh to MED file. Additionally returns a permutation array
5922 * in "Old to New" mode.
5923 * \return DataArrayIdType * - a new instance of DataArrayIdType. The caller is to delete
5924 * this array using decrRef() as it is no more needed.
5925 * \throw If the nodal connectivity of cells is not defined.
5927 DataArrayIdType *MEDCouplingUMesh::sortCellsInMEDFileFrmt()
5929 checkConnectivityFullyDefined();
5930 MCAuto<DataArrayIdType> ret=getRenumArrForMEDFileFrmt();
5931 renumberCells(ret->begin(),false);
5936 * This methods checks that cells are sorted by their types.
5937 * This method makes asumption (no check) that connectivity is correctly set before calling.
5939 bool MEDCouplingUMesh::checkConsecutiveCellTypes() const
5941 checkFullyDefined();
5942 const mcIdType *conn=_nodal_connec->begin();
5943 const mcIdType *connI=_nodal_connec_index->begin();
5944 mcIdType nbOfCells=getNumberOfCells();
5945 std::set<INTERP_KERNEL::NormalizedCellType> types;
5946 for(const mcIdType *i=connI;i!=connI+nbOfCells;)
5948 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5949 if(types.find(curType)!=types.end())
5951 types.insert(curType);
5952 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
5958 * This method is a specialization of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method that is called here.
5959 * The geometric type order is specified by MED file.
5961 * \sa MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder
5963 bool MEDCouplingUMesh::checkConsecutiveCellTypesForMEDFileFrmt() const
5965 return checkConsecutiveCellTypesAndOrder(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
5969 * This method performs the same job as checkConsecutiveCellTypes except that the order of types sequence is analyzed to check
5970 * that the order is specified in array defined by [ \a orderBg , \a orderEnd ).
5971 * If there is some geo types in \a this \b NOT in [ \a orderBg, \a orderEnd ) it is OK (return true) if contiguous.
5972 * If there is some geo types in [ \a orderBg, \a orderEnd ) \b NOT in \a this it is OK too (return true) if contiguous.
5974 bool MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
5976 checkFullyDefined();
5977 const mcIdType *conn=_nodal_connec->begin();
5978 const mcIdType *connI=_nodal_connec_index->begin();
5979 mcIdType nbOfCells=getNumberOfCells();
5982 mcIdType lastPos=-1;
5983 std::set<INTERP_KERNEL::NormalizedCellType> sg;
5984 for(const mcIdType *i=connI;i!=connI+nbOfCells;)
5986 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5987 const INTERP_KERNEL::NormalizedCellType *isTypeExists=std::find(orderBg,orderEnd,curType);
5988 if(isTypeExists!=orderEnd)
5990 mcIdType pos=ToIdType(std::distance(orderBg,isTypeExists));
5994 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
5998 if(sg.find(curType)==sg.end())
6000 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6011 * This method returns 2 newly allocated DataArrayIdType instances. The first is an array of size 'this->getNumberOfCells()' with one component,
6012 * 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
6013 * 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'.
6015 DataArrayIdType *MEDCouplingUMesh::getLevArrPerCellTypes(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd, DataArrayIdType *&nbPerType) const
6017 checkConnectivityFullyDefined();
6018 mcIdType nbOfCells=getNumberOfCells();
6019 const mcIdType *conn=_nodal_connec->begin();
6020 const mcIdType *connI=_nodal_connec_index->begin();
6021 MCAuto<DataArrayIdType> tmpa=DataArrayIdType::New();
6022 MCAuto<DataArrayIdType> tmpb=DataArrayIdType::New();
6023 tmpa->alloc(nbOfCells,1);
6024 tmpb->alloc(std::distance(orderBg,orderEnd),1);
6025 tmpb->fillWithZero();
6026 mcIdType *tmp=tmpa->getPointer();
6027 mcIdType *tmp2=tmpb->getPointer();
6028 for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6030 const INTERP_KERNEL::NormalizedCellType *where=std::find(orderBg,orderEnd,(INTERP_KERNEL::NormalizedCellType)conn[*i]);
6033 mcIdType pos=ToIdType(std::distance(orderBg,where));
6035 tmp[std::distance(connI,i)]=pos;
6039 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*i]);
6040 std::ostringstream oss; oss << "MEDCouplingUMesh::getLevArrPerCellTypes : Cell #" << std::distance(connI,i);
6041 oss << " has a type " << cm.getRepr() << " not in input array of type !";
6042 throw INTERP_KERNEL::Exception(oss.str());
6045 nbPerType=tmpb.retn();
6050 * This method behaves exactly as MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec but the order is those defined in MED file spec.
6052 * \return a new object containing the old to new correspondence.
6054 * \sa MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec, MEDCouplingUMesh::sortCellsInMEDFileFrmt.
6056 DataArrayIdType *MEDCouplingUMesh::getRenumArrForMEDFileFrmt() const
6058 return getRenumArrForConsecutiveCellTypesSpec(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
6062 * 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.
6063 * This method returns an array of size getNumberOfCells() that gives a renumber array old2New that can be used as input of MEDCouplingMesh::renumberCells.
6064 * The mesh after this call to MEDCouplingMesh::renumberCells will pass the test of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder with the same inputs.
6065 * The returned array minimizes the permutations that is to say the order of cells inside same geometric type remains the same.
6067 DataArrayIdType *MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
6069 DataArrayIdType *nbPerType=0;
6070 MCAuto<DataArrayIdType> tmpa=getLevArrPerCellTypes(orderBg,orderEnd,nbPerType);
6071 nbPerType->decrRef();
6072 return tmpa->buildPermArrPerLevel();
6076 * This method reorganize the cells of \a this so that the cells with same geometric types are put together.
6077 * The number of cells remains unchanged after the call of this method.
6078 * This method tries to minimizes the number of needed permutations. So, this method behaves not exactly as
6079 * MEDCouplingUMesh::sortCellsInMEDFileFrmt.
6081 * \return the array giving the correspondence old to new.
6083 DataArrayIdType *MEDCouplingUMesh::rearrange2ConsecutiveCellTypes()
6085 checkFullyDefined();
6087 const mcIdType *conn=_nodal_connec->begin();
6088 const mcIdType *connI=_nodal_connec_index->begin();
6089 mcIdType nbOfCells=getNumberOfCells();
6090 std::vector<INTERP_KERNEL::NormalizedCellType> types;
6091 for(const mcIdType *i=connI;i!=connI+nbOfCells && (types.size()!=_types.size());)
6092 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)conn[*i])==types.end())
6094 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6095 types.push_back(curType);
6096 for(i++;i!=connI+nbOfCells && (INTERP_KERNEL::NormalizedCellType)conn[*i]==curType;i++);
6098 DataArrayIdType *ret=DataArrayIdType::New();
6099 ret->alloc(nbOfCells,1);
6100 mcIdType *retPtr=ret->getPointer();
6101 std::fill(retPtr,retPtr+nbOfCells,-1);
6102 mcIdType newCellId=0;
6103 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
6105 for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6106 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
6107 retPtr[std::distance(connI,i)]=newCellId++;
6109 renumberCells(retPtr,false);
6114 * This method splits \a this into as mush as untructured meshes that consecutive set of same type cells.
6115 * So this method has typically a sense if MEDCouplingUMesh::checkConsecutiveCellTypes has a sense.
6116 * This method makes asumption that connectivity is correctly set before calling.
6118 std::vector<MEDCouplingUMesh *> MEDCouplingUMesh::splitByType() const
6120 checkConnectivityFullyDefined();
6121 const mcIdType *conn=_nodal_connec->begin();
6122 const mcIdType *connI=_nodal_connec_index->begin();
6123 mcIdType nbOfCells=getNumberOfCells();
6124 std::vector<MEDCouplingUMesh *> ret;
6125 for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6127 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6128 mcIdType beginCellId=ToIdType(std::distance(connI,i));
6129 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6130 mcIdType endCellId=ToIdType(std::distance(connI,i));
6131 mcIdType sz=endCellId-beginCellId;
6132 mcIdType *cells=new mcIdType[sz];
6133 for(mcIdType j=0;j<sz;j++)
6134 cells[j]=beginCellId+j;
6135 MEDCouplingUMesh *m=(MEDCouplingUMesh *)buildPartOfMySelf(cells,cells+sz,true);
6143 * This method performs the opposite operation than those in MEDCoupling1SGTUMesh::buildUnstructured.
6144 * If \a this is a single geometric type unstructured mesh, it will be converted into a more compact data structure,
6145 * MEDCoupling1GTUMesh instance. The returned instance will aggregate the same DataArrayDouble instance of coordinates than \a this.
6147 * \return a newly allocated instance, that the caller must manage.
6148 * \throw If \a this contains more than one geometric type.
6149 * \throw If the nodal connectivity of \a this is not fully defined.
6150 * \throw If the internal data is not coherent.
6152 MEDCoupling1GTUMesh *MEDCouplingUMesh::convertIntoSingleGeoTypeMesh() const
6154 checkConnectivityFullyDefined();
6155 if(_types.size()!=1)
6156 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6157 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6158 MCAuto<MEDCoupling1GTUMesh> ret=MEDCoupling1GTUMesh::New(getName(),typ);
6159 ret->setCoords(getCoords());
6160 MEDCoupling1SGTUMesh *retC=dynamic_cast<MEDCoupling1SGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6163 MCAuto<DataArrayIdType> c=convertNodalConnectivityToStaticGeoTypeMesh();
6164 retC->setNodalConnectivity(c);
6168 MEDCoupling1DGTUMesh *retD=dynamic_cast<MEDCoupling1DGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6170 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : Internal error !");
6171 DataArrayIdType *c=0,*ci=0;
6172 convertNodalConnectivityToDynamicGeoTypeMesh(c,ci);
6173 MCAuto<DataArrayIdType> cs(c),cis(ci);
6174 retD->setNodalConnectivity(cs,cis);
6179 DataArrayIdType *MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh() const
6181 checkConnectivityFullyDefined();
6182 if(_types.size()!=1)
6183 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6184 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6185 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6188 std::ostringstream oss; oss << "MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : this contains a single geo type (" << cm.getRepr() << ") but ";
6189 oss << "this type is dynamic ! Only static geometric type is possible for that type ! call convertNodalConnectivityToDynamicGeoTypeMesh instead !";
6190 throw INTERP_KERNEL::Exception(oss.str());
6192 mcIdType nbCells=getNumberOfCells();
6193 mcIdType typi=ToIdType(typ);
6194 mcIdType nbNodesPerCell=ToIdType(cm.getNumberOfNodes());
6195 MCAuto<DataArrayIdType> connOut=DataArrayIdType::New(); connOut->alloc(nbCells*nbNodesPerCell,1);
6196 mcIdType *outPtr=connOut->getPointer();
6197 const mcIdType *conn=_nodal_connec->begin();
6198 const mcIdType *connI=_nodal_connec_index->begin();
6200 for(mcIdType i=0;i<nbCells;i++,connI++)
6202 if(conn[connI[0]]==typi && connI[1]-connI[0]==nbNodesPerCell)
6203 outPtr=std::copy(conn+connI[0]+1,conn+connI[1],outPtr);
6206 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 << ") !";
6207 throw INTERP_KERNEL::Exception(oss.str());
6210 return connOut.retn();
6214 * Convert the nodal connectivity of the mesh so that all the cells are of dynamic types (polygon or quadratic
6215 * polygon). This returns the corresponding new nodal connectivity in \ref numbering-indirect format.
6219 void MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh(DataArrayIdType *&nodalConn, DataArrayIdType *&nodalConnIndex) const
6221 static const char msg0[]="MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : nodal connectivity in this are invalid ! Call checkConsistency !";
6222 checkConnectivityFullyDefined();
6223 if(_types.size()!=1)
6224 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6225 mcIdType nbCells=getNumberOfCells(),
6226 lgth=_nodal_connec->getNumberOfTuples();
6228 throw INTERP_KERNEL::Exception(msg0);
6229 MCAuto<DataArrayIdType> c(DataArrayIdType::New()),ci(DataArrayIdType::New());
6230 c->alloc(lgth-nbCells,1); ci->alloc(nbCells+1,1);
6231 mcIdType *cp(c->getPointer()),*cip(ci->getPointer());
6232 const mcIdType *incp(_nodal_connec->begin()),*incip(_nodal_connec_index->begin());
6234 for(mcIdType i=0;i<nbCells;i++,cip++,incip++)
6236 mcIdType strt(incip[0]+1),stop(incip[1]);//+1 to skip geo type
6237 mcIdType delta(stop-strt);
6240 if((strt>=0 && strt<lgth) && (stop>=0 && stop<=lgth))
6241 cp=std::copy(incp+strt,incp+stop,cp);
6243 throw INTERP_KERNEL::Exception(msg0);
6246 throw INTERP_KERNEL::Exception(msg0);
6247 cip[1]=cip[0]+delta;
6249 nodalConn=c.retn(); nodalConnIndex=ci.retn();
6253 * This method takes in input a vector of MEDCouplingUMesh instances lying on the same coordinates with same mesh dimensions.
6254 * Each mesh in \b ms must be sorted by type with the same order (typically using MEDCouplingUMesh::sortCellsInMEDFileFrmt).
6255 * This method is particularly useful for MED file interaction. It allows to aggregate several meshes and keeping the type sorting
6256 * and the track of the permutation by chunk of same geotype cells to retrieve it. The traditional formats old2new and new2old
6257 * are not used here to avoid the build of big permutation array.
6259 * \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
6260 * those specified in MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6261 * \param [out] szOfCellGrpOfSameType is a newly allocated DataArrayIdType instance whose number of tuples is equal to the number of chunks of same geotype
6262 * in all meshes in \b ms. The accumulation of all values of this array is equal to the number of cells of returned mesh.
6263 * \param [out] idInMsOfCellGrpOfSameType is a newly allocated DataArrayIdType instance having the same size than \b szOfCellGrpOfSameType. This
6264 * output array gives for each chunck of same type the corresponding mesh id in \b ms.
6265 * \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
6266 * is sorted by type following the geo cell types order of MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6268 MEDCouplingUMesh *MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& ms,
6269 DataArrayIdType *&szOfCellGrpOfSameType,
6270 DataArrayIdType *&idInMsOfCellGrpOfSameType)
6272 std::vector<const MEDCouplingUMesh *> ms2;
6273 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms.begin();it!=ms.end();it++)
6276 (*it)->checkConnectivityFullyDefined();
6280 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : input vector is empty !");
6281 const DataArrayDouble *refCoo=ms2[0]->getCoords();
6282 int meshDim=ms2[0]->getMeshDimension();
6283 std::vector<const MEDCouplingUMesh *> m1ssm;
6284 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmAuto;
6286 std::vector<const MEDCouplingUMesh *> m1ssmSingle;
6287 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmSingleAuto;
6288 mcIdType fake=0,rk=0;
6289 MCAuto<DataArrayIdType> ret1(DataArrayIdType::New()),ret2(DataArrayIdType::New());
6290 ret1->alloc(0,1); ret2->alloc(0,1);
6291 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms2.begin();it!=ms2.end();it++,rk++)
6293 if(meshDim!=(*it)->getMeshDimension())
6294 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshdims mismatch !");
6295 if(refCoo!=(*it)->getCoords())
6296 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshes are not shared by a single coordinates coords !");
6297 std::vector<MEDCouplingUMesh *> sp=(*it)->splitByType();
6298 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<const MEDCouplingUMesh *> >(m1ssm));
6299 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<MCAuto<MEDCouplingUMesh> > >(m1ssmAuto));
6300 for(std::vector<MEDCouplingUMesh *>::const_iterator it2=sp.begin();it2!=sp.end();it2++)
6302 MEDCouplingUMesh *singleCell=static_cast<MEDCouplingUMesh *>((*it2)->buildPartOfMySelf(&fake,&fake+1,true));
6303 m1ssmSingleAuto.push_back(singleCell);
6304 m1ssmSingle.push_back(singleCell);
6305 ret1->pushBackSilent((*it2)->getNumberOfCells()); ret2->pushBackSilent(rk);
6308 MCAuto<MEDCouplingUMesh> m1ssmSingle2=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmSingle);
6309 MCAuto<DataArrayIdType> renum=m1ssmSingle2->sortCellsInMEDFileFrmt();
6310 std::vector<const MEDCouplingUMesh *> m1ssmfinal(m1ssm.size());
6311 for(mcIdType i=0;i<ToIdType(m1ssm.size());i++)
6312 m1ssmfinal[renum->getIJ(i,0)]=m1ssm[i];
6313 MCAuto<MEDCouplingUMesh> ret0=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmfinal);
6314 szOfCellGrpOfSameType=ret1->renumber(renum->begin());
6315 idInMsOfCellGrpOfSameType=ret2->renumber(renum->begin());
6320 * This method returns a newly created DataArrayIdType instance.
6321 * This method retrieves cell ids in [ \a begin, \a end ) that have the type \a type.
6323 DataArrayIdType *MEDCouplingUMesh::keepCellIdsByType(INTERP_KERNEL::NormalizedCellType type, const mcIdType *begin, const mcIdType *end) const
6325 checkFullyDefined();
6326 const mcIdType *conn=_nodal_connec->begin();
6327 const mcIdType *connIndex=_nodal_connec_index->begin();
6328 MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(0,1);
6329 for(const mcIdType *w=begin;w!=end;w++)
6330 if((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]==type)
6331 ret->pushBackSilent(*w);
6336 * This method makes the assumption that da->getNumberOfTuples()<this->getNumberOfCells(). This method makes the assumption that ids contained in 'da'
6337 * are in [0:getNumberOfCells())
6339 DataArrayIdType *MEDCouplingUMesh::convertCellArrayPerGeoType(const DataArrayIdType *da) const
6341 checkFullyDefined();
6342 const mcIdType *conn=_nodal_connec->begin();
6343 const mcIdType *connI=_nodal_connec_index->begin();
6344 mcIdType nbOfCells=getNumberOfCells();
6345 std::set<INTERP_KERNEL::NormalizedCellType> types(getAllGeoTypes());
6346 mcIdType *tmp=new mcIdType[nbOfCells];
6347 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
6350 for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6351 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
6352 tmp[std::distance(connI,i)]=j++;
6354 DataArrayIdType *ret=DataArrayIdType::New();
6355 ret->alloc(da->getNumberOfTuples(),da->getNumberOfComponents());
6356 ret->copyStringInfoFrom(*da);
6357 mcIdType *retPtr=ret->getPointer();
6358 const mcIdType *daPtr=da->begin();
6359 mcIdType nbOfElems=da->getNbOfElems();
6360 for(mcIdType k=0;k<nbOfElems;k++)
6361 retPtr[k]=tmp[daPtr[k]];
6367 * This method reduced number of cells of this by keeping cells whose type is different from 'type' and if type=='type'
6368 * This method \b works \b for mesh sorted by type.
6369 * cells whose ids is in 'idsPerGeoType' array.
6370 * This method conserves coords and name of mesh.
6372 MEDCouplingUMesh *MEDCouplingUMesh::keepSpecifiedCells(INTERP_KERNEL::NormalizedCellType type, const mcIdType *idsPerGeoTypeBg, const mcIdType *idsPerGeoTypeEnd) const
6374 std::vector<mcIdType> code=getDistributionOfTypes();
6375 std::size_t nOfTypesInThis=code.size()/3;
6376 mcIdType sz=0,szOfType=0;
6377 for(std::size_t i=0;i<nOfTypesInThis;i++)
6382 szOfType=code[3*i+1];
6384 for(const mcIdType *work=idsPerGeoTypeBg;work!=idsPerGeoTypeEnd;work++)
6385 if(*work<0 || *work>=szOfType)
6387 std::ostringstream oss; oss << "MEDCouplingUMesh::keepSpecifiedCells : Request on type " << type << " at place #" << std::distance(idsPerGeoTypeBg,work) << " value " << *work;
6388 oss << ". It should be in [0," << szOfType << ") !";
6389 throw INTERP_KERNEL::Exception(oss.str());
6391 MCAuto<DataArrayIdType> idsTokeep=DataArrayIdType::New(); idsTokeep->alloc(sz+std::distance(idsPerGeoTypeBg,idsPerGeoTypeEnd),1);
6392 mcIdType *idsPtr=idsTokeep->getPointer();
6394 for(std::size_t i=0;i<nOfTypesInThis;i++)
6397 for(mcIdType j=0;j<code[3*i+1];j++)
6400 idsPtr=std::transform(idsPerGeoTypeBg,idsPerGeoTypeEnd,idsPtr,std::bind2nd(std::plus<mcIdType>(),offset));
6401 offset+=code[3*i+1];
6403 MCAuto<MEDCouplingUMesh> ret=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(idsTokeep->begin(),idsTokeep->end(),true));
6404 ret->copyTinyInfoFrom(this);
6409 * This method returns a vector of size 'this->getNumberOfCells()'.
6410 * This method retrieves for each cell in \a this if it is linear (false) or quadratic(true).
6412 std::vector<bool> MEDCouplingUMesh::getQuadraticStatus() const
6414 mcIdType ncell=getNumberOfCells();
6415 std::vector<bool> ret(ncell);
6416 const mcIdType *cI=getNodalConnectivityIndex()->begin();
6417 const mcIdType *c=getNodalConnectivity()->begin();
6418 for(mcIdType i=0;i<ncell;i++)
6420 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[i]];
6421 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6422 ret[i]=cm.isQuadratic();
6428 * Returns a newly created mesh (with ref count ==1) that contains merge of \a this and \a other.
6430 MEDCouplingMesh *MEDCouplingUMesh::mergeMyselfWith(const MEDCouplingMesh *other) const
6432 if(other->getType()!=UNSTRUCTURED)
6433 throw INTERP_KERNEL::Exception("Merge of umesh only available with umesh each other !");
6434 const MEDCouplingUMesh *otherC=static_cast<const MEDCouplingUMesh *>(other);
6435 return MergeUMeshes(this,otherC);
6439 * Returns a new DataArrayDouble holding barycenters of all cells. The barycenter is
6440 * computed by averaging coordinates of cell nodes, so this method is not a right
6441 * choice for degenerated meshes (not well oriented, cells with measure close to zero).
6442 * Beware also that for quadratic meshes, degenerated arc of circles are turned into linear edges for the computation.
6443 * This happens with a default detection precision of eps=1.0e-14. If you need control over this use computeCellCenterOfMassWithPrecision().
6444 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
6445 * this->getNumberOfCells() tuples per \a this->getSpaceDimension()
6446 * components. The caller is to delete this array using decrRef() as it is
6448 * \throw If the coordinates array is not set.
6449 * \throw If the nodal connectivity of cells is not defined.
6450 * \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
6451 * \sa MEDCouplingUMesh::computeCellCenterOfMassWithPrecision
6453 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMass() const
6455 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6456 int spaceDim=getSpaceDimension();
6457 mcIdType nbOfCells=getNumberOfCells();
6458 ret->alloc(nbOfCells,spaceDim);
6459 ret->copyStringInfoFrom(*getCoords());
6460 double *ptToFill=ret->getPointer();
6461 const mcIdType *nodal=_nodal_connec->begin();
6462 const mcIdType *nodalI=_nodal_connec_index->begin();
6463 const double *coor=_coords->begin();
6464 for(mcIdType i=0;i<nbOfCells;i++)
6466 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6467 INTERP_KERNEL::computeBarycenter2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[i]+1,nodalI[i+1]-nodalI[i]-1,coor,spaceDim,ptToFill);
6475 * See computeCellCenterOfMass().
6476 * \param eps a precision for the detection of degenerated arc of circles.
6477 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
6478 * this->getNumberOfCells() tuples per \a this->getSpaceDimension()
6479 * components. The caller is to delete this array using decrRef() as it is
6481 * \throw If the coordinates array is not set.
6482 * \throw If the nodal connectivity of cells is not defined.
6483 * \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
6484 * \sa MEDCouplingUMesh::computeCellCenterOfMassWithPrecision
6486 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMassWithPrecision(double eps) const
6488 INTERP_KERNEL::QuadraticPlanarPrecision prec(eps);
6489 MCAuto<DataArrayDouble> ret = computeCellCenterOfMass();
6495 * This method computes for each cell in \a this, the location of the iso barycenter of nodes constituting
6496 * the cell. Contrary to badly named MEDCouplingUMesh::computeCellCenterOfMass method that returns the center of inertia of the
6498 * \return a newly allocated DataArrayDouble instance that the caller has to deal with. The returned
6499 * DataArrayDouble instance will have \c this->getNumberOfCells() tuples and \c this->getSpaceDimension() components.
6501 * \sa MEDCouplingUMesh::computeCellCenterOfMass
6502 * \throw If \a this is not fully defined (coordinates and connectivity)
6503 * \throw If there is presence in nodal connectivity in \a this of node ids not in [0, \c this->getNumberOfNodes() )
6505 DataArrayDouble *MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell() const
6507 checkFullyDefined();
6508 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6509 int spaceDim=getSpaceDimension();
6510 mcIdType nbOfCells=getNumberOfCells();
6511 mcIdType nbOfNodes=getNumberOfNodes();
6512 ret->alloc(nbOfCells,spaceDim);
6513 double *ptToFill=ret->getPointer();
6514 const mcIdType *nodal=_nodal_connec->begin();
6515 const mcIdType *nodalI=_nodal_connec_index->begin();
6516 const double *coor=_coords->begin();
6517 for(mcIdType i=0;i<nbOfCells;i++,ptToFill+=spaceDim)
6519 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6520 std::fill(ptToFill,ptToFill+spaceDim,0.);
6521 if(type!=INTERP_KERNEL::NORM_POLYHED)
6523 for(const mcIdType *conn=nodal+nodalI[i]+1;conn!=nodal+nodalI[i+1];conn++)
6525 if(*conn>=0 && *conn<nbOfNodes)
6526 std::transform(coor+spaceDim*conn[0],coor+spaceDim*(conn[0]+1),ptToFill,ptToFill,std::plus<double>());
6529 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of nodeId #" << *conn << " should be in [0," << nbOfNodes << ") !";
6530 throw INTERP_KERNEL::Exception(oss.str());
6533 mcIdType nbOfNodesInCell=nodalI[i+1]-nodalI[i]-1;
6534 if(nbOfNodesInCell>0)
6535 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies<double>(),1./(double)nbOfNodesInCell));
6538 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of cell with no nodes !";
6539 throw INTERP_KERNEL::Exception(oss.str());
6544 std::set<mcIdType> s(nodal+nodalI[i]+1,nodal+nodalI[i+1]);
6546 for(std::set<mcIdType>::const_iterator it=s.begin();it!=s.end();it++)
6548 if(*it>=0 && *it<nbOfNodes)
6549 std::transform(coor+spaceDim*(*it),coor+spaceDim*((*it)+1),ptToFill,ptToFill,std::plus<double>());
6552 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell polyhedron cell #" << i << " presence of nodeId #" << *it << " should be in [0," << nbOfNodes << ") !";
6553 throw INTERP_KERNEL::Exception(oss.str());
6557 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies<double>(),1./(double)s.size()));
6560 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on polyhedron cell #" << i << " there are no nodes !";
6561 throw INTERP_KERNEL::Exception(oss.str());
6569 * Returns a new DataArrayDouble holding barycenters of specified cells. The
6570 * barycenter is computed by averaging coordinates of cell nodes. The cells to treat
6571 * are specified via an array of cell ids.
6572 * \warning Validity of the specified cell ids is not checked!
6573 * Valid range is [ 0, \a this->getNumberOfCells() ).
6574 * \param [in] begin - an array of cell ids of interest.
6575 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
6576 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size ( \a
6577 * end - \a begin ) tuples per \a this->getSpaceDimension() components. The
6578 * caller is to delete this array using decrRef() as it is no more needed.
6579 * \throw If the coordinates array is not set.
6580 * \throw If the nodal connectivity of cells is not defined.
6582 * \if ENABLE_EXAMPLES
6583 * \ref cpp_mcumesh_getPartBarycenterAndOwner "Here is a C++ example".<br>
6584 * \ref py_mcumesh_getPartBarycenterAndOwner "Here is a Python example".
6587 DataArrayDouble *MEDCouplingUMesh::getPartBarycenterAndOwner(const mcIdType *begin, const mcIdType *end) const
6589 DataArrayDouble *ret=DataArrayDouble::New();
6590 int spaceDim=getSpaceDimension();
6591 std::size_t nbOfTuple=std::distance(begin,end);
6592 ret->alloc(nbOfTuple,spaceDim);
6593 double *ptToFill=ret->getPointer();
6594 double *tmp=new double[spaceDim];
6595 const mcIdType *nodal=_nodal_connec->begin();
6596 const mcIdType *nodalI=_nodal_connec_index->begin();
6597 const double *coor=_coords->begin();
6598 for(const mcIdType *w=begin;w!=end;w++)
6600 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[*w]];
6601 INTERP_KERNEL::computeBarycenter2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[*w]+1,nodalI[*w+1]-nodalI[*w]-1,coor,spaceDim,ptToFill);
6609 * 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".
6610 * So the returned instance will have 4 components and \c this->getNumberOfCells() tuples.
6611 * So this method expects that \a this has a spaceDimension equal to 3 and meshDimension equal to 2.
6612 * The computation of the plane equation is done using each time the 3 first nodes of 2D cells.
6613 * This method is useful to detect 2D cells in 3D space that are not coplanar.
6615 * \return DataArrayDouble * - a new instance of DataArrayDouble having 4 components and a number of tuples equal to number of cells in \a this.
6616 * \throw If spaceDim!=3 or meshDim!=2.
6617 * \throw If connectivity of \a this is invalid.
6618 * \throw If connectivity of a cell in \a this points to an invalid node.
6620 DataArrayDouble *MEDCouplingUMesh::computePlaneEquationOf3DFaces() const
6622 MCAuto<DataArrayDouble> ret(DataArrayDouble::New());
6623 mcIdType nbOfCells=getNumberOfCells();
6624 mcIdType nbOfNodes(getNumberOfNodes());
6625 if(getSpaceDimension()!=3 || getMeshDimension()!=2)
6626 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computePlaneEquationOf3DFaces : This method must be applied on a mesh having meshDimension equal 2 and a spaceDimension equal to 3 !");
6627 ret->alloc(nbOfCells,4);
6628 double *retPtr(ret->getPointer());
6629 const mcIdType *nodal(_nodal_connec->begin()),*nodalI(_nodal_connec_index->begin());
6630 const double *coor(_coords->begin());
6631 for(mcIdType i=0;i<nbOfCells;i++,nodalI++,retPtr+=4)
6633 double matrix[16]={0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,0},matrix2[16];
6634 if(nodalI[1]-nodalI[0]>=4)
6636 double aa[3]={coor[nodal[nodalI[0]+1+1]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6637 coor[nodal[nodalI[0]+1+1]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6638 coor[nodal[nodalI[0]+1+1]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]}
6639 ,bb[3]={coor[nodal[nodalI[0]+1+2]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6640 coor[nodal[nodalI[0]+1+2]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6641 coor[nodal[nodalI[0]+1+2]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]};
6642 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]};
6643 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]));
6644 for(int j=0;j<3;j++)
6646 mcIdType nodeId(nodal[nodalI[0]+1+j]);
6647 if(nodeId>=0 && nodeId<nbOfNodes)
6648 std::copy(coor+nodeId*3,coor+(nodeId+1)*3,matrix+4*j);
6651 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! This cell points to an invalid nodeId : " << nodeId << " !";
6652 throw INTERP_KERNEL::Exception(oss.str());
6655 if(sqrt(cc[0]*cc[0]+cc[1]*cc[1]+cc[2]*cc[2])>(1e-3*aa_norm*bb_norm))
6657 INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6658 retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6662 if(nodalI[1]-nodalI[0]==4)
6664 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : cell" << i << " : Presence of The 3 colinear points !";
6665 throw INTERP_KERNEL::Exception(oss.str());
6668 double dd[3]={0.,0.,0.};
6669 for(mcIdType offset=nodalI[0]+1;offset<nodalI[1];offset++)
6670 std::transform(coor+3*nodal[offset],coor+3*(nodal[offset]+1),dd,dd,std::plus<double>());
6671 mcIdType nbOfNodesInCell(nodalI[1]-nodalI[0]-1);
6672 std::transform(dd,dd+3,dd,std::bind2nd(std::multiplies<double>(),1./(double)nbOfNodesInCell));
6673 std::copy(dd,dd+3,matrix+4*2);
6674 INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6675 retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6680 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! Must be constitued by more than 3 nodes !";
6681 throw INTERP_KERNEL::Exception(oss.str());
6688 * This method expects as input a DataArrayDouble non nul instance 'da' that should be allocated. If not an exception is thrown.
6691 MEDCouplingUMesh *MEDCouplingUMesh::Build0DMeshFromCoords(DataArrayDouble *da)
6694 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build0DMeshFromCoords : instance of DataArrayDouble must be not null !");
6695 da->checkAllocated();
6696 std::string name(da->getName());
6697 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New(name,0));
6699 ret->setName("Mesh");
6701 mcIdType nbOfTuples(da->getNumberOfTuples());
6702 MCAuto<DataArrayIdType> c(DataArrayIdType::New()),cI(DataArrayIdType::New());
6703 c->alloc(2*nbOfTuples,1);
6704 cI->alloc(nbOfTuples+1,1);
6705 mcIdType *cp(c->getPointer()),*cip(cI->getPointer());
6707 for(mcIdType i=0;i<nbOfTuples;i++)
6709 *cp++=INTERP_KERNEL::NORM_POINT1;
6713 ret->setConnectivity(c,cI,true);
6717 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::Build1DMeshFromCoords(DataArrayDouble *da)
6720 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build01MeshFromCoords : instance of DataArrayDouble must be not null !");
6721 da->checkAllocated();
6722 std::string name(da->getName());
6723 MCAuto<MEDCouplingUMesh> ret;
6725 MCAuto<MEDCouplingCMesh> tmp(MEDCouplingCMesh::New());
6726 MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
6727 arr->alloc(da->getNumberOfTuples());
6728 tmp->setCoordsAt(0,arr);
6729 ret=tmp->buildUnstructured();
6733 ret->setName("Mesh");
6740 * Creates a new MEDCouplingUMesh by concatenating two given meshes of the same dimension.
6741 * Cells and nodes of
6742 * the first mesh precede cells and nodes of the second mesh within the result mesh.
6743 * \param [in] mesh1 - the first mesh.
6744 * \param [in] mesh2 - the second mesh.
6745 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6746 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6747 * is no more needed.
6748 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
6749 * \throw If the coordinates array is not set in none of the meshes.
6750 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
6751 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
6753 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
6755 std::vector<const MEDCouplingUMesh *> tmp(2);
6756 tmp[0]=const_cast<MEDCouplingUMesh *>(mesh1); tmp[1]=const_cast<MEDCouplingUMesh *>(mesh2);
6757 return MergeUMeshes(tmp);
6761 * Creates a new MEDCouplingUMesh by concatenating all given meshes of the same dimension.
6762 * Cells and nodes of
6763 * the *i*-th mesh precede cells and nodes of the (*i*+1)-th mesh within the result mesh.
6764 * \param [in] a - a vector of meshes (MEDCouplingUMesh) to concatenate.
6765 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6766 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6767 * is no more needed.
6768 * \throw If \a a.size() == 0.
6769 * \throw If \a a[ *i* ] == NULL.
6770 * \throw If the coordinates array is not set in none of the meshes.
6771 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
6772 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
6774 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const std::vector<const MEDCouplingUMesh *>& a)
6776 std::size_t sz=a.size();
6778 return MergeUMeshesLL(a);
6779 for(std::size_t ii=0;ii<sz;ii++)
6782 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshes : item #" << ii << " in input array of size "<< sz << " is empty !";
6783 throw INTERP_KERNEL::Exception(oss.str());
6785 std::vector< MCAuto<MEDCouplingUMesh> > bb(sz);
6786 std::vector< const MEDCouplingUMesh * > aa(sz);
6788 for(std::size_t i=0;i<sz && spaceDim==-3;i++)
6790 const MEDCouplingUMesh *cur=a[i];
6791 const DataArrayDouble *coo=cur->getCoords();
6793 spaceDim=int(coo->getNumberOfComponents());
6796 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : no spaceDim specified ! unable to perform merge !");
6797 for(std::size_t i=0;i<sz;i++)
6799 bb[i]=a[i]->buildSetInstanceFromThis(spaceDim);
6802 return MergeUMeshesLL(aa);
6806 * Creates a new MEDCouplingUMesh by concatenating cells of two given meshes of same
6807 * dimension and sharing the node coordinates array.
6808 * All cells of the first mesh precede all cells of the second mesh
6809 * within the result mesh.
6810 * \param [in] mesh1 - the first mesh.
6811 * \param [in] mesh2 - the second mesh.
6812 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6813 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6814 * is no more needed.
6815 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
6816 * \throw If the meshes do not share the node coordinates array.
6817 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
6818 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
6820 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
6822 std::vector<const MEDCouplingUMesh *> tmp(2);
6823 tmp[0]=mesh1; tmp[1]=mesh2;
6824 return MergeUMeshesOnSameCoords(tmp);
6828 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
6829 * dimension and sharing the node coordinates array.
6830 * All cells of the *i*-th mesh precede all cells of the
6831 * (*i*+1)-th mesh within the result mesh.
6832 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
6833 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6834 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6835 * is no more needed.
6836 * \throw If \a a.size() == 0.
6837 * \throw If \a a[ *i* ] == NULL.
6838 * \throw If the meshes do not share the node coordinates array.
6839 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
6840 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
6842 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes)
6845 throw INTERP_KERNEL::Exception("meshes input parameter is expected to be non empty.");
6846 for(std::size_t ii=0;ii<meshes.size();ii++)
6849 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshesOnSameCoords : item #" << ii << " in input array of size "<< meshes.size() << " is empty !";
6850 throw INTERP_KERNEL::Exception(oss.str());
6852 const DataArrayDouble *coords=meshes.front()->getCoords();
6853 int meshDim=meshes.front()->getMeshDimension();
6854 std::vector<const MEDCouplingUMesh *>::const_iterator iter=meshes.begin();
6855 mcIdType meshLgth=0;
6856 mcIdType meshIndexLgth=0;
6857 for(;iter!=meshes.end();iter++)
6859 if(coords!=(*iter)->getCoords())
6860 throw INTERP_KERNEL::Exception("meshes does not share the same coords ! Try using tryToShareSameCoords method !");
6861 if(meshDim!=(*iter)->getMeshDimension())
6862 throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, FuseUMeshesOnSameCoords impossible !");
6863 meshLgth+=(*iter)->getNodalConnectivityArrayLen();
6864 meshIndexLgth+=(*iter)->getNumberOfCells();
6866 MCAuto<DataArrayIdType> nodal=DataArrayIdType::New();
6867 nodal->alloc(meshLgth,1);
6868 mcIdType *nodalPtr=nodal->getPointer();
6869 MCAuto<DataArrayIdType> nodalIndex=DataArrayIdType::New();
6870 nodalIndex->alloc(meshIndexLgth+1,1);
6871 mcIdType *nodalIndexPtr=nodalIndex->getPointer();
6873 for(iter=meshes.begin();iter!=meshes.end();iter++)
6875 const mcIdType *nod=(*iter)->getNodalConnectivity()->begin();
6876 const mcIdType *index=(*iter)->getNodalConnectivityIndex()->begin();
6877 mcIdType nbOfCells=(*iter)->getNumberOfCells();
6878 mcIdType meshLgth2=(*iter)->getNodalConnectivityArrayLen();
6879 nodalPtr=std::copy(nod,nod+meshLgth2,nodalPtr);
6880 if(iter!=meshes.begin())
6881 nodalIndexPtr=std::transform(index+1,index+nbOfCells+1,nodalIndexPtr,std::bind2nd(std::plus<mcIdType>(),offset));
6883 nodalIndexPtr=std::copy(index,index+nbOfCells+1,nodalIndexPtr);
6886 MEDCouplingUMesh *ret=MEDCouplingUMesh::New();
6887 ret->setName("merge");
6888 ret->setMeshDimension(meshDim);
6889 ret->setConnectivity(nodal,nodalIndex,true);
6890 ret->setCoords(coords);
6895 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
6896 * dimension and sharing the node coordinates array. Cells of the *i*-th mesh precede
6897 * cells of the (*i*+1)-th mesh within the result mesh. Duplicates of cells are
6898 * removed from \a this mesh and arrays mapping between new and old cell ids in "Old to
6899 * New" mode are returned for each input mesh.
6900 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
6901 * \param [in] compType - specifies a cell comparison technique. For meaning of its
6902 * valid values [0,1,2], see zipConnectivityTraducer().
6903 * \param [in,out] corr - an array of DataArrayIdType, of the same size as \a
6904 * meshes. The *i*-th array describes cell ids mapping for \a meshes[ *i* ]
6905 * mesh. The caller is to delete each of the arrays using decrRef() as it is
6907 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6908 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6909 * is no more needed.
6910 * \throw If \a meshes.size() == 0.
6911 * \throw If \a meshes[ *i* ] == NULL.
6912 * \throw If the meshes do not share the node coordinates array.
6913 * \throw If \a meshes[ *i* ]->getMeshDimension() < 0.
6914 * \throw If the \a meshes are of different dimension (getMeshDimension()).
6915 * \throw If the nodal connectivity of cells of any of \a meshes is not defined.
6916 * \throw If the nodal connectivity any of \a meshes includes an invalid id.
6918 MEDCouplingUMesh *MEDCouplingUMesh::FuseUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes, int compType, std::vector<DataArrayIdType *>& corr)
6920 //All checks are delegated to MergeUMeshesOnSameCoords
6921 MCAuto<MEDCouplingUMesh> ret=MergeUMeshesOnSameCoords(meshes);
6922 MCAuto<DataArrayIdType> o2n=ret->zipConnectivityTraducer(compType);
6923 corr.resize(meshes.size());
6924 std::size_t nbOfMeshes=meshes.size();
6926 const mcIdType *o2nPtr=o2n->begin();
6927 for(std::size_t i=0;i<nbOfMeshes;i++)
6929 DataArrayIdType *tmp=DataArrayIdType::New();
6930 mcIdType curNbOfCells=meshes[i]->getNumberOfCells();
6931 tmp->alloc(curNbOfCells,1);
6932 std::copy(o2nPtr+offset,o2nPtr+offset+curNbOfCells,tmp->getPointer());
6933 offset+=curNbOfCells;
6934 tmp->setName(meshes[i]->getName());
6941 * Makes all given meshes share the nodal connectivity array. The common connectivity
6942 * array is created by concatenating the connectivity arrays of all given meshes. All
6943 * the given meshes must be of the same space dimension but dimension of cells **can
6944 * differ**. This method is particularly useful in MEDLoader context to build a \ref
6945 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
6946 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
6947 * \param [in,out] meshes - a vector of meshes to update.
6948 * \throw If any of \a meshes is NULL.
6949 * \throw If the coordinates array is not set in any of \a meshes.
6950 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
6951 * \throw If \a meshes are of different space dimension.
6953 void MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords(const std::vector<MEDCouplingUMesh *>& meshes)
6955 std::size_t sz=meshes.size();
6958 std::vector< const DataArrayDouble * > coords(meshes.size());
6959 std::vector< const DataArrayDouble * >::iterator it2=coords.begin();
6960 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++,it2++)
6964 (*it)->checkConnectivityFullyDefined();
6965 const DataArrayDouble *coo=(*it)->getCoords();
6970 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
6971 oss << " has no coordinate array defined !";
6972 throw INTERP_KERNEL::Exception(oss.str());
6977 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
6978 oss << " is null !";
6979 throw INTERP_KERNEL::Exception(oss.str());
6982 MCAuto<DataArrayDouble> res=DataArrayDouble::Aggregate(coords);
6983 std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();
6984 mcIdType offset=(*it)->getNumberOfNodes();
6985 (*it++)->setCoords(res);
6986 for(;it!=meshes.end();it++)
6988 mcIdType oldNumberOfNodes=(*it)->getNumberOfNodes();
6989 (*it)->setCoords(res);
6990 (*it)->shiftNodeNumbersInConn(offset);
6991 offset+=oldNumberOfNodes;
6996 * Merges nodes coincident with a given precision within all given meshes that share
6997 * the nodal connectivity array. The given meshes **can be of different** mesh
6998 * dimension. This method is particularly useful in MEDLoader context to build a \ref
6999 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
7000 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
7001 * \param [in,out] meshes - a vector of meshes to update.
7002 * \param [in] eps - the precision used to detect coincident nodes (infinite norm).
7003 * \throw If any of \a meshes is NULL.
7004 * \throw If the \a meshes do not share the same node coordinates array.
7005 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
7007 void MEDCouplingUMesh::MergeNodesOnUMeshesSharingSameCoords(const std::vector<MEDCouplingUMesh *>& meshes, double eps)
7011 std::set<const DataArrayDouble *> s;
7012 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
7015 s.insert((*it)->getCoords());
7018 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 !";
7019 throw INTERP_KERNEL::Exception(oss.str());
7024 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 !";
7025 throw INTERP_KERNEL::Exception(oss.str());
7027 const DataArrayDouble *coo=*(s.begin());
7031 DataArrayIdType *comm,*commI;
7032 coo->findCommonTuples(eps,-1,comm,commI);
7033 MCAuto<DataArrayIdType> tmp1(comm),tmp2(commI);
7034 mcIdType oldNbOfNodes=coo->getNumberOfTuples();
7035 mcIdType newNbOfNodes;
7036 MCAuto<DataArrayIdType> o2n=DataArrayIdType::ConvertIndexArrayToO2N(oldNbOfNodes,comm->begin(),commI->begin(),commI->end(),newNbOfNodes);
7037 if(oldNbOfNodes==newNbOfNodes)
7039 MCAuto<DataArrayDouble> newCoords=coo->renumberAndReduce(o2n->begin(),newNbOfNodes);
7040 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
7042 (*it)->renumberNodesInConn(o2n->begin());
7043 (*it)->setCoords(newCoords);
7049 * This static operates only for coords in 3D. The polygon is specified by its connectivity nodes in [ \a begin , \a end ).
7051 bool MEDCouplingUMesh::IsPolygonWellOriented(bool isQuadratic, const double *vec, const mcIdType *begin, const mcIdType *end, const double *coords)
7054 double v[3]={0.,0.,0.};
7055 std::size_t sz=std::distance(begin,end);
7059 // Algorithm: sum in v the cross products of (e1, e2) where e_i it the vector between (0,0,0) and point i
7060 // and e2 is linear point directly following e1 in the connectivity. All points are used.
7061 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];
7062 v[1]+=coords[3*begin[i]+2]*coords[3*begin[(i+1)%sz]]-coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+2];
7063 v[2]+=coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+1]-coords[3*begin[i]+1]*coords[3*begin[(i+1)%sz]];
7067 // Same algorithm as above but also using intermediate quadratic points.
7068 // (taking only linear points might lead to issues if the linearized version of the
7069 // polygon is not convex or self-intersecting ... see testCellOrientation4)
7070 std::size_t hsz = sz/2;
7071 for(std::size_t j=0;j<sz;j++)
7073 if (j%2) // current point i is quadratic, next point i+1 is standard
7076 ip1 = ((j-1)/2 + 1)%hsz; // ip1 means "i+1", i.e. next point
7078 else // current point i is standard, next point i+1 is quadratic
7083 v[0]+=coords[3*begin[i]+1]*coords[3*begin[ip1]+2]-coords[3*begin[i]+2]*coords[3*begin[ip1]+1];
7084 v[1]+=coords[3*begin[i]+2]*coords[3*begin[ip1]]-coords[3*begin[i]]*coords[3*begin[ip1]+2];
7085 v[2]+=coords[3*begin[i]]*coords[3*begin[ip1]+1]-coords[3*begin[i]+1]*coords[3*begin[ip1]];
7088 double ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
7093 * The polyhedron is specified by its connectivity nodes in [ \a begin , \a end ).
7095 bool MEDCouplingUMesh::IsPolyhedronWellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7097 std::vector<std::pair<mcIdType,mcIdType> > edges;
7098 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
7099 const mcIdType *bgFace=begin;
7100 for(std::size_t i=0;i<nbOfFaces;i++)
7102 const mcIdType *endFace=std::find(bgFace+1,end,-1);
7103 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
7104 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7106 std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7107 if(std::find(edges.begin(),edges.end(),p1)!=edges.end())
7109 edges.push_back(p1);
7113 return INTERP_KERNEL::calculateVolumeForPolyh2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,ToIdType(std::distance(begin,end)),coords)>-EPS_FOR_POLYH_ORIENTATION;
7117 * The 3D extruded static cell (PENTA6,HEXA8,HEXAGP12...) its connectivity nodes in [ \a begin , \a end ).
7119 bool MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7121 double vec0[3],vec1[3];
7122 std::size_t sz=std::distance(begin,end);
7124 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented : the length of nodal connectivity of extruded cell is not even !");
7125 mcIdType nbOfNodes=ToIdType(sz/2);
7126 INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,nbOfNodes,coords,vec0);
7127 const double *pt0=coords+3*begin[0];
7128 const double *pt1=coords+3*begin[nbOfNodes];
7129 vec1[0]=pt1[0]-pt0[0]; vec1[1]=pt1[1]-pt0[1]; vec1[2]=pt1[2]-pt0[2];
7130 return (vec0[0]*vec1[0]+vec0[1]*vec1[1]+vec0[2]*vec1[2])<0.;
7133 void MEDCouplingUMesh::CorrectExtrudedStaticCell(mcIdType *begin, mcIdType *end)
7135 std::size_t sz=std::distance(begin,end);
7136 INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz];
7137 std::size_t nbOfNodes(sz/2);
7138 std::copy(begin,end,(mcIdType *)tmp);
7139 for(std::size_t j=1;j<nbOfNodes;j++)
7141 begin[j]=tmp[nbOfNodes-j];
7142 begin[j+nbOfNodes]=tmp[nbOfNodes+nbOfNodes-j];
7146 bool MEDCouplingUMesh::IsTetra4WellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7148 std::size_t sz=std::distance(begin,end);
7150 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsTetra4WellOriented : Tetra4 cell with not 4 nodes ! Call checkConsistency !");
7151 double vec0[3],vec1[3];
7152 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[1],*pt2=coords+3*begin[2],*pt3=coords+3*begin[3];
7153 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];
7154 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;
7157 bool MEDCouplingUMesh::IsPyra5WellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7159 std::size_t sz=std::distance(begin,end);
7161 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsPyra5WellOriented : Pyra5 cell with not 5 nodes ! Call checkConsistency !");
7163 INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,4,coords,vec0);
7164 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[4];
7165 return (vec0[0]*(pt1[0]-pt0[0])+vec0[1]*(pt1[1]-pt0[1])+vec0[2]*(pt1[2]-pt0[2]))<0.;
7169 * 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 )
7170 * 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
7173 * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not.
7174 * \param [in] coords the coordinates with nb of components exactly equal to 3
7175 * \param [in] begin begin of the nodal connectivity (geometric type included) of a single polyhedron cell
7176 * \param [in] end end of nodal connectivity of a single polyhedron cell (excluded)
7177 * \param [out] res the result is put at the end of the vector without any alteration of the data.
7179 void MEDCouplingUMesh::SimplifyPolyhedronCell(double eps, const DataArrayDouble *coords, mcIdType index, DataArrayIdType *res, MEDCouplingUMesh *faces,
7180 DataArrayIdType *E_Fi, DataArrayIdType *E_F, DataArrayIdType *F_Ei, DataArrayIdType *F_E)
7182 mcIdType nbFaces = E_Fi->getIJ(index + 1, 0) - E_Fi->getIJ(index, 0);
7183 MCAuto<DataArrayDouble> v=DataArrayDouble::New(); v->alloc(nbFaces,3);
7184 double *vPtr=v->getPointer();
7185 MCAuto<DataArrayDouble> p=DataArrayDouble::New(); p->alloc(nbFaces,2);
7186 double *pPtr=p->getPointer();
7187 mcIdType *e_fi = E_Fi->getPointer(), *e_f = E_F->getPointer(), *f_ei = F_Ei->getPointer(), *f_e = F_E->getPointer();
7188 const mcIdType *f_idx = faces->getNodalConnectivityIndex()->getPointer(), *f_cnn = faces->getNodalConnectivity()->getPointer();
7189 for(mcIdType i=0;i<nbFaces;i++,vPtr+=3,pPtr++)
7191 mcIdType face = e_f[e_fi[index] + i];
7192 ComputeVecAndPtOfFace(eps, coords->begin(), f_cnn + f_idx[face] + 1, f_cnn + f_idx[face + 1], vPtr, pPtr);
7193 // to differentiate faces going to different cells:
7195 for (mcIdType j = f_ei[face]; j < f_ei[face + 1]; j++)
7196 *pPtr += FromIdType<double>(f_e[j]);
7198 pPtr=p->getPointer(); vPtr=v->getPointer();
7199 DataArrayIdType *comm1=0,*commI1=0;
7200 v->findCommonTuples(eps,-1,comm1,commI1);
7201 for (mcIdType i = 0; i < nbFaces; i++)
7202 if (comm1->findIdFirstEqual(i) < 0)
7204 comm1->pushBackSilent(i);
7205 commI1->pushBackSilent(comm1->getNumberOfTuples());
7207 MCAuto<DataArrayIdType> comm1Auto(comm1),commI1Auto(commI1);
7208 const mcIdType *comm1Ptr=comm1->begin();
7209 const mcIdType *commI1Ptr=commI1->begin();
7210 mcIdType nbOfGrps1=commI1Auto->getNumberOfTuples()-1;
7211 res->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYHED));
7213 for(mcIdType i=0;i<nbOfGrps1;i++)
7215 mcIdType vecId=comm1Ptr[commI1Ptr[i]];
7216 MCAuto<DataArrayDouble> tmpgrp2=p->selectByTupleId(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7217 DataArrayIdType *comm2=0,*commI2=0;
7218 tmpgrp2->findCommonTuples(eps,-1,comm2,commI2);
7219 for (mcIdType j = 0; j < commI1Ptr[i+1] - commI1Ptr[i]; j++)
7220 if (comm2->findIdFirstEqual(j) < 0)
7222 comm2->pushBackSilent(j);
7223 commI2->pushBackSilent(comm2->getNumberOfTuples());
7225 MCAuto<DataArrayIdType> comm2Auto(comm2),commI2Auto(commI2);
7226 const mcIdType *comm2Ptr=comm2->begin();
7227 const mcIdType *commI2Ptr=commI2->begin();
7228 mcIdType nbOfGrps2=commI2Auto->getNumberOfTuples()-1;
7229 for(mcIdType j=0;j<nbOfGrps2;j++)
7231 if(commI2Ptr[j+1] == commI2Ptr[j] + 1)
7233 mcIdType face = e_f[e_fi[index] + comm1Ptr[commI1Ptr[i] + comm2Ptr[commI2Ptr[j]]]]; //hmmm
7234 res->insertAtTheEnd(f_cnn + f_idx[face] + 1, f_cnn + f_idx[face + 1]);
7235 res->pushBackSilent(-1);
7239 mcIdType pointId=comm1Ptr[commI1Ptr[i]+comm2Ptr[commI2Ptr[j]]];
7240 MCAuto<DataArrayIdType> ids2=comm2->selectByTupleIdSafeSlice(commI2Ptr[j],commI2Ptr[j+1],1);
7241 ids2->transformWithIndArr(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7242 ids2->transformWithIndArr(e_f + e_fi[index], e_f + e_fi[index + 1]);
7243 MCAuto<MEDCouplingUMesh> mm3=static_cast<MEDCouplingUMesh *>(faces->buildPartOfMySelf(ids2->begin(),ids2->end(),true));
7244 MCAuto<DataArrayIdType> idsNodeTmp=mm3->zipCoordsTraducer();
7245 MCAuto<DataArrayIdType> idsNode=idsNodeTmp->invertArrayO2N2N2O(mm3->getNumberOfNodes());
7246 const mcIdType *idsNodePtr=idsNode->begin();
7247 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];
7248 double vec[3]; vec[0]=vPtr[3*vecId+1]; vec[1]=-vPtr[3*vecId]; vec[2]=0.;
7249 double norm=vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2];
7250 if(std::abs(norm)>eps)
7252 double angle=INTERP_KERNEL::EdgeArcCircle::SafeAsin(norm);
7253 mm3->rotate(center,vec,angle);
7255 mm3->changeSpaceDimension(2);
7256 MCAuto<MEDCouplingUMesh> mm4=mm3->buildSpreadZonesWithPoly();
7257 const mcIdType *conn4=mm4->getNodalConnectivity()->begin();
7258 const mcIdType *connI4=mm4->getNodalConnectivityIndex()->begin();
7259 mcIdType nbOfCells=mm4->getNumberOfCells();
7260 for(mcIdType k=0;k<nbOfCells;k++)
7263 for(const mcIdType *work=conn4+connI4[k]+1;work!=conn4+connI4[k+1];work++,l++)
7264 res->pushBackSilent(idsNodePtr[*work]);
7265 res->pushBackSilent(-1);
7270 res->popBackSilent();
7274 * 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
7275 * through origin. The plane is defined by its nodal connectivity [ \b begin, \b end ).
7277 * \param [in] eps below that value the dot product of 2 vectors is considered as colinears
7278 * \param [in] coords coordinates expected to have 3 components.
7279 * \param [in] begin start of the nodal connectivity of the face.
7280 * \param [in] end end of the nodal connectivity (excluded) of the face.
7281 * \param [out] v the normalized vector of size 3
7282 * \param [out] p the pos of plane
7284 void MEDCouplingUMesh::ComputeVecAndPtOfFace(double eps, const double *coords, const mcIdType *begin, const mcIdType *end, double *v, double *p)
7286 std::size_t nbPoints=std::distance(begin,end);
7288 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeVecAndPtOfFace : < of 3 points in face ! not able to find a plane on that face !");
7289 double vec[3]={0.,0.,0.};
7291 bool refFound=false;
7292 for(;j<nbPoints-1 && !refFound;j++)
7294 vec[0]=coords[3*begin[j+1]]-coords[3*begin[j]];
7295 vec[1]=coords[3*begin[j+1]+1]-coords[3*begin[j]+1];
7296 vec[2]=coords[3*begin[j+1]+2]-coords[3*begin[j]+2];
7297 double norm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
7301 vec[0]/=norm; vec[1]/=norm; vec[2]/=norm;
7304 for(std::size_t i=j;i<nbPoints-1;i++)
7307 curVec[0]=coords[3*begin[i+1]]-coords[3*begin[i]];
7308 curVec[1]=coords[3*begin[i+1]+1]-coords[3*begin[i]+1];
7309 curVec[2]=coords[3*begin[i+1]+2]-coords[3*begin[i]+2];
7310 double norm=sqrt(curVec[0]*curVec[0]+curVec[1]*curVec[1]+curVec[2]*curVec[2]);
7313 curVec[0]/=norm; curVec[1]/=norm; curVec[2]/=norm;
7314 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];
7315 norm=sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
7318 v[0]/=norm; v[1]/=norm; v[2]/=norm;
7319 *p=v[0]*coords[3*begin[i]]+v[1]*coords[3*begin[i]+1]+v[2]*coords[3*begin[i]+2];
7323 throw INTERP_KERNEL::Exception("Not able to find a normal vector of that 3D face !");
7327 * This method tries to obtain a well oriented polyhedron.
7328 * If the algorithm fails, an exception will be thrown.
7330 void MEDCouplingUMesh::TryToCorrectPolyhedronOrientation(mcIdType *begin, mcIdType *end, const double *coords)
7332 std::list< std::pair<mcIdType,mcIdType> > edgesOK,edgesFinished;
7333 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
7334 std::vector<bool> isPerm(nbOfFaces,false);//field on faces False: I don't know, True : oriented
7336 mcIdType *bgFace=begin,*endFace=std::find(begin+1,end,-1);
7337 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
7338 for(std::size_t l=0;l<nbOfEdgesInFace;l++) { std::pair<mcIdType,mcIdType> p1(bgFace[l],bgFace[(l+1)%nbOfEdgesInFace]); edgesOK.push_back(p1); }
7340 while(std::find(isPerm.begin(),isPerm.end(),false)!=isPerm.end())
7343 std::size_t smthChanged=0;
7344 for(std::size_t i=0;i<nbOfFaces;i++)
7346 endFace=std::find(bgFace+1,end,-1);
7347 nbOfEdgesInFace=std::distance(bgFace,endFace);
7351 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7353 std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7354 std::pair<mcIdType,mcIdType> p2(p1.second,p1.first);
7355 bool b1=std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end();
7356 bool b2=std::find(edgesOK.begin(),edgesOK.end(),p2)!=edgesOK.end();
7357 if(b1 || b2) { b=b2; isPerm[i]=true; smthChanged++; break; }
7362 std::reverse(bgFace+1,endFace);
7363 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7365 std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7366 std::pair<mcIdType,mcIdType> p2(p1.second,p1.first);
7367 if(std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end())
7368 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7369 if(std::find(edgesFinished.begin(),edgesFinished.end(),p1)!=edgesFinished.end() || std::find(edgesFinished.begin(),edgesFinished.end(),p2)!=edgesFinished.end())
7370 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7371 std::list< std::pair<mcIdType,mcIdType> >::iterator it=std::find(edgesOK.begin(),edgesOK.end(),p2);
7372 if(it!=edgesOK.end())
7375 edgesFinished.push_back(p1);
7378 edgesOK.push_back(p1);
7385 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired !"); }
7387 if(!edgesOK.empty())
7388 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired : Some edges are shared only once !"); }
7389 if(INTERP_KERNEL::calculateVolumeForPolyh2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,ToIdType(std::distance(begin,end)),coords)<-EPS_FOR_POLYH_ORIENTATION)
7390 {//not lucky ! The first face was not correctly oriented : reorient all faces...
7392 for(std::size_t i=0;i<nbOfFaces;i++)
7394 endFace=std::find(bgFace+1,end,-1);
7395 std::reverse(bgFace+1,endFace);
7403 * This method makes the assumption spacedimension == meshdimension == 2.
7404 * This method works only for linear cells.
7406 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYGON in pos#0)
7408 DataArrayIdType *MEDCouplingUMesh::buildUnionOf2DMesh() const
7410 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
7411 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : meshdimension, spacedimension must be equal to 2 !");
7412 MCAuto<MEDCouplingUMesh> skin(computeSkin());
7413 mcIdType oldNbOfNodes(skin->getNumberOfNodes());
7414 MCAuto<DataArrayIdType> o2n(skin->zipCoordsTraducer());
7415 mcIdType nbOfNodesExpected(skin->getNumberOfNodes());
7416 MCAuto<DataArrayIdType> n2o(o2n->invertArrayO2N2N2O(oldNbOfNodes));
7417 mcIdType nbCells=skin->getNumberOfCells();
7418 if(nbCells==nbOfNodesExpected)
7419 return buildUnionOf2DMeshLinear(skin,n2o);
7420 else if(2*nbCells==nbOfNodesExpected)
7421 return buildUnionOf2DMeshQuadratic(skin,n2o);
7423 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : the mesh 2D in input appears to be not in a single part of a 2D mesh !");
7427 * This method makes the assumption spacedimension == meshdimension == 3.
7428 * This method works only for linear cells.
7430 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYHED in pos#0)
7432 DataArrayIdType *MEDCouplingUMesh::buildUnionOf3DMesh() const
7434 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
7435 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf3DMesh : meshdimension, spacedimension must be equal to 2 !");
7436 MCAuto<MEDCouplingUMesh> m=computeSkin();
7437 const mcIdType *conn=m->getNodalConnectivity()->begin();
7438 const mcIdType *connI=m->getNodalConnectivityIndex()->begin();
7439 mcIdType nbOfCells=m->getNumberOfCells();
7440 MCAuto<DataArrayIdType> ret=DataArrayIdType::New(); ret->alloc(m->getNodalConnectivity()->getNumberOfTuples(),1);
7441 mcIdType *work=ret->getPointer(); *work++=INTERP_KERNEL::NORM_POLYHED;
7444 work=std::copy(conn+connI[0]+1,conn+connI[1],work);
7445 for(mcIdType i=1;i<nbOfCells;i++)
7448 work=std::copy(conn+connI[i]+1,conn+connI[i+1],work);
7454 * \brief Creates a graph of cell neighbors
7455 * \return MEDCouplingSkyLineArray * - an sky line array the user should delete.
7456 * In the sky line array, graph arcs are stored in terms of (index,value) notation.
7458 * - index: 0 3 5 6 6
7459 * - value: 1 2 3 2 3 3
7460 * means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7461 * Arcs are not doubled but reflexive (1,1) arcs are present for each cell
7463 MEDCouplingSkyLineArray* MEDCouplingUMesh::generateGraph() const
7465 checkConnectivityFullyDefined();
7467 int meshDim = this->getMeshDimension();
7468 MEDCoupling::DataArrayIdType* indexr=MEDCoupling::DataArrayIdType::New();
7469 MEDCoupling::DataArrayIdType* revConn=MEDCoupling::DataArrayIdType::New();
7470 this->getReverseNodalConnectivity(revConn,indexr);
7471 const mcIdType* indexr_ptr=indexr->begin();
7472 const mcIdType* revConn_ptr=revConn->begin();
7474 const MEDCoupling::DataArrayIdType* index;
7475 const MEDCoupling::DataArrayIdType* conn;
7476 conn=this->getNodalConnectivity(); // it includes a type as the 1st element!!!
7477 index=this->getNodalConnectivityIndex();
7478 mcIdType nbCells=this->getNumberOfCells();
7479 const mcIdType* index_ptr=index->begin();
7480 const mcIdType* conn_ptr=conn->begin();
7482 //creating graph arcs (cell to cell relations)
7483 //arcs are stored in terms of (index,value) notation
7486 // means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7487 // in present version arcs are not doubled but reflexive (1,1) arcs are present for each cell
7489 //warning here one node have less than or equal effective number of cell with it
7490 //but cell could have more than effective nodes
7491 //because other equals nodes in other domain (with other global inode)
7492 std::vector <mcIdType> cell2cell_index(nbCells+1,0);
7493 std::vector <mcIdType> cell2cell;
7494 cell2cell.reserve(3*nbCells);
7496 for (mcIdType icell=0; icell<nbCells;icell++)
7498 std::map<mcIdType,mcIdType > counter;
7499 for (mcIdType iconn=index_ptr[icell]+1; iconn<index_ptr[icell+1];iconn++)
7501 mcIdType inode=conn_ptr[iconn];
7502 for (mcIdType iconnr=indexr_ptr[inode]; iconnr<indexr_ptr[inode+1];iconnr++)
7504 mcIdType icell2=revConn_ptr[iconnr];
7505 std::map<mcIdType,mcIdType>::iterator iter=counter.find(icell2);
7506 if (iter!=counter.end()) (iter->second)++;
7507 else counter.insert(std::make_pair(icell2,1));
7510 for (std::map<mcIdType,mcIdType>::const_iterator iter=counter.begin();
7511 iter!=counter.end(); iter++)
7512 if (iter->second >= meshDim)
7514 cell2cell_index[icell+1]++;
7515 cell2cell.push_back(iter->first);
7520 cell2cell_index[0]=0;
7521 for (mcIdType icell=0; icell<nbCells;icell++)
7522 cell2cell_index[icell+1]=cell2cell_index[icell]+cell2cell_index[icell+1];
7524 //filling up index and value to create skylinearray structure
7525 MEDCouplingSkyLineArray * array(MEDCouplingSkyLineArray::New(cell2cell_index,cell2cell));
7530 void MEDCouplingUMesh::writeVTKLL(std::ostream& ofs, const std::string& cellData, const std::string& pointData, DataArrayByte *byteData) const
7532 mcIdType nbOfCells=getNumberOfCells();
7534 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::writeVTK : the unstructured mesh has no cells !");
7535 ofs << " <" << getVTKDataSetType() << ">\n";
7536 ofs << " <Piece NumberOfPoints=\"" << getNumberOfNodes() << "\" NumberOfCells=\"" << nbOfCells << "\">\n";
7537 ofs << " <PointData>\n" << pointData << std::endl;
7538 ofs << " </PointData>\n";
7539 ofs << " <CellData>\n" << cellData << std::endl;
7540 ofs << " </CellData>\n";
7541 ofs << " <Points>\n";
7542 if(getSpaceDimension()==3)
7543 _coords->writeVTK(ofs,8,"Points",byteData);
7546 MCAuto<DataArrayDouble> coo=_coords->changeNbOfComponents(3,0.);
7547 coo->writeVTK(ofs,8,"Points",byteData);
7549 ofs << " </Points>\n";
7550 ofs << " <Cells>\n";
7551 const mcIdType *cPtr=_nodal_connec->begin();
7552 const mcIdType *cIPtr=_nodal_connec_index->begin();
7553 MCAuto<DataArrayIdType> faceoffsets=DataArrayIdType::New(); faceoffsets->alloc(nbOfCells,1);
7554 MCAuto<DataArrayIdType> types=DataArrayIdType::New(); types->alloc(nbOfCells,1);
7555 MCAuto<DataArrayIdType> offsets=DataArrayIdType::New(); offsets->alloc(nbOfCells,1);
7556 MCAuto<DataArrayIdType> connectivity=DataArrayIdType::New(); connectivity->alloc(_nodal_connec->getNumberOfTuples()-nbOfCells,1);
7557 mcIdType *w1=faceoffsets->getPointer(),*w2=types->getPointer(),*w3=offsets->getPointer(),*w4=connectivity->getPointer();
7558 mcIdType szFaceOffsets=0,szConn=0;
7559 for(mcIdType i=0;i<nbOfCells;i++,w1++,w2++,w3++)
7562 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]!=INTERP_KERNEL::NORM_POLYHED)
7565 *w3=szConn+cIPtr[i+1]-cIPtr[i]-1; szConn+=cIPtr[i+1]-cIPtr[i]-1;
7566 w4=std::copy(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],w4);
7570 mcIdType deltaFaceOffset=cIPtr[i+1]-cIPtr[i]+1;
7571 *w1=szFaceOffsets+deltaFaceOffset; szFaceOffsets+=deltaFaceOffset;
7572 std::set<mcIdType> c(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1]); c.erase(-1);
7573 *w3=szConn+ToIdType(c.size()); szConn+=ToIdType(c.size());
7574 w4=std::copy(c.begin(),c.end(),w4);
7577 std::unique_ptr<mcIdType[]> medcoupling2vtkTypeTraducer_mcIdType(new mcIdType[MEDCOUPLING2VTKTYPETRADUCER_LGTH]);
7578 for(auto ii = 0; ii<MEDCOUPLING2VTKTYPETRADUCER_LGTH ; ++ii)
7579 medcoupling2vtkTypeTraducer_mcIdType[ii] = MEDCOUPLING2VTKTYPETRADUCER[ii]!=MEDCOUPLING2VTKTYPETRADUCER_NONE?MEDCOUPLING2VTKTYPETRADUCER[ii] : -1;
7580 types->transformWithIndArr(medcoupling2vtkTypeTraducer_mcIdType.get(),medcoupling2vtkTypeTraducer_mcIdType.get()+MEDCOUPLING2VTKTYPETRADUCER_LGTH);
7581 types->writeVTK(ofs,8,"UInt8","types",byteData);
7582 std::string vtkTypeName = Traits<mcIdType>::VTKReprStr;
7583 offsets->writeVTK(ofs,8,vtkTypeName,"offsets",byteData);
7584 if(szFaceOffsets!=0)
7585 {//presence of Polyhedra
7586 connectivity->reAlloc(szConn);
7587 faceoffsets->writeVTK(ofs,8,vtkTypeName,"faceoffsets",byteData);
7588 MCAuto<DataArrayIdType> faces=DataArrayIdType::New(); faces->alloc(szFaceOffsets,1);
7589 w1=faces->getPointer();
7590 for(mcIdType i=0;i<nbOfCells;i++)
7591 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]==INTERP_KERNEL::NORM_POLYHED)
7593 mcIdType nbFaces=ToIdType(std::count(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],-1))+1;
7595 const mcIdType *w6=cPtr+cIPtr[i]+1,*w5=0;
7596 for(mcIdType j=0;j<nbFaces;j++)
7598 w5=std::find(w6,cPtr+cIPtr[i+1],-1);
7599 *w1++=ToIdType(std::distance(w6,w5));
7600 w1=std::copy(w6,w5,w1);
7604 faces->writeVTK(ofs,8,vtkTypeName,"faces",byteData);
7606 connectivity->writeVTK(ofs,8,vtkTypeName,"connectivity",byteData);
7607 ofs << " </Cells>\n";
7608 ofs << " </Piece>\n";
7609 ofs << " </" << getVTKDataSetType() << ">\n";
7612 void MEDCouplingUMesh::reprQuickOverview(std::ostream& stream) const
7614 stream << "MEDCouplingUMesh C++ instance at " << this << ". Name : \"" << getName() << "\".";
7616 { stream << " Not set !"; return ; }
7617 stream << " Mesh dimension : " << _mesh_dim << ".";
7621 { stream << " No coordinates set !"; return ; }
7622 if(!_coords->isAllocated())
7623 { stream << " Coordinates set but not allocated !"; return ; }
7624 stream << " Space dimension : " << _coords->getNumberOfComponents() << "." << std::endl;
7625 stream << "Number of nodes : " << _coords->getNumberOfTuples() << ".";
7626 if(!_nodal_connec_index)
7627 { stream << std::endl << "Nodal connectivity NOT set !"; return ; }
7628 if(!_nodal_connec_index->isAllocated())
7629 { stream << std::endl << "Nodal connectivity set but not allocated !"; return ; }
7630 mcIdType lgth=_nodal_connec_index->getNumberOfTuples();
7631 std::size_t cpt=_nodal_connec_index->getNumberOfComponents();
7632 if(cpt!=1 || lgth<1)
7634 stream << std::endl << "Number of cells : " << lgth-1 << ".";
7637 std::string MEDCouplingUMesh::getVTKDataSetType() const
7639 return std::string("UnstructuredGrid");
7642 std::string MEDCouplingUMesh::getVTKFileExtension() const
7644 return std::string("vtu");
7650 * Provides a renumbering of the cells of this (which has to be a piecewise connected 1D line), so that
7651 * the segments of the line are indexed in consecutive order (i.e. cells \a i and \a i+1 are neighbors).
7652 * This doesn't modify the mesh. This method only works using nodal connectivity consideration. Coordinates of nodes are ignored here.
7653 * The caller is to deal with the resulting DataArrayIdType.
7654 * \throw If the coordinate array is not set.
7655 * \throw If the nodal connectivity of the cells is not defined.
7656 * \throw If m1 is not a mesh of dimension 2, or m1 is not a mesh of dimension 1
7657 * \throw If m2 is not a (piecewise) line (i.e. if a point has more than 2 adjacent segments)
7659 * \sa DataArrayIdType::sortEachPairToMakeALinkedList
7661 DataArrayIdType *MEDCouplingUMesh::orderConsecutiveCells1D() const
7663 checkFullyDefined();
7664 if(getMeshDimension()!=1)
7665 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D works on unstructured mesh with meshdim = 1 !");
7667 // Check that this is a line (and not a more complex 1D mesh) - each point is used at most by 2 segments:
7668 MCAuto<DataArrayIdType> _d(DataArrayIdType::New()),_dI(DataArrayIdType::New());
7669 MCAuto<DataArrayIdType> _rD(DataArrayIdType::New()),_rDI(DataArrayIdType::New());
7670 MCAuto<MEDCouplingUMesh> m_points(buildDescendingConnectivity(_d, _dI, _rD, _rDI));
7671 const mcIdType *d(_d->begin()), *dI(_dI->begin());
7672 const mcIdType *rD(_rD->begin()), *rDI(_rDI->begin());
7673 MCAuto<DataArrayIdType> _dsi(_rDI->deltaShiftIndex());
7674 const mcIdType * dsi(_dsi->begin());
7675 MCAuto<DataArrayIdType> dsii = _dsi->findIdsNotInRange(0,3);
7677 if (dsii->getNumberOfTuples())
7678 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D only work with a mesh being a (piecewise) connected line!");
7680 mcIdType nc=getNumberOfCells();
7681 MCAuto<DataArrayIdType> result(DataArrayIdType::New());
7682 result->alloc(nc,1);
7684 // set of edges not used so far
7685 std::set<mcIdType> edgeSet;
7686 for (mcIdType i=0; i<nc; edgeSet.insert(i), i++);
7688 mcIdType startSeg=0;
7690 // while we have points with only one neighbor segments
7693 std::list<mcIdType> linePiece;
7694 // fills a list of consecutive segment linked to startSeg. This can go forward or backward.
7695 for (int direction=0;direction<2;direction++) // direction=0 --> forward, direction=1 --> backward
7697 // Fill the list forward (resp. backward) from the start segment:
7698 mcIdType activeSeg = startSeg;
7699 mcIdType prevPointId = -20;
7701 while (!edgeSet.empty())
7703 if (!(direction == 1 && prevPointId==-20)) // prevent adding twice startSeg
7706 linePiece.push_back(activeSeg);
7708 linePiece.push_front(activeSeg);
7709 edgeSet.erase(activeSeg);
7712 mcIdType ptId1 = d[dI[activeSeg]], ptId2 = d[dI[activeSeg]+1];
7713 ptId = direction ? (ptId1 == prevPointId ? ptId2 : ptId1) : (ptId2 == prevPointId ? ptId1 : ptId2);
7714 if (dsi[ptId] == 1) // hitting the end of the line
7717 mcIdType seg1 = rD[rDI[ptId]], seg2 = rD[rDI[ptId]+1];
7718 activeSeg = (seg1 == activeSeg) ? seg2 : seg1;
7721 // Done, save final piece into DA:
7722 std::copy(linePiece.begin(), linePiece.end(), result->getPointer()+newIdx);
7723 newIdx += ToIdType(linePiece.size());
7725 // identify next valid start segment (one which is not consumed)
7726 if(!edgeSet.empty())
7727 startSeg = *(edgeSet.begin());
7729 while (!edgeSet.empty());
7730 return result.retn();
7734 * This method split some of edges of 2D cells in \a this. The edges to be split are specified in \a subNodesInSeg
7735 * and in \a subNodesInSegI using \ref numbering-indirect storage mode.
7736 * To do the work this method can optionally needs information about middle of subedges for quadratic cases if
7737 * a minimal creation of new nodes is wanted.
7738 * So this method try to reduce at most the number of new nodes. The only case that can lead this method to add
7739 * nodes if a SEG3 is split without information of middle.
7740 * \b WARNING : is returned value is different from 0 a call to MEDCouplingUMesh::mergeNodes is necessary to
7741 * avoid to have a non conform mesh.
7743 * \return mcIdType - the number of new nodes created (in most of cases 0).
7745 * \throw If \a this is not coherent.
7746 * \throw If \a this has not spaceDim equal to 2.
7747 * \throw If \a this has not meshDim equal to 2.
7748 * \throw If some subcells needed to be split are orphan.
7749 * \sa MEDCouplingUMesh::conformize2D
7751 mcIdType MEDCouplingUMesh::split2DCells(const DataArrayIdType *desc, const DataArrayIdType *descI, const DataArrayIdType *subNodesInSeg, const DataArrayIdType *subNodesInSegI, const DataArrayIdType *midOpt, const DataArrayIdType *midOptI)
7753 if(!desc || !descI || !subNodesInSeg || !subNodesInSegI)
7754 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : the 4 first arrays must be not null !");
7755 desc->checkAllocated(); descI->checkAllocated(); subNodesInSeg->checkAllocated(); subNodesInSegI->checkAllocated();
7756 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
7757 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : This method only works for meshes with spaceDim=2 and meshDim=2 !");
7758 if(midOpt==0 && midOptI==0)
7760 split2DCellsLinear(desc,descI,subNodesInSeg,subNodesInSegI);
7763 else if(midOpt!=0 && midOptI!=0)
7764 return split2DCellsQuadratic(desc,descI,subNodesInSeg,subNodesInSegI,midOpt,midOptI);
7766 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : middle parameters must be set to null for all or not null for all.");
7770 * 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
7771 * 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
7772 * the geometric cell type set to INTERP_KERNEL::NORM_POLYGON.
7773 * 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
7774 * 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.
7776 * \return false if the input connectivity represents already the convex hull, true if the input cell needs to be reordered.
7778 bool MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis(const double *coords, const mcIdType *nodalConnBg, const mcIdType *nodalConnEnd, DataArrayIdType *nodalConnecOut)
7780 std::size_t sz=std::distance(nodalConnBg,nodalConnEnd);
7783 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)*nodalConnBg);
7784 if(cm.getDimension()==2)
7786 const mcIdType *node=nodalConnBg+1;
7787 mcIdType startNode=*node++;
7788 double refX=coords[2*startNode];
7789 for(;node!=nodalConnEnd;node++)
7791 if(coords[2*(*node)]<refX)
7794 refX=coords[2*startNode];
7797 std::vector<mcIdType> tmpOut; tmpOut.reserve(sz); tmpOut.push_back(startNode);
7801 double angle0=-M_PI/2;
7803 mcIdType nextNode=-1;
7804 mcIdType prevNode=-1;
7806 double angleNext=0.;
7807 while(nextNode!=startNode)
7811 for(node=nodalConnBg+1;node!=nodalConnEnd;node++)
7813 if(*node!=tmpOut.back() && *node!=prevNode)
7815 tmp2[0]=coords[2*(*node)]-coords[2*tmpOut.back()]; tmp2[1]=coords[2*(*node)+1]-coords[2*tmpOut.back()+1];
7816 double angleM=INTERP_KERNEL::EdgeArcCircle::GetAbsoluteAngle(tmp2,tmp1);
7821 res=angle0-angleM+2.*M_PI;
7830 if(nextNode!=startNode)
7832 angle0=angleNext-M_PI;
7835 prevNode=tmpOut.back();
7836 tmpOut.push_back(nextNode);
7839 std::vector<mcIdType> tmp3(2*(sz-1));
7840 std::vector<mcIdType>::iterator it=std::copy(nodalConnBg+1,nodalConnEnd,tmp3.begin());
7841 std::copy(nodalConnBg+1,nodalConnEnd,it);
7842 if(std::search(tmp3.begin(),tmp3.end(),tmpOut.begin(),tmpOut.end())!=tmp3.end())
7844 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
7847 if(std::search(tmp3.rbegin(),tmp3.rend(),tmpOut.begin(),tmpOut.end())!=tmp3.rend())
7849 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
7854 nodalConnecOut->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYGON));
7855 nodalConnecOut->insertAtTheEnd(tmpOut.begin(),tmpOut.end());
7860 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
7863 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
7867 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
7868 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
7869 * 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]].
7870 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
7871 * A negative value in \b arrIn means that it is ignored.
7872 * 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.
7874 * \param [in] arrIn arr origin array from which the extraction will be done.
7875 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7876 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
7877 * \sa MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed, MEDCouplingUMesh::partitionBySpreadZone
7879 DataArrayIdType *MEDCouplingUMesh::ComputeSpreadZoneGradually(const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn)
7881 mcIdType seed=0,nbOfDepthPeelingPerformed=0;
7882 return ComputeSpreadZoneGraduallyFromSeed(&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfDepthPeelingPerformed);
7886 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
7887 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
7888 * 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]].
7889 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
7890 * A negative value in \b arrIn means that it is ignored.
7891 * 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.
7892 * \param [in] seedBg the begin pointer (included) of an array containing the seed of the search zone
7893 * \param [in] seedEnd the end pointer (not included) of an array containing the seed of the search zone
7894 * \param [in] arrIn arr origin array from which the extraction will be done.
7895 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7896 * \param [in] nbOfDepthPeeling the max number of peels requested in search. By default -1, that is to say, no limit.
7897 * \param [out] nbOfDepthPeelingPerformed the number of peels effectively performed. May be different from \a nbOfDepthPeeling
7898 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
7899 * \sa MEDCouplingUMesh::partitionBySpreadZone
7901 DataArrayIdType *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(const mcIdType *seedBg, const mcIdType *seedEnd, const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn, mcIdType nbOfDepthPeeling, mcIdType& nbOfDepthPeelingPerformed)
7903 nbOfDepthPeelingPerformed=0;
7905 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed : arrIndxIn input pointer is NULL !");
7906 mcIdType nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
7909 DataArrayIdType *ret=DataArrayIdType::New(); ret->alloc(0,1);
7913 std::vector<bool> fetched(nbOfTuples,false);
7914 return ComputeSpreadZoneGraduallyFromSeedAlg(fetched,seedBg,seedEnd,arrIn,arrIndxIn,nbOfDepthPeeling,nbOfDepthPeelingPerformed);
7920 * \b this is expected to be a mesh fully defined whose spaceDim==meshDim.
7921 * It returns a new allocated mesh having the same mesh dimension and lying on same coordinates.
7922 * The returned mesh contains as poly cells as number of contiguous zone (regarding connectivity).
7923 * A spread contiguous zone is built using poly cells (polyhedra in 3D, polygons in 2D and polyline in 1D).
7924 * The sum of measure field of returned mesh is equal to the sum of measure field of this.
7926 * \return a newly allocated mesh lying on the same coords than \b this with same meshdimension than \b this.
7928 MEDCouplingUMesh *MEDCouplingUMesh::buildSpreadZonesWithPoly() const
7930 checkFullyDefined();
7931 int mdim=getMeshDimension();
7932 int spaceDim=getSpaceDimension();
7934 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension and spacedimension do not match !");
7935 std::vector<DataArrayIdType *> partition=partitionBySpreadZone();
7936 std::vector< MCAuto<DataArrayIdType> > partitionAuto; partitionAuto.reserve(partition.size());
7937 std::copy(partition.begin(),partition.end(),std::back_insert_iterator<std::vector< MCAuto<DataArrayIdType> > >(partitionAuto));
7938 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
7939 ret->setCoords(getCoords());
7940 ret->allocateCells(ToIdType(partition.size()));
7942 for(std::vector<DataArrayIdType *>::const_iterator it=partition.begin();it!=partition.end();it++)
7944 MCAuto<MEDCouplingUMesh> tmp=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf((*it)->begin(),(*it)->end(),true));
7945 MCAuto<DataArrayIdType> cell;
7949 cell=tmp->buildUnionOf2DMesh();
7952 cell=tmp->buildUnionOf3DMesh();
7955 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension supported are [2,3] ! Not implemented yet for others !");
7958 ret->insertNextCell((INTERP_KERNEL::NormalizedCellType)cell->getIJSafe(0,0),cell->getNumberOfTuples()-1,cell->begin()+1);
7961 ret->finishInsertingCells();
7966 * This method partitions \b this into contiguous zone.
7967 * This method only needs a well defined connectivity. Coordinates are not considered here.
7968 * This method returns a vector of \b newly allocated arrays that the caller has to deal with.
7970 std::vector<DataArrayIdType *> MEDCouplingUMesh::partitionBySpreadZone() const
7972 DataArrayIdType *neigh=0,*neighI=0;
7973 computeNeighborsOfCells(neigh,neighI);
7974 MCAuto<DataArrayIdType> neighAuto(neigh),neighIAuto(neighI);
7975 return PartitionBySpreadZone(neighAuto,neighIAuto);
7978 std::vector<DataArrayIdType *> MEDCouplingUMesh::PartitionBySpreadZone(const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn)
7980 if(!arrIn || !arrIndxIn)
7981 throw INTERP_KERNEL::Exception("PartitionBySpreadZone : null input pointers !");
7982 arrIn->checkAllocated(); arrIndxIn->checkAllocated();
7983 mcIdType nbOfTuples(arrIndxIn->getNumberOfTuples());
7984 if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1 || nbOfTuples<1)
7985 throw INTERP_KERNEL::Exception("PartitionBySpreadZone : invalid arrays in input !");
7986 mcIdType nbOfCellsCur(nbOfTuples-1);
7987 std::vector<DataArrayIdType *> ret;
7990 std::vector<bool> fetchedCells(nbOfCellsCur,false);
7991 std::vector< MCAuto<DataArrayIdType> > ret2;
7993 while(seed<nbOfCellsCur)
7995 mcIdType nbOfPeelPerformed=0;
7996 ret2.push_back(ComputeSpreadZoneGraduallyFromSeedAlg(fetchedCells,&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfPeelPerformed));
7997 seed=ToIdType(std::distance(fetchedCells.begin(),std::find(fetchedCells.begin()+seed,fetchedCells.end(),false)));
7999 for(std::vector< MCAuto<DataArrayIdType> >::iterator it=ret2.begin();it!=ret2.end();it++)
8000 ret.push_back((*it).retn());
8005 * This method returns given a distribution of cell type (returned for example by MEDCouplingUMesh::getDistributionOfTypes method and customized after) a
8006 * newly allocated DataArrayIdType instance with 2 components ready to be interpreted as input of DataArrayIdType::findRangeIdForEachTuple method.
8008 * \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.
8009 * \return a newly allocated DataArrayIdType to be managed by the caller.
8010 * \throw In case of \a code has not the right format (typically of size 3*n)
8012 DataArrayIdType *MEDCouplingUMesh::ComputeRangesFromTypeDistribution(const std::vector<mcIdType>& code)
8014 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
8015 std::size_t nb=code.size()/3;
8016 if(code.size()%3!=0)
8017 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeRangesFromTypeDistribution : invalid input code !");
8019 mcIdType *retPtr=ret->getPointer();
8020 for(std::size_t i=0;i<nb;i++,retPtr+=2)
8022 retPtr[0]=code[3*i+2];
8023 retPtr[1]=code[3*i+2]+code[3*i+1];
8029 * This method expects that \a this a 3D mesh (spaceDim=3 and meshDim=3) with all coordinates and connectivities set.
8030 * All cells in \a this are expected to be linear 3D cells.
8031 * This method will split **all** 3D cells in \a this into INTERP_KERNEL::NORM_TETRA4 cells and put them in the returned mesh.
8032 * It leads to an increase to number of cells.
8033 * This method contrary to MEDCouplingUMesh::simplexize can append coordinates in \a this to perform its work.
8034 * The \a nbOfAdditionalPoints returned value informs about it. If > 0, the coordinates array in returned mesh will have \a nbOfAdditionalPoints
8035 * more tuples (nodes) than in \a this. Anyway, all the nodes in \a this (with the same order) will be in the returned mesh.
8037 * \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.
8038 * For all other cells, the splitting policy will be ignored. See INTERP_KERNEL::SplittingPolicy for the images.
8039 * \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.
8040 * \param [out] n2oCells - A new instance of DataArrayIdType holding, for each new cell,
8041 * an id of old cell producing it. The caller is to delete this array using
8042 * decrRef() as it is no more needed.
8043 * \return MEDCoupling1SGTUMesh * - the mesh containing only INTERP_KERNEL::NORM_TETRA4 cells.
8045 * \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
8046 * the policy PLANAR_FACE_6 should be used on a mesh sorted with MEDCoupling1SGTUMesh::sortHexa8EachOther.
8048 * \throw If \a this is not a 3D mesh (spaceDim==3 and meshDim==3).
8049 * \throw If \a this is not fully constituted with linear 3D cells.
8050 * \sa MEDCouplingUMesh::simplexize, MEDCoupling1SGTUMesh::sortHexa8EachOther
8052 MEDCoupling1SGTUMesh *MEDCouplingUMesh::tetrahedrize(int policy, DataArrayIdType *& n2oCells, mcIdType& nbOfAdditionalPoints) const
8054 INTERP_KERNEL::SplittingPolicy pol((INTERP_KERNEL::SplittingPolicy)policy);
8055 checkConnectivityFullyDefined();
8056 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
8057 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tetrahedrize : only available for mesh with meshdim == 3 and spacedim == 3 !");
8058 mcIdType nbOfCells=getNumberOfCells();
8059 mcIdType nbNodes(getNumberOfNodes());
8060 MCAuto<MEDCoupling1SGTUMesh> ret0(MEDCoupling1SGTUMesh::New(getName(),INTERP_KERNEL::NORM_TETRA4));
8061 MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(nbOfCells,1);
8062 mcIdType *retPt(ret->getPointer());
8063 MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()); newConn->alloc(0,1);
8064 MCAuto<DataArrayDouble> addPts(DataArrayDouble::New()); addPts->alloc(0,1);
8065 const mcIdType *oldc(_nodal_connec->begin());
8066 const mcIdType *oldci(_nodal_connec_index->begin());
8067 const double *coords(_coords->begin());
8068 for(mcIdType i=0;i<nbOfCells;i++,oldci++,retPt++)
8070 std::vector<mcIdType> a; std::vector<double> b;
8071 INTERP_KERNEL::SplitIntoTetras(pol,(INTERP_KERNEL::NormalizedCellType)oldc[oldci[0]],oldc+oldci[0]+1,oldc+oldci[1],coords,a,b);
8072 std::size_t nbOfTet(a.size()/4); *retPt=ToIdType(nbOfTet);
8073 const mcIdType *aa(&a[0]);
8076 for(std::vector<mcIdType>::iterator it=a.begin();it!=a.end();it++)
8078 *it=(-(*(it))-1+nbNodes);
8079 addPts->insertAtTheEnd(b.begin(),b.end());
8080 nbNodes+=ToIdType(b.size()/3);
8082 for(std::size_t j=0;j<nbOfTet;j++,aa+=4)
8083 newConn->insertAtTheEnd(aa,aa+4);
8085 if(!addPts->empty())
8087 addPts->rearrange(3);
8088 nbOfAdditionalPoints=addPts->getNumberOfTuples();
8089 addPts=DataArrayDouble::Aggregate(getCoords(),addPts);
8090 ret0->setCoords(addPts);
8094 nbOfAdditionalPoints=0;
8095 ret0->setCoords(getCoords());
8097 ret0->setNodalConnectivity(newConn);
8099 ret->computeOffsetsFull();
8100 n2oCells=ret->buildExplicitArrOfSliceOnScaledArr(0,nbOfCells,1);
8104 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),
8105 _own_cell(true),_cell_id(-1),_nb_cell(0)
8110 _nb_cell=mesh->getNumberOfCells();
8114 MEDCouplingUMeshCellIterator::~MEDCouplingUMeshCellIterator()
8122 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh, MEDCouplingUMeshCell *itc, mcIdType bg, mcIdType end):_mesh(mesh),_cell(itc),
8123 _own_cell(false),_cell_id(bg-1),
8130 MEDCouplingUMeshCell *MEDCouplingUMeshCellIterator::nextt()
8133 if(_cell_id<_nb_cell)
8142 MEDCouplingUMeshCellByTypeEntry::MEDCouplingUMeshCellByTypeEntry(MEDCouplingUMesh *mesh):_mesh(mesh)
8148 MEDCouplingUMeshCellByTypeIterator *MEDCouplingUMeshCellByTypeEntry::iterator()
8150 return new MEDCouplingUMeshCellByTypeIterator(_mesh);
8153 MEDCouplingUMeshCellByTypeEntry::~MEDCouplingUMeshCellByTypeEntry()
8159 MEDCouplingUMeshCellEntry::MEDCouplingUMeshCellEntry(MEDCouplingUMesh *mesh, INTERP_KERNEL::NormalizedCellType type, MEDCouplingUMeshCell *itc, mcIdType bg, mcIdType end):_mesh(mesh),_type(type),
8167 MEDCouplingUMeshCellEntry::~MEDCouplingUMeshCellEntry()
8173 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCellEntry::getType() const
8178 mcIdType MEDCouplingUMeshCellEntry::getNumberOfElems() const
8183 MEDCouplingUMeshCellIterator *MEDCouplingUMeshCellEntry::iterator()
8185 return new MEDCouplingUMeshCellIterator(_mesh,_itc,_bg,_end);
8188 MEDCouplingUMeshCellByTypeIterator::MEDCouplingUMeshCellByTypeIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),_cell_id(0),_nb_cell(0)
8193 _nb_cell=mesh->getNumberOfCells();
8197 MEDCouplingUMeshCellByTypeIterator::~MEDCouplingUMeshCellByTypeIterator()
8204 MEDCouplingUMeshCellEntry *MEDCouplingUMeshCellByTypeIterator::nextt()
8206 const mcIdType *c=_mesh->getNodalConnectivity()->begin();
8207 const mcIdType *ci=_mesh->getNodalConnectivityIndex()->begin();
8208 if(_cell_id<_nb_cell)
8210 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[_cell_id]];
8211 mcIdType nbOfElems=ToIdType(std::distance(ci+_cell_id,std::find_if(ci+_cell_id,ci+_nb_cell,MEDCouplingImpl::ConnReader(c,type))));
8212 mcIdType startId=_cell_id;
8213 _cell_id+=nbOfElems;
8214 return new MEDCouplingUMeshCellEntry(_mesh,type,_cell,startId,_cell_id);
8220 MEDCouplingUMeshCell::MEDCouplingUMeshCell(MEDCouplingUMesh *mesh):_conn(0),_conn_indx(0),_conn_lgth(NOTICABLE_FIRST_VAL)
8224 _conn=mesh->getNodalConnectivity()->getPointer();
8225 _conn_indx=mesh->getNodalConnectivityIndex()->getPointer();
8229 void MEDCouplingUMeshCell::next()
8231 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8236 _conn_lgth=_conn_indx[1]-_conn_indx[0];
8239 std::string MEDCouplingUMeshCell::repr() const
8241 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8243 std::ostringstream oss; oss << "Cell Type " << INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)_conn[0]).getRepr();
8245 std::copy(_conn+1,_conn+_conn_lgth,std::ostream_iterator<mcIdType>(oss," "));
8249 return std::string("MEDCouplingUMeshCell::repr : Invalid pos");
8252 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCell::getType() const
8254 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8255 return (INTERP_KERNEL::NormalizedCellType)_conn[0];
8257 return INTERP_KERNEL::NORM_ERROR;
8260 const mcIdType *MEDCouplingUMeshCell::getAllConn(mcIdType& lgth) const
8263 if(_conn_lgth!=NOTICABLE_FIRST_VAL)