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->getPointerSilent()+pos,commonCells->getPointerSilent()+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());
1850 if(other->getNumberOfCells()==0)
1852 MCAuto<DataArrayIdType> dftRet(DataArrayIdType::New()); dftRet->alloc(0,1); arr=dftRet.retn(); arr->setName(other->getName());
1855 DataArrayIdType *commonCells(nullptr),*commonCellsI(nullptr);
1856 mesh->findCommonCells(compType,nbOfCells,commonCells,commonCellsI);
1857 MCAuto<DataArrayIdType> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1858 mcIdType newNbOfCells=-1;
1859 MCAuto<DataArrayIdType> o2n = DataArrayIdType::ConvertIndexArrayToO2N(ToIdType(mesh->getNumberOfCells()),commonCells->begin(),commonCellsI->begin(),commonCellsI->end(),newNbOfCells);
1860 MCAuto<DataArrayIdType> p0(o2n->selectByTupleIdSafeSlice(0,nbOfCells,1));
1861 mcIdType maxPart(p0->getMaxValueInArray());
1862 bool ret(maxPart==newNbOfCells-1);
1863 MCAuto<DataArrayIdType> p1(p0->invertArrayO2N2N2O(newNbOfCells));
1864 // fill p1 array in case of presence of cells in other not in this
1865 mcIdType *pt(p1->getPointer());
1866 for(mcIdType i = maxPart ; i < newNbOfCells-1 ; ++i )
1869 MCAuto<DataArrayIdType> p2(o2n->subArray(nbOfCells));
1870 p2->transformWithIndArr(p1->begin(),p1->end()); p2->setName(other->getName());
1876 * This method makes the assumption that \a this and \a other share the same coords. If not an exception will be thrown !
1877 * This method tries to determine if \b other is fully included in \b this.
1878 * The main difference is that this method is not expected to throw exception.
1879 * This method has two outputs :
1881 * \param other other mesh
1882 * \param arr is an output parameter that returns a \b newly created instance. This array is of size 'other->getNumberOfCells()'.
1883 * \return If \a other is fully included in 'this 'true is returned. If not false is returned.
1885 bool MEDCouplingUMesh::areCellsIncludedInPolicy7(const MEDCouplingUMesh *other, DataArrayIdType *& arr) const
1887 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1888 DataArrayIdType *commonCells=0,*commonCellsI=0;
1889 mcIdType thisNbCells=getNumberOfCells();
1890 mesh->findCommonCells(7,thisNbCells,commonCells,commonCellsI);
1891 MCAuto<DataArrayIdType> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1892 const mcIdType *commonCellsPtr=commonCells->getConstPointer(),*commonCellsIPtr=commonCellsI->getConstPointer();
1893 mcIdType otherNbCells=other->getNumberOfCells();
1894 MCAuto<DataArrayIdType> arr2=DataArrayIdType::New();
1895 arr2->alloc(otherNbCells,1);
1896 arr2->fillWithZero();
1897 mcIdType *arr2Ptr=arr2->getPointer();
1898 mcIdType nbOfCommon=commonCellsI->getNumberOfTuples()-1;
1899 for(mcIdType i=0;i<nbOfCommon;i++)
1901 mcIdType start=commonCellsPtr[commonCellsIPtr[i]];
1902 if(start<thisNbCells)
1904 for(mcIdType j=commonCellsIPtr[i]+1;j!=commonCellsIPtr[i+1];j++)
1906 mcIdType sig=commonCellsPtr[j]>0?1:-1;
1907 mcIdType val=std::abs(commonCellsPtr[j])-1;
1908 if(val>=thisNbCells)
1909 arr2Ptr[val-thisNbCells]=sig*(start+1);
1913 arr2->setName(other->getName());
1914 if(arr2->presenceOfValue(0))
1920 MEDCouplingUMesh *MEDCouplingUMesh::mergeMyselfWithOnSameCoords(const MEDCouplingPointSet *other) const
1923 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : input other is null !");
1924 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
1926 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : the input other mesh is not of type unstructured !");
1927 std::vector<const MEDCouplingUMesh *> ms(2);
1930 return MergeUMeshesOnSameCoords(ms);
1934 * Build a sub part of \b this lying or not on the same coordinates than \b this (regarding value of \b keepCoords).
1935 * By default coordinates are kept. This method is close to MEDCouplingUMesh::buildPartOfMySelf except that here input
1936 * cellIds is not given explicitly but by a range python like.
1941 * \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.
1942 * \return a newly allocated
1944 * \warning This method modifies can generate an unstructured mesh whose cells are not sorted by geometric type order.
1945 * In view of the MED file writing, a renumbering of cells of returned unstructured mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
1947 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfSlice(mcIdType start, mcIdType end, mcIdType step, bool keepCoords) const
1949 if(getMeshDimension()!=-1)
1950 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelfSlice(start,end,step,keepCoords));
1953 mcIdType newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfSlice for -1 dimension mesh ");
1955 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
1957 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
1959 return const_cast<MEDCouplingUMesh *>(this);
1964 * Creates a new MEDCouplingUMesh containing specified cells of \a this mesh.
1965 * The result mesh shares or not the node coordinates array with \a this mesh depending
1966 * on \a keepCoords parameter.
1967 * \warning Cells of the result mesh can be \b not sorted by geometric type, hence,
1968 * to write this mesh to the MED file, its cells must be sorted using
1969 * sortCellsInMEDFileFrmt().
1970 * \param [in] begin - an array of cell ids to include to the new mesh.
1971 * \param [in] end - a pointer to last-plus-one-th element of \a begin.
1972 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
1973 * array of \a this mesh, else "free" nodes are removed from the result mesh
1974 * by calling zipCoords().
1975 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
1976 * to delete this mesh using decrRef() as it is no more needed.
1977 * \throw If the coordinates array is not set.
1978 * \throw If the nodal connectivity of cells is not defined.
1979 * \throw If any cell id in the array \a begin is not valid.
1981 * \if ENABLE_EXAMPLES
1982 * \ref cpp_mcumesh_buildPartOfMySelf "Here is a C++ example".<br>
1983 * \ref py_mcumesh_buildPartOfMySelf "Here is a Python example".
1986 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelf(const mcIdType *begin, const mcIdType *end, bool keepCoords) const
1988 if(getMeshDimension()!=-1)
1989 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelf(begin,end,keepCoords));
1993 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
1995 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
1997 return const_cast<MEDCouplingUMesh *>(this);
2002 * This method operates only on nodal connectivity on \b this. Coordinates of \b this is completely ignored here.
2004 * 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.
2005 * Size of [ \b cellIdsBg, \b cellIdsEnd ) ) must be equal to the number of cells of otherOnSameCoordsThanThis.
2006 * The number of cells of \b this will remain the same with this method.
2008 * \param [in] cellIdsBg begin of cell ids (included) of cells in this to assign
2009 * \param [in] cellIdsEnd end of cell ids (excluded) of cells in this to assign
2010 * \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 ).
2011 * Coordinate pointer of \b this and those of \b otherOnSameCoordsThanThis must be the same
2013 void MEDCouplingUMesh::setPartOfMySelf(const mcIdType *cellIdsBg, const mcIdType *cellIdsEnd, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2015 checkConnectivityFullyDefined();
2016 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2017 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2018 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelf : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2019 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2021 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2022 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2023 throw INTERP_KERNEL::Exception(oss.str());
2025 mcIdType nbOfCellsToModify( ToIdType((std::distance(cellIdsBg,cellIdsEnd))));
2026 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2028 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2029 throw INTERP_KERNEL::Exception(oss.str());
2031 mcIdType nbOfCells(getNumberOfCells());
2032 bool easyAssign(true);
2033 const mcIdType *connI(_nodal_connec_index->begin());
2034 const mcIdType *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->begin();
2035 for(const mcIdType *it=cellIdsBg;it!=cellIdsEnd && easyAssign;it++,connIOther++)
2037 if(*it>=0 && *it<nbOfCells)
2039 easyAssign=(connIOther[1]-connIOther[0])==(connI[*it+1]-connI[*it]);
2043 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : On pos #" << std::distance(cellIdsBg,it) << " id is equal to " << *it << " which is not in [0," << nbOfCells << ") !";
2044 throw INTERP_KERNEL::Exception(oss.str());
2049 DataArrayIdType::SetPartOfIndexedArraysSameIdx(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2054 DataArrayIdType *arrOut=0,*arrIOut=0;
2055 DataArrayIdType::SetPartOfIndexedArrays(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2057 MCAuto<DataArrayIdType> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2058 setConnectivity(arrOut,arrIOut,true);
2062 void MEDCouplingUMesh::setPartOfMySelfSlice(mcIdType start, mcIdType end, mcIdType step, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2064 checkConnectivityFullyDefined();
2065 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2066 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2067 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelfSlice : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2068 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2070 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2071 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2072 throw INTERP_KERNEL::Exception(oss.str());
2074 mcIdType nbOfCellsToModify=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::setPartOfMySelfSlice : ");
2075 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2077 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2078 throw INTERP_KERNEL::Exception(oss.str());
2080 mcIdType nbOfCells=getNumberOfCells();
2081 bool easyAssign=true;
2082 const mcIdType *connI=_nodal_connec_index->getConstPointer();
2083 const mcIdType *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2085 for(mcIdType i=0;i<nbOfCellsToModify && easyAssign;i++,it+=step,connIOther++)
2087 if(it>=0 && it<nbOfCells)
2089 easyAssign=(connIOther[1]-connIOther[0])==(connI[it+1]-connI[it]);
2093 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : On pos #" << i << " id is equal to " << it << " which is not in [0," << nbOfCells << ") !";
2094 throw INTERP_KERNEL::Exception(oss.str());
2099 DataArrayIdType::SetPartOfIndexedArraysSameIdxSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2104 DataArrayIdType *arrOut=0,*arrIOut=0;
2105 DataArrayIdType::SetPartOfIndexedArraysSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2107 MCAuto<DataArrayIdType> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2108 setConnectivity(arrOut,arrIOut,true);
2114 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2115 * this->getMeshDimension(), that bound some cells of \a this mesh.
2116 * The cells of lower dimension to include to the result mesh are selected basing on
2117 * specified node ids and the value of \a fullyIn parameter. If \a fullyIn ==\c true, a
2118 * cell is copied if its all nodes are in the array \a begin of node ids. If \a fullyIn
2119 * ==\c false, a cell is copied if any its node is in the array of node ids. The
2120 * created mesh shares the node coordinates array with \a this mesh.
2121 * \param [in] begin - the array of node ids.
2122 * \param [in] end - a pointer to the (last+1)-th element of \a begin.
2123 * \param [in] fullyIn - if \c true, then cells whose all nodes are in the
2124 * array \a begin are added, else cells whose any node is in the
2125 * array \a begin are added.
2126 * \return MEDCouplingUMesh * - new instance of MEDCouplingUMesh. The caller is
2127 * to delete this mesh using decrRef() as it is no more needed.
2128 * \throw If the coordinates array is not set.
2129 * \throw If the nodal connectivity of cells is not defined.
2130 * \throw If any node id in \a begin is not valid.
2132 * \if ENABLE_EXAMPLES
2133 * \ref cpp_mcumesh_buildFacePartOfMySelfNode "Here is a C++ example".<br>
2134 * \ref py_mcumesh_buildFacePartOfMySelfNode "Here is a Python example".
2137 MEDCouplingUMesh *MEDCouplingUMesh::buildFacePartOfMySelfNode(const mcIdType *begin, const mcIdType *end, bool fullyIn) const
2139 MCAuto<DataArrayIdType> desc,descIndx,revDesc,revDescIndx;
2140 desc=DataArrayIdType::New(); descIndx=DataArrayIdType::New(); revDesc=DataArrayIdType::New(); revDescIndx=DataArrayIdType::New();
2141 MCAuto<MEDCouplingUMesh> subMesh=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2142 desc=0; descIndx=0; revDesc=0; revDescIndx=0;
2143 return static_cast<MEDCouplingUMesh*>(subMesh->buildPartOfMySelfNode(begin,end,fullyIn));
2147 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2148 * this->getMeshDimension(), which bound only one cell of \a this mesh.
2149 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2150 * array of \a this mesh, else "free" nodes are removed from the result mesh
2151 * by calling zipCoords().
2152 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2153 * to delete this mesh using decrRef() as it is no more needed.
2154 * \throw If the coordinates array is not set.
2155 * \throw If the nodal connectivity of cells is not defined.
2157 * \if ENABLE_EXAMPLES
2158 * \ref cpp_mcumesh_buildBoundaryMesh "Here is a C++ example".<br>
2159 * \ref py_mcumesh_buildBoundaryMesh "Here is a Python example".
2162 MEDCouplingUMesh *MEDCouplingUMesh::buildBoundaryMesh(bool keepCoords) const
2164 DataArrayIdType *desc=DataArrayIdType::New();
2165 DataArrayIdType *descIndx=DataArrayIdType::New();
2166 DataArrayIdType *revDesc=DataArrayIdType::New();
2167 DataArrayIdType *revDescIndx=DataArrayIdType::New();
2169 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2172 descIndx->decrRef();
2173 mcIdType nbOfCells=meshDM1->getNumberOfCells();
2174 const mcIdType *revDescIndxC=revDescIndx->getConstPointer();
2175 std::vector<mcIdType> boundaryCells;
2176 for(mcIdType i=0;i<nbOfCells;i++)
2177 if(revDescIndxC[i+1]-revDescIndxC[i]==1)
2178 boundaryCells.push_back(i);
2179 revDescIndx->decrRef();
2180 MEDCouplingUMesh *ret=meshDM1->buildPartOfMySelf(&boundaryCells[0],&boundaryCells[0]+boundaryCells.size(),keepCoords);
2185 * This method returns a newly created DataArrayIdType instance containing ids of cells located in boundary.
2186 * A cell is detected to be on boundary if it contains one or more than one face having only one father.
2187 * This method makes the assumption that \a this is fully defined (coords,connectivity). If not an exception will be thrown.
2189 DataArrayIdType *MEDCouplingUMesh::findCellIdsOnBoundary() const
2191 checkFullyDefined();
2192 MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
2193 MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
2194 MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
2195 MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
2197 buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx)->decrRef();
2198 desc=(DataArrayIdType*)0; descIndx=(DataArrayIdType*)0;
2200 MCAuto<DataArrayIdType> tmp=revDescIndx->deltaShiftIndex();
2201 MCAuto<DataArrayIdType> faceIds=tmp->findIdsEqual(1); tmp=(DataArrayIdType*)0;
2202 const mcIdType *revDescPtr=revDesc->getConstPointer();
2203 const mcIdType *revDescIndxPtr=revDescIndx->getConstPointer();
2204 mcIdType nbOfCells=getNumberOfCells();
2205 std::vector<bool> ret1(nbOfCells,false);
2207 for(const mcIdType *pt=faceIds->begin();pt!=faceIds->end();pt++)
2208 if(!ret1[revDescPtr[revDescIndxPtr[*pt]]])
2209 { ret1[revDescPtr[revDescIndxPtr[*pt]]]=true; sz++; }
2211 DataArrayIdType *ret2=DataArrayIdType::New();
2213 mcIdType *ret2Ptr=ret2->getPointer();
2215 for(std::vector<bool>::const_iterator it=ret1.begin();it!=ret1.end();it++,sz++)
2218 ret2->setName("BoundaryCells");
2223 * This method finds in \b this the cell ids that lie on mesh \b otherDimM1OnSameCoords.
2224 * \b this and \b otherDimM1OnSameCoords have to lie on the same coordinate array pointer. The coherency of that coords array with connectivity
2225 * of \b this and \b otherDimM1OnSameCoords is not important here because this method works only on connectivity.
2226 * this->getMeshDimension() - 1 must be equal to otherDimM1OnSameCoords.getMeshDimension()
2228 * s0 is the cell ids set in \b this lying on at least one node in the fetched nodes in \b otherDimM1OnSameCoords.
2229 * 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
2230 * equals a cell in \b otherDimM1OnSameCoords.
2232 * \throw if \b otherDimM1OnSameCoords is not part of constituent of \b this, or if coordinate pointer of \b this and \b otherDimM1OnSameCoords
2233 * are not same, or if this->getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension()
2235 * \param [in] otherDimM1OnSameCoords
2236 * \param [out] cellIdsRk0 a newly allocated array containing the cell ids of s0 (which are cell ids of \b this) in the above algorithm.
2237 * \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
2238 * cellIdsRk1->transformWithIndArr(cellIdsRk0->begin(),cellIdsRk0->end());
2240 void MEDCouplingUMesh::findCellIdsLyingOn(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayIdType *&cellIdsRk0, DataArrayIdType *&cellIdsRk1) const
2242 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2243 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : coordinates pointer are not the same ! Use tryToShareSameCoords method !");
2244 checkConnectivityFullyDefined();
2245 otherDimM1OnSameCoords.checkConnectivityFullyDefined();
2246 if(getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension())
2247 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : invalid mesh dimension of input mesh regarding meshdimesion of this !");
2248 MCAuto<DataArrayIdType> fetchedNodeIds1=otherDimM1OnSameCoords.computeFetchedNodeIds();
2249 MCAuto<DataArrayIdType> s0arr=getCellIdsLyingOnNodes(fetchedNodeIds1->begin(),fetchedNodeIds1->end(),false);
2250 MCAuto<MEDCouplingUMesh> thisPart=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(s0arr->begin(),s0arr->end(),true));
2251 MCAuto<DataArrayIdType> descThisPart=DataArrayIdType::New(),descIThisPart=DataArrayIdType::New(),revDescThisPart=DataArrayIdType::New(),revDescIThisPart=DataArrayIdType::New();
2252 MCAuto<MEDCouplingUMesh> thisPartConsti=thisPart->buildDescendingConnectivity(descThisPart,descIThisPart,revDescThisPart,revDescIThisPart);
2253 const mcIdType *revDescThisPartPtr=revDescThisPart->getConstPointer(),*revDescIThisPartPtr=revDescIThisPart->getConstPointer();
2254 DataArrayIdType *idsOtherInConsti=0;
2255 bool b=thisPartConsti->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsOtherInConsti);
2256 MCAuto<DataArrayIdType> idsOtherInConstiAuto(idsOtherInConsti);
2258 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : the given mdim-1 mesh in other is not a constituent of this !");
2259 std::set<mcIdType> s1;
2260 for(const mcIdType *idOther=idsOtherInConsti->begin();idOther!=idsOtherInConsti->end();idOther++)
2261 s1.insert(revDescThisPartPtr+revDescIThisPartPtr[*idOther],revDescThisPartPtr+revDescIThisPartPtr[*idOther+1]);
2262 MCAuto<DataArrayIdType> s1arr_renum1=DataArrayIdType::New(); s1arr_renum1->alloc(s1.size(),1); std::copy(s1.begin(),s1.end(),s1arr_renum1->getPointer());
2263 s1arr_renum1->sort();
2264 cellIdsRk0=s0arr.retn();
2265 //cellIdsRk1=s_renum1.retn();
2266 cellIdsRk1=s1arr_renum1.retn();
2270 * 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
2271 * returned. This subpart of meshdim-1 mesh is built using meshdim-1 cells in it shared only one cell in \b this.
2273 * \return a newly allocated mesh lying on the same coordinates than \b this. The caller has to deal with returned mesh.
2275 MEDCouplingUMesh *MEDCouplingUMesh::computeSkin() const
2277 MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
2278 MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
2279 MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
2280 MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
2282 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2283 revDesc=0; desc=0; descIndx=0;
2284 MCAuto<DataArrayIdType> revDescIndx2=revDescIndx->deltaShiftIndex();
2285 MCAuto<DataArrayIdType> part=revDescIndx2->findIdsEqual(1);
2286 return static_cast<MEDCouplingUMesh *>(meshDM1->buildPartOfMySelf(part->begin(),part->end(),true));
2290 * Finds nodes lying on the boundary of \a this mesh.
2291 * \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of found
2292 * nodes. The caller is to delete this array using decrRef() as it is no
2294 * \throw If the coordinates array is not set.
2295 * \throw If the nodal connectivity of cells is node defined.
2297 * \if ENABLE_EXAMPLES
2298 * \ref cpp_mcumesh_findBoundaryNodes "Here is a C++ example".<br>
2299 * \ref py_mcumesh_findBoundaryNodes "Here is a Python example".
2302 DataArrayIdType *MEDCouplingUMesh::findBoundaryNodes() const
2304 MCAuto<MEDCouplingUMesh> skin=computeSkin();
2305 return skin->computeFetchedNodeIds();
2308 MEDCouplingUMesh *MEDCouplingUMesh::buildUnstructured() const
2311 return const_cast<MEDCouplingUMesh *>(this);
2315 * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2316 * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2317 * 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.
2318 * 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.
2319 * 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.
2321 * \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
2322 * parameter is altered during the call.
2323 * \param [out] nodeIdsToDuplicate node ids needed to be duplicated following the algorithm explain above.
2324 * \param [out] cellIdsNeededToBeRenum cell ids in \b this in which the renumber of nodes should be performed.
2325 * \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.
2327 * \warning This method modifies param \b otherDimM1OnSameCoords (for speed reasons).
2329 void MEDCouplingUMesh::findNodesToDuplicate(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayIdType *& nodeIdsToDuplicate,
2330 DataArrayIdType *& cellIdsNeededToBeRenum, DataArrayIdType *& cellIdsNotModified) const
2332 typedef MCAuto<DataArrayIdType> DAInt;
2333 typedef MCAuto<MEDCouplingUMesh> MCUMesh;
2335 checkFullyDefined();
2336 otherDimM1OnSameCoords.checkFullyDefined();
2337 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2338 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : meshes do not share the same coords array !");
2339 if(otherDimM1OnSameCoords.getMeshDimension()!=getMeshDimension()-1)
2340 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the mesh given in other parameter must have this->getMeshDimension()-1 !");
2342 // Checking star-shaped M1 group:
2343 DAInt dt0=DataArrayIdType::New(),dit0=DataArrayIdType::New(),rdt0=DataArrayIdType::New(),rdit0=DataArrayIdType::New();
2344 MCUMesh meshM2 = otherDimM1OnSameCoords.buildDescendingConnectivity(dt0, dit0, rdt0, rdit0);
2345 DAInt dsi = rdit0->deltaShiftIndex();
2346 DAInt idsTmp0 = dsi->findIdsNotInRange(-1, 3);
2347 if(idsTmp0->getNumberOfTuples())
2348 throw INTERP_KERNEL::Exception("MEDFileUMesh::buildInnerBoundaryAlongM1Group: group is too complex: some points (or edges) have more than two connected segments (or faces)!");
2349 dt0=0; dit0=0; rdt0=0; rdit0=0; idsTmp0=0;
2351 // Get extreme nodes from the group (they won't be duplicated), ie nodes belonging to boundary cells of M1
2352 DAInt xtremIdsM2 = dsi->findIdsEqual(1); dsi = 0;
2353 MCUMesh meshM2Part = static_cast<MEDCouplingUMesh *>(meshM2->buildPartOfMySelf(xtremIdsM2->begin(), xtremIdsM2->end(),true));
2354 DAInt xtrem = meshM2Part->computeFetchedNodeIds();
2355 // Remove from the list points on the boundary of the M0 mesh (those need duplication!)
2356 dt0=DataArrayIdType::New(),dit0=DataArrayIdType::New(),rdt0=DataArrayIdType::New(),rdit0=DataArrayIdType::New();
2357 MCUMesh m0desc = buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); dt0=0; dit0=0; rdt0=0;
2358 dsi = rdit0->deltaShiftIndex();
2359 DAInt boundSegs = dsi->findIdsEqual(1); // boundary segs/faces of the M0 mesh
2360 MCUMesh m0descSkin = static_cast<MEDCouplingUMesh *>(m0desc->buildPartOfMySelf(boundSegs->begin(),boundSegs->end(), true));
2361 DAInt fNodes = m0descSkin->computeFetchedNodeIds();
2362 // In 3D, some points on the boundary of M0 still need duplication:
2364 if (getMeshDimension() == 3)
2366 DAInt dnu1=DataArrayIdType::New(), dnu2=DataArrayIdType::New(), dnu3=DataArrayIdType::New(), dnu4=DataArrayIdType::New();
2367 MCUMesh m0descSkinDesc = m0descSkin->buildDescendingConnectivity(dnu1, dnu2, dnu3, dnu4);
2368 dnu1=0;dnu2=0;dnu3=0;dnu4=0;
2369 DataArrayIdType * corresp=0;
2370 meshM2->areCellsIncludedIn(m0descSkinDesc,2,corresp);
2371 DAInt validIds = corresp->findIdsInRange(0, meshM2->getNumberOfCells());
2373 if (validIds->getNumberOfTuples())
2375 MCUMesh m1IntersecSkin = static_cast<MEDCouplingUMesh *>(m0descSkinDesc->buildPartOfMySelf(validIds->begin(), validIds->end(), true));
2376 DAInt notDuplSkin = m1IntersecSkin->findBoundaryNodes();
2377 DAInt fNodes1 = fNodes->buildSubstraction(notDuplSkin);
2378 notDup = xtrem->buildSubstraction(fNodes1);
2381 notDup = xtrem->buildSubstraction(fNodes);
2384 notDup = xtrem->buildSubstraction(fNodes);
2386 // Now compute cells around group (i.e. cells where we will do the propagation to identify the two sub-sets delimited by the group)
2387 DAInt m1Nodes = otherDimM1OnSameCoords.computeFetchedNodeIds();
2388 DAInt dupl = m1Nodes->buildSubstraction(notDup);
2389 DAInt cellsAroundGroup = getCellIdsLyingOnNodes(dupl->begin(), dupl->end(), false); // false= take cell in, even if not all nodes are in notDup
2392 MCUMesh m0Part2=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(cellsAroundGroup->begin(),cellsAroundGroup->end(),true));
2393 mcIdType nCells2 = m0Part2->getNumberOfCells();
2394 DAInt desc00=DataArrayIdType::New(),descI00=DataArrayIdType::New(),revDesc00=DataArrayIdType::New(),revDescI00=DataArrayIdType::New();
2395 MCUMesh m01=m0Part2->buildDescendingConnectivity(desc00,descI00,revDesc00,revDescI00);
2397 // Neighbor information of the mesh without considering the crack (serves to count how many connex pieces it is made of)
2398 DataArrayIdType *tmp00=0,*tmp11=0;
2399 MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00, tmp00, tmp11);
2400 DAInt neighInit00(tmp00);
2401 DAInt neighIInit00(tmp11);
2402 // Neighbor information of the mesh WITH the crack (some neighbors are removed):
2403 DataArrayIdType *idsTmp=0;
2404 m01->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsTmp);
2406 // In the neighbor information remove the connection between high dimension cells and its low level constituents which are part
2407 // of the frontier given in parameter (i.e. the cells of low dimension from the group delimiting the crack):
2408 DataArrayIdType::RemoveIdsFromIndexedArrays(ids->begin(),ids->end(),desc00,descI00);
2409 DataArrayIdType *tmp0=0,*tmp1=0;
2410 // Compute the neighbor of each cell in m0Part2, taking into account the broken link above. Two
2411 // cells on either side of the crack (defined by the mesh of low dimension) are not neighbor anymore.
2412 ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00,tmp0,tmp1);
2413 DAInt neigh00(tmp0);
2414 DAInt neighI00(tmp1);
2416 // For each initial connex part of the sub-mesh (or said differently for each independent crack):
2417 mcIdType seed = 0, nIter = 0;
2418 mcIdType nIterMax = nCells2+1; // Safety net for the loop
2419 DAInt hitCells = DataArrayIdType::New(); hitCells->alloc(nCells2);
2420 hitCells->fillWithValue(-1);
2421 DAInt cellsToModifyConn0_torenum = DataArrayIdType::New();
2422 cellsToModifyConn0_torenum->alloc(0,1);
2423 while (nIter < nIterMax)
2425 DAInt t = hitCells->findIdsEqual(-1);
2426 if (!t->getNumberOfTuples())
2428 // Connex zone without the crack (to compute the next seed really)
2430 DAInt connexCheck = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neighInit00,neighIInit00, -1, dnu);
2432 for (mcIdType * ptr = connexCheck->getPointer(); cnt < connexCheck->getNumberOfTuples(); ptr++, cnt++)
2433 hitCells->setIJ(*ptr,0,1);
2434 // Connex zone WITH the crack (to identify cells lying on either part of the crack)
2435 DAInt spreadZone = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neigh00,neighI00, -1, dnu);
2436 cellsToModifyConn0_torenum = DataArrayIdType::Aggregate(cellsToModifyConn0_torenum, spreadZone, 0);
2437 // Compute next seed, i.e. a cell in another connex part, which was not covered by the previous iterations
2438 DAInt comple = cellsToModifyConn0_torenum->buildComplement(nCells2);
2439 DAInt nonHitCells = hitCells->findIdsEqual(-1);
2440 DAInt intersec = nonHitCells->buildIntersection(comple);
2441 if (intersec->getNumberOfTuples())
2442 { seed = intersec->getIJ(0,0); }
2447 if (nIter >= nIterMax)
2448 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate(): internal error - too many iterations.");
2450 DAInt cellsToModifyConn1_torenum=cellsToModifyConn0_torenum->buildComplement(neighI00->getNumberOfTuples()-1);
2451 cellsToModifyConn0_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2452 cellsToModifyConn1_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2454 cellIdsNeededToBeRenum=cellsToModifyConn0_torenum.retn();
2455 cellIdsNotModified=cellsToModifyConn1_torenum.retn();
2456 nodeIdsToDuplicate=dupl.retn();
2460 * This method operates a modification of the connectivity and coords in \b this.
2461 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2462 * its ids will be modified to id this->getNumberOfNodes()+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2463 * 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
2464 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id this->getNumberOfNodes()+0, node id nodeIdsToDuplicateBg[1] will have id this->getNumberOfNodes()+1,
2465 * node id nodeIdsToDuplicateBg[2] will have id this->getNumberOfNodes()+2...
2467 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2469 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2470 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2472 void MEDCouplingUMesh::duplicateNodes(const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd)
2474 mcIdType nbOfNodes=getNumberOfNodes();
2475 duplicateNodesInCoords(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd);
2476 duplicateNodesInConn(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,nbOfNodes);
2480 * This method renumbers only nodal connectivity in \a this. The renumbering is only an offset applied. So this method is a specialization of
2481 * \a renumberNodesInConn. \b WARNING, this method does not check that the resulting node ids in the nodal connectivity is in a valid range !
2483 * \param [in] offset - specifies the offset to be applied on each element of connectivity.
2485 * \sa renumberNodesInConn
2487 void MEDCouplingUMesh::renumberNodesWithOffsetInConn(mcIdType offset)
2489 checkConnectivityFullyDefined();
2490 mcIdType *conn(getNodalConnectivity()->getPointer());
2491 const mcIdType *connIndex(getNodalConnectivityIndex()->getConstPointer());
2492 mcIdType nbOfCells=getNumberOfCells();
2493 for(mcIdType i=0;i<nbOfCells;i++)
2494 for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2496 mcIdType& node=conn[iconn];
2497 if(node>=0)//avoid polyhedron separator
2502 _nodal_connec->declareAsNew();
2507 * Same than renumberNodesInConn(const mcIdType *) except that here the format of old-to-new traducer is using map instead
2508 * 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
2511 void MEDCouplingUMesh::renumberNodesInConn(const INTERP_KERNEL::HashMap<mcIdType,mcIdType>& newNodeNumbersO2N)
2513 this->renumberNodesInConnT< INTERP_KERNEL::HashMap<mcIdType,mcIdType> >(newNodeNumbersO2N);
2517 * Same than renumberNodesInConn(const mcIdType *) except that here the format of old-to-new traducer is using map instead
2518 * 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
2521 void MEDCouplingUMesh::renumberNodesInConn(const std::map<mcIdType,mcIdType>& newNodeNumbersO2N)
2523 this->renumberNodesInConnT< std::map<mcIdType,mcIdType> >(newNodeNumbersO2N);
2527 * Changes ids of nodes within the nodal connectivity arrays according to a permutation
2528 * array in "Old to New" mode. The node coordinates array is \b not changed by this method.
2529 * This method is a generalization of shiftNodeNumbersInConn().
2530 * \warning This method performs no check of validity of new ids. **Use it with care !**
2531 * \param [in] newNodeNumbersO2N - a permutation array, of length \a
2532 * this->getNumberOfNodes(), in "Old to New" mode.
2533 * See \ref numbering for more info on renumbering modes.
2534 * \throw If the nodal connectivity of cells is not defined.
2536 * \if ENABLE_EXAMPLES
2537 * \ref cpp_mcumesh_renumberNodesInConn "Here is a C++ example".<br>
2538 * \ref py_mcumesh_renumberNodesInConn "Here is a Python example".
2541 void MEDCouplingUMesh::renumberNodesInConn(const mcIdType *newNodeNumbersO2N)
2543 checkConnectivityFullyDefined();
2544 mcIdType *conn=getNodalConnectivity()->getPointer();
2545 const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2546 mcIdType nbOfCells=getNumberOfCells();
2547 for(mcIdType i=0;i<nbOfCells;i++)
2548 for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2550 mcIdType& node=conn[iconn];
2551 if(node>=0)//avoid polyhedron separator
2553 node=newNodeNumbersO2N[node];
2556 _nodal_connec->declareAsNew();
2561 * This method renumbers nodes \b in \b connectivity \b only \b without \b any \b reference \b to \b coords.
2562 * This method performs no check on the fact that new coordinate ids are valid. \b Use \b it \b with \b care !
2563 * This method is an specialization of \ref MEDCoupling::MEDCouplingUMesh::renumberNodesInConn "renumberNodesInConn method".
2565 * \param [in] delta specifies the shift size applied to nodeId in nodal connectivity in \b this.
2567 void MEDCouplingUMesh::shiftNodeNumbersInConn(mcIdType delta)
2569 checkConnectivityFullyDefined();
2570 mcIdType *conn=getNodalConnectivity()->getPointer();
2571 const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2572 mcIdType nbOfCells=getNumberOfCells();
2573 for(mcIdType i=0;i<nbOfCells;i++)
2574 for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2576 mcIdType& node=conn[iconn];
2577 if(node>=0)//avoid polyhedron separator
2582 _nodal_connec->declareAsNew();
2587 * This method operates a modification of the connectivity in \b this.
2588 * 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.
2589 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2590 * its ids will be modified to id offset+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2591 * 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
2592 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id offset+0, node id nodeIdsToDuplicateBg[1] will have id offset+1,
2593 * node id nodeIdsToDuplicateBg[2] will have id offset+2...
2595 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2596 * As an another consequense after the call of this method \b this can be transiently non cohrent.
2598 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2599 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2600 * \param [in] offset the offset applied to all node ids in connectivity that are in [ \a nodeIdsToDuplicateBg, \a nodeIdsToDuplicateEnd ).
2602 void MEDCouplingUMesh::duplicateNodesInConn(const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd, mcIdType offset)
2604 checkConnectivityFullyDefined();
2605 std::map<mcIdType,mcIdType> m;
2606 mcIdType val=offset;
2607 for(const mcIdType *work=nodeIdsToDuplicateBg;work!=nodeIdsToDuplicateEnd;work++,val++)
2609 mcIdType *conn=getNodalConnectivity()->getPointer();
2610 const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2611 mcIdType nbOfCells=getNumberOfCells();
2612 for(mcIdType i=0;i<nbOfCells;i++)
2613 for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2615 mcIdType& node=conn[iconn];
2616 if(node>=0)//avoid polyhedron separator
2618 std::map<mcIdType,mcIdType>::iterator it=m.find(node);
2627 * This method renumbers cells of \a this using the array specified by [old2NewBg;old2NewBg+getNumberOfCells())
2629 * Contrary to MEDCouplingPointSet::renumberNodes, this method makes a permutation without any fuse of cell.
2630 * After the call of this method the number of cells remains the same as before.
2632 * If 'check' equals true the method will check that any elements in [ \a old2NewBg; \a old2NewEnd ) is unique ; if not
2633 * an INTERP_KERNEL::Exception will be thrown. When 'check' equals true [ \a old2NewBg ; \a old2NewEnd ) is not expected to
2634 * be strictly in [0;this->getNumberOfCells()).
2636 * If 'check' equals false the method will not check the content of [ \a old2NewBg ; \a old2NewEnd ).
2637 * To avoid any throw of SIGSEGV when 'check' equals false, the elements in [ \a old2NewBg ; \a old2NewEnd ) should be unique and
2638 * should be contained in[0;this->getNumberOfCells()).
2640 * \param [in] old2NewBg is expected to be a dynamically allocated pointer of size at least equal to this->getNumberOfCells()
2643 void MEDCouplingUMesh::renumberCells(const mcIdType *old2NewBg, bool check)
2645 checkConnectivityFullyDefined();
2646 mcIdType nbCells=getNumberOfCells();
2647 const mcIdType *array=old2NewBg;
2649 array=DataArrayIdType::CheckAndPreparePermutation(old2NewBg,old2NewBg+nbCells);
2651 const mcIdType *conn=_nodal_connec->getConstPointer();
2652 const mcIdType *connI=_nodal_connec_index->getConstPointer();
2653 MCAuto<DataArrayIdType> o2n=DataArrayIdType::New(); o2n->useArray(array,false,DeallocType::C_DEALLOC,nbCells,1);
2654 MCAuto<DataArrayIdType> n2o=o2n->invertArrayO2N2N2O(nbCells);
2655 const mcIdType *n2oPtr=n2o->begin();
2656 MCAuto<DataArrayIdType> newConn=DataArrayIdType::New();
2657 newConn->alloc(_nodal_connec->getNumberOfTuples(),_nodal_connec->getNumberOfComponents());
2658 newConn->copyStringInfoFrom(*_nodal_connec);
2659 MCAuto<DataArrayIdType> newConnI=DataArrayIdType::New();
2660 newConnI->alloc(_nodal_connec_index->getNumberOfTuples(),_nodal_connec_index->getNumberOfComponents());
2661 newConnI->copyStringInfoFrom(*_nodal_connec_index);
2663 mcIdType *newC=newConn->getPointer();
2664 mcIdType *newCI=newConnI->getPointer();
2667 for(mcIdType i=0;i<nbCells;i++)
2669 mcIdType pos=n2oPtr[i];
2670 mcIdType nbOfElts=connI[pos+1]-connI[pos];
2671 newC=std::copy(conn+connI[pos],conn+connI[pos+1],newC);
2676 setConnectivity(newConn,newConnI);
2678 free(const_cast<mcIdType *>(array));
2682 * Finds cells whose bounding boxes intersect a given bounding box.
2683 * \param [in] bbox - an array defining the bounding box via coordinates of its
2684 * extremum points in "no interlace" mode, i.e. xMin, xMax, yMin, yMax, zMin,
2686 * \param [in] eps - a factor used to increase size of the bounding box of cell
2687 * before comparing it with \a bbox. This factor is multiplied by the maximal
2688 * extent of the bounding box of cell to produce an addition to this bounding box.
2689 * \return DataArrayIdType * - a new instance of DataArrayIdType holding ids for found
2690 * cells. The caller is to delete this array using decrRef() as it is no more
2692 * \throw If the coordinates array is not set.
2693 * \throw If the nodal connectivity of cells is not defined.
2695 * \if ENABLE_EXAMPLES
2696 * \ref cpp_mcumesh_getCellsInBoundingBox "Here is a C++ example".<br>
2697 * \ref py_mcumesh_getCellsInBoundingBox "Here is a Python example".
2700 DataArrayIdType *MEDCouplingUMesh::getCellsInBoundingBox(const double *bbox, double eps) const
2702 MCAuto<DataArrayIdType> elems=DataArrayIdType::New(); elems->alloc(0,1);
2703 if(getMeshDimension()==-1)
2705 elems->pushBackSilent(0);
2706 return elems.retn();
2708 int dim=getSpaceDimension();
2709 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2710 const mcIdType* conn = getNodalConnectivity()->getConstPointer();
2711 const mcIdType* conn_index= getNodalConnectivityIndex()->getConstPointer();
2712 const double* coords = getCoords()->getConstPointer();
2713 mcIdType nbOfCells=getNumberOfCells();
2714 for ( mcIdType ielem=0; ielem<nbOfCells;ielem++ )
2716 for (int i=0; i<dim; i++)
2718 elem_bb[i*2]=std::numeric_limits<double>::max();
2719 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2722 for (mcIdType inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2724 mcIdType node= conn[inode];
2725 if(node>=0)//avoid polyhedron separator
2727 for (int idim=0; idim<dim; idim++)
2729 if ( coords[node*dim+idim] < elem_bb[idim*2] )
2731 elem_bb[idim*2] = coords[node*dim+idim] ;
2733 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2735 elem_bb[idim*2+1] = coords[node*dim+idim] ;
2740 if (intersectsBoundingBox(elem_bb, bbox, dim, eps))
2741 elems->pushBackSilent(ielem);
2743 return elems.retn();
2747 * Given a boundary box 'bbox' returns elements 'elems' contained in this 'bbox' or touching 'bbox' (within 'eps' distance).
2748 * Warning 'elems' is incremented during the call so if elems is not empty before call returned elements will be
2749 * added in 'elems' parameter.
2751 DataArrayIdType *MEDCouplingUMesh::getCellsInBoundingBox(const INTERP_KERNEL::DirectedBoundingBox& bbox, double eps)
2753 MCAuto<DataArrayIdType> elems=DataArrayIdType::New(); elems->alloc(0,1);
2754 if(getMeshDimension()==-1)
2756 elems->pushBackSilent(0);
2757 return elems.retn();
2759 int dim=getSpaceDimension();
2760 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2761 const mcIdType* conn = getNodalConnectivity()->getConstPointer();
2762 const mcIdType* conn_index= getNodalConnectivityIndex()->getConstPointer();
2763 const double* coords = getCoords()->getConstPointer();
2764 mcIdType nbOfCells=getNumberOfCells();
2765 for ( mcIdType ielem=0; ielem<nbOfCells;ielem++ )
2767 for (int i=0; i<dim; i++)
2769 elem_bb[i*2]=std::numeric_limits<double>::max();
2770 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2773 for (mcIdType inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2775 mcIdType node= conn[inode];
2776 if(node>=0)//avoid polyhedron separator
2778 for (int idim=0; idim<dim; idim++)
2780 if ( coords[node*dim+idim] < elem_bb[idim*2] )
2782 elem_bb[idim*2] = coords[node*dim+idim] ;
2784 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2786 elem_bb[idim*2+1] = coords[node*dim+idim] ;
2791 if(intersectsBoundingBox(bbox, elem_bb, dim, eps))
2792 elems->pushBackSilent(ielem);
2794 return elems.retn();
2798 * Returns a type of a cell by its id.
2799 * \param [in] cellId - the id of the cell of interest.
2800 * \return INTERP_KERNEL::NormalizedCellType - enumeration item describing the cell type.
2801 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2803 INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::getTypeOfCell(mcIdType cellId) const
2805 const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
2806 if(cellId<_nodal_connec_index->getNbOfElems()-1)
2807 return (INTERP_KERNEL::NormalizedCellType) pt[ptI[cellId]];
2810 std::ostringstream oss; oss << "MEDCouplingUMesh::getTypeOfCell : Requesting type of cell #" << cellId << " but it should be in [0," << _nodal_connec_index->getNbOfElems()-1 << ") !";
2811 throw INTERP_KERNEL::Exception(oss.str());
2816 * This method returns a newly allocated array containing cell ids (ascendingly sorted) whose geometric type are equal to type.
2817 * This method does not throw exception if geometric type \a type is not in \a this.
2818 * This method throws an INTERP_KERNEL::Exception if meshdimension of \b this is not equal to those of \b type.
2819 * The coordinates array is not considered here.
2821 * \param [in] type the geometric type
2822 * \return cell ids in this having geometric type \a type.
2824 DataArrayIdType *MEDCouplingUMesh::giveCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2827 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
2829 checkConnectivityFullyDefined();
2830 mcIdType nbCells=getNumberOfCells();
2831 int mdim=getMeshDimension();
2832 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
2833 if(mdim!=ToIdType(cm.getDimension()))
2834 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::giveCellsWithType : Mismatch between mesh dimension and dimension of the cell !");
2835 const mcIdType *ptI=_nodal_connec_index->getConstPointer();
2836 const mcIdType *pt=_nodal_connec->getConstPointer();
2837 for(mcIdType i=0;i<nbCells;i++)
2839 if((INTERP_KERNEL::NormalizedCellType)pt[ptI[i]]==type)
2840 ret->pushBackSilent(i);
2846 * Returns nb of cells having the geometric type \a type. No throw if no cells in \a this has the geometric type \a type.
2848 mcIdType MEDCouplingUMesh::getNumberOfCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2850 const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
2851 mcIdType nbOfCells(getNumberOfCells()),ret(0);
2852 for(mcIdType i=0;i<nbOfCells;i++)
2853 if((INTERP_KERNEL::NormalizedCellType) pt[ptI[i]]==type)
2859 * Returns the nodal connectivity of a given cell.
2860 * The separator of faces within polyhedron connectivity (-1) is not returned, thus
2861 * all returned node ids can be used in getCoordinatesOfNode().
2862 * \param [in] cellId - an id of the cell of interest.
2863 * \param [in,out] conn - a vector where the node ids are appended. It is not
2864 * cleared before the appending.
2865 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2867 void MEDCouplingUMesh::getNodeIdsOfCell(mcIdType cellId, std::vector<mcIdType>& conn) const
2869 const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
2870 for(const mcIdType *w=pt+ptI[cellId]+1;w!=pt+ptI[cellId+1];w++)
2875 std::string MEDCouplingUMesh::simpleRepr() const
2877 static const char msg0[]="No coordinates specified !";
2878 std::ostringstream ret;
2879 ret << "Unstructured mesh with name : \"" << getName() << "\"\n";
2880 ret << "Description of mesh : \"" << getDescription() << "\"\n";
2882 double tt=getTime(tmpp1,tmpp2);
2883 ret << "Time attached to the mesh [unit] : " << tt << " [" << getTimeUnit() << "]\n";
2884 ret << "Iteration : " << tmpp1 << " Order : " << tmpp2 << "\n";
2886 { ret << "Mesh dimension : " << _mesh_dim << "\nSpace dimension : "; }
2888 { ret << " Mesh dimension has not been set or is invalid !"; }
2891 const int spaceDim=getSpaceDimension();
2892 ret << spaceDim << "\nInfo attached on space dimension : ";
2893 for(int i=0;i<spaceDim;i++)
2894 ret << "\"" << _coords->getInfoOnComponent(i) << "\" ";
2898 ret << msg0 << "\n";
2899 ret << "Number of nodes : ";
2901 ret << getNumberOfNodes() << "\n";
2903 ret << msg0 << "\n";
2904 ret << "Number of cells : ";
2905 if(_nodal_connec!=0 && _nodal_connec_index!=0)
2906 ret << getNumberOfCells() << "\n";
2908 ret << "No connectivity specified !" << "\n";
2909 ret << "Cell types present : ";
2910 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
2912 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter);
2913 ret << cm.getRepr() << " ";
2919 std::string MEDCouplingUMesh::advancedRepr() const
2921 std::ostringstream ret;
2922 ret << simpleRepr();
2923 ret << "\nCoordinates array : \n___________________\n\n";
2925 _coords->reprWithoutNameStream(ret);
2927 ret << "No array set !\n";
2928 ret << "\n\nConnectivity arrays : \n_____________________\n\n";
2929 reprConnectivityOfThisLL(ret);
2934 * This method returns a C++ code that is a dump of \a this.
2935 * This method will throw if this is not fully defined.
2937 std::string MEDCouplingUMesh::cppRepr() const
2939 static const char coordsName[]="coords";
2940 static const char connName[]="conn";
2941 static const char connIName[]="connI";
2942 checkFullyDefined();
2943 std::ostringstream ret; ret << "// coordinates" << std::endl;
2944 _coords->reprCppStream(coordsName,ret); ret << std::endl << "// connectivity" << std::endl;
2945 _nodal_connec->reprCppStream(connName,ret); ret << std::endl;
2946 _nodal_connec_index->reprCppStream(connIName,ret); ret << std::endl;
2947 ret << "MEDCouplingUMesh *mesh=MEDCouplingUMesh::New(\"" << getName() << "\"," << getMeshDimension() << ");" << std::endl;
2948 ret << "mesh->setCoords(" << coordsName << ");" << std::endl;
2949 ret << "mesh->setConnectivity(" << connName << "," << connIName << ",true);" << std::endl;
2950 ret << coordsName << "->decrRef(); " << connName << "->decrRef(); " << connIName << "->decrRef();" << std::endl;
2954 std::string MEDCouplingUMesh::reprConnectivityOfThis() const
2956 std::ostringstream ret;
2957 reprConnectivityOfThisLL(ret);
2962 * This method builds a newly allocated instance (with the same name than \a this) that the caller has the responsibility to deal with.
2963 * This method returns an instance with all arrays allocated (connectivity, connectivity index, coordinates)
2964 * but with length of these arrays set to 0. It allows to define an "empty" mesh (with nor cells nor nodes but compliant with
2967 * This method expects that \a this has a mesh dimension set and higher or equal to 0. If not an exception will be thrown.
2968 * 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
2969 * with number of tuples set to 0, if not the array is taken as this in the returned instance.
2971 MEDCouplingUMesh *MEDCouplingUMesh::buildSetInstanceFromThis(std::size_t spaceDim) const
2973 int mdim=getMeshDimension();
2975 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSetInstanceFromThis : invalid mesh dimension ! Should be >= 0 !");
2976 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
2977 MCAuto<DataArrayIdType> tmp1,tmp2;
2978 bool needToCpyCT=true;
2981 tmp1=DataArrayIdType::New(); tmp1->alloc(0,1);
2989 if(!_nodal_connec_index)
2991 tmp2=DataArrayIdType::New(); tmp2->alloc(1,1); tmp2->setIJ(0,0,0);
2996 tmp2=_nodal_connec_index;
2999 ret->setConnectivity(tmp1,tmp2,false);
3004 MCAuto<DataArrayDouble> coords=DataArrayDouble::New(); coords->alloc(0,spaceDim);
3005 ret->setCoords(coords);
3008 ret->setCoords(_coords);
3012 mcIdType MEDCouplingUMesh::getNumberOfNodesInCell(mcIdType cellId) const
3014 const mcIdType *ptI=_nodal_connec_index->getConstPointer();
3015 const mcIdType *pt=_nodal_connec->getConstPointer();
3016 if(pt[ptI[cellId]]!=INTERP_KERNEL::NORM_POLYHED)
3017 return ptI[cellId+1]-ptI[cellId]-1;
3019 return ToIdType(std::count_if(pt+ptI[cellId]+1,pt+ptI[cellId+1],std::bind2nd(std::not_equal_to<mcIdType>(),-1)));
3023 * Returns types of cells of the specified part of \a this mesh.
3024 * This method avoids computing sub-mesh explicitly to get its types.
3025 * \param [in] begin - an array of cell ids of interest.
3026 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3027 * \return std::set<INTERP_KERNEL::NormalizedCellType> - a set of enumeration items
3028 * describing the cell types.
3029 * \throw If the coordinates array is not set.
3030 * \throw If the nodal connectivity of cells is not defined.
3031 * \sa getAllGeoTypes()
3033 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getTypesOfPart(const mcIdType *begin, const mcIdType *end) const
3035 checkFullyDefined();
3036 std::set<INTERP_KERNEL::NormalizedCellType> ret;
3037 const mcIdType *conn=_nodal_connec->getConstPointer();
3038 const mcIdType *connIndex=_nodal_connec_index->getConstPointer();
3039 for(const mcIdType *w=begin;w!=end;w++)
3040 ret.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]);
3045 * Defines the nodal connectivity using given connectivity arrays in \ref numbering-indirect format.
3046 * Optionally updates
3047 * a set of types of cells constituting \a this mesh.
3048 * This method is for advanced users having prepared their connectivity before. For
3049 * more info on using this method see \ref MEDCouplingUMeshAdvBuild.
3050 * \param [in] conn - the nodal connectivity array.
3051 * \param [in] connIndex - the nodal connectivity index array.
3052 * \param [in] isComputingTypes - if \c true, the set of types constituting \a this
3055 void MEDCouplingUMesh::setConnectivity(DataArrayIdType *conn, DataArrayIdType *connIndex, bool isComputingTypes)
3057 DataArrayIdType::SetArrayIn(conn,_nodal_connec);
3058 DataArrayIdType::SetArrayIn(connIndex,_nodal_connec_index);
3059 if(isComputingTypes)
3065 * Copy constructor. If 'deepCopy' is false \a this is a shallow copy of other.
3066 * If 'deeCpy' is true all arrays (coordinates and connectivities) are deeply copied.
3068 MEDCouplingUMesh::MEDCouplingUMesh(const MEDCouplingUMesh& other, bool deepCpy):MEDCouplingPointSet(other,deepCpy),_mesh_dim(other._mesh_dim),
3069 _nodal_connec(0),_nodal_connec_index(0),
3070 _types(other._types)
3072 if(other._nodal_connec)
3073 _nodal_connec=other._nodal_connec->performCopyOrIncrRef(deepCpy);
3074 if(other._nodal_connec_index)
3075 _nodal_connec_index=other._nodal_connec_index->performCopyOrIncrRef(deepCpy);
3078 MEDCouplingUMesh::~MEDCouplingUMesh()
3081 _nodal_connec->decrRef();
3082 if(_nodal_connec_index)
3083 _nodal_connec_index->decrRef();
3087 * Recomputes a set of cell types of \a this mesh. For more info see
3088 * \ref MEDCouplingUMeshNodalConnectivity.
3090 void MEDCouplingUMesh::computeTypes()
3092 ComputeAllTypesInternal(_types,_nodal_connec,_nodal_connec_index);
3097 * Returns a number of cells constituting \a this mesh.
3098 * \return mcIdType - the number of cells in \a this mesh.
3099 * \throw If the nodal connectivity of cells is not defined.
3101 mcIdType MEDCouplingUMesh::getNumberOfCells() const
3103 if(_nodal_connec_index)
3104 return _nodal_connec_index->getNumberOfTuples()-1;
3109 throw INTERP_KERNEL::Exception("Unable to get number of cells because no connectivity specified !");
3113 * Returns a dimension of \a this mesh, i.e. a dimension of cells constituting \a this
3114 * mesh. For more info see \ref meshes.
3115 * \return int - the dimension of \a this mesh.
3116 * \throw If the mesh dimension is not defined using setMeshDimension().
3118 int MEDCouplingUMesh::getMeshDimension() const
3121 throw INTERP_KERNEL::Exception("No mesh dimension specified !");
3126 * Returns a length of the nodal connectivity array.
3127 * This method is for test reason. Normally the integer returned is not useable by
3128 * user. For more info see \ref MEDCouplingUMeshNodalConnectivity.
3129 * \return mcIdType - the length of the nodal connectivity array.
3131 mcIdType MEDCouplingUMesh::getNodalConnectivityArrayLen() const
3133 return _nodal_connec->getNbOfElems();
3137 * First step of serialization process. Used by ParaMEDMEM and MEDCouplingCorba to transfert data between process.
3139 void MEDCouplingUMesh::getTinySerializationInformation(std::vector<double>& tinyInfoD, std::vector<mcIdType>& tinyInfo, std::vector<std::string>& littleStrings) const
3141 MEDCouplingPointSet::getTinySerializationInformation(tinyInfoD,tinyInfo,littleStrings);
3142 tinyInfo.push_back(ToIdType(getMeshDimension()));
3143 tinyInfo.push_back(getNumberOfCells());
3145 tinyInfo.push_back(getNodalConnectivityArrayLen());
3147 tinyInfo.push_back(-1);
3151 * First step of unserialization process.
3153 bool MEDCouplingUMesh::isEmptyMesh(const std::vector<mcIdType>& tinyInfo) const
3155 return tinyInfo[6]<=0;
3159 * Second step of serialization process.
3160 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3163 * \param littleStrings
3165 void MEDCouplingUMesh::resizeForUnserialization(const std::vector<mcIdType>& tinyInfo, DataArrayIdType *a1, DataArrayDouble *a2, std::vector<std::string>& littleStrings) const
3167 MEDCouplingPointSet::resizeForUnserialization(tinyInfo,a1,a2,littleStrings);
3169 a1->alloc(tinyInfo[7]+tinyInfo[6]+1,1);
3173 * Third and final step of serialization process.
3175 void MEDCouplingUMesh::serialize(DataArrayIdType *&a1, DataArrayDouble *&a2) const
3177 MEDCouplingPointSet::serialize(a1,a2);
3178 if(getMeshDimension()>-1)
3180 a1=DataArrayIdType::New();
3181 a1->alloc(getNodalConnectivityArrayLen()+getNumberOfCells()+1,1);
3182 mcIdType *ptA1=a1->getPointer();
3183 const mcIdType *conn=getNodalConnectivity()->getConstPointer();
3184 const mcIdType *index=getNodalConnectivityIndex()->getConstPointer();
3185 ptA1=std::copy(index,index+getNumberOfCells()+1,ptA1);
3186 std::copy(conn,conn+getNodalConnectivityArrayLen(),ptA1);
3193 * Second and final unserialization process.
3194 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3196 void MEDCouplingUMesh::unserialization(const std::vector<double>& tinyInfoD, const std::vector<mcIdType>& tinyInfo, const DataArrayIdType *a1, DataArrayDouble *a2, const std::vector<std::string>& littleStrings)
3198 MEDCouplingPointSet::unserialization(tinyInfoD,tinyInfo,a1,a2,littleStrings);
3199 setMeshDimension(FromIdType<int>(tinyInfo[5]));
3203 const mcIdType *recvBuffer=a1->getConstPointer();
3204 MCAuto<DataArrayIdType> myConnecIndex=DataArrayIdType::New();
3205 myConnecIndex->alloc(tinyInfo[6]+1,1);
3206 std::copy(recvBuffer,recvBuffer+tinyInfo[6]+1,myConnecIndex->getPointer());
3207 MCAuto<DataArrayIdType> myConnec=DataArrayIdType::New();
3208 myConnec->alloc(tinyInfo[7],1);
3209 std::copy(recvBuffer+tinyInfo[6]+1,recvBuffer+tinyInfo[6]+1+tinyInfo[7],myConnec->getPointer());
3210 setConnectivity(myConnec, myConnecIndex);
3217 * Returns a new MEDCouplingFieldDouble containing volumes of cells constituting \a this
3219 * For 1D cells, the returned field contains lengths.<br>
3220 * For 2D cells, the returned field contains areas.<br>
3221 * For 3D cells, the returned field contains volumes.
3222 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3223 * orientation, i.e. the volume is always positive.
3224 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on cells
3225 * and one time . The caller is to delete this field using decrRef() as it is no
3228 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureField(bool isAbs) const
3230 std::string name="MeasureOfMesh_";
3232 mcIdType nbelem=getNumberOfCells();
3233 MCAuto<MEDCouplingFieldDouble> field=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3234 field->setName(name);
3235 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3236 array->alloc(nbelem,1);
3237 double *area_vol=array->getPointer();
3238 field->setArray(array) ; array=0;
3239 field->setMesh(const_cast<MEDCouplingUMesh *>(this));
3240 field->synchronizeTimeWithMesh();
3241 if(getMeshDimension()!=-1)
3244 INTERP_KERNEL::NormalizedCellType type;
3245 int dim_space=getSpaceDimension();
3246 const double *coords=getCoords()->getConstPointer();
3247 const mcIdType *connec=getNodalConnectivity()->getConstPointer();
3248 const mcIdType *connec_index=getNodalConnectivityIndex()->getConstPointer();
3249 for(mcIdType iel=0;iel<nbelem;iel++)
3251 ipt=connec_index[iel];
3252 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3253 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);
3256 std::transform(area_vol,area_vol+nbelem,area_vol,std::ptr_fun<double,double>(fabs));
3260 area_vol[0]=std::numeric_limits<double>::max();
3262 return field.retn();
3266 * Returns a new DataArrayDouble containing volumes of specified cells of \a this
3268 * For 1D cells, the returned array contains lengths.<br>
3269 * For 2D cells, the returned array contains areas.<br>
3270 * For 3D cells, the returned array contains volumes.
3271 * This method avoids building explicitly a part of \a this mesh to perform the work.
3272 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3273 * orientation, i.e. the volume is always positive.
3274 * \param [in] begin - an array of cell ids of interest.
3275 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3276 * \return DataArrayDouble * - a new instance of DataArrayDouble. The caller is to
3277 * delete this array using decrRef() as it is no more needed.
3279 * \if ENABLE_EXAMPLES
3280 * \ref cpp_mcumesh_getPartMeasureField "Here is a C++ example".<br>
3281 * \ref py_mcumesh_getPartMeasureField "Here is a Python example".
3283 * \sa getMeasureField()
3285 DataArrayDouble *MEDCouplingUMesh::getPartMeasureField(bool isAbs, const mcIdType *begin, const mcIdType *end) const
3287 std::string name="PartMeasureOfMesh_";
3289 std::size_t nbelem=std::distance(begin,end);
3290 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3291 array->setName(name);
3292 array->alloc(nbelem,1);
3293 double *area_vol=array->getPointer();
3294 if(getMeshDimension()!=-1)
3297 INTERP_KERNEL::NormalizedCellType type;
3298 int dim_space=getSpaceDimension();
3299 const double *coords=getCoords()->getConstPointer();
3300 const mcIdType *connec=getNodalConnectivity()->getConstPointer();
3301 const mcIdType *connec_index=getNodalConnectivityIndex()->getConstPointer();
3302 for(const mcIdType *iel=begin;iel!=end;iel++)
3304 ipt=connec_index[*iel];
3305 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3306 *area_vol++=INTERP_KERNEL::computeVolSurfOfCell2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,connec+ipt+1,connec_index[*iel+1]-ipt-1,coords,dim_space);
3309 std::transform(array->getPointer(),area_vol,array->getPointer(),std::ptr_fun<double,double>(fabs));
3313 area_vol[0]=std::numeric_limits<double>::max();
3315 return array.retn();
3319 * Returns a new MEDCouplingFieldDouble containing volumes of cells of a dual mesh of
3320 * \a this one. The returned field contains the dual cell volume for each corresponding
3321 * node in \a this mesh. In other words, the field returns the getMeasureField() of
3322 * the dual mesh in P1 sens of \a this.<br>
3323 * For 1D cells, the returned field contains lengths.<br>
3324 * For 2D cells, the returned field contains areas.<br>
3325 * For 3D cells, the returned field contains volumes.
3326 * This method is useful to check "P1*" conservative interpolators.
3327 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3328 * orientation, i.e. the volume is always positive.
3329 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3330 * nodes and one time. The caller is to delete this array using decrRef() as
3331 * it is no more needed.
3333 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureFieldOnNode(bool isAbs) const
3335 MCAuto<MEDCouplingFieldDouble> tmp=getMeasureField(isAbs);
3336 std::string name="MeasureOnNodeOfMesh_";
3338 mcIdType nbNodes=getNumberOfNodes();
3339 MCAuto<DataArrayDouble> nnpc;
3341 MCAuto<DataArrayIdType> tmp(computeNbOfNodesPerCell());
3342 nnpc=tmp->convertToDblArr();
3344 std::for_each(nnpc->rwBegin(),nnpc->rwEnd(),[](double& v) { v=1./v; });
3345 const double *nnpcPtr(nnpc->begin());
3346 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_NODES);
3347 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3348 array->alloc(nbNodes,1);
3349 double *valsToFill=array->getPointer();
3350 std::fill(valsToFill,valsToFill+nbNodes,0.);
3351 const double *values=tmp->getArray()->getConstPointer();
3352 MCAuto<DataArrayIdType> da=DataArrayIdType::New();
3353 MCAuto<DataArrayIdType> daInd=DataArrayIdType::New();
3354 getReverseNodalConnectivity(da,daInd);
3355 const mcIdType *daPtr=da->getConstPointer();
3356 const mcIdType *daIPtr=daInd->getConstPointer();
3357 for(mcIdType i=0;i<nbNodes;i++)
3358 for(const mcIdType *cell=daPtr+daIPtr[i];cell!=daPtr+daIPtr[i+1];cell++)
3359 valsToFill[i]+=nnpcPtr[*cell]*values[*cell];
3361 ret->setArray(array);
3366 * Returns a new MEDCouplingFieldDouble holding normal vectors to cells of \a this
3367 * mesh. The returned normal vectors to each cell have a norm2 equal to 1.
3368 * The computed vectors have <em> this->getMeshDimension()+1 </em> components
3369 * and are normalized.
3370 * <br> \a this can be either
3371 * - a 2D mesh in 2D or 3D space or
3372 * - an 1D mesh in 2D space.
3374 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3375 * cells and one time. The caller is to delete this field using decrRef() as
3376 * it is no more needed.
3377 * \throw If the nodal connectivity of cells is not defined.
3378 * \throw If the coordinates array is not set.
3379 * \throw If the mesh dimension is not set.
3380 * \throw If the mesh and space dimension is not as specified above.
3382 MEDCouplingFieldDouble *MEDCouplingUMesh::buildOrthogonalField() const
3384 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3385 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3386 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3387 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3388 mcIdType nbOfCells=getNumberOfCells();
3389 int nbComp=getMeshDimension()+1;
3390 array->alloc(nbOfCells,nbComp);
3391 double *vals=array->getPointer();
3392 const mcIdType *connI=_nodal_connec_index->getConstPointer();
3393 const mcIdType *conn=_nodal_connec->getConstPointer();
3394 const double *coords=_coords->getConstPointer();
3395 if(getMeshDimension()==2)
3397 if(getSpaceDimension()==3)
3399 MCAuto<DataArrayDouble> loc=computeCellCenterOfMass();
3400 const double *locPtr=loc->getConstPointer();
3401 for(mcIdType i=0;i<nbOfCells;i++,vals+=3)
3403 mcIdType offset=connI[i];
3404 INTERP_KERNEL::crossprod<3>(locPtr+3*i,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3405 double n=INTERP_KERNEL::norm<3>(vals);
3406 std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3411 MCAuto<MEDCouplingFieldDouble> isAbs=getMeasureField(false);
3412 const double *isAbsPtr=isAbs->getArray()->begin();
3413 for(mcIdType i=0;i<nbOfCells;i++,isAbsPtr++)
3414 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=*isAbsPtr>0.?1.:-1.; }
3417 else//meshdimension==1
3420 for(mcIdType i=0;i<nbOfCells;i++)
3422 mcIdType offset=connI[i];
3423 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3424 double n=INTERP_KERNEL::norm<2>(tmp);
3425 std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3430 ret->setArray(array);
3432 ret->synchronizeTimeWithSupport();
3437 * Returns a new MEDCouplingFieldDouble holding normal vectors to specified cells of
3438 * \a this mesh. The computed vectors have <em> this->getMeshDimension()+1 </em> components
3439 * and are normalized.
3440 * <br> \a this can be either
3441 * - a 2D mesh in 2D or 3D space or
3442 * - an 1D mesh in 2D space.
3444 * This method avoids building explicitly a part of \a this mesh to perform the work.
3445 * \param [in] begin - an array of cell ids of interest.
3446 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3447 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3448 * cells and one time. The caller is to delete this field using decrRef() as
3449 * it is no more needed.
3450 * \throw If the nodal connectivity of cells is not defined.
3451 * \throw If the coordinates array is not set.
3452 * \throw If the mesh dimension is not set.
3453 * \throw If the mesh and space dimension is not as specified above.
3454 * \sa buildOrthogonalField()
3456 * \if ENABLE_EXAMPLES
3457 * \ref cpp_mcumesh_buildPartOrthogonalField "Here is a C++ example".<br>
3458 * \ref py_mcumesh_buildPartOrthogonalField "Here is a Python example".
3461 MEDCouplingFieldDouble *MEDCouplingUMesh::buildPartOrthogonalField(const mcIdType *begin, const mcIdType *end) const
3463 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3464 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3465 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3466 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3467 std::size_t nbelems=std::distance(begin,end);
3468 int nbComp=getMeshDimension()+1;
3469 array->alloc(nbelems,nbComp);
3470 double *vals=array->getPointer();
3471 const mcIdType *connI=_nodal_connec_index->getConstPointer();
3472 const mcIdType *conn=_nodal_connec->getConstPointer();
3473 const double *coords=_coords->getConstPointer();
3474 if(getMeshDimension()==2)
3476 if(getSpaceDimension()==3)
3478 MCAuto<DataArrayDouble> loc=getPartBarycenterAndOwner(begin,end);
3479 const double *locPtr=loc->getConstPointer();
3480 for(const mcIdType *i=begin;i!=end;i++,vals+=3,locPtr+=3)
3482 mcIdType offset=connI[*i];
3483 INTERP_KERNEL::crossprod<3>(locPtr,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3484 double n=INTERP_KERNEL::norm<3>(vals);
3485 std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3490 for(std::size_t i=0;i<nbelems;i++)
3491 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=1.; }
3494 else//meshdimension==1
3497 for(const mcIdType *i=begin;i!=end;i++)
3499 mcIdType offset=connI[*i];
3500 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3501 double n=INTERP_KERNEL::norm<2>(tmp);
3502 std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3507 ret->setArray(array);
3509 ret->synchronizeTimeWithSupport();
3514 * Returns a new MEDCouplingFieldDouble holding a direction vector for each SEG2 in \a
3515 * this 1D mesh. The computed vectors have <em> this->getSpaceDimension() </em> components
3516 * and are \b not normalized.
3517 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3518 * cells and one time. The caller is to delete this field using decrRef() as
3519 * it is no more needed.
3520 * \throw If the nodal connectivity of cells is not defined.
3521 * \throw If the coordinates array is not set.
3522 * \throw If \a this->getMeshDimension() != 1.
3523 * \throw If \a this mesh includes cells of type other than SEG2.
3525 MEDCouplingFieldDouble *MEDCouplingUMesh::buildDirectionVectorField() const
3527 if(getMeshDimension()!=1)
3528 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for buildDirectionVectorField !");
3529 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3530 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for buildDirectionVectorField !");
3531 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3532 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3533 mcIdType nbOfCells=getNumberOfCells();
3534 int spaceDim=getSpaceDimension();
3535 array->alloc(nbOfCells,spaceDim);
3536 double *pt=array->getPointer();
3537 const double *coo=getCoords()->getConstPointer();
3538 std::vector<mcIdType> conn;
3540 for(mcIdType i=0;i<nbOfCells;i++)
3543 getNodeIdsOfCell(i,conn);
3544 pt=std::transform(coo+conn[1]*spaceDim,coo+(conn[1]+1)*spaceDim,coo+conn[0]*spaceDim,pt,std::minus<double>());
3546 ret->setArray(array);
3548 ret->synchronizeTimeWithSupport();
3553 * Creates a 2D mesh by cutting \a this 3D mesh with a plane. In addition to the mesh,
3554 * returns a new DataArrayIdType, of length equal to the number of 2D cells in the result
3555 * mesh, holding, for each cell in the result mesh, an id of a 3D cell it comes
3556 * from. If a result face is shared by two 3D cells, then the face in included twice in
3558 * \param [in] origin - 3 components of a point defining location of the plane.
3559 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3560 * must be greater than 1e-6.
3561 * \param [in] eps - half-thickness of the plane.
3562 * \param [out] cellIds - a new instance of DataArrayIdType holding ids of 3D cells
3563 * producing correspondent 2D cells. The caller is to delete this array
3564 * using decrRef() as it is no more needed.
3565 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This mesh does
3566 * not share the node coordinates array with \a this mesh. The caller is to
3567 * delete this mesh using decrRef() as it is no more needed.
3568 * \throw If the coordinates array is not set.
3569 * \throw If the nodal connectivity of cells is not defined.
3570 * \throw If \a this->getMeshDimension() != 3 or \a this->getSpaceDimension() != 3.
3571 * \throw If magnitude of \a vec is less than 1e-6.
3572 * \throw If the plane does not intersect any 3D cell of \a this mesh.
3573 * \throw If \a this includes quadratic cells.
3575 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3D(const double *origin, const double *vec, double eps, DataArrayIdType *&cellIds) const
3577 checkFullyDefined();
3578 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3579 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3580 MCAuto<DataArrayIdType> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3581 if(candidates->empty())
3582 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane considering bounding boxes !");
3583 std::vector<mcIdType> nodes;
3584 DataArrayIdType *cellIds1D=0;
3585 MCAuto<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3586 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3587 MCAuto<DataArrayIdType> desc1=DataArrayIdType::New(),desc2=DataArrayIdType::New();
3588 MCAuto<DataArrayIdType> descIndx1=DataArrayIdType::New(),descIndx2=DataArrayIdType::New();
3589 MCAuto<DataArrayIdType> revDesc1=DataArrayIdType::New(),revDesc2=DataArrayIdType::New();
3590 MCAuto<DataArrayIdType> revDescIndx1=DataArrayIdType::New(),revDescIndx2=DataArrayIdType::New();
3591 MCAuto<MEDCouplingUMesh> mDesc2=subMesh->buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2);//meshDim==2 spaceDim==3
3592 revDesc2=0; revDescIndx2=0;
3593 MCAuto<MEDCouplingUMesh> mDesc1=mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3594 revDesc1=0; revDescIndx1=0;
3595 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3596 MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3598 std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3599 for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3601 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3602 std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(mDesc2->getNumberOfCells());
3603 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->getConstPointer(),mDesc2->getNodalConnectivityIndex()->getConstPointer(),
3604 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3605 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3606 MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New()),cellIds2(DataArrayIdType::New());
3607 connI->pushBackSilent(0); conn->alloc(0,1); cellIds2->alloc(0,1);
3608 subMesh->assemblyForSplitFrom3DSurf(cut3DSurf,desc2->getConstPointer(),descIndx2->getConstPointer(),conn,connI,cellIds2);
3609 if(cellIds2->empty())
3610 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3611 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3D",2);
3612 ret->setCoords(mDesc1->getCoords());
3613 ret->setConnectivity(conn,connI,true);
3614 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3619 * Creates an 1D mesh by cutting \a this 2D mesh in 3D space with a plane. In
3620 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
3621 from. If a result segment is shared by two 2D cells, then the segment in included twice in
3623 * \param [in] origin - 3 components of a point defining location of the plane.
3624 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3625 * must be greater than 1e-6.
3626 * \param [in] eps - half-thickness of the plane.
3627 * \param [out] cellIds - a new instance of DataArrayIdType holding ids of faces
3628 * producing correspondent segments. The caller is to delete this array
3629 * using decrRef() as it is no more needed.
3630 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This is an 1D
3631 * mesh in 3D space. This mesh does not share the node coordinates array with
3632 * \a this mesh. The caller is to delete this mesh using decrRef() as it is
3634 * \throw If the coordinates array is not set.
3635 * \throw If the nodal connectivity of cells is not defined.
3636 * \throw If \a this->getMeshDimension() != 2 or \a this->getSpaceDimension() != 3.
3637 * \throw If magnitude of \a vec is less than 1e-6.
3638 * \throw If the plane does not intersect any 2D cell of \a this mesh.
3639 * \throw If \a this includes quadratic cells.
3641 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3DSurf(const double *origin, const double *vec, double eps, DataArrayIdType *&cellIds) const
3643 checkFullyDefined();
3644 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
3645 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf works on umeshes with meshdim equal to 2 and spaceDim equal to 3 !");
3646 MCAuto<DataArrayIdType> candidates(getCellIdsCrossingPlane(origin,vec,eps));
3647 if(candidates->empty())
3648 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3D surf cells in this intercepts the specified plane considering bounding boxes !");
3649 std::vector<mcIdType> nodes;
3650 DataArrayIdType *cellIds1D(0);
3651 MCAuto<MEDCouplingUMesh> subMesh(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3652 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3653 MCAuto<DataArrayIdType> desc1(DataArrayIdType::New()),descIndx1(DataArrayIdType::New()),revDesc1(DataArrayIdType::New()),revDescIndx1(DataArrayIdType::New());
3654 MCAuto<MEDCouplingUMesh> mDesc1(subMesh->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3655 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3656 MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3658 std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3659 for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3661 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3662 mcIdType ncellsSub=subMesh->getNumberOfCells();
3663 std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(ncellsSub);
3664 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,subMesh->getNodalConnectivity()->getConstPointer(),subMesh->getNodalConnectivityIndex()->getConstPointer(),
3665 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3666 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3667 MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New()),cellIds2(DataArrayIdType::New()); connI->pushBackSilent(0);
3669 const mcIdType *nodal=subMesh->getNodalConnectivity()->getConstPointer();
3670 const mcIdType *nodalI=subMesh->getNodalConnectivityIndex()->getConstPointer();
3671 for(mcIdType i=0;i<ncellsSub;i++)
3673 if(cut3DSurf[i].first!=-1 && cut3DSurf[i].second!=-1)
3675 if(cut3DSurf[i].first!=-2)
3677 conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_SEG2)); conn->pushBackSilent(cut3DSurf[i].first); conn->pushBackSilent(cut3DSurf[i].second);
3678 connI->pushBackSilent(conn->getNumberOfTuples());
3679 cellIds2->pushBackSilent(i);
3683 mcIdType cellId3DSurf=cut3DSurf[i].second;
3684 mcIdType offset=nodalI[cellId3DSurf]+1;
3685 mcIdType nbOfEdges=nodalI[cellId3DSurf+1]-offset;
3686 for(mcIdType j=0;j<nbOfEdges;j++)
3688 conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_SEG2)); conn->pushBackSilent(nodal[offset+j]); conn->pushBackSilent(nodal[offset+(j+1)%nbOfEdges]);
3689 connI->pushBackSilent(conn->getNumberOfTuples());
3690 cellIds2->pushBackSilent(cellId3DSurf);
3695 if(cellIds2->empty())
3696 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3DSurf cells in this intercepts the specified plane !");
3697 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3DSurf",1);
3698 ret->setCoords(mDesc1->getCoords());
3699 ret->setConnectivity(conn,connI,true);
3700 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3704 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::clipSingle3DCellByPlane(const double origin[3], const double vec[3], double eps) const
3706 checkFullyDefined();
3707 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3708 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3709 if(getNumberOfCells()!=1)
3710 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works only on mesh containing exactly one cell !");
3712 std::vector<mcIdType> nodes;
3713 findNodesOnPlane(origin,vec,eps,nodes);
3714 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());
3715 MCAuto<MEDCouplingUMesh> mDesc2(buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2));//meshDim==2 spaceDim==3
3716 revDesc2=0; revDescIndx2=0;
3717 MCAuto<MEDCouplingUMesh> mDesc1(mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3718 revDesc1=0; revDescIndx1=0;
3719 DataArrayIdType *cellIds1D(0);
3720 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3721 MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3722 std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3723 for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3727 mcIdType oldNbNodes(mDesc1->getNumberOfNodes());
3728 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3729 sameNbNodes=(mDesc1->getNumberOfNodes()==oldNbNodes);
3731 std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(mDesc2->getNumberOfCells());
3732 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->begin(),mDesc2->getNodalConnectivityIndex()->begin(),
3733 mDesc1->getNodalConnectivity()->begin(),mDesc1->getNodalConnectivityIndex()->begin(),
3734 desc1->begin(),descIndx1->begin(),cut3DSurf);
3735 MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New());
3736 connI->pushBackSilent(0); conn->alloc(0,1);
3738 MCAuto<DataArrayIdType> cellIds2(DataArrayIdType::New()); cellIds2->alloc(0,1);
3739 assemblyForSplitFrom3DSurf(cut3DSurf,desc2->begin(),descIndx2->begin(),conn,connI,cellIds2);
3740 if(cellIds2->empty())
3741 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3743 std::vector<std::vector<mcIdType> > res;
3744 buildSubCellsFromCut(cut3DSurf,desc2->begin(),descIndx2->begin(),mDesc1->getCoords()->begin(),eps,res);
3745 std::size_t sz(res.size());
3746 if(ToIdType(res.size())==mDesc1->getNumberOfCells() && sameNbNodes)
3747 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane : cell is not clipped !");
3748 for(std::size_t i=0;i<sz;i++)
3750 conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYGON));
3751 conn->insertAtTheEnd(res[i].begin(),res[i].end());
3752 connI->pushBackSilent(conn->getNumberOfTuples());
3754 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
3755 ret->setCoords(mDesc1->getCoords());
3756 ret->setConnectivity(conn,connI,true);
3757 mcIdType nbCellsRet(ret->getNumberOfCells());
3759 MCAuto<DataArrayDouble> vec2(DataArrayDouble::New()); vec2->alloc(1,3); std::copy(vec,vec+3,vec2->getPointer());
3760 MCAuto<MEDCouplingFieldDouble> ortho(ret->buildOrthogonalField());
3761 MCAuto<DataArrayDouble> ortho2(ortho->getArray()->selectByTupleIdSafeSlice(0,1,1));
3762 MCAuto<DataArrayDouble> dott(DataArrayDouble::Dot(ortho2,vec2));
3763 MCAuto<DataArrayDouble> ccm(ret->computeCellCenterOfMass());
3764 MCAuto<DataArrayDouble> occm;
3766 MCAuto<DataArrayDouble> pt(DataArrayDouble::New()); pt->alloc(1,3); std::copy(origin,origin+3,pt->getPointer());
3767 occm=DataArrayDouble::Substract(ccm,pt);
3769 vec2=DataArrayDouble::New(); vec2->alloc(nbCellsRet,3);
3770 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);
3771 MCAuto<DataArrayDouble> dott2(DataArrayDouble::Dot(occm,vec2));
3773 const mcIdType *cPtr(ret->getNodalConnectivity()->begin()),*ciPtr(ret->getNodalConnectivityIndex()->begin());
3774 MCAuto<MEDCouplingUMesh> ret2(MEDCouplingUMesh::New("Clip3D",3));
3775 ret2->setCoords(mDesc1->getCoords());
3776 MCAuto<DataArrayIdType> conn2(DataArrayIdType::New()),conn2I(DataArrayIdType::New());
3777 conn2I->pushBackSilent(0); conn2->alloc(0,1);
3778 std::vector<mcIdType> cell0(1,ToIdType(INTERP_KERNEL::NORM_POLYHED));
3779 std::vector<mcIdType> cell1(1,ToIdType(INTERP_KERNEL::NORM_POLYHED));
3780 if(dott->getIJ(0,0)>0)
3782 cell0.insert(cell0.end(),cPtr+1,cPtr+ciPtr[1]);
3783 std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell1,cell1.end()));
3787 cell1.insert(cell1.end(),cPtr+1,cPtr+ciPtr[1]);
3788 std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell0,cell0.end()));
3790 for(mcIdType i=1;i<nbCellsRet;i++)
3792 if(dott2->getIJ(i,0)<0)
3794 if(ciPtr[i+1]-ciPtr[i]>=4)
3796 cell0.push_back(-1);
3797 cell0.insert(cell0.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
3802 if(ciPtr[i+1]-ciPtr[i]>=4)
3804 cell1.push_back(-1);
3805 cell1.insert(cell1.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
3809 conn2->insertAtTheEnd(cell0.begin(),cell0.end());
3810 conn2I->pushBackSilent(conn2->getNumberOfTuples());
3811 conn2->insertAtTheEnd(cell1.begin(),cell1.end());
3812 conn2I->pushBackSilent(conn2->getNumberOfTuples());
3813 ret2->setConnectivity(conn2,conn2I,true);
3814 ret2->checkConsistencyLight();
3815 ret2->orientCorrectlyPolyhedrons();
3820 * Finds cells whose bounding boxes intersect a given plane.
3821 * \param [in] origin - 3 components of a point defining location of the plane.
3822 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3823 * must be greater than 1e-6.
3824 * \param [in] eps - half-thickness of the plane.
3825 * \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of the found
3826 * cells. The caller is to delete this array using decrRef() as it is no more
3828 * \throw If the coordinates array is not set.
3829 * \throw If the nodal connectivity of cells is not defined.
3830 * \throw If \a this->getSpaceDimension() != 3.
3831 * \throw If magnitude of \a vec is less than 1e-6.
3832 * \sa buildSlice3D()
3834 DataArrayIdType *MEDCouplingUMesh::getCellIdsCrossingPlane(const double *origin, const double *vec, double eps) const
3836 checkFullyDefined();
3837 if(getSpaceDimension()!=3)
3838 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with spaceDim equal to 3 !");
3839 double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
3841 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellIdsCrossingPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
3843 vec2[0]=vec[1]; vec2[1]=-vec[0]; vec2[2]=0.;//vec2 is the result of cross product of vec with (0,0,1)
3844 double angle=acos(vec[2]/normm);
3845 MCAuto<DataArrayIdType> cellIds;
3849 MCAuto<DataArrayDouble> coo=_coords->deepCopy();
3850 double normm2(sqrt(vec2[0]*vec2[0]+vec2[1]*vec2[1]+vec2[2]*vec2[2]));
3851 if(normm2/normm>1e-6)
3852 DataArrayDouble::Rotate3DAlg(origin,vec2,angle,coo->getNumberOfTuples(),coo->getPointer(),coo->getPointer());
3853 MCAuto<MEDCouplingUMesh> mw=clone(false);//false -> shallow copy
3855 mw->getBoundingBox(bbox);
3856 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3857 cellIds=mw->getCellsInBoundingBox(bbox,eps);
3861 getBoundingBox(bbox);
3862 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3863 cellIds=getCellsInBoundingBox(bbox,eps);
3865 return cellIds.retn();
3869 * This method checks that \a this is a contiguous mesh. The user is expected to call this method on a mesh with meshdim==1.
3870 * If not an exception will thrown. If this is an empty mesh with no cell an exception will be thrown too.
3871 * No consideration of coordinate is done by this method.
3872 * 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)
3873 * If not false is returned. In case that false is returned a call to MEDCoupling::MEDCouplingUMesh::mergeNodes could be useful.
3875 bool MEDCouplingUMesh::isContiguous1D() const
3877 if(getMeshDimension()!=1)
3878 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense only for 1D mesh !");
3879 mcIdType nbCells=getNumberOfCells();
3881 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense for non empty mesh !");
3882 const mcIdType *connI(_nodal_connec_index->begin()),*conn(_nodal_connec->begin());
3883 mcIdType ref=conn[connI[0]+2];
3884 for(mcIdType i=1;i<nbCells;i++)
3886 if(conn[connI[i]+1]!=ref)
3888 ref=conn[connI[i]+2];
3894 * This method is only callable on mesh with meshdim == 1 containing only SEG2 and spaceDim==3.
3895 * This method projects this on the 3D line defined by (pt,v). This methods first checks that all SEG2 are along v vector.
3896 * \param pt reference point of the line
3897 * \param v normalized director vector of the line
3898 * \param eps max precision before throwing an exception
3899 * \param res output of size this->getNumberOfCells
3901 void MEDCouplingUMesh::project1D(const double *pt, const double *v, double eps, double *res) const
3903 if(getMeshDimension()!=1)
3904 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for project1D !");
3905 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3906 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for project1D !");
3907 if(getSpaceDimension()!=3)
3908 throw INTERP_KERNEL::Exception("Expected a umesh with spaceDim==3 for project1D !");
3909 MCAuto<MEDCouplingFieldDouble> f=buildDirectionVectorField();
3910 const double *fPtr=f->getArray()->getConstPointer();
3912 for(mcIdType i=0;i<getNumberOfCells();i++)
3914 const double *tmp1=fPtr+3*i;
3915 tmp[0]=tmp1[1]*v[2]-tmp1[2]*v[1];
3916 tmp[1]=tmp1[2]*v[0]-tmp1[0]*v[2];
3917 tmp[2]=tmp1[0]*v[1]-tmp1[1]*v[0];
3918 double n1=INTERP_KERNEL::norm<3>(tmp);
3919 n1/=INTERP_KERNEL::norm<3>(tmp1);
3921 throw INTERP_KERNEL::Exception("UMesh::Projection 1D failed !");
3923 const double *coo=getCoords()->getConstPointer();
3924 for(mcIdType i=0;i<getNumberOfNodes();i++)
3926 std::transform(coo+i*3,coo+i*3+3,pt,tmp,std::minus<double>());
3927 std::transform(tmp,tmp+3,v,tmp,std::multiplies<double>());
3928 res[i]=std::accumulate(tmp,tmp+3,0.);
3933 * 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.
3934 * \a this is expected to be a mesh so that its space dimension is equal to its
3935 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
3936 * 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).
3938 * 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
3939 * 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).
3940 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
3942 * So this method is more accurate (so, more costly) than simply searching for the closest point in \a this.
3943 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
3945 * \param [in] ptBg the start pointer (included) of the coordinates of the point
3946 * \param [in] ptEnd the end pointer (not included) of the coordinates of the point
3947 * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
3948 * \return the positive value of the distance.
3949 * \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
3951 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoints
3953 double MEDCouplingUMesh::distanceToPoint(const double *ptBg, const double *ptEnd, mcIdType& cellId) const
3955 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
3956 if(meshDim!=spaceDim-1)
3957 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint works only for spaceDim=meshDim+1 !");
3958 if(meshDim!=2 && meshDim!=1)
3959 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint : only mesh dimension 2 and 1 are implemented !");
3960 checkFullyDefined();
3961 if(ToIdType(std::distance(ptBg,ptEnd))!=spaceDim)
3962 { 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()); }
3963 DataArrayIdType *ret1=0;
3964 MCAuto<DataArrayDouble> pts=DataArrayDouble::New(); pts->useArray(ptBg,false,DeallocType::C_DEALLOC,1,spaceDim);
3965 MCAuto<DataArrayDouble> ret0=distanceToPoints(pts,ret1);
3966 MCAuto<DataArrayIdType> ret1Safe(ret1);
3967 cellId=*ret1Safe->begin();
3968 return *ret0->begin();
3972 * This method computes the distance from each point of points serie \a pts (stored in a DataArrayDouble in which each tuple represents a point)
3973 * to \a this and the first \a cellId in \a this corresponding to the returned distance.
3974 * 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
3975 * 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).
3976 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
3978 * \a this is expected to be a mesh so that its space dimension is equal to its
3979 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
3980 * 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).
3982 * So this method is more accurate (so, more costly) than simply searching for each point in \a pts the closest point in \a this.
3983 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
3985 * \param [in] pts the list of points in which each tuple represents a point
3986 * \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.
3987 * \return a newly allocated object to be dealed by the caller that tells for each point in \a pts the distance to \a this.
3988 * \throw if number of components of \a pts is not equal to the space dimension.
3989 * \throw if mesh dimension of \a this is not equal to space dimension - 1.
3990 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoint
3992 DataArrayDouble *MEDCouplingUMesh::distanceToPoints(const DataArrayDouble *pts, DataArrayIdType *& cellIds) const
3995 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : input points pointer is NULL !");
3996 pts->checkAllocated();
3997 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
3998 if(meshDim!=spaceDim-1)
3999 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints works only for spaceDim=meshDim+1 !");
4000 if(meshDim!=2 && meshDim!=1)
4001 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only mesh dimension 2 and 1 are implemented !");
4002 if(ToIdType(pts->getNumberOfComponents())!=spaceDim)
4004 std::ostringstream oss; oss << "MEDCouplingUMesh::distanceToPoints : input pts DataArrayDouble has " << pts->getNumberOfComponents() << " components whereas it should be equal to " << spaceDim << " (mesh spaceDimension) !";
4005 throw INTERP_KERNEL::Exception(oss.str());
4007 checkFullyDefined();
4008 mcIdType nbCells=getNumberOfCells();
4010 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : no cells in this !");
4011 mcIdType nbOfPts=pts->getNumberOfTuples();
4012 MCAuto<DataArrayDouble> ret0=DataArrayDouble::New(); ret0->alloc(nbOfPts,1);
4013 MCAuto<DataArrayIdType> ret1=DataArrayIdType::New(); ret1->alloc(nbOfPts,1);
4014 const mcIdType *nc=_nodal_connec->begin(),*ncI=_nodal_connec_index->begin(); const double *coords=_coords->begin();
4015 double *ret0Ptr=ret0->getPointer(); mcIdType *ret1Ptr=ret1->getPointer(); const double *ptsPtr=pts->begin();
4016 MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree());
4017 const double *bbox(bboxArr->begin());
4022 BBTreeDst<3> myTree(bbox,0,0,nbCells);
4023 for(mcIdType i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=3)
4025 double x=std::numeric_limits<double>::max();
4026 std::vector<mcIdType> elems;
4027 myTree.getMinDistanceOfMax(ptsPtr,x);
4028 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4029 DistanceToPoint3DSurfAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4035 BBTreeDst<2> myTree(bbox,0,0,nbCells);
4036 for(mcIdType i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=2)
4038 double x=std::numeric_limits<double>::max();
4039 std::vector<mcIdType> elems;
4040 myTree.getMinDistanceOfMax(ptsPtr,x);
4041 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4042 DistanceToPoint2DCurveAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4047 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only spacedim 2 and 3 supported !");
4049 cellIds=ret1.retn();
4058 * Finds cells in contact with a ball (i.e. a point with precision).
4059 * 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.
4060 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4062 * \warning This method is suitable if the caller intends to evaluate only one
4063 * point, for more points getCellsContainingPoints() is recommended as it is
4065 * \param [in] pos - array of coordinates of the ball central point.
4066 * \param [in] eps - ball radius.
4067 * \return mcIdType - a smallest id of cells being in contact with the ball, -1 in case
4068 * if there are no such cells.
4069 * \throw If the coordinates array is not set.
4070 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4072 mcIdType MEDCouplingUMesh::getCellContainingPoint(const double *pos, double eps) const
4074 std::vector<mcIdType> elts;
4075 getCellsContainingPoint(pos,eps,elts);
4078 return elts.front();
4082 * Finds cells in contact with a ball (i.e. a point with precision).
4083 * 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.
4084 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4085 * \warning This method is suitable if the caller intends to evaluate only one
4086 * point, for more points getCellsContainingPoints() is recommended as it is
4088 * \param [in] pos - array of coordinates of the ball central point.
4089 * \param [in] eps - ball radius.
4090 * \param [out] elts - vector returning ids of the found cells. It is cleared
4091 * before inserting ids.
4092 * \throw If the coordinates array is not set.
4093 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4095 * \if ENABLE_EXAMPLES
4096 * \ref cpp_mcumesh_getCellsContainingPoint "Here is a C++ example".<br>
4097 * \ref py_mcumesh_getCellsContainingPoint "Here is a Python example".
4100 void MEDCouplingUMesh::getCellsContainingPoint(const double *pos, double eps, std::vector<mcIdType>& elts) const
4102 MCAuto<DataArrayIdType> eltsUg,eltsIndexUg;
4103 getCellsContainingPoints(pos,1,eps,eltsUg,eltsIndexUg);
4104 elts.clear(); elts.insert(elts.end(),eltsUg->begin(),eltsUg->end());
4107 void MEDCouplingUMesh::getCellsContainingPointsZeAlg(const double *pos, mcIdType nbOfPoints, double eps,
4108 MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex,
4109 std::function<bool(INTERP_KERNEL::NormalizedCellType,mcIdType)> sensibilityTo2DQuadraticLinearCellsFunc) const
4111 int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
4116 const double *coords=_coords->getConstPointer();
4117 getCellsContainingPointsAlg<3>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4120 throw INTERP_KERNEL::Exception("For spaceDim==3 only meshDim==3 implemented for getelementscontainingpoints !");
4122 else if(spaceDim==2)
4126 const double *coords=_coords->getConstPointer();
4127 getCellsContainingPointsAlg<2>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4130 throw INTERP_KERNEL::Exception("For spaceDim==2 only meshDim==2 implemented for getelementscontainingpoints !");
4132 else if(spaceDim==1)
4136 const double *coords=_coords->getConstPointer();
4137 getCellsContainingPointsAlg<1>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4140 throw INTERP_KERNEL::Exception("For spaceDim==1 only meshDim==1 implemented for getelementscontainingpoints !");
4143 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPoints : not managed for mdim not in [1,2,3] !");
4147 * Finds cells in contact with several balls (i.e. points with precision).
4148 * This method is an extension of getCellContainingPoint() and
4149 * getCellsContainingPoint() for the case of multiple points.
4150 * 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.
4151 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4152 * \param [in] pos - an array of coordinates of points in full interlace mode :
4153 * X0,Y0,Z0,X1,Y1,Z1,... Size of the array must be \a
4154 * this->getSpaceDimension() * \a nbOfPoints
4155 * \param [in] nbOfPoints - number of points to locate within \a this mesh.
4156 * \param [in] eps - radius of balls (i.e. the precision).
4157 * \param [out] elts - vector returning ids of found cells.
4158 * \param [out] eltsIndex - an array, of length \a nbOfPoints + 1,
4159 * dividing cell ids in \a elts into groups each referring to one
4160 * point. Its every element (except the last one) is an index pointing to the
4161 * first id of a group of cells. For example cells in contact with the *i*-th
4162 * point are described by following range of indices:
4163 * [ \a eltsIndex[ *i* ], \a eltsIndex[ *i*+1 ] ) and the cell ids are
4164 * \a elts[ \a eltsIndex[ *i* ]], \a elts[ \a eltsIndex[ *i* ] + 1 ], ...
4165 * Number of cells in contact with the *i*-th point is
4166 * \a eltsIndex[ *i*+1 ] - \a eltsIndex[ *i* ].
4167 * \throw If the coordinates array is not set.
4168 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4170 * \if ENABLE_EXAMPLES
4171 * \ref cpp_mcumesh_getCellsContainingPoints "Here is a C++ example".<br>
4172 * \ref py_mcumesh_getCellsContainingPoints "Here is a Python example".
4175 void MEDCouplingUMesh::getCellsContainingPoints(const double *pos, mcIdType nbOfPoints, double eps,
4176 MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex) const
4178 auto yesImSensibleTo2DQuadraticLinearCellsFunc([](INTERP_KERNEL::NormalizedCellType ct, int mdim) { return INTERP_KERNEL::CellModel::GetCellModel(ct).isQuadratic() && mdim == 2; } );
4179 this->getCellsContainingPointsZeAlg(pos,nbOfPoints,eps,elts,eltsIndex,yesImSensibleTo2DQuadraticLinearCellsFunc);
4183 * Behaves like MEDCouplingMesh::getCellsContainingPoints for cells in \a this that are linear.
4184 * For quadratic cells in \a this, this method behaves by just considering linear part of cells.
4185 * This method is here only for backward compatibility (interpolation GaussPoints to GaussPoints).
4187 * \sa MEDCouplingUMesh::getCellsContainingPoints, MEDCouplingRemapper::prepareNotInterpKernelOnlyGaussGauss
4189 void MEDCouplingUMesh::getCellsContainingPointsLinearPartOnlyOnNonDynType(const double *pos, mcIdType nbOfPoints, double eps, MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex) const
4191 auto noImNotSensibleTo2DQuadraticLinearCellsFunc([](INTERP_KERNEL::NormalizedCellType,mcIdType) { return false; } );
4192 this->getCellsContainingPointsZeAlg(pos,nbOfPoints,eps,elts,eltsIndex,noImNotSensibleTo2DQuadraticLinearCellsFunc);
4196 * Finds butterfly cells in \a this mesh. A 2D cell is considered to be butterfly if at
4197 * least two its edges intersect each other anywhere except their extremities. An
4198 * INTERP_KERNEL::NORM_NORI3 cell can \b not be butterfly.
4199 * \param [in,out] cells - a vector returning ids of the found cells. It is not
4200 * cleared before filling in.
4201 * \param [in] eps - precision.
4202 * \throw If \a this->getMeshDimension() != 2.
4203 * \throw If \a this->getSpaceDimension() != 2 && \a this->getSpaceDimension() != 3.
4205 void MEDCouplingUMesh::checkButterflyCells(std::vector<mcIdType>& cells, double eps) const
4207 const char msg[]="Butterfly detection work only for 2D cells with spaceDim==2 or 3!";
4208 if(getMeshDimension()!=2)
4209 throw INTERP_KERNEL::Exception(msg);
4210 int spaceDim=getSpaceDimension();
4211 if(spaceDim!=2 && spaceDim!=3)
4212 throw INTERP_KERNEL::Exception(msg);
4213 const mcIdType *conn=_nodal_connec->getConstPointer();
4214 const mcIdType *connI=_nodal_connec_index->getConstPointer();
4215 mcIdType nbOfCells=getNumberOfCells();
4216 std::vector<double> cell2DinS2;
4217 for(mcIdType i=0;i<nbOfCells;i++)
4219 mcIdType offset=connI[i];
4220 mcIdType nbOfNodesForCell=connI[i+1]-offset-1;
4221 if(nbOfNodesForCell<=3)
4223 bool isQuad=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[offset]).isQuadratic();
4224 project2DCellOnXY(conn+offset+1,conn+connI[i+1],cell2DinS2);
4225 if(isButterfly2DCell(cell2DinS2,isQuad,eps))
4232 * This method is typically requested to unbutterfly 2D linear cells in \b this.
4234 * 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.
4235 * 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.
4237 * For each 2D linear cell in \b this, this method builds the convex envelop (or the convex hull) of the current cell.
4238 * This convex envelop is computed using Jarvis march algorithm.
4239 * The coordinates and the number of cells of \b this remain unchanged on invocation of this method.
4240 * 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)
4241 * 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.
4243 * \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.
4244 * \sa MEDCouplingUMesh::colinearize2D
4246 DataArrayIdType *MEDCouplingUMesh::convexEnvelop2D()
4248 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
4249 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convexEnvelop2D works only for meshDim=2 and spaceDim=2 !");
4250 checkFullyDefined();
4251 const double *coords=getCoords()->getConstPointer();
4252 mcIdType nbOfCells=getNumberOfCells();
4253 MCAuto<DataArrayIdType> nodalConnecIndexOut=DataArrayIdType::New();
4254 nodalConnecIndexOut->alloc(nbOfCells+1,1);
4255 MCAuto<DataArrayIdType> nodalConnecOut(DataArrayIdType::New());
4256 mcIdType *workIndexOut=nodalConnecIndexOut->getPointer();
4258 const mcIdType *nodalConnecIn=_nodal_connec->getConstPointer();
4259 const mcIdType *nodalConnecIndexIn=_nodal_connec_index->getConstPointer();
4260 std::set<INTERP_KERNEL::NormalizedCellType> types;
4261 MCAuto<DataArrayIdType> isChanged(DataArrayIdType::New());
4262 isChanged->alloc(0,1);
4263 for(mcIdType i=0;i<nbOfCells;i++,workIndexOut++)
4265 mcIdType pos=nodalConnecOut->getNumberOfTuples();
4266 if(BuildConvexEnvelopOf2DCellJarvis(coords,nodalConnecIn+nodalConnecIndexIn[i],nodalConnecIn+nodalConnecIndexIn[i+1],nodalConnecOut))
4267 isChanged->pushBackSilent(i);
4268 types.insert((INTERP_KERNEL::NormalizedCellType)nodalConnecOut->getIJ(pos,0));
4269 workIndexOut[1]=nodalConnecOut->getNumberOfTuples();
4271 if(isChanged->empty())
4273 setConnectivity(nodalConnecOut,nodalConnecIndexOut,false);
4275 return isChanged.retn();
4279 * This method is \b NOT const because it can modify \a this.
4280 * \a this is expected to be an unstructured mesh with meshDim==2 and spaceDim==3. If not an exception will be thrown.
4281 * \param mesh1D is an unstructured mesh with MeshDim==1 and spaceDim==3. If not an exception will be thrown.
4282 * \param policy specifies the type of extrusion chosen:
4283 * - \b 0 for translation only (most simple): the cells of the 1D mesh represent the vectors along which the 2D mesh
4284 * will be repeated to build each level
4285 * - \b 1 for translation and rotation: the translation is done as above. For each level, an arc of circle is fitted on
4286 * 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
4287 * 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
4289 * \return an unstructured mesh with meshDim==3 and spaceDim==3. The returned mesh has the same coords than \a this.
4291 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMesh(const MEDCouplingUMesh *mesh1D, int policy)
4293 checkFullyDefined();
4294 mesh1D->checkFullyDefined();
4295 if(!mesh1D->isContiguous1D())
4296 throw INTERP_KERNEL::Exception("buildExtrudedMesh : 1D mesh passed in parameter is not contiguous !");
4297 if(getSpaceDimension()!=mesh1D->getSpaceDimension())
4298 throw INTERP_KERNEL::Exception("Invalid call to buildExtrudedMesh this and mesh1D must have same space dimension !");
4299 if((getMeshDimension()!=2 || getSpaceDimension()!=3) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
4300 throw INTERP_KERNEL::Exception("Invalid 'this' for buildExtrudedMesh method : must be (meshDim==2 and spaceDim==3) or (meshDim==1 and spaceDim==2) !");
4301 if(mesh1D->getMeshDimension()!=1)
4302 throw INTERP_KERNEL::Exception("Invalid 'mesh1D' for buildExtrudedMesh method : must be meshDim==1 !");
4304 if(isPresenceOfQuadratic())
4306 if(mesh1D->isFullyQuadratic())
4309 throw INTERP_KERNEL::Exception("Invalid 2D mesh and 1D mesh because 2D mesh has quadratic cells and 1D is not fully quadratic !");
4311 mcIdType oldNbOfNodes(getNumberOfNodes());
4312 MCAuto<DataArrayDouble> newCoords;
4317 newCoords=fillExtCoordsUsingTranslation(mesh1D,isQuad);
4322 newCoords=fillExtCoordsUsingTranslAndAutoRotation(mesh1D,isQuad);
4326 throw INTERP_KERNEL::Exception("Not implemented extrusion policy : must be in (0) !");
4328 setCoords(newCoords);
4329 MCAuto<MEDCouplingUMesh> ret(buildExtrudedMeshFromThisLowLev(oldNbOfNodes,isQuad));
4336 * Checks if \a this mesh is constituted by only quadratic cells.
4337 * \return bool - \c true if there are only quadratic cells in \a this mesh.
4338 * \throw If the coordinates array is not set.
4339 * \throw If the nodal connectivity of cells is not defined.
4341 bool MEDCouplingUMesh::isFullyQuadratic() const
4343 checkFullyDefined();
4345 mcIdType nbOfCells=getNumberOfCells();
4346 for(mcIdType i=0;i<nbOfCells && ret;i++)
4348 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4349 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4350 ret=cm.isQuadratic();
4356 * Checks if \a this mesh includes any quadratic cell.
4357 * \return bool - \c true if there is at least one quadratic cells in \a this mesh.
4358 * \throw If the coordinates array is not set.
4359 * \throw If the nodal connectivity of cells is not defined.
4361 bool MEDCouplingUMesh::isPresenceOfQuadratic() const
4363 checkFullyDefined();
4365 mcIdType nbOfCells=getNumberOfCells();
4366 for(mcIdType i=0;i<nbOfCells && !ret;i++)
4368 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4369 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4370 ret=cm.isQuadratic();
4376 * Converts all quadratic cells to linear ones. If there are no quadratic cells in \a
4377 * this mesh, it remains unchanged.
4378 * \throw If the coordinates array is not set.
4379 * \throw If the nodal connectivity of cells is not defined.
4381 void MEDCouplingUMesh::convertQuadraticCellsToLinear()
4383 checkFullyDefined();
4384 mcIdType nbOfCells=getNumberOfCells();
4386 const mcIdType *iciptr=_nodal_connec_index->begin();
4387 for(mcIdType i=0;i<nbOfCells;i++)
4389 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4390 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4391 if(cm.isQuadratic())
4393 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4394 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4395 if(!cml.isDynamic())
4396 delta+=cm.getNumberOfNodes()-cml.getNumberOfNodes();
4398 delta+=(iciptr[i+1]-iciptr[i]-1)/2;
4403 MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()),newConnI(DataArrayIdType::New());
4404 const mcIdType *icptr(_nodal_connec->begin());
4405 newConn->alloc(getNodalConnectivityArrayLen()-delta,1);
4406 newConnI->alloc(nbOfCells+1,1);
4407 mcIdType *ocptr(newConn->getPointer()),*ociptr(newConnI->getPointer());
4410 for(mcIdType i=0;i<nbOfCells;i++,ociptr++)
4412 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)icptr[iciptr[i]];
4413 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4414 if(!cm.isQuadratic())
4416 _types.insert(type);
4417 ocptr=std::copy(icptr+iciptr[i],icptr+iciptr[i+1],ocptr);
4418 ociptr[1]=ociptr[0]+iciptr[i+1]-iciptr[i];
4422 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4423 _types.insert(typel);
4424 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4425 mcIdType newNbOfNodes=cml.getNumberOfNodes();
4427 newNbOfNodes=(iciptr[i+1]-iciptr[i]-1)/2;
4428 *ocptr++=ToIdType(typel);
4429 ocptr=std::copy(icptr+iciptr[i]+1,icptr+iciptr[i]+newNbOfNodes+1,ocptr);
4430 ociptr[1]=ociptr[0]+newNbOfNodes+1;
4433 setConnectivity(newConn,newConnI,false);
4437 * This method converts all linear cell in \a this to quadratic one.
4438 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, here it is needed to specify the target
4439 * 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)
4440 * 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.
4441 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, the coordinates in \a this can be become bigger. All created nodes will be put at the
4442 * end of the existing coordinates.
4444 * \param [in] conversionType specifies the type of conversion expected. Only 0 (default) and 1 are supported presently. 0 those that creates the 'most' simple
4445 * corresponding quadratic cells. 1 is those creating the 'most' complex.
4446 * \return a newly created DataArrayIdType instance that the caller should deal with containing cell ids of converted cells.
4448 * \throw if \a this is not fully defined. It throws too if \a conversionType is not in [0,1].
4450 * \sa MEDCouplingUMesh::convertQuadraticCellsToLinear
4452 DataArrayIdType *MEDCouplingUMesh::convertLinearCellsToQuadratic(int conversionType)
4454 DataArrayIdType *conn=0,*connI=0;
4455 DataArrayDouble *coords=0;
4456 std::set<INTERP_KERNEL::NormalizedCellType> types;
4457 checkFullyDefined();
4458 MCAuto<DataArrayIdType> ret,connSafe,connISafe;
4459 MCAuto<DataArrayDouble> coordsSafe;
4460 int meshDim=getMeshDimension();
4461 switch(conversionType)
4467 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);
4468 connSafe=conn; connISafe=connI; coordsSafe=coords;
4471 ret=convertLinearCellsToQuadratic2D0(conn,connI,coords,types);
4472 connSafe=conn; connISafe=connI; coordsSafe=coords;
4475 ret=convertLinearCellsToQuadratic3D0(conn,connI,coords,types);
4476 connSafe=conn; connISafe=connI; coordsSafe=coords;
4479 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 0 mesh dimensions available are [1,2,3] !");
4487 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);//it is not a bug. In 1D policy 0 and 1 are equals
4488 connSafe=conn; connISafe=connI; coordsSafe=coords;
4491 ret=convertLinearCellsToQuadratic2D1(conn,connI,coords,types);
4492 connSafe=conn; connISafe=connI; coordsSafe=coords;
4495 ret=convertLinearCellsToQuadratic3D1(conn,connI,coords,types);
4496 connSafe=conn; connISafe=connI; coordsSafe=coords;
4499 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 1 mesh dimensions available are [1,2,3] !");
4504 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion type available are 0 (default, the simplest) and 1 (the most complex) !");
4506 setConnectivity(connSafe,connISafe,false);
4508 setCoords(coordsSafe);
4513 * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
4514 * so that the number of cells remains the same. Quadratic faces are converted to
4515 * polygons. This method works only for 2D meshes in
4516 * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
4517 * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
4518 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
4519 * \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
4520 * a polylinized edge constituting the input polygon.
4521 * \throw If the coordinates array is not set.
4522 * \throw If the nodal connectivity of cells is not defined.
4523 * \throw If \a this->getMeshDimension() != 2.
4524 * \throw If \a this->getSpaceDimension() != 2.
4526 void MEDCouplingUMesh::tessellate2D(double eps)
4528 int meshDim(getMeshDimension()),spaceDim(getSpaceDimension());
4530 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : works only with space dimension equal to 2 !");
4534 return tessellate2DCurveInternal(eps);
4536 return tessellate2DInternal(eps);
4538 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : mesh dimension must be in [1,2] !");
4544 * This method only works if \a this has spaceDimension equal to 2 and meshDimension also equal to 2.
4545 * This method allows to modify connectivity of cells in \a this that shares some edges in \a edgeIdsToBeSplit.
4546 * The nodes to be added in those 2D cells are defined by the pair of \a nodeIdsToAdd and \a nodeIdsIndexToAdd.
4547 * Length of \a nodeIdsIndexToAdd is expected to equal to length of \a edgeIdsToBeSplit + 1.
4548 * The node ids in \a nodeIdsToAdd should be valid. Those nodes have to be sorted exactly following exactly the direction of the edge.
4549 * This method can be seen as the opposite method of colinearize2D.
4550 * 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
4551 * to avoid to modify the numbering of existing nodes.
4553 * \param [in] nodeIdsToAdd - the list of node ids to be added (\a nodeIdsIndexToAdd array allows to walk on this array)
4554 * \param [in] nodeIdsIndexToAdd - the entry point of \a nodeIdsToAdd to point to the corresponding nodes to be added.
4555 * \param [in] mesh1Desc - 1st output of buildDescendingConnectivity2 on \a this.
4556 * \param [in] desc - 2nd output of buildDescendingConnectivity2 on \a this.
4557 * \param [in] descI - 3rd output of buildDescendingConnectivity2 on \a this.
4558 * \param [in] revDesc - 4th output of buildDescendingConnectivity2 on \a this.
4559 * \param [in] revDescI - 5th output of buildDescendingConnectivity2 on \a this.
4561 * \sa buildDescendingConnectivity2
4563 void MEDCouplingUMesh::splitSomeEdgesOf2DMesh(const DataArrayIdType *nodeIdsToAdd, const DataArrayIdType *nodeIdsIndexToAdd, const DataArrayIdType *edgeIdsToBeSplit,
4564 const MEDCouplingUMesh *mesh1Desc, const DataArrayIdType *desc, const DataArrayIdType *descI, const DataArrayIdType *revDesc, const DataArrayIdType *revDescI)
4566 if(!nodeIdsToAdd || !nodeIdsIndexToAdd || !edgeIdsToBeSplit || !mesh1Desc || !desc || !descI || !revDesc || !revDescI)
4567 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : input pointers must be not NULL !");
4568 nodeIdsToAdd->checkAllocated(); nodeIdsIndexToAdd->checkAllocated(); edgeIdsToBeSplit->checkAllocated(); desc->checkAllocated(); descI->checkAllocated(); revDesc->checkAllocated(); revDescI->checkAllocated();
4569 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
4570 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : this must have spacedim=meshdim=2 !");
4571 if(mesh1Desc->getSpaceDimension()!=2 || mesh1Desc->getMeshDimension()!=1)
4572 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : mesh1Desc must be the explosion of this with spaceDim=2 and meshDim = 1 !");
4573 //DataArrayIdType *out0(0),*outi0(0);
4574 //MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
4575 //MCAuto<DataArrayIdType> out0s(out0),outi0s(outi0);
4576 //out0s=out0s->buildUnique(); out0s->sort(true);
4582 * Divides every cell of \a this mesh into simplices (triangles in 2D and tetrahedra in 3D).
4583 * In addition, returns an array mapping new cells to old ones. <br>
4584 * This method typically increases the number of cells in \a this mesh
4585 * but the number of nodes remains \b unchanged.
4586 * That's why the 3D splitting policies
4587 * INTERP_KERNEL::GENERAL_24 and INTERP_KERNEL::GENERAL_48 are not available here.
4588 * \param [in] policy - specifies a pattern used for splitting.
4589 * The semantic of \a policy is:
4590 * - 0 - to split QUAD4 by cutting it along 0-2 diagonal (for 2D mesh only).
4591 * - 1 - to split QUAD4 by cutting it along 1-3 diagonal (for 2D mesh only).
4592 * - INTERP_KERNEL::PLANAR_FACE_5 - to split HEXA8 into 5 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4593 * - INTERP_KERNEL::PLANAR_FACE_6 - to split HEXA8 into 6 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4596 * \return DataArrayIdType * - a new instance of DataArrayIdType holding, for each new cell,
4597 * an id of old cell producing it. The caller is to delete this array using
4598 * decrRef() as it is no more needed.
4600 * \throw If \a policy is 0 or 1 and \a this->getMeshDimension() != 2.
4601 * \throw If \a policy is INTERP_KERNEL::PLANAR_FACE_5 or INTERP_KERNEL::PLANAR_FACE_6
4602 * and \a this->getMeshDimension() != 3.
4603 * \throw If \a policy is not one of the four discussed above.
4604 * \throw If the nodal connectivity of cells is not defined.
4605 * \sa MEDCouplingUMesh::tetrahedrize, MEDCoupling1SGTUMesh::sortHexa8EachOther
4607 DataArrayIdType *MEDCouplingUMesh::simplexize(int policy)
4612 return simplexizePol0();
4614 return simplexizePol1();
4615 case INTERP_KERNEL::PLANAR_FACE_5:
4616 return simplexizePlanarFace5();
4617 case INTERP_KERNEL::PLANAR_FACE_6:
4618 return simplexizePlanarFace6();
4620 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)");
4625 * Checks if \a this mesh is constituted by simplex cells only. Simplex cells are:
4626 * - 1D: INTERP_KERNEL::NORM_SEG2
4627 * - 2D: INTERP_KERNEL::NORM_TRI3
4628 * - 3D: INTERP_KERNEL::NORM_TETRA4.
4630 * This method is useful for users that need to use P1 field services as
4631 * MEDCouplingFieldDouble::getValueOn(), MEDCouplingField::buildMeasureField() etc.
4632 * All these methods need mesh support containing only simplex cells.
4633 * \return bool - \c true if there are only simplex cells in \a this mesh.
4634 * \throw If the coordinates array is not set.
4635 * \throw If the nodal connectivity of cells is not defined.
4636 * \throw If \a this->getMeshDimension() < 1.
4638 bool MEDCouplingUMesh::areOnlySimplexCells() const
4640 checkFullyDefined();
4641 int mdim=getMeshDimension();
4642 if(mdim<1 || mdim>3)
4643 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::areOnlySimplexCells : only available with meshes having a meshdim 1, 2 or 3 !");
4644 mcIdType nbCells=getNumberOfCells();
4645 const mcIdType *conn=_nodal_connec->begin();
4646 const mcIdType *connI=_nodal_connec_index->begin();
4647 for(mcIdType i=0;i<nbCells;i++)
4649 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4659 * Converts degenerated 2D or 3D linear cells of \a this mesh into cells of simpler
4660 * type. For example an INTERP_KERNEL::NORM_QUAD4 cell having only three unique nodes in
4661 * its connectivity is transformed into an INTERP_KERNEL::NORM_TRI3 cell.
4662 * Quadratic cells in 2D are also handled. In those cells edges where start=end=midpoint are removed.
4663 * This method does \b not perform geometrical checks and checks only nodal connectivity of cells,
4664 * so it can be useful to call mergeNodes() before calling this method.
4665 * \throw If \a this->getMeshDimension() <= 1.
4666 * \throw If the coordinates array is not set.
4667 * \throw If the nodal connectivity of cells is not defined.
4669 void MEDCouplingUMesh::convertDegeneratedCells()
4671 checkFullyDefined();
4672 if(getMeshDimension()<=1)
4673 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4674 mcIdType nbOfCells=getNumberOfCells();
4677 mcIdType initMeshLgth=getNodalConnectivityArrayLen();
4678 mcIdType *conn=_nodal_connec->getPointer();
4679 mcIdType *index=_nodal_connec_index->getPointer();
4680 mcIdType posOfCurCell=0;
4682 mcIdType lgthOfCurCell;
4683 for(mcIdType i=0;i<nbOfCells;i++)
4685 lgthOfCurCell=index[i+1]-posOfCurCell;
4686 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4688 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
4689 conn+newPos+1,newLgth);
4690 conn[newPos]=newType;
4692 posOfCurCell=index[i+1];
4695 if(newPos!=initMeshLgth)
4696 _nodal_connec->reAlloc(newPos);
4701 * Same as MEDCouplingUMesh::convertDegeneratedCells() plus deletion of the flat cells.
4702 * A cell is flat in the following cases:
4703 * - for a linear cell, all points in the connectivity are equal
4704 * - for a quadratic cell, either the above, or a quadratic polygon with two (linear) points and two
4705 * identical quadratic points
4706 * \return a new instance of DataArrayIdType holding ids of removed cells. The caller is to delete
4707 * this array using decrRef() as it is no more needed.
4709 DataArrayIdType *MEDCouplingUMesh::convertDegeneratedCellsAndRemoveFlatOnes()
4711 checkFullyDefined();
4712 if(getMeshDimension()<=1)
4713 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4714 mcIdType nbOfCells=getNumberOfCells();
4715 MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(0,1);
4718 mcIdType initMeshLgth=getNodalConnectivityArrayLen();
4719 mcIdType *conn=_nodal_connec->getPointer();
4720 mcIdType *index=_nodal_connec_index->getPointer();
4721 mcIdType posOfCurCell=0;
4723 mcIdType lgthOfCurCell, nbDelCells(0);
4724 for(mcIdType i=0;i<nbOfCells;i++)
4726 lgthOfCurCell=index[i+1]-posOfCurCell;
4727 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4729 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
4730 conn+newPos+1,newLgth);
4731 // Shall we delete the cell if it is completely degenerated:
4732 bool delCell=INTERP_KERNEL::CellSimplify::isFlatCell(conn, newPos, newLgth, newType);
4736 ret->pushBackSilent(i);
4738 else //if the cell is to be deleted, simply stay at the same place
4740 conn[newPos]=newType;
4743 posOfCurCell=index[i+1];
4744 index[i+1-nbDelCells]=newPos;
4746 if(newPos!=initMeshLgth)
4747 _nodal_connec->reAlloc(newPos);
4748 const mcIdType nCellDel=ret->getNumberOfTuples();
4750 _nodal_connec_index->reAlloc(nbOfCells-nCellDel+1);
4756 * This method remove null 1D cells from \a this. A 1D cell is considered null if start node is equal to end node.
4757 * Only connectivity is considered here.
4759 bool MEDCouplingUMesh::removeDegenerated1DCells()
4761 checkConnectivityFullyDefined();
4762 if(getMeshDimension()!=1)
4763 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::removeDegenerated1DCells works on umeshes with meshdim equals to 1 !");
4764 std::size_t nbCells(getNumberOfCells()),newSize(0),newSize2(0);
4765 const mcIdType *conn(getNodalConnectivity()->begin()),*conni(getNodalConnectivityIndex()->begin());
4767 for(std::size_t i=0;i<nbCells;i++)
4769 INTERP_KERNEL::NormalizedCellType ct((INTERP_KERNEL::NormalizedCellType)conn[conni[i]]);
4770 if(ct==INTERP_KERNEL::NORM_SEG2 || ct==INTERP_KERNEL::NORM_SEG3)
4772 if(conn[conni[i]+1]!=conn[conni[i]+2])
4775 newSize2+=conni[i+1]-conni[i];
4780 std::ostringstream oss; oss << "MEDCouplingUMesh::removeDegenerated1DCells : cell #" << i << " in this is not of type SEG2/SEG3 !";
4781 throw INTERP_KERNEL::Exception(oss.str());
4785 if(newSize==nbCells)//no cells has been removed -> do nothing
4787 MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()),newConnI(DataArrayIdType::New()); newConnI->alloc(newSize+1,1); newConn->alloc(newSize2,1);
4788 mcIdType *newConnPtr(newConn->getPointer()),*newConnIPtr(newConnI->getPointer()); newConnIPtr[0]=0;
4789 for(std::size_t i=0;i<nbCells;i++)
4791 if(conn[conni[i]+1]!=conn[conni[i]+2])
4793 newConnIPtr[1]=newConnIPtr[0]+conni[i+1]-conni[i];
4794 newConnPtr=std::copy(conn+conni[i],conn+conni[i+1],newConnPtr);
4798 setConnectivity(newConn,newConnI,true);
4803 * Finds incorrectly oriented cells of this 2D mesh in 3D space.
4804 * A cell is considered to be oriented correctly if an angle between its
4805 * normal vector and a given vector is less than \c PI / \c 2.
4806 * \param [in] vec - 3 components of the vector specifying the correct orientation of
4808 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
4810 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
4811 * is not cleared before filling in.
4812 * \throw If \a this->getMeshDimension() != 2.
4813 * \throw If \a this->getSpaceDimension() != 3.
4815 * \if ENABLE_EXAMPLES
4816 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
4817 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
4820 void MEDCouplingUMesh::are2DCellsNotCorrectlyOriented(const double *vec, bool polyOnly, std::vector<mcIdType>& cells) const
4822 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
4823 throw INTERP_KERNEL::Exception("Invalid mesh to apply are2DCellsNotCorrectlyOriented on it : must be meshDim==2 and spaceDim==3 !");
4824 mcIdType nbOfCells=getNumberOfCells();
4825 const mcIdType *conn=_nodal_connec->begin();
4826 const mcIdType *connI=_nodal_connec_index->begin();
4827 const double *coordsPtr=_coords->begin();
4828 for(mcIdType i=0;i<nbOfCells;i++)
4830 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4831 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
4833 bool isQuadratic=INTERP_KERNEL::CellModel::GetCellModel(type).isQuadratic();
4834 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4841 * Reverse connectivity of 2D cells whose orientation is not correct. A cell is
4842 * considered to be oriented correctly if an angle between its normal vector and a
4843 * given vector is less than \c PI / \c 2.
4844 * \param [in] vec - 3 components of the vector specifying the correct orientation of
4846 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
4848 * \throw If \a this->getMeshDimension() != 2.
4849 * \throw If \a this->getSpaceDimension() != 3.
4851 * \if ENABLE_EXAMPLES
4852 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
4853 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
4856 * \sa changeOrientationOfCells
4858 void MEDCouplingUMesh::orientCorrectly2DCells(const double *vec, bool polyOnly)
4860 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
4861 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectly2DCells on it : must be meshDim==2 and spaceDim==3 !");
4862 mcIdType nbOfCells=getNumberOfCells();
4863 mcIdType *conn(_nodal_connec->getPointer());
4864 const mcIdType *connI(_nodal_connec_index->begin());
4865 const double *coordsPtr(_coords->begin());
4866 bool isModified(false);
4867 for(mcIdType i=0;i<nbOfCells;i++)
4869 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4870 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
4872 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
4873 bool isQuadratic(cm.isQuadratic());
4874 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4877 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
4882 _nodal_connec->declareAsNew();
4887 * This method change the orientation of cells in \a this without any consideration of coordinates. Only connectivity is impacted.
4889 * \sa orientCorrectly2DCells
4891 void MEDCouplingUMesh::changeOrientationOfCells()
4893 int mdim(getMeshDimension());
4894 if(mdim!=2 && mdim!=1)
4895 throw INTERP_KERNEL::Exception("Invalid mesh to apply changeOrientationOfCells on it : must be meshDim==2 or meshDim==1 !");
4896 mcIdType nbOfCells=getNumberOfCells();
4897 mcIdType *conn(_nodal_connec->getPointer());
4898 const mcIdType *connI(_nodal_connec_index->begin());
4901 for(mcIdType i=0;i<nbOfCells;i++)
4903 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4904 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
4905 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
4910 for(mcIdType i=0;i<nbOfCells;i++)
4912 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4913 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
4914 cm.changeOrientationOf1D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
4920 * Finds incorrectly oriented polyhedral cells, i.e. polyhedrons having correctly
4921 * oriented facets. The normal vector of the facet should point out of the cell.
4922 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
4923 * is not cleared before filling in.
4924 * \throw If \a this->getMeshDimension() != 3.
4925 * \throw If \a this->getSpaceDimension() != 3.
4926 * \throw If the coordinates array is not set.
4927 * \throw If the nodal connectivity of cells is not defined.
4929 * \if ENABLE_EXAMPLES
4930 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
4931 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
4934 void MEDCouplingUMesh::arePolyhedronsNotCorrectlyOriented(std::vector<mcIdType>& cells) const
4936 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
4937 throw INTERP_KERNEL::Exception("Invalid mesh to apply arePolyhedronsNotCorrectlyOriented on it : must be meshDim==3 and spaceDim==3 !");
4938 mcIdType nbOfCells=getNumberOfCells();
4939 const mcIdType *conn=_nodal_connec->begin();
4940 const mcIdType *connI=_nodal_connec_index->begin();
4941 const double *coordsPtr=_coords->begin();
4942 for(mcIdType i=0;i<nbOfCells;i++)
4944 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4945 if(type==INTERP_KERNEL::NORM_POLYHED)
4947 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4954 * Tries to fix connectivity of polyhedra, so that normal vector of all facets to point
4956 * \throw If \a this->getMeshDimension() != 3.
4957 * \throw If \a this->getSpaceDimension() != 3.
4958 * \throw If the coordinates array is not set.
4959 * \throw If the nodal connectivity of cells is not defined.
4960 * \throw If the reparation fails.
4962 * \if ENABLE_EXAMPLES
4963 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
4964 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
4966 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
4968 void MEDCouplingUMesh::orientCorrectlyPolyhedrons()
4970 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
4971 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectlyPolyhedrons on it : must be meshDim==3 and spaceDim==3 !");
4972 mcIdType nbOfCells=getNumberOfCells();
4973 mcIdType *conn=_nodal_connec->getPointer();
4974 const mcIdType *connI=_nodal_connec_index->begin();
4975 const double *coordsPtr=_coords->begin();
4976 for(mcIdType i=0;i<nbOfCells;i++)
4978 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4979 if(type==INTERP_KERNEL::NORM_POLYHED)
4983 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4984 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
4986 catch(INTERP_KERNEL::Exception& e)
4988 std::ostringstream oss; oss << "Something wrong in polyhedron #" << i << " : " << e.what();
4989 throw INTERP_KERNEL::Exception(oss.str());
4997 * This method invert orientation of all cells in \a this.
4998 * After calling this method the absolute value of measure of cells in \a this are the same than before calling.
4999 * This method only operates on the connectivity so coordinates are not touched at all.
5001 void MEDCouplingUMesh::invertOrientationOfAllCells()
5003 checkConnectivityFullyDefined();
5004 std::set<INTERP_KERNEL::NormalizedCellType> gts(getAllGeoTypes());
5005 mcIdType *conn(_nodal_connec->getPointer());
5006 const mcIdType *conni(_nodal_connec_index->begin());
5007 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator gt=gts.begin();gt!=gts.end();gt++)
5009 INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::OrientationInverter> oi(INTERP_KERNEL::OrientationInverter::BuildInstanceFrom(*gt));
5010 MCAuto<DataArrayIdType> cwt(giveCellsWithType(*gt));
5011 for(const mcIdType *it=cwt->begin();it!=cwt->end();it++)
5012 oi->operate(conn+conni[*it]+1,conn+conni[*it+1]);
5018 * Finds and fixes incorrectly oriented linear extruded volumes (INTERP_KERNEL::NORM_HEXA8,
5019 * INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXGP12 etc) to respect the MED convention
5020 * according to which the first facet of the cell should be oriented to have the normal vector
5021 * pointing out of cell.
5022 * \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of fixed
5023 * cells. The caller is to delete this array using decrRef() as it is no more
5025 * \throw If \a this->getMeshDimension() != 3.
5026 * \throw If \a this->getSpaceDimension() != 3.
5027 * \throw If the coordinates array is not set.
5028 * \throw If the nodal connectivity of cells is not defined.
5030 * \if ENABLE_EXAMPLES
5031 * \ref cpp_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a C++ example".<br>
5032 * \ref py_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a Python example".
5034 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
5036 DataArrayIdType *MEDCouplingUMesh::findAndCorrectBadOriented3DExtrudedCells()
5038 const char msg[]="check3DCellsWellOriented detection works only for 3D cells !";
5039 if(getMeshDimension()!=3)
5040 throw INTERP_KERNEL::Exception(msg);
5041 int spaceDim=getSpaceDimension();
5043 throw INTERP_KERNEL::Exception(msg);
5045 mcIdType nbOfCells=getNumberOfCells();
5046 mcIdType *conn=_nodal_connec->getPointer();
5047 const mcIdType *connI=_nodal_connec_index->begin();
5048 const double *coo=getCoords()->begin();
5049 MCAuto<DataArrayIdType> cells(DataArrayIdType::New()); cells->alloc(0,1);
5050 for(mcIdType i=0;i<nbOfCells;i++)
5052 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5053 if(cm.isExtruded() && !cm.isDynamic() && !cm.isQuadratic())
5055 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coo))
5057 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
5058 cells->pushBackSilent(i);
5062 return cells.retn();
5066 * This method is a faster method to correct orientation of all 3D cells in \a this.
5067 * 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.
5068 * This method makes the hypothesis that \a this a coherent that is to say MEDCouplingUMesh::checkConsistency should throw no exception.
5070 * \return a newly allocated mcIdType array with one components containing cell ids renumbered to fit the convention of MED (MED file and MEDCoupling)
5071 * \sa MEDCouplingUMesh::orientCorrectlyPolyhedrons,
5073 DataArrayIdType *MEDCouplingUMesh::findAndCorrectBadOriented3DCells()
5075 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
5076 throw INTERP_KERNEL::Exception("Invalid mesh to apply findAndCorrectBadOriented3DCells on it : must be meshDim==3 and spaceDim==3 !");
5077 mcIdType nbOfCells=getNumberOfCells();
5078 mcIdType *conn=_nodal_connec->getPointer();
5079 const mcIdType *connI=_nodal_connec_index->begin();
5080 const double *coordsPtr=_coords->begin();
5081 MCAuto<DataArrayIdType> ret=DataArrayIdType::New(); ret->alloc(0,1);
5082 for(mcIdType i=0;i<nbOfCells;i++)
5084 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5087 case INTERP_KERNEL::NORM_TETRA4:
5089 if(!IsTetra4WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5091 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+3));
5092 ret->pushBackSilent(i);
5096 case INTERP_KERNEL::NORM_PYRA5:
5098 if(!IsPyra5WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5100 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+4));
5101 ret->pushBackSilent(i);
5105 case INTERP_KERNEL::NORM_PENTA6:
5106 case INTERP_KERNEL::NORM_HEXA8:
5107 case INTERP_KERNEL::NORM_HEXGP12:
5109 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5111 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
5112 ret->pushBackSilent(i);
5116 case INTERP_KERNEL::NORM_POLYHED:
5118 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5120 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
5121 ret->pushBackSilent(i);
5126 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 !");
5134 * This method has a sense for meshes with spaceDim==3 and meshDim==2.
5135 * If it is not the case an exception will be thrown.
5136 * This method is fast because the first cell of \a this is used to compute the plane.
5137 * \param vec output of size at least 3 used to store the normal vector (with norm equal to Area ) of searched plane.
5138 * \param pos output of size at least 3 used to store a point owned of searched plane.
5140 void MEDCouplingUMesh::getFastAveragePlaneOfThis(double *vec, double *pos) const
5142 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
5143 throw INTERP_KERNEL::Exception("Invalid mesh to apply getFastAveragePlaneOfThis on it : must be meshDim==2 and spaceDim==3 !");
5144 const mcIdType *conn=_nodal_connec->begin();
5145 const mcIdType *connI=_nodal_connec_index->begin();
5146 const double *coordsPtr=_coords->begin();
5147 INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(conn+1,connI[1]-connI[0]-1,coordsPtr,vec);
5148 std::copy(coordsPtr+3*conn[1],coordsPtr+3*conn[1]+3,pos);
5152 * Creates a new MEDCouplingFieldDouble holding Edge Ratio values of all
5153 * cells. Currently cells of the following types are treated:
5154 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5155 * For a cell of other type an exception is thrown.
5156 * Space dimension of a 2D mesh can be either 2 or 3.
5157 * The Edge Ratio of a cell \f$t\f$ is:
5158 * \f$\frac{|t|_\infty}{|t|_0}\f$,
5159 * where \f$|t|_\infty\f$ and \f$|t|_0\f$ respectively denote the greatest and
5160 * the smallest edge lengths of \f$t\f$.
5161 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5162 * cells and one time, lying on \a this mesh. The caller is to delete this
5163 * field using decrRef() as it is no more needed.
5164 * \throw If the coordinates array is not set.
5165 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5166 * \throw If the connectivity data array has more than one component.
5167 * \throw If the connectivity data array has a named component.
5168 * \throw If the connectivity index data array has more than one component.
5169 * \throw If the connectivity index data array has a named component.
5170 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
5171 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5172 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5174 MEDCouplingFieldDouble *MEDCouplingUMesh::getEdgeRatioField() const
5176 checkConsistencyLight();
5177 int spaceDim=getSpaceDimension();
5178 int meshDim=getMeshDimension();
5179 if(spaceDim!=2 && spaceDim!=3)
5180 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : SpaceDimension must be equal to 2 or 3 !");
5181 if(meshDim!=2 && meshDim!=3)
5182 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : MeshDimension must be equal to 2 or 3 !");
5183 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5185 mcIdType nbOfCells=getNumberOfCells();
5186 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5187 arr->alloc(nbOfCells,1);
5188 double *pt=arr->getPointer();
5189 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5190 const mcIdType *conn=_nodal_connec->begin();
5191 const mcIdType *connI=_nodal_connec_index->begin();
5192 const double *coo=_coords->begin();
5194 for(mcIdType i=0;i<nbOfCells;i++,pt++)
5196 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5199 case INTERP_KERNEL::NORM_TRI3:
5201 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5202 *pt=INTERP_KERNEL::triEdgeRatio(tmp);
5205 case INTERP_KERNEL::NORM_QUAD4:
5207 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5208 *pt=INTERP_KERNEL::quadEdgeRatio(tmp);
5211 case INTERP_KERNEL::NORM_TETRA4:
5213 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5214 *pt=INTERP_KERNEL::tetraEdgeRatio(tmp);
5218 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5220 conn+=connI[i+1]-connI[i];
5222 ret->setName("EdgeRatio");
5223 ret->synchronizeTimeWithSupport();
5228 * Creates a new MEDCouplingFieldDouble holding Aspect Ratio values of all
5229 * cells. Currently cells of the following types are treated:
5230 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5231 * For a cell of other type an exception is thrown.
5232 * Space dimension of a 2D mesh can be either 2 or 3.
5233 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5234 * cells and one time, lying on \a this mesh. The caller is to delete this
5235 * field using decrRef() as it is no more needed.
5236 * \throw If the coordinates array is not set.
5237 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5238 * \throw If the connectivity data array has more than one component.
5239 * \throw If the connectivity data array has a named component.
5240 * \throw If the connectivity index data array has more than one component.
5241 * \throw If the connectivity index data array has a named component.
5242 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
5243 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5244 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5246 MEDCouplingFieldDouble *MEDCouplingUMesh::getAspectRatioField() const
5248 checkConsistencyLight();
5249 int spaceDim=getSpaceDimension();
5250 int meshDim=getMeshDimension();
5251 if(spaceDim!=2 && spaceDim!=3)
5252 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : SpaceDimension must be equal to 2 or 3 !");
5253 if(meshDim!=2 && meshDim!=3)
5254 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : MeshDimension must be equal to 2 or 3 !");
5255 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5257 mcIdType nbOfCells=getNumberOfCells();
5258 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5259 arr->alloc(nbOfCells,1);
5260 double *pt=arr->getPointer();
5261 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5262 const mcIdType *conn=_nodal_connec->begin();
5263 const mcIdType *connI=_nodal_connec_index->begin();
5264 const double *coo=_coords->begin();
5266 for(mcIdType i=0;i<nbOfCells;i++,pt++)
5268 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5271 case INTERP_KERNEL::NORM_TRI3:
5273 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5274 *pt=INTERP_KERNEL::triAspectRatio(tmp);
5277 case INTERP_KERNEL::NORM_QUAD4:
5279 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5280 *pt=INTERP_KERNEL::quadAspectRatio(tmp);
5283 case INTERP_KERNEL::NORM_TETRA4:
5285 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5286 *pt=INTERP_KERNEL::tetraAspectRatio(tmp);
5290 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5292 conn+=connI[i+1]-connI[i];
5294 ret->setName("AspectRatio");
5295 ret->synchronizeTimeWithSupport();
5300 * Creates a new MEDCouplingFieldDouble holding Warping factor values of all
5301 * cells of \a this 2D mesh in 3D space. It is a measure of the "planarity" of 2D cell
5302 * in 3D space. Currently only cells of the following types are
5303 * treated: INTERP_KERNEL::NORM_QUAD4.
5304 * For a cell of other type an exception is thrown.
5305 * The warp field is computed as follows: let (a,b,c,d) be the points of the quad.
5307 * \f$t=\vec{da}\times\vec{ab}\f$,
5308 * \f$u=\vec{ab}\times\vec{bc}\f$
5309 * \f$v=\vec{bc}\times\vec{cd}\f$
5310 * \f$w=\vec{cd}\times\vec{da}\f$, the warp is defined as \f$W^3\f$ with
5312 * W=min(\frac{t}{|t|}\cdot\frac{v}{|v|}, \frac{u}{|u|}\cdot\frac{w}{|w|})
5314 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5315 * cells and one time, lying on \a this mesh. The caller is to delete this
5316 * field using decrRef() as it is no more needed.
5317 * \throw If the coordinates array is not set.
5318 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5319 * \throw If the connectivity data array has more than one component.
5320 * \throw If the connectivity data array has a named component.
5321 * \throw If the connectivity index data array has more than one component.
5322 * \throw If the connectivity index data array has a named component.
5323 * \throw If \a this->getMeshDimension() != 2.
5324 * \throw If \a this->getSpaceDimension() != 3.
5325 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5327 MEDCouplingFieldDouble *MEDCouplingUMesh::getWarpField() const
5329 checkConsistencyLight();
5330 int spaceDim=getSpaceDimension();
5331 int meshDim=getMeshDimension();
5333 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : SpaceDimension must be equal to 3 !");
5335 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : MeshDimension must be equal to 2 !");
5336 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5338 mcIdType nbOfCells=getNumberOfCells();
5339 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5340 arr->alloc(nbOfCells,1);
5341 double *pt=arr->getPointer();
5342 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5343 const mcIdType *conn=_nodal_connec->begin();
5344 const mcIdType *connI=_nodal_connec_index->begin();
5345 const double *coo=_coords->begin();
5347 for(mcIdType i=0;i<nbOfCells;i++,pt++)
5349 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5352 case INTERP_KERNEL::NORM_QUAD4:
5354 FillInCompact3DMode(3,4,conn+1,coo,tmp);
5355 *pt=INTERP_KERNEL::quadWarp(tmp);
5359 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : A cell with not manged type (NORM_QUAD4) has been detected !");
5361 conn+=connI[i+1]-connI[i];
5363 ret->setName("Warp");
5364 ret->synchronizeTimeWithSupport();
5370 * Creates a new MEDCouplingFieldDouble holding Skew factor values of all
5371 * cells of \a this 2D mesh in 3D space. Currently cells of the following types are
5372 * treated: INTERP_KERNEL::NORM_QUAD4.
5373 * The skew is computed as follow for a quad with points (a,b,c,d): let
5374 * \f$u=\vec{ab}+\vec{dc}\f$ and \f$v=\vec{ac}+\vec{bd}\f$
5375 * then the skew is computed as:
5377 * s=\frac{u}{|u|}\cdot\frac{v}{|v|}
5380 * For a cell of other type an exception is thrown.
5381 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5382 * cells and one time, lying on \a this mesh. The caller is to delete this
5383 * field using decrRef() as it is no more needed.
5384 * \throw If the coordinates array is not set.
5385 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5386 * \throw If the connectivity data array has more than one component.
5387 * \throw If the connectivity data array has a named component.
5388 * \throw If the connectivity index data array has more than one component.
5389 * \throw If the connectivity index data array has a named component.
5390 * \throw If \a this->getMeshDimension() != 2.
5391 * \throw If \a this->getSpaceDimension() != 3.
5392 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5394 MEDCouplingFieldDouble *MEDCouplingUMesh::getSkewField() const
5396 checkConsistencyLight();
5397 int spaceDim=getSpaceDimension();
5398 int meshDim=getMeshDimension();
5400 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : SpaceDimension must be equal to 3 !");
5402 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : MeshDimension must be equal to 2 !");
5403 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5405 mcIdType nbOfCells=getNumberOfCells();
5406 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5407 arr->alloc(nbOfCells,1);
5408 double *pt=arr->getPointer();
5409 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5410 const mcIdType *conn=_nodal_connec->begin();
5411 const mcIdType *connI=_nodal_connec_index->begin();
5412 const double *coo=_coords->begin();
5414 for(mcIdType i=0;i<nbOfCells;i++,pt++)
5416 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5419 case INTERP_KERNEL::NORM_QUAD4:
5421 FillInCompact3DMode(3,4,conn+1,coo,tmp);
5422 *pt=INTERP_KERNEL::quadSkew(tmp);
5426 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : A cell with not manged type (NORM_QUAD4) has been detected !");
5428 conn+=connI[i+1]-connI[i];
5430 ret->setName("Skew");
5431 ret->synchronizeTimeWithSupport();
5436 * 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.
5438 * \return a new instance of field containing the result. The returned instance has to be deallocated by the caller.
5440 * \sa getSkewField, getWarpField, getAspectRatioField, getEdgeRatioField
5442 MEDCouplingFieldDouble *MEDCouplingUMesh::computeDiameterField() const
5444 checkConsistencyLight();
5445 MCAuto<MEDCouplingFieldDouble> ret(MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME));
5447 std::set<INTERP_KERNEL::NormalizedCellType> types;
5448 ComputeAllTypesInternal(types,_nodal_connec,_nodal_connec_index);
5449 int spaceDim(getSpaceDimension());
5450 mcIdType nbCells(getNumberOfCells());
5451 MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
5452 arr->alloc(nbCells,1);
5453 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++)
5455 INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::DiameterCalculator> dc(INTERP_KERNEL::CellModel::GetCellModel(*it).buildInstanceOfDiameterCalulator(spaceDim));
5456 MCAuto<DataArrayIdType> cellIds(giveCellsWithType(*it));
5457 dc->computeForListOfCellIdsUMeshFrmt(cellIds->begin(),cellIds->end(),_nodal_connec_index->begin(),_nodal_connec->begin(),getCoords()->begin(),arr->getPointer());
5460 ret->setName("Diameter");
5465 * This method aggregate the bbox of each cell and put it into bbox parameter (xmin,xmax,ymin,ymax,zmin,zmax).
5467 * \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)
5468 * For all other cases this input parameter is ignored.
5469 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5471 * \throw If \a this is not fully set (coordinates and connectivity).
5472 * \throw If a cell in \a this has no valid nodeId.
5473 * \sa MEDCouplingUMesh::getBoundingBoxForBBTreeFast, MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5475 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree(double arcDetEps) const
5477 int mDim(getMeshDimension()),sDim(getSpaceDimension());
5478 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.
5479 return getBoundingBoxForBBTreeFast();
5480 if((mDim==2 && sDim==2) || (mDim==1 && sDim==2))
5482 bool presenceOfQuadratic(false);
5483 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=_types.begin();it!=_types.end();it++)
5485 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(*it));
5486 if(cm.isQuadratic())
5487 presenceOfQuadratic=true;
5489 if(!presenceOfQuadratic)
5490 return getBoundingBoxForBBTreeFast();
5491 if(mDim==2 && sDim==2)
5492 return getBoundingBoxForBBTree2DQuadratic(arcDetEps);
5494 return getBoundingBoxForBBTree1DQuadratic(arcDetEps);
5496 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) !");
5500 * This method aggregate the bbox of each cell only considering the nodes constituting each cell and put it into bbox parameter.
5501 * So meshes having quadratic cells the computed bounding boxes can be invalid !
5503 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5505 * \throw If \a this is not fully set (coordinates and connectivity).
5506 * \throw If a cell in \a this has no valid nodeId.
5508 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTreeFast() const
5510 checkFullyDefined();
5511 int spaceDim(getSpaceDimension());
5512 mcIdType nbOfCells(getNumberOfCells()), nbOfNodes(getNumberOfNodes());
5513 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5514 double *bbox(ret->getPointer());
5515 for(mcIdType i=0;i<nbOfCells*spaceDim;i++)
5517 bbox[2*i]=std::numeric_limits<double>::max();
5518 bbox[2*i+1]=-std::numeric_limits<double>::max();
5520 const double *coordsPtr(_coords->begin());
5521 const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5522 for(mcIdType i=0;i<nbOfCells;i++)
5524 mcIdType offset=connI[i]+1;
5525 mcIdType nbOfNodesForCell(connI[i+1]-offset),kk(0);
5526 for(mcIdType j=0;j<nbOfNodesForCell;j++)
5528 mcIdType nodeId=conn[offset+j];
5529 if(nodeId>=0 && nodeId<nbOfNodes)
5531 for(int k=0;k<spaceDim;k++)
5533 bbox[2*spaceDim*i+2*k]=std::min(bbox[2*spaceDim*i+2*k],coordsPtr[spaceDim*nodeId+k]);
5534 bbox[2*spaceDim*i+2*k+1]=std::max(bbox[2*spaceDim*i+2*k+1],coordsPtr[spaceDim*nodeId+k]);
5541 std::ostringstream oss; oss << "MEDCouplingUMesh::getBoundingBoxForBBTree : cell #" << i << " contains no valid nodeId !";
5542 throw INTERP_KERNEL::Exception(oss.str());
5549 * This method aggregates the bbox of each 2D cell in \a this considering the whole shape. This method is particularly
5550 * useful for 2D meshes having quadratic cells
5551 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5552 * the two extremities of the arc of circle).
5554 * \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)
5555 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5556 * \throw If \a this is not fully defined.
5557 * \throw If \a this is not a mesh with meshDimension equal to 2.
5558 * \throw If \a this is not a mesh with spaceDimension equal to 2.
5559 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic
5561 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic(double arcDetEps) const
5563 checkFullyDefined();
5564 INTERP_KERNEL::QuadraticPlanarPrecision arcPrec(arcDetEps);
5566 int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
5567 mcIdType nbOfCells=getNumberOfCells();
5568 if(spaceDim!=2 || mDim!=2)
5569 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!");
5570 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5571 double *bbox(ret->getPointer());
5572 const double *coords(_coords->begin());
5573 const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5574 for(mcIdType i=0;i<nbOfCells;i++,bbox+=4,connI++)
5576 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5577 mcIdType sz(connI[1]-connI[0]-1);
5578 std::vector<INTERP_KERNEL::Node *> nodes(sz);
5579 INTERP_KERNEL::QuadraticPolygon *pol(0);
5580 for(mcIdType j=0;j<sz;j++)
5582 mcIdType nodeId(conn[*connI+1+j]);
5583 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5585 if(!cm.isQuadratic())
5586 pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
5588 pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
5589 INTERP_KERNEL::Bounds b; b.prepareForAggregation(); pol->fillBounds(b); delete pol;
5590 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax();
5596 * This method aggregates the bbox of each 1D cell in \a this considering the whole shape. This method is particularly
5597 * useful for 2D meshes having quadratic cells
5598 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5599 * the two extremities of the arc of circle).
5601 * \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)
5602 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5603 * \throw If \a this is not fully defined.
5604 * \throw If \a this is not a mesh with meshDimension equal to 1.
5605 * \throw If \a this is not a mesh with spaceDimension equal to 2.
5606 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5608 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic(double arcDetEps) const
5610 checkFullyDefined();
5611 int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
5612 mcIdType nbOfCells=getNumberOfCells();
5613 if(spaceDim!=2 || mDim!=1)
5614 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!");
5615 INTERP_KERNEL::QuadraticPlanarPrecision arcPrec(arcDetEps);
5616 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5617 double *bbox(ret->getPointer());
5618 const double *coords(_coords->begin());
5619 const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5620 for(mcIdType i=0;i<nbOfCells;i++,bbox+=4,connI++)
5622 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5623 mcIdType sz(connI[1]-connI[0]-1);
5624 std::vector<INTERP_KERNEL::Node *> nodes(sz);
5625 INTERP_KERNEL::Edge *edge(0);
5626 for(mcIdType j=0;j<sz;j++)
5628 mcIdType nodeId(conn[*connI+1+j]);
5629 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5631 if(!cm.isQuadratic())
5632 edge=INTERP_KERNEL::QuadraticPolygon::BuildLinearEdge(nodes);
5634 edge=INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(nodes);
5635 const INTERP_KERNEL::Bounds& b(edge->getBounds());
5636 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax(); edge->decrRef();
5643 namespace MEDCouplingImpl
5648 ConnReader(const mcIdType *c, mcIdType val):_conn(c),_val(val) { }
5649 bool operator() (const mcIdType& pos) { return _conn[pos]!=_val; }
5651 const mcIdType *_conn;
5658 ConnReader2(const mcIdType *c, mcIdType val):_conn(c),_val(val) { }
5659 bool operator() (const mcIdType& pos) { return _conn[pos]==_val; }
5661 const mcIdType *_conn;
5669 * This method expects that \a this is sorted by types. If not an exception will be thrown.
5670 * This method returns in the same format as code (see MEDCouplingUMesh::checkTypeConsistencyAndContig or MEDCouplingUMesh::splitProfilePerType) how
5671 * \a this is composed in cell types.
5672 * The returned array is of size 3*n where n is the number of different types present in \a this.
5673 * For every k in [0,n] ret[3*k+2]==-1 because it has no sense here.
5674 * This parameter is kept only for compatibility with other method listed above.
5676 std::vector<mcIdType> MEDCouplingUMesh::getDistributionOfTypes() const
5678 checkConnectivityFullyDefined();
5679 const mcIdType *conn=_nodal_connec->begin();
5680 const mcIdType *connI=_nodal_connec_index->begin();
5681 const mcIdType *work=connI;
5682 mcIdType nbOfCells=getNumberOfCells();
5683 std::size_t n=getAllGeoTypes().size();
5684 std::vector<mcIdType> ret(3*n,-1); //ret[3*k+2]==-1 because it has no sense here
5685 std::set<INTERP_KERNEL::NormalizedCellType> types;
5686 for(std::size_t i=0;work!=connI+nbOfCells;i++)
5688 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn[*work];
5689 if(types.find(typ)!=types.end())
5691 std::ostringstream oss; oss << "MEDCouplingUMesh::getDistributionOfTypes : Type " << INTERP_KERNEL::CellModel::GetCellModel(typ).getRepr();
5692 oss << " is not contiguous !";
5693 throw INTERP_KERNEL::Exception(oss.str());
5697 const mcIdType *work2=std::find_if(work+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,typ));
5698 ret[3*i+1]=ToIdType(std::distance(work,work2));
5705 * This method is used to check that this has contiguous cell type in same order than described in \a code.
5706 * only for types cell, type node is not managed.
5707 * Format of \a code is the following. \a code should be of size 3*n and non empty. If not an exception is thrown.
5708 * foreach k in [0,n) on 3*k pos represent the geometric type and 3*k+1 number of elements of type 3*k.
5709 * 3*k+2 refers if different from -1 the pos in 'idsPerType' to get the corresponding array.
5710 * If 2 or more same geometric type is in \a code and exception is thrown too.
5712 * This method firstly checks
5713 * If it exists k so that 3*k geometric type is not in geometric types of this an exception will be thrown.
5714 * If it exists k so that 3*k geometric type exists but the number of consecutive cell types does not match,
5715 * an exception is thrown too.
5717 * If all geometric types in \a code are exactly those in \a this null pointer is returned.
5718 * If it exists a geometric type in \a this \b not in \a code \b no exception is thrown
5719 * and a DataArrayIdType instance is returned that the user has the responsibility to deallocate.
5721 DataArrayIdType *MEDCouplingUMesh::checkTypeConsistencyAndContig(const std::vector<mcIdType>& code, const std::vector<const DataArrayIdType *>& idsPerType) const
5724 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code is empty, should not !");
5725 std::size_t sz=code.size();
5728 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code size is NOT %3 !");
5729 std::vector<INTERP_KERNEL::NormalizedCellType> types;
5731 bool isNoPflUsed=true;
5732 for(std::size_t i=0;i<n;i++)
5733 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)code[3*i])==types.end())
5735 types.push_back((INTERP_KERNEL::NormalizedCellType)code[3*i]);
5737 if(_types.find((INTERP_KERNEL::NormalizedCellType)code[3*i])==_types.end())
5738 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : expected geo types not in this !");
5739 isNoPflUsed=isNoPflUsed && (code[3*i+2]==-1);
5742 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code contains duplication of types in unstructured mesh !");
5745 if(!checkConsecutiveCellTypesAndOrder(&types[0],&types[0]+types.size()))
5746 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : non contiguous type !");
5747 if(types.size()==_types.size())
5750 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
5752 mcIdType *retPtr=ret->getPointer();
5753 const mcIdType *connI=_nodal_connec_index->begin();
5754 const mcIdType *conn=_nodal_connec->begin();
5755 mcIdType nbOfCells=getNumberOfCells();
5756 const mcIdType *i=connI;
5758 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++,kk++)
5760 i=std::find_if(i,connI+nbOfCells,MEDCouplingImpl::ConnReader2(conn,ToIdType((*it))));
5761 mcIdType offset=ToIdType(std::distance(connI,i));
5762 const mcIdType *j=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType((*it))));
5763 mcIdType nbOfCellsOfCurType=ToIdType(std::distance(i,j));
5764 if(code[3*kk+2]==-1)
5765 for(mcIdType k=0;k<nbOfCellsOfCurType;k++)
5769 mcIdType idInIdsPerType=code[3*kk+2];
5770 if(idInIdsPerType>=0 && idInIdsPerType<ToIdType(idsPerType.size()))
5772 const DataArrayIdType *zePfl=idsPerType[idInIdsPerType];
5775 zePfl->checkAllocated();
5776 if(zePfl->getNumberOfComponents()==1)
5778 for(const mcIdType *k=zePfl->begin();k!=zePfl->end();k++,retPtr++)
5780 if(*k>=0 && *k<nbOfCellsOfCurType)
5781 *retPtr=(*k)+offset;
5784 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : the section " << kk << " points to the profile #" << idInIdsPerType;
5785 oss << ", and this profile contains a value " << *k << " should be in [0," << nbOfCellsOfCurType << ") !";
5786 throw INTERP_KERNEL::Exception(oss.str());
5791 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of a profile with nb of compo != 1 !");
5794 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of null profile !");
5798 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : at section " << kk << " of code it points to the array #" << idInIdsPerType;
5799 oss << " should be in [0," << idsPerType.size() << ") !";
5800 throw INTERP_KERNEL::Exception(oss.str());
5809 * This method makes the hypothesis that \a this is sorted by type. If not an exception will be thrown.
5810 * 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.
5811 * 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.
5812 * This method has 1 input \a profile and 3 outputs \a code \a idsInPflPerType and \a idsPerType.
5814 * \param [in] profile
5815 * \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.
5816 * \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,
5817 * \a idsInPflPerType[i] stores the tuple ids in \a profile that correspond to the geometric type code[3*i+0]
5818 * \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.
5819 * This vector can be empty in case of all geometric type cells are fully covered in ascending in the given input \a profile.
5820 * \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
5822 void MEDCouplingUMesh::splitProfilePerType(const DataArrayIdType *profile, std::vector<mcIdType>& code, std::vector<DataArrayIdType *>& idsInPflPerType, std::vector<DataArrayIdType *>& idsPerType, bool smartPflKiller) const
5825 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile is NULL !");
5826 if(profile->getNumberOfComponents()!=1)
5827 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile should have exactly one component !");
5828 checkConnectivityFullyDefined();
5829 const mcIdType *conn=_nodal_connec->begin();
5830 const mcIdType *connI=_nodal_connec_index->begin();
5831 mcIdType nbOfCells=getNumberOfCells();
5832 std::vector<INTERP_KERNEL::NormalizedCellType> types;
5833 std::vector<mcIdType> typeRangeVals(1);
5834 for(const mcIdType *i=connI;i!=connI+nbOfCells;)
5836 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5837 if(std::find(types.begin(),types.end(),curType)!=types.end())
5839 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : current mesh is not sorted by type !");
5841 types.push_back(curType);
5842 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
5843 typeRangeVals.push_back(ToIdType(std::distance(connI,i)));
5846 DataArrayIdType *castArr=0,*rankInsideCast=0,*castsPresent=0;
5847 profile->splitByValueRange(&typeRangeVals[0],&typeRangeVals[0]+typeRangeVals.size(),castArr,rankInsideCast,castsPresent);
5848 MCAuto<DataArrayIdType> tmp0=castArr;
5849 MCAuto<DataArrayIdType> tmp1=rankInsideCast;
5850 MCAuto<DataArrayIdType> tmp2=castsPresent;
5852 mcIdType nbOfCastsFinal=castsPresent->getNumberOfTuples();
5853 code.resize(3*nbOfCastsFinal);
5854 std::vector< MCAuto<DataArrayIdType> > idsInPflPerType2;
5855 std::vector< MCAuto<DataArrayIdType> > idsPerType2;
5856 for(mcIdType i=0;i<nbOfCastsFinal;i++)
5858 mcIdType castId=castsPresent->getIJ(i,0);
5859 MCAuto<DataArrayIdType> tmp3=castArr->findIdsEqual(castId);
5860 idsInPflPerType2.push_back(tmp3);
5861 code[3*i]=ToIdType(types[castId]);
5862 code[3*i+1]=tmp3->getNumberOfTuples();
5863 MCAuto<DataArrayIdType> tmp4=rankInsideCast->selectByTupleId(tmp3->begin(),tmp3->begin()+tmp3->getNumberOfTuples());
5864 if(!smartPflKiller || !tmp4->isIota(typeRangeVals[castId+1]-typeRangeVals[castId]))
5866 tmp4->copyStringInfoFrom(*profile);
5867 idsPerType2.push_back(tmp4);
5868 code[3*i+2]=ToIdType(idsPerType2.size())-1;
5875 std::size_t sz2=idsInPflPerType2.size();
5876 idsInPflPerType.resize(sz2);
5877 for(std::size_t i=0;i<sz2;i++)
5879 DataArrayIdType *locDa=idsInPflPerType2[i];
5881 idsInPflPerType[i]=locDa;
5883 std::size_t sz=idsPerType2.size();
5884 idsPerType.resize(sz);
5885 for(std::size_t i=0;i<sz;i++)
5887 DataArrayIdType *locDa=idsPerType2[i];
5889 idsPerType[i]=locDa;
5894 * This method is here too emulate the MEDMEM behaviour on BDC (buildDescendingConnectivity). Hoping this method becomes deprecated very soon.
5895 * This method make the assumption that \a this and 'nM1LevMesh' mesh lyies on same coords (same pointer) as MED and MEDMEM does.
5896 * The following equality should be verified 'nM1LevMesh->getMeshDimension()==this->getMeshDimension()-1'
5897 * 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.
5899 MEDCouplingUMesh *MEDCouplingUMesh::emulateMEDMEMBDC(const MEDCouplingUMesh *nM1LevMesh, DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *&revDesc, DataArrayIdType *&revDescIndx, DataArrayIdType *& nM1LevMeshIds, DataArrayIdType *&meshnM1Old2New) const
5901 checkFullyDefined();
5902 nM1LevMesh->checkFullyDefined();
5903 if(getMeshDimension()-1!=nM1LevMesh->getMeshDimension())
5904 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : The mesh passed as first argument should have a meshDim equal to this->getMeshDimension()-1 !" );
5905 if(_coords!=nM1LevMesh->getCoords())
5906 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : 'this' and mesh in first argument should share the same coords : Use tryToShareSameCoords method !");
5907 MCAuto<DataArrayIdType> tmp0=DataArrayIdType::New();
5908 MCAuto<DataArrayIdType> tmp1=DataArrayIdType::New();
5909 MCAuto<MEDCouplingUMesh> ret1=buildDescendingConnectivity(desc,descIndx,tmp0,tmp1);
5910 MCAuto<DataArrayIdType> ret0=ret1->sortCellsInMEDFileFrmt();
5911 desc->transformWithIndArr(ret0->begin(),ret0->begin()+ret0->getNbOfElems());
5912 MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
5913 tmp->setConnectivity(tmp0,tmp1);
5914 tmp->renumberCells(ret0->begin(),false);
5915 revDesc=tmp->getNodalConnectivity();
5916 revDescIndx=tmp->getNodalConnectivityIndex();
5917 DataArrayIdType *ret=0;
5918 if(!ret1->areCellsIncludedIn(nM1LevMesh,2,ret))
5921 ret->getMaxValue(tmp2);
5923 std::ostringstream oss; oss << "MEDCouplingUMesh::emulateMEDMEMBDC : input N-1 mesh present a cell not in descending mesh ... Id of cell is " << tmp2 << " !";
5924 throw INTERP_KERNEL::Exception(oss.str());
5929 revDescIndx->incrRef();
5932 meshnM1Old2New=ret0;
5937 * Permutes the nodal connectivity arrays so that the cells are sorted by type, which is
5938 * necessary for writing the mesh to MED file. Additionally returns a permutation array
5939 * in "Old to New" mode.
5940 * \return DataArrayIdType * - a new instance of DataArrayIdType. The caller is to delete
5941 * this array using decrRef() as it is no more needed.
5942 * \throw If the nodal connectivity of cells is not defined.
5944 DataArrayIdType *MEDCouplingUMesh::sortCellsInMEDFileFrmt()
5946 checkConnectivityFullyDefined();
5947 MCAuto<DataArrayIdType> ret=getRenumArrForMEDFileFrmt();
5948 renumberCells(ret->begin(),false);
5953 * This methods checks that cells are sorted by their types.
5954 * This method makes asumption (no check) that connectivity is correctly set before calling.
5956 bool MEDCouplingUMesh::checkConsecutiveCellTypes() const
5958 checkFullyDefined();
5959 const mcIdType *conn=_nodal_connec->begin();
5960 const mcIdType *connI=_nodal_connec_index->begin();
5961 mcIdType nbOfCells=getNumberOfCells();
5962 std::set<INTERP_KERNEL::NormalizedCellType> types;
5963 for(const mcIdType *i=connI;i!=connI+nbOfCells;)
5965 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5966 if(types.find(curType)!=types.end())
5968 types.insert(curType);
5969 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
5975 * This method is a specialization of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method that is called here.
5976 * The geometric type order is specified by MED file.
5978 * \sa MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder
5980 bool MEDCouplingUMesh::checkConsecutiveCellTypesForMEDFileFrmt() const
5982 return checkConsecutiveCellTypesAndOrder(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
5986 * This method performs the same job as checkConsecutiveCellTypes except that the order of types sequence is analyzed to check
5987 * that the order is specified in array defined by [ \a orderBg , \a orderEnd ).
5988 * If there is some geo types in \a this \b NOT in [ \a orderBg, \a orderEnd ) it is OK (return true) if contiguous.
5989 * If there is some geo types in [ \a orderBg, \a orderEnd ) \b NOT in \a this it is OK too (return true) if contiguous.
5991 bool MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
5993 checkFullyDefined();
5994 const mcIdType *conn=_nodal_connec->begin();
5995 const mcIdType *connI=_nodal_connec_index->begin();
5996 mcIdType nbOfCells=getNumberOfCells();
5999 mcIdType lastPos=-1;
6000 std::set<INTERP_KERNEL::NormalizedCellType> sg;
6001 for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6003 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6004 const INTERP_KERNEL::NormalizedCellType *isTypeExists=std::find(orderBg,orderEnd,curType);
6005 if(isTypeExists!=orderEnd)
6007 mcIdType pos=ToIdType(std::distance(orderBg,isTypeExists));
6011 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6015 if(sg.find(curType)==sg.end())
6017 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6028 * This method returns 2 newly allocated DataArrayIdType instances. The first is an array of size 'this->getNumberOfCells()' with one component,
6029 * 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
6030 * 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'.
6032 DataArrayIdType *MEDCouplingUMesh::getLevArrPerCellTypes(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd, DataArrayIdType *&nbPerType) const
6034 checkConnectivityFullyDefined();
6035 mcIdType nbOfCells=getNumberOfCells();
6036 const mcIdType *conn=_nodal_connec->begin();
6037 const mcIdType *connI=_nodal_connec_index->begin();
6038 MCAuto<DataArrayIdType> tmpa=DataArrayIdType::New();
6039 MCAuto<DataArrayIdType> tmpb=DataArrayIdType::New();
6040 tmpa->alloc(nbOfCells,1);
6041 tmpb->alloc(std::distance(orderBg,orderEnd),1);
6042 tmpb->fillWithZero();
6043 mcIdType *tmp=tmpa->getPointer();
6044 mcIdType *tmp2=tmpb->getPointer();
6045 for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6047 const INTERP_KERNEL::NormalizedCellType *where=std::find(orderBg,orderEnd,(INTERP_KERNEL::NormalizedCellType)conn[*i]);
6050 mcIdType pos=ToIdType(std::distance(orderBg,where));
6052 tmp[std::distance(connI,i)]=pos;
6056 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*i]);
6057 std::ostringstream oss; oss << "MEDCouplingUMesh::getLevArrPerCellTypes : Cell #" << std::distance(connI,i);
6058 oss << " has a type " << cm.getRepr() << " not in input array of type !";
6059 throw INTERP_KERNEL::Exception(oss.str());
6062 nbPerType=tmpb.retn();
6067 * This method behaves exactly as MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec but the order is those defined in MED file spec.
6069 * \return a new object containing the old to new correspondence.
6071 * \sa MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec, MEDCouplingUMesh::sortCellsInMEDFileFrmt.
6073 DataArrayIdType *MEDCouplingUMesh::getRenumArrForMEDFileFrmt() const
6075 return getRenumArrForConsecutiveCellTypesSpec(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
6079 * 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.
6080 * This method returns an array of size getNumberOfCells() that gives a renumber array old2New that can be used as input of MEDCouplingMesh::renumberCells.
6081 * The mesh after this call to MEDCouplingMesh::renumberCells will pass the test of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder with the same inputs.
6082 * The returned array minimizes the permutations that is to say the order of cells inside same geometric type remains the same.
6084 DataArrayIdType *MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
6086 DataArrayIdType *nbPerType=0;
6087 MCAuto<DataArrayIdType> tmpa=getLevArrPerCellTypes(orderBg,orderEnd,nbPerType);
6088 nbPerType->decrRef();
6089 return tmpa->buildPermArrPerLevel();
6093 * This method reorganize the cells of \a this so that the cells with same geometric types are put together.
6094 * The number of cells remains unchanged after the call of this method.
6095 * This method tries to minimizes the number of needed permutations. So, this method behaves not exactly as
6096 * MEDCouplingUMesh::sortCellsInMEDFileFrmt.
6098 * \return the array giving the correspondence old to new.
6100 DataArrayIdType *MEDCouplingUMesh::rearrange2ConsecutiveCellTypes()
6102 checkFullyDefined();
6104 const mcIdType *conn=_nodal_connec->begin();
6105 const mcIdType *connI=_nodal_connec_index->begin();
6106 mcIdType nbOfCells=getNumberOfCells();
6107 std::vector<INTERP_KERNEL::NormalizedCellType> types;
6108 for(const mcIdType *i=connI;i!=connI+nbOfCells && (types.size()!=_types.size());)
6109 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)conn[*i])==types.end())
6111 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6112 types.push_back(curType);
6113 for(i++;i!=connI+nbOfCells && (INTERP_KERNEL::NormalizedCellType)conn[*i]==curType;i++);
6115 DataArrayIdType *ret=DataArrayIdType::New();
6116 ret->alloc(nbOfCells,1);
6117 mcIdType *retPtr=ret->getPointer();
6118 std::fill(retPtr,retPtr+nbOfCells,-1);
6119 mcIdType newCellId=0;
6120 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
6122 for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6123 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
6124 retPtr[std::distance(connI,i)]=newCellId++;
6126 renumberCells(retPtr,false);
6131 * This method splits \a this into as mush as untructured meshes that consecutive set of same type cells.
6132 * So this method has typically a sense if MEDCouplingUMesh::checkConsecutiveCellTypes has a sense.
6133 * This method makes asumption that connectivity is correctly set before calling.
6135 std::vector<MEDCouplingUMesh *> MEDCouplingUMesh::splitByType() const
6137 checkConnectivityFullyDefined();
6138 const mcIdType *conn=_nodal_connec->begin();
6139 const mcIdType *connI=_nodal_connec_index->begin();
6140 mcIdType nbOfCells=getNumberOfCells();
6141 std::vector<MEDCouplingUMesh *> ret;
6142 for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6144 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6145 mcIdType beginCellId=ToIdType(std::distance(connI,i));
6146 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6147 mcIdType endCellId=ToIdType(std::distance(connI,i));
6148 mcIdType sz=endCellId-beginCellId;
6149 mcIdType *cells=new mcIdType[sz];
6150 for(mcIdType j=0;j<sz;j++)
6151 cells[j]=beginCellId+j;
6152 MEDCouplingUMesh *m=(MEDCouplingUMesh *)buildPartOfMySelf(cells,cells+sz,true);
6160 * This method performs the opposite operation than those in MEDCoupling1SGTUMesh::buildUnstructured.
6161 * If \a this is a single geometric type unstructured mesh, it will be converted into a more compact data structure,
6162 * MEDCoupling1GTUMesh instance. The returned instance will aggregate the same DataArrayDouble instance of coordinates than \a this.
6164 * \return a newly allocated instance, that the caller must manage.
6165 * \throw If \a this contains more than one geometric type.
6166 * \throw If the nodal connectivity of \a this is not fully defined.
6167 * \throw If the internal data is not coherent.
6169 MEDCoupling1GTUMesh *MEDCouplingUMesh::convertIntoSingleGeoTypeMesh() const
6171 checkConnectivityFullyDefined();
6172 if(_types.size()!=1)
6173 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6174 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6175 MCAuto<MEDCoupling1GTUMesh> ret=MEDCoupling1GTUMesh::New(getName(),typ);
6176 ret->setCoords(getCoords());
6177 MEDCoupling1SGTUMesh *retC=dynamic_cast<MEDCoupling1SGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6180 MCAuto<DataArrayIdType> c=convertNodalConnectivityToStaticGeoTypeMesh();
6181 retC->setNodalConnectivity(c);
6185 MEDCoupling1DGTUMesh *retD=dynamic_cast<MEDCoupling1DGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6187 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : Internal error !");
6188 DataArrayIdType *c=0,*ci=0;
6189 convertNodalConnectivityToDynamicGeoTypeMesh(c,ci);
6190 MCAuto<DataArrayIdType> cs(c),cis(ci);
6191 retD->setNodalConnectivity(cs,cis);
6196 DataArrayIdType *MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh() const
6198 checkConnectivityFullyDefined();
6199 if(_types.size()!=1)
6200 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6201 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6202 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6205 std::ostringstream oss; oss << "MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : this contains a single geo type (" << cm.getRepr() << ") but ";
6206 oss << "this type is dynamic ! Only static geometric type is possible for that type ! call convertNodalConnectivityToDynamicGeoTypeMesh instead !";
6207 throw INTERP_KERNEL::Exception(oss.str());
6209 mcIdType nbCells=getNumberOfCells();
6210 mcIdType typi=ToIdType(typ);
6211 mcIdType nbNodesPerCell=ToIdType(cm.getNumberOfNodes());
6212 MCAuto<DataArrayIdType> connOut=DataArrayIdType::New(); connOut->alloc(nbCells*nbNodesPerCell,1);
6213 mcIdType *outPtr=connOut->getPointer();
6214 const mcIdType *conn=_nodal_connec->begin();
6215 const mcIdType *connI=_nodal_connec_index->begin();
6217 for(mcIdType i=0;i<nbCells;i++,connI++)
6219 if(conn[connI[0]]==typi && connI[1]-connI[0]==nbNodesPerCell)
6220 outPtr=std::copy(conn+connI[0]+1,conn+connI[1],outPtr);
6223 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 << ") !";
6224 throw INTERP_KERNEL::Exception(oss.str());
6227 return connOut.retn();
6231 * Convert the nodal connectivity of the mesh so that all the cells are of dynamic types (polygon or quadratic
6232 * polygon). This returns the corresponding new nodal connectivity in \ref numbering-indirect format.
6236 void MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh(DataArrayIdType *&nodalConn, DataArrayIdType *&nodalConnIndex) const
6238 static const char msg0[]="MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : nodal connectivity in this are invalid ! Call checkConsistency !";
6239 checkConnectivityFullyDefined();
6240 if(_types.size()!=1)
6241 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6242 mcIdType nbCells=getNumberOfCells(),
6243 lgth=_nodal_connec->getNumberOfTuples();
6245 throw INTERP_KERNEL::Exception(msg0);
6246 MCAuto<DataArrayIdType> c(DataArrayIdType::New()),ci(DataArrayIdType::New());
6247 c->alloc(lgth-nbCells,1); ci->alloc(nbCells+1,1);
6248 mcIdType *cp(c->getPointer()),*cip(ci->getPointer());
6249 const mcIdType *incp(_nodal_connec->begin()),*incip(_nodal_connec_index->begin());
6251 for(mcIdType i=0;i<nbCells;i++,cip++,incip++)
6253 mcIdType strt(incip[0]+1),stop(incip[1]);//+1 to skip geo type
6254 mcIdType delta(stop-strt);
6257 if((strt>=0 && strt<lgth) && (stop>=0 && stop<=lgth))
6258 cp=std::copy(incp+strt,incp+stop,cp);
6260 throw INTERP_KERNEL::Exception(msg0);
6263 throw INTERP_KERNEL::Exception(msg0);
6264 cip[1]=cip[0]+delta;
6266 nodalConn=c.retn(); nodalConnIndex=ci.retn();
6270 * This method takes in input a vector of MEDCouplingUMesh instances lying on the same coordinates with same mesh dimensions.
6271 * Each mesh in \b ms must be sorted by type with the same order (typically using MEDCouplingUMesh::sortCellsInMEDFileFrmt).
6272 * This method is particularly useful for MED file interaction. It allows to aggregate several meshes and keeping the type sorting
6273 * and the track of the permutation by chunk of same geotype cells to retrieve it. The traditional formats old2new and new2old
6274 * are not used here to avoid the build of big permutation array.
6276 * \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
6277 * those specified in MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6278 * \param [out] szOfCellGrpOfSameType is a newly allocated DataArrayIdType instance whose number of tuples is equal to the number of chunks of same geotype
6279 * in all meshes in \b ms. The accumulation of all values of this array is equal to the number of cells of returned mesh.
6280 * \param [out] idInMsOfCellGrpOfSameType is a newly allocated DataArrayIdType instance having the same size than \b szOfCellGrpOfSameType. This
6281 * output array gives for each chunck of same type the corresponding mesh id in \b ms.
6282 * \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
6283 * is sorted by type following the geo cell types order of MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6285 MEDCouplingUMesh *MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& ms,
6286 DataArrayIdType *&szOfCellGrpOfSameType,
6287 DataArrayIdType *&idInMsOfCellGrpOfSameType)
6289 std::vector<const MEDCouplingUMesh *> ms2;
6290 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms.begin();it!=ms.end();it++)
6293 (*it)->checkConnectivityFullyDefined();
6297 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : input vector is empty !");
6298 const DataArrayDouble *refCoo=ms2[0]->getCoords();
6299 int meshDim=ms2[0]->getMeshDimension();
6300 std::vector<const MEDCouplingUMesh *> m1ssm;
6301 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmAuto;
6303 std::vector<const MEDCouplingUMesh *> m1ssmSingle;
6304 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmSingleAuto;
6305 mcIdType fake=0,rk=0;
6306 MCAuto<DataArrayIdType> ret1(DataArrayIdType::New()),ret2(DataArrayIdType::New());
6307 ret1->alloc(0,1); ret2->alloc(0,1);
6308 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms2.begin();it!=ms2.end();it++,rk++)
6310 if(meshDim!=(*it)->getMeshDimension())
6311 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshdims mismatch !");
6312 if(refCoo!=(*it)->getCoords())
6313 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshes are not shared by a single coordinates coords !");
6314 std::vector<MEDCouplingUMesh *> sp=(*it)->splitByType();
6315 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<const MEDCouplingUMesh *> >(m1ssm));
6316 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<MCAuto<MEDCouplingUMesh> > >(m1ssmAuto));
6317 for(std::vector<MEDCouplingUMesh *>::const_iterator it2=sp.begin();it2!=sp.end();it2++)
6319 MEDCouplingUMesh *singleCell=static_cast<MEDCouplingUMesh *>((*it2)->buildPartOfMySelf(&fake,&fake+1,true));
6320 m1ssmSingleAuto.push_back(singleCell);
6321 m1ssmSingle.push_back(singleCell);
6322 ret1->pushBackSilent((*it2)->getNumberOfCells()); ret2->pushBackSilent(rk);
6325 MCAuto<MEDCouplingUMesh> m1ssmSingle2=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmSingle);
6326 MCAuto<DataArrayIdType> renum=m1ssmSingle2->sortCellsInMEDFileFrmt();
6327 std::vector<const MEDCouplingUMesh *> m1ssmfinal(m1ssm.size());
6328 for(mcIdType i=0;i<ToIdType(m1ssm.size());i++)
6329 m1ssmfinal[renum->getIJ(i,0)]=m1ssm[i];
6330 MCAuto<MEDCouplingUMesh> ret0=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmfinal);
6331 szOfCellGrpOfSameType=ret1->renumber(renum->begin());
6332 idInMsOfCellGrpOfSameType=ret2->renumber(renum->begin());
6337 * This method returns a newly created DataArrayIdType instance.
6338 * This method retrieves cell ids in [ \a begin, \a end ) that have the type \a type.
6340 DataArrayIdType *MEDCouplingUMesh::keepCellIdsByType(INTERP_KERNEL::NormalizedCellType type, const mcIdType *begin, const mcIdType *end) const
6342 checkFullyDefined();
6343 const mcIdType *conn=_nodal_connec->begin();
6344 const mcIdType *connIndex=_nodal_connec_index->begin();
6345 MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(0,1);
6346 for(const mcIdType *w=begin;w!=end;w++)
6347 if((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]==type)
6348 ret->pushBackSilent(*w);
6353 * This method makes the assumption that da->getNumberOfTuples()<this->getNumberOfCells(). This method makes the assumption that ids contained in 'da'
6354 * are in [0:getNumberOfCells())
6356 DataArrayIdType *MEDCouplingUMesh::convertCellArrayPerGeoType(const DataArrayIdType *da) const
6358 checkFullyDefined();
6359 const mcIdType *conn=_nodal_connec->begin();
6360 const mcIdType *connI=_nodal_connec_index->begin();
6361 mcIdType nbOfCells=getNumberOfCells();
6362 std::set<INTERP_KERNEL::NormalizedCellType> types(getAllGeoTypes());
6363 mcIdType *tmp=new mcIdType[nbOfCells];
6364 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
6367 for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6368 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
6369 tmp[std::distance(connI,i)]=j++;
6371 DataArrayIdType *ret=DataArrayIdType::New();
6372 ret->alloc(da->getNumberOfTuples(),da->getNumberOfComponents());
6373 ret->copyStringInfoFrom(*da);
6374 mcIdType *retPtr=ret->getPointer();
6375 const mcIdType *daPtr=da->begin();
6376 mcIdType nbOfElems=da->getNbOfElems();
6377 for(mcIdType k=0;k<nbOfElems;k++)
6378 retPtr[k]=tmp[daPtr[k]];
6384 * This method reduced number of cells of this by keeping cells whose type is different from 'type' and if type=='type'
6385 * This method \b works \b for mesh sorted by type.
6386 * cells whose ids is in 'idsPerGeoType' array.
6387 * This method conserves coords and name of mesh.
6389 MEDCouplingUMesh *MEDCouplingUMesh::keepSpecifiedCells(INTERP_KERNEL::NormalizedCellType type, const mcIdType *idsPerGeoTypeBg, const mcIdType *idsPerGeoTypeEnd) const
6391 std::vector<mcIdType> code=getDistributionOfTypes();
6392 std::size_t nOfTypesInThis=code.size()/3;
6393 mcIdType sz=0,szOfType=0;
6394 for(std::size_t i=0;i<nOfTypesInThis;i++)
6399 szOfType=code[3*i+1];
6401 for(const mcIdType *work=idsPerGeoTypeBg;work!=idsPerGeoTypeEnd;work++)
6402 if(*work<0 || *work>=szOfType)
6404 std::ostringstream oss; oss << "MEDCouplingUMesh::keepSpecifiedCells : Request on type " << type << " at place #" << std::distance(idsPerGeoTypeBg,work) << " value " << *work;
6405 oss << ". It should be in [0," << szOfType << ") !";
6406 throw INTERP_KERNEL::Exception(oss.str());
6408 MCAuto<DataArrayIdType> idsTokeep=DataArrayIdType::New(); idsTokeep->alloc(sz+std::distance(idsPerGeoTypeBg,idsPerGeoTypeEnd),1);
6409 mcIdType *idsPtr=idsTokeep->getPointer();
6411 for(std::size_t i=0;i<nOfTypesInThis;i++)
6414 for(mcIdType j=0;j<code[3*i+1];j++)
6417 idsPtr=std::transform(idsPerGeoTypeBg,idsPerGeoTypeEnd,idsPtr,std::bind2nd(std::plus<mcIdType>(),offset));
6418 offset+=code[3*i+1];
6420 MCAuto<MEDCouplingUMesh> ret=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(idsTokeep->begin(),idsTokeep->end(),true));
6421 ret->copyTinyInfoFrom(this);
6426 * This method returns a vector of size 'this->getNumberOfCells()'.
6427 * This method retrieves for each cell in \a this if it is linear (false) or quadratic(true).
6429 std::vector<bool> MEDCouplingUMesh::getQuadraticStatus() const
6431 mcIdType ncell=getNumberOfCells();
6432 std::vector<bool> ret(ncell);
6433 const mcIdType *cI=getNodalConnectivityIndex()->begin();
6434 const mcIdType *c=getNodalConnectivity()->begin();
6435 for(mcIdType i=0;i<ncell;i++)
6437 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[i]];
6438 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6439 ret[i]=cm.isQuadratic();
6445 * Returns a newly created mesh (with ref count ==1) that contains merge of \a this and \a other.
6447 MEDCouplingMesh *MEDCouplingUMesh::mergeMyselfWith(const MEDCouplingMesh *other) const
6449 if(other->getType()!=UNSTRUCTURED)
6450 throw INTERP_KERNEL::Exception("Merge of umesh only available with umesh each other !");
6451 const MEDCouplingUMesh *otherC=static_cast<const MEDCouplingUMesh *>(other);
6452 return MergeUMeshes(this,otherC);
6456 * Returns a new DataArrayDouble holding barycenters of all cells. The barycenter is
6457 * computed by averaging coordinates of cell nodes, so this method is not a right
6458 * choice for degenerated meshes (not well oriented, cells with measure close to zero).
6459 * Beware also that for quadratic meshes, degenerated arc of circles are turned into linear edges for the computation.
6460 * This happens with a default detection precision of eps=1.0e-14. If you need control over this use computeCellCenterOfMassWithPrecision().
6461 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
6462 * this->getNumberOfCells() tuples per \a this->getSpaceDimension()
6463 * components. The caller is to delete this array using decrRef() as it is
6465 * \throw If the coordinates array is not set.
6466 * \throw If the nodal connectivity of cells is not defined.
6467 * \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
6468 * \sa MEDCouplingUMesh::computeCellCenterOfMassWithPrecision
6470 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMass() const
6472 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6473 int spaceDim=getSpaceDimension();
6474 mcIdType nbOfCells=getNumberOfCells();
6475 ret->alloc(nbOfCells,spaceDim);
6476 ret->copyStringInfoFrom(*getCoords());
6477 double *ptToFill=ret->getPointer();
6478 const mcIdType *nodal=_nodal_connec->begin();
6479 const mcIdType *nodalI=_nodal_connec_index->begin();
6480 const double *coor=_coords->begin();
6481 for(mcIdType i=0;i<nbOfCells;i++)
6483 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6484 INTERP_KERNEL::computeBarycenter2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[i]+1,nodalI[i+1]-nodalI[i]-1,coor,spaceDim,ptToFill);
6492 * See computeCellCenterOfMass().
6493 * \param eps a precision for the detection of degenerated arc of circles.
6494 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
6495 * this->getNumberOfCells() tuples per \a this->getSpaceDimension()
6496 * components. The caller is to delete this array using decrRef() as it is
6498 * \throw If the coordinates array is not set.
6499 * \throw If the nodal connectivity of cells is not defined.
6500 * \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
6501 * \sa MEDCouplingUMesh::computeCellCenterOfMassWithPrecision
6503 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMassWithPrecision(double eps) const
6505 INTERP_KERNEL::QuadraticPlanarPrecision prec(eps);
6506 MCAuto<DataArrayDouble> ret = computeCellCenterOfMass();
6512 * This method computes for each cell in \a this, the location of the iso barycenter of nodes constituting
6513 * the cell. Contrary to badly named MEDCouplingUMesh::computeCellCenterOfMass method that returns the center of inertia of the
6515 * \return a newly allocated DataArrayDouble instance that the caller has to deal with. The returned
6516 * DataArrayDouble instance will have \c this->getNumberOfCells() tuples and \c this->getSpaceDimension() components.
6518 * \sa MEDCouplingUMesh::computeCellCenterOfMass
6519 * \throw If \a this is not fully defined (coordinates and connectivity)
6520 * \throw If there is presence in nodal connectivity in \a this of node ids not in [0, \c this->getNumberOfNodes() )
6522 DataArrayDouble *MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell() const
6524 checkFullyDefined();
6525 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6526 int spaceDim=getSpaceDimension();
6527 mcIdType nbOfCells=getNumberOfCells();
6528 mcIdType nbOfNodes=getNumberOfNodes();
6529 ret->alloc(nbOfCells,spaceDim);
6530 double *ptToFill=ret->getPointer();
6531 const mcIdType *nodal=_nodal_connec->begin();
6532 const mcIdType *nodalI=_nodal_connec_index->begin();
6533 const double *coor=_coords->begin();
6534 for(mcIdType i=0;i<nbOfCells;i++,ptToFill+=spaceDim)
6536 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6537 std::fill(ptToFill,ptToFill+spaceDim,0.);
6538 if(type!=INTERP_KERNEL::NORM_POLYHED)
6540 for(const mcIdType *conn=nodal+nodalI[i]+1;conn!=nodal+nodalI[i+1];conn++)
6542 if(*conn>=0 && *conn<nbOfNodes)
6543 std::transform(coor+spaceDim*conn[0],coor+spaceDim*(conn[0]+1),ptToFill,ptToFill,std::plus<double>());
6546 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of nodeId #" << *conn << " should be in [0," << nbOfNodes << ") !";
6547 throw INTERP_KERNEL::Exception(oss.str());
6550 mcIdType nbOfNodesInCell=nodalI[i+1]-nodalI[i]-1;
6551 if(nbOfNodesInCell>0)
6552 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies<double>(),1./(double)nbOfNodesInCell));
6555 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of cell with no nodes !";
6556 throw INTERP_KERNEL::Exception(oss.str());
6561 std::set<mcIdType> s(nodal+nodalI[i]+1,nodal+nodalI[i+1]);
6563 for(std::set<mcIdType>::const_iterator it=s.begin();it!=s.end();it++)
6565 if(*it>=0 && *it<nbOfNodes)
6566 std::transform(coor+spaceDim*(*it),coor+spaceDim*((*it)+1),ptToFill,ptToFill,std::plus<double>());
6569 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell polyhedron cell #" << i << " presence of nodeId #" << *it << " should be in [0," << nbOfNodes << ") !";
6570 throw INTERP_KERNEL::Exception(oss.str());
6574 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies<double>(),1./(double)s.size()));
6577 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on polyhedron cell #" << i << " there are no nodes !";
6578 throw INTERP_KERNEL::Exception(oss.str());
6586 * Returns a new DataArrayDouble holding barycenters of specified cells. The
6587 * barycenter is computed by averaging coordinates of cell nodes. The cells to treat
6588 * are specified via an array of cell ids.
6589 * \warning Validity of the specified cell ids is not checked!
6590 * Valid range is [ 0, \a this->getNumberOfCells() ).
6591 * \param [in] begin - an array of cell ids of interest.
6592 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
6593 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size ( \a
6594 * end - \a begin ) tuples per \a this->getSpaceDimension() components. The
6595 * caller is to delete this array using decrRef() as it is no more needed.
6596 * \throw If the coordinates array is not set.
6597 * \throw If the nodal connectivity of cells is not defined.
6599 * \if ENABLE_EXAMPLES
6600 * \ref cpp_mcumesh_getPartBarycenterAndOwner "Here is a C++ example".<br>
6601 * \ref py_mcumesh_getPartBarycenterAndOwner "Here is a Python example".
6604 DataArrayDouble *MEDCouplingUMesh::getPartBarycenterAndOwner(const mcIdType *begin, const mcIdType *end) const
6606 DataArrayDouble *ret=DataArrayDouble::New();
6607 int spaceDim=getSpaceDimension();
6608 std::size_t nbOfTuple=std::distance(begin,end);
6609 ret->alloc(nbOfTuple,spaceDim);
6610 double *ptToFill=ret->getPointer();
6611 double *tmp=new double[spaceDim];
6612 const mcIdType *nodal=_nodal_connec->begin();
6613 const mcIdType *nodalI=_nodal_connec_index->begin();
6614 const double *coor=_coords->begin();
6615 for(const mcIdType *w=begin;w!=end;w++)
6617 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[*w]];
6618 INTERP_KERNEL::computeBarycenter2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[*w]+1,nodalI[*w+1]-nodalI[*w]-1,coor,spaceDim,ptToFill);
6626 * 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".
6627 * So the returned instance will have 4 components and \c this->getNumberOfCells() tuples.
6628 * So this method expects that \a this has a spaceDimension equal to 3 and meshDimension equal to 2.
6629 * The computation of the plane equation is done using each time the 3 first nodes of 2D cells.
6630 * This method is useful to detect 2D cells in 3D space that are not coplanar.
6632 * \return DataArrayDouble * - a new instance of DataArrayDouble having 4 components and a number of tuples equal to number of cells in \a this.
6633 * \throw If spaceDim!=3 or meshDim!=2.
6634 * \throw If connectivity of \a this is invalid.
6635 * \throw If connectivity of a cell in \a this points to an invalid node.
6637 DataArrayDouble *MEDCouplingUMesh::computePlaneEquationOf3DFaces() const
6639 MCAuto<DataArrayDouble> ret(DataArrayDouble::New());
6640 mcIdType nbOfCells=getNumberOfCells();
6641 mcIdType nbOfNodes(getNumberOfNodes());
6642 if(getSpaceDimension()!=3 || getMeshDimension()!=2)
6643 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computePlaneEquationOf3DFaces : This method must be applied on a mesh having meshDimension equal 2 and a spaceDimension equal to 3 !");
6644 ret->alloc(nbOfCells,4);
6645 double *retPtr(ret->getPointer());
6646 const mcIdType *nodal(_nodal_connec->begin()),*nodalI(_nodal_connec_index->begin());
6647 const double *coor(_coords->begin());
6648 for(mcIdType i=0;i<nbOfCells;i++,nodalI++,retPtr+=4)
6650 double matrix[16]={0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,0},matrix2[16];
6651 if(nodalI[1]-nodalI[0]>=4)
6653 double aa[3]={coor[nodal[nodalI[0]+1+1]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6654 coor[nodal[nodalI[0]+1+1]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6655 coor[nodal[nodalI[0]+1+1]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]}
6656 ,bb[3]={coor[nodal[nodalI[0]+1+2]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6657 coor[nodal[nodalI[0]+1+2]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6658 coor[nodal[nodalI[0]+1+2]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]};
6659 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]};
6660 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]));
6661 for(int j=0;j<3;j++)
6663 mcIdType nodeId(nodal[nodalI[0]+1+j]);
6664 if(nodeId>=0 && nodeId<nbOfNodes)
6665 std::copy(coor+nodeId*3,coor+(nodeId+1)*3,matrix+4*j);
6668 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! This cell points to an invalid nodeId : " << nodeId << " !";
6669 throw INTERP_KERNEL::Exception(oss.str());
6672 if(sqrt(cc[0]*cc[0]+cc[1]*cc[1]+cc[2]*cc[2])>(1e-3*aa_norm*bb_norm))
6674 INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6675 retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6679 if(nodalI[1]-nodalI[0]==4)
6681 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : cell" << i << " : Presence of The 3 colinear points !";
6682 throw INTERP_KERNEL::Exception(oss.str());
6685 double dd[3]={0.,0.,0.};
6686 for(mcIdType offset=nodalI[0]+1;offset<nodalI[1];offset++)
6687 std::transform(coor+3*nodal[offset],coor+3*(nodal[offset]+1),dd,dd,std::plus<double>());
6688 mcIdType nbOfNodesInCell(nodalI[1]-nodalI[0]-1);
6689 std::transform(dd,dd+3,dd,std::bind2nd(std::multiplies<double>(),1./(double)nbOfNodesInCell));
6690 std::copy(dd,dd+3,matrix+4*2);
6691 INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6692 retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6697 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! Must be constitued by more than 3 nodes !";
6698 throw INTERP_KERNEL::Exception(oss.str());
6705 * This method expects as input a DataArrayDouble non nul instance 'da' that should be allocated. If not an exception is thrown.
6708 MEDCouplingUMesh *MEDCouplingUMesh::Build0DMeshFromCoords(DataArrayDouble *da)
6711 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build0DMeshFromCoords : instance of DataArrayDouble must be not null !");
6712 da->checkAllocated();
6713 std::string name(da->getName());
6714 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New(name,0));
6716 ret->setName("Mesh");
6718 mcIdType nbOfTuples(da->getNumberOfTuples());
6719 MCAuto<DataArrayIdType> c(DataArrayIdType::New()),cI(DataArrayIdType::New());
6720 c->alloc(2*nbOfTuples,1);
6721 cI->alloc(nbOfTuples+1,1);
6722 mcIdType *cp(c->getPointer()),*cip(cI->getPointer());
6724 for(mcIdType i=0;i<nbOfTuples;i++)
6726 *cp++=INTERP_KERNEL::NORM_POINT1;
6730 ret->setConnectivity(c,cI,true);
6734 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::Build1DMeshFromCoords(DataArrayDouble *da)
6737 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build01MeshFromCoords : instance of DataArrayDouble must be not null !");
6738 da->checkAllocated();
6739 std::string name(da->getName());
6740 MCAuto<MEDCouplingUMesh> ret;
6742 MCAuto<MEDCouplingCMesh> tmp(MEDCouplingCMesh::New());
6743 MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
6744 arr->alloc(da->getNumberOfTuples());
6745 tmp->setCoordsAt(0,arr);
6746 ret=tmp->buildUnstructured();
6750 ret->setName("Mesh");
6757 * Creates a new MEDCouplingUMesh by concatenating two given meshes of the same dimension.
6758 * Cells and nodes of
6759 * the first mesh precede cells and nodes of the second mesh within the result mesh.
6760 * \param [in] mesh1 - the first mesh.
6761 * \param [in] mesh2 - the second mesh.
6762 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6763 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6764 * is no more needed.
6765 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
6766 * \throw If the coordinates array is not set in none of the meshes.
6767 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
6768 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
6770 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
6772 std::vector<const MEDCouplingUMesh *> tmp(2);
6773 tmp[0]=const_cast<MEDCouplingUMesh *>(mesh1); tmp[1]=const_cast<MEDCouplingUMesh *>(mesh2);
6774 return MergeUMeshes(tmp);
6778 * Creates a new MEDCouplingUMesh by concatenating all given meshes of the same dimension.
6779 * Cells and nodes of
6780 * the *i*-th mesh precede cells and nodes of the (*i*+1)-th mesh within the result mesh.
6781 * \param [in] a - a vector of meshes (MEDCouplingUMesh) to concatenate.
6782 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6783 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6784 * is no more needed.
6785 * \throw If \a a.size() == 0.
6786 * \throw If \a a[ *i* ] == NULL.
6787 * \throw If the coordinates array is not set in none of the meshes.
6788 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
6789 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
6791 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const std::vector<const MEDCouplingUMesh *>& a)
6793 std::size_t sz=a.size();
6795 return MergeUMeshesLL(a);
6796 for(std::size_t ii=0;ii<sz;ii++)
6799 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshes : item #" << ii << " in input array of size "<< sz << " is empty !";
6800 throw INTERP_KERNEL::Exception(oss.str());
6802 std::vector< MCAuto<MEDCouplingUMesh> > bb(sz);
6803 std::vector< const MEDCouplingUMesh * > aa(sz);
6805 for(std::size_t i=0;i<sz && spaceDim==-3;i++)
6807 const MEDCouplingUMesh *cur=a[i];
6808 const DataArrayDouble *coo=cur->getCoords();
6810 spaceDim=int(coo->getNumberOfComponents());
6813 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : no spaceDim specified ! unable to perform merge !");
6814 for(std::size_t i=0;i<sz;i++)
6816 bb[i]=a[i]->buildSetInstanceFromThis(spaceDim);
6819 return MergeUMeshesLL(aa);
6823 * Creates a new MEDCouplingUMesh by concatenating cells of two given meshes of same
6824 * dimension and sharing the node coordinates array.
6825 * All cells of the first mesh precede all cells of the second mesh
6826 * within the result mesh.
6827 * \param [in] mesh1 - the first mesh.
6828 * \param [in] mesh2 - the second mesh.
6829 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6830 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6831 * is no more needed.
6832 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
6833 * \throw If the meshes do not share the node coordinates array.
6834 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
6835 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
6837 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
6839 std::vector<const MEDCouplingUMesh *> tmp(2);
6840 tmp[0]=mesh1; tmp[1]=mesh2;
6841 return MergeUMeshesOnSameCoords(tmp);
6845 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
6846 * dimension and sharing the node coordinates array.
6847 * All cells of the *i*-th mesh precede all cells of the
6848 * (*i*+1)-th mesh within the result mesh.
6849 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
6850 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6851 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6852 * is no more needed.
6853 * \throw If \a a.size() == 0.
6854 * \throw If \a a[ *i* ] == NULL.
6855 * \throw If the meshes do not share the node coordinates array.
6856 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
6857 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
6859 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes)
6862 throw INTERP_KERNEL::Exception("meshes input parameter is expected to be non empty.");
6863 for(std::size_t ii=0;ii<meshes.size();ii++)
6866 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshesOnSameCoords : item #" << ii << " in input array of size "<< meshes.size() << " is empty !";
6867 throw INTERP_KERNEL::Exception(oss.str());
6869 const DataArrayDouble *coords=meshes.front()->getCoords();
6870 int meshDim=meshes.front()->getMeshDimension();
6871 std::vector<const MEDCouplingUMesh *>::const_iterator iter=meshes.begin();
6872 mcIdType meshLgth=0;
6873 mcIdType meshIndexLgth=0;
6874 for(;iter!=meshes.end();iter++)
6876 if(coords!=(*iter)->getCoords())
6877 throw INTERP_KERNEL::Exception("meshes does not share the same coords ! Try using tryToShareSameCoords method !");
6878 if(meshDim!=(*iter)->getMeshDimension())
6879 throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, FuseUMeshesOnSameCoords impossible !");
6880 meshLgth+=(*iter)->getNodalConnectivityArrayLen();
6881 meshIndexLgth+=(*iter)->getNumberOfCells();
6883 MCAuto<DataArrayIdType> nodal=DataArrayIdType::New();
6884 nodal->alloc(meshLgth,1);
6885 mcIdType *nodalPtr=nodal->getPointer();
6886 MCAuto<DataArrayIdType> nodalIndex=DataArrayIdType::New();
6887 nodalIndex->alloc(meshIndexLgth+1,1);
6888 mcIdType *nodalIndexPtr=nodalIndex->getPointer();
6890 for(iter=meshes.begin();iter!=meshes.end();iter++)
6892 const mcIdType *nod=(*iter)->getNodalConnectivity()->begin();
6893 const mcIdType *index=(*iter)->getNodalConnectivityIndex()->begin();
6894 mcIdType nbOfCells=(*iter)->getNumberOfCells();
6895 mcIdType meshLgth2=(*iter)->getNodalConnectivityArrayLen();
6896 nodalPtr=std::copy(nod,nod+meshLgth2,nodalPtr);
6897 if(iter!=meshes.begin())
6898 nodalIndexPtr=std::transform(index+1,index+nbOfCells+1,nodalIndexPtr,std::bind2nd(std::plus<mcIdType>(),offset));
6900 nodalIndexPtr=std::copy(index,index+nbOfCells+1,nodalIndexPtr);
6903 MEDCouplingUMesh *ret=MEDCouplingUMesh::New();
6904 ret->setName("merge");
6905 ret->setMeshDimension(meshDim);
6906 ret->setConnectivity(nodal,nodalIndex,true);
6907 ret->setCoords(coords);
6912 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
6913 * dimension and sharing the node coordinates array. Cells of the *i*-th mesh precede
6914 * cells of the (*i*+1)-th mesh within the result mesh. Duplicates of cells are
6915 * removed from \a this mesh and arrays mapping between new and old cell ids in "Old to
6916 * New" mode are returned for each input mesh.
6917 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
6918 * \param [in] compType - specifies a cell comparison technique. For meaning of its
6919 * valid values [0,1,2], see zipConnectivityTraducer().
6920 * \param [in,out] corr - an array of DataArrayIdType, of the same size as \a
6921 * meshes. The *i*-th array describes cell ids mapping for \a meshes[ *i* ]
6922 * mesh. The caller is to delete each of the arrays using decrRef() as it is
6924 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6925 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6926 * is no more needed.
6927 * \throw If \a meshes.size() == 0.
6928 * \throw If \a meshes[ *i* ] == NULL.
6929 * \throw If the meshes do not share the node coordinates array.
6930 * \throw If \a meshes[ *i* ]->getMeshDimension() < 0.
6931 * \throw If the \a meshes are of different dimension (getMeshDimension()).
6932 * \throw If the nodal connectivity of cells of any of \a meshes is not defined.
6933 * \throw If the nodal connectivity any of \a meshes includes an invalid id.
6935 MEDCouplingUMesh *MEDCouplingUMesh::FuseUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes, int compType, std::vector<DataArrayIdType *>& corr)
6937 //All checks are delegated to MergeUMeshesOnSameCoords
6938 MCAuto<MEDCouplingUMesh> ret=MergeUMeshesOnSameCoords(meshes);
6939 MCAuto<DataArrayIdType> o2n=ret->zipConnectivityTraducer(compType);
6940 corr.resize(meshes.size());
6941 std::size_t nbOfMeshes=meshes.size();
6943 const mcIdType *o2nPtr=o2n->begin();
6944 for(std::size_t i=0;i<nbOfMeshes;i++)
6946 DataArrayIdType *tmp=DataArrayIdType::New();
6947 mcIdType curNbOfCells=meshes[i]->getNumberOfCells();
6948 tmp->alloc(curNbOfCells,1);
6949 std::copy(o2nPtr+offset,o2nPtr+offset+curNbOfCells,tmp->getPointer());
6950 offset+=curNbOfCells;
6951 tmp->setName(meshes[i]->getName());
6958 * Makes all given meshes share the nodal connectivity array. The common connectivity
6959 * array is created by concatenating the connectivity arrays of all given meshes. All
6960 * the given meshes must be of the same space dimension but dimension of cells **can
6961 * differ**. This method is particularly useful in MEDLoader context to build a \ref
6962 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
6963 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
6964 * \param [in,out] meshes - a vector of meshes to update.
6965 * \throw If any of \a meshes is NULL.
6966 * \throw If the coordinates array is not set in any of \a meshes.
6967 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
6968 * \throw If \a meshes are of different space dimension.
6970 void MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords(const std::vector<MEDCouplingUMesh *>& meshes)
6972 std::size_t sz=meshes.size();
6975 std::vector< const DataArrayDouble * > coords(meshes.size());
6976 std::vector< const DataArrayDouble * >::iterator it2=coords.begin();
6977 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++,it2++)
6981 (*it)->checkConnectivityFullyDefined();
6982 const DataArrayDouble *coo=(*it)->getCoords();
6987 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
6988 oss << " has no coordinate array defined !";
6989 throw INTERP_KERNEL::Exception(oss.str());
6994 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
6995 oss << " is null !";
6996 throw INTERP_KERNEL::Exception(oss.str());
6999 MCAuto<DataArrayDouble> res=DataArrayDouble::Aggregate(coords);
7000 std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();
7001 mcIdType offset=(*it)->getNumberOfNodes();
7002 (*it++)->setCoords(res);
7003 for(;it!=meshes.end();it++)
7005 mcIdType oldNumberOfNodes=(*it)->getNumberOfNodes();
7006 (*it)->setCoords(res);
7007 (*it)->shiftNodeNumbersInConn(offset);
7008 offset+=oldNumberOfNodes;
7013 * Merges nodes coincident with a given precision within all given meshes that share
7014 * the nodal connectivity array. The given meshes **can be of different** mesh
7015 * dimension. This method is particularly useful in MEDLoader context to build a \ref
7016 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
7017 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
7018 * \param [in,out] meshes - a vector of meshes to update.
7019 * \param [in] eps - the precision used to detect coincident nodes (infinite norm).
7020 * \throw If any of \a meshes is NULL.
7021 * \throw If the \a meshes do not share the same node coordinates array.
7022 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
7024 void MEDCouplingUMesh::MergeNodesOnUMeshesSharingSameCoords(const std::vector<MEDCouplingUMesh *>& meshes, double eps)
7028 std::set<const DataArrayDouble *> s;
7029 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
7032 s.insert((*it)->getCoords());
7035 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 !";
7036 throw INTERP_KERNEL::Exception(oss.str());
7041 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 !";
7042 throw INTERP_KERNEL::Exception(oss.str());
7044 const DataArrayDouble *coo=*(s.begin());
7048 DataArrayIdType *comm,*commI;
7049 coo->findCommonTuples(eps,-1,comm,commI);
7050 MCAuto<DataArrayIdType> tmp1(comm),tmp2(commI);
7051 mcIdType oldNbOfNodes=coo->getNumberOfTuples();
7052 mcIdType newNbOfNodes;
7053 MCAuto<DataArrayIdType> o2n=DataArrayIdType::ConvertIndexArrayToO2N(oldNbOfNodes,comm->begin(),commI->begin(),commI->end(),newNbOfNodes);
7054 if(oldNbOfNodes==newNbOfNodes)
7056 MCAuto<DataArrayDouble> newCoords=coo->renumberAndReduce(o2n->begin(),newNbOfNodes);
7057 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
7059 (*it)->renumberNodesInConn(o2n->begin());
7060 (*it)->setCoords(newCoords);
7066 * This static operates only for coords in 3D. The polygon is specified by its connectivity nodes in [ \a begin , \a end ).
7068 bool MEDCouplingUMesh::IsPolygonWellOriented(bool isQuadratic, const double *vec, const mcIdType *begin, const mcIdType *end, const double *coords)
7071 double v[3]={0.,0.,0.};
7072 std::size_t sz=std::distance(begin,end);
7076 // Algorithm: sum in v the cross products of (e1, e2) where e_i it the vector between (0,0,0) and point i
7077 // and e2 is linear point directly following e1 in the connectivity. All points are used.
7078 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];
7079 v[1]+=coords[3*begin[i]+2]*coords[3*begin[(i+1)%sz]]-coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+2];
7080 v[2]+=coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+1]-coords[3*begin[i]+1]*coords[3*begin[(i+1)%sz]];
7084 // Same algorithm as above but also using intermediate quadratic points.
7085 // (taking only linear points might lead to issues if the linearized version of the
7086 // polygon is not convex or self-intersecting ... see testCellOrientation4)
7087 std::size_t hsz = sz/2;
7088 for(std::size_t j=0;j<sz;j++)
7090 if (j%2) // current point i is quadratic, next point i+1 is standard
7093 ip1 = ((j-1)/2 + 1)%hsz; // ip1 means "i+1", i.e. next point
7095 else // current point i is standard, next point i+1 is quadratic
7100 v[0]+=coords[3*begin[i]+1]*coords[3*begin[ip1]+2]-coords[3*begin[i]+2]*coords[3*begin[ip1]+1];
7101 v[1]+=coords[3*begin[i]+2]*coords[3*begin[ip1]]-coords[3*begin[i]]*coords[3*begin[ip1]+2];
7102 v[2]+=coords[3*begin[i]]*coords[3*begin[ip1]+1]-coords[3*begin[i]+1]*coords[3*begin[ip1]];
7105 double ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
7110 * The polyhedron is specified by its connectivity nodes in [ \a begin , \a end ).
7112 bool MEDCouplingUMesh::IsPolyhedronWellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7114 std::vector<std::pair<mcIdType,mcIdType> > edges;
7115 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
7116 const mcIdType *bgFace=begin;
7117 for(std::size_t i=0;i<nbOfFaces;i++)
7119 const mcIdType *endFace=std::find(bgFace+1,end,-1);
7120 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
7121 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7123 std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7124 if(std::find(edges.begin(),edges.end(),p1)!=edges.end())
7126 edges.push_back(p1);
7130 return INTERP_KERNEL::calculateVolumeForPolyh2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,ToIdType(std::distance(begin,end)),coords)>-EPS_FOR_POLYH_ORIENTATION;
7134 * The 3D extruded static cell (PENTA6,HEXA8,HEXAGP12...) its connectivity nodes in [ \a begin , \a end ).
7136 bool MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7138 double vec0[3],vec1[3];
7139 std::size_t sz=std::distance(begin,end);
7141 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented : the length of nodal connectivity of extruded cell is not even !");
7142 mcIdType nbOfNodes=ToIdType(sz/2);
7143 INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,nbOfNodes,coords,vec0);
7144 const double *pt0=coords+3*begin[0];
7145 const double *pt1=coords+3*begin[nbOfNodes];
7146 vec1[0]=pt1[0]-pt0[0]; vec1[1]=pt1[1]-pt0[1]; vec1[2]=pt1[2]-pt0[2];
7147 return (vec0[0]*vec1[0]+vec0[1]*vec1[1]+vec0[2]*vec1[2])<0.;
7150 void MEDCouplingUMesh::CorrectExtrudedStaticCell(mcIdType *begin, mcIdType *end)
7152 std::size_t sz=std::distance(begin,end);
7153 INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz];
7154 std::size_t nbOfNodes(sz/2);
7155 std::copy(begin,end,(mcIdType *)tmp);
7156 for(std::size_t j=1;j<nbOfNodes;j++)
7158 begin[j]=tmp[nbOfNodes-j];
7159 begin[j+nbOfNodes]=tmp[nbOfNodes+nbOfNodes-j];
7163 bool MEDCouplingUMesh::IsTetra4WellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7165 std::size_t sz=std::distance(begin,end);
7167 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsTetra4WellOriented : Tetra4 cell with not 4 nodes ! Call checkConsistency !");
7168 double vec0[3],vec1[3];
7169 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[1],*pt2=coords+3*begin[2],*pt3=coords+3*begin[3];
7170 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];
7171 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;
7174 bool MEDCouplingUMesh::IsPyra5WellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7176 std::size_t sz=std::distance(begin,end);
7178 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsPyra5WellOriented : Pyra5 cell with not 5 nodes ! Call checkConsistency !");
7180 INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,4,coords,vec0);
7181 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[4];
7182 return (vec0[0]*(pt1[0]-pt0[0])+vec0[1]*(pt1[1]-pt0[1])+vec0[2]*(pt1[2]-pt0[2]))<0.;
7186 * 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 )
7187 * 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
7190 * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not.
7191 * \param [in] coords the coordinates with nb of components exactly equal to 3
7192 * \param [in] begin begin of the nodal connectivity (geometric type included) of a single polyhedron cell
7193 * \param [in] end end of nodal connectivity of a single polyhedron cell (excluded)
7194 * \param [out] res the result is put at the end of the vector without any alteration of the data.
7196 void MEDCouplingUMesh::SimplifyPolyhedronCell(double eps, const DataArrayDouble *coords, mcIdType index, DataArrayIdType *res, MEDCouplingUMesh *faces,
7197 DataArrayIdType *E_Fi, DataArrayIdType *E_F, DataArrayIdType *F_Ei, DataArrayIdType *F_E)
7199 mcIdType nbFaces = E_Fi->getIJ(index + 1, 0) - E_Fi->getIJ(index, 0);
7200 MCAuto<DataArrayDouble> v=DataArrayDouble::New(); v->alloc(nbFaces,3);
7201 double *vPtr=v->getPointer();
7202 MCAuto<DataArrayDouble> p=DataArrayDouble::New(); p->alloc(nbFaces,2);
7203 double *pPtr=p->getPointer();
7204 mcIdType *e_fi = E_Fi->getPointer(), *e_f = E_F->getPointer(), *f_ei = F_Ei->getPointer(), *f_e = F_E->getPointer();
7205 const mcIdType *f_idx = faces->getNodalConnectivityIndex()->getPointer(), *f_cnn = faces->getNodalConnectivity()->getPointer();
7206 for(mcIdType i=0;i<nbFaces;i++,vPtr+=3,pPtr++)
7208 mcIdType face = e_f[e_fi[index] + i];
7209 ComputeVecAndPtOfFace(eps, coords->begin(), f_cnn + f_idx[face] + 1, f_cnn + f_idx[face + 1], vPtr, pPtr);
7210 // to differentiate faces going to different cells:
7212 for (mcIdType j = f_ei[face]; j < f_ei[face + 1]; j++)
7213 *pPtr += FromIdType<double>(f_e[j]);
7215 pPtr=p->getPointer(); vPtr=v->getPointer();
7216 DataArrayIdType *comm1=0,*commI1=0;
7217 v->findCommonTuples(eps,-1,comm1,commI1);
7218 for (mcIdType i = 0; i < nbFaces; i++)
7219 if (comm1->findIdFirstEqual(i) < 0)
7221 comm1->pushBackSilent(i);
7222 commI1->pushBackSilent(comm1->getNumberOfTuples());
7224 MCAuto<DataArrayIdType> comm1Auto(comm1),commI1Auto(commI1);
7225 const mcIdType *comm1Ptr=comm1->begin();
7226 const mcIdType *commI1Ptr=commI1->begin();
7227 mcIdType nbOfGrps1=commI1Auto->getNumberOfTuples()-1;
7228 res->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYHED));
7230 for(mcIdType i=0;i<nbOfGrps1;i++)
7232 mcIdType vecId=comm1Ptr[commI1Ptr[i]];
7233 MCAuto<DataArrayDouble> tmpgrp2=p->selectByTupleId(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7234 DataArrayIdType *comm2=0,*commI2=0;
7235 tmpgrp2->findCommonTuples(eps,-1,comm2,commI2);
7236 for (mcIdType j = 0; j < commI1Ptr[i+1] - commI1Ptr[i]; j++)
7237 if (comm2->findIdFirstEqual(j) < 0)
7239 comm2->pushBackSilent(j);
7240 commI2->pushBackSilent(comm2->getNumberOfTuples());
7242 MCAuto<DataArrayIdType> comm2Auto(comm2),commI2Auto(commI2);
7243 const mcIdType *comm2Ptr=comm2->begin();
7244 const mcIdType *commI2Ptr=commI2->begin();
7245 mcIdType nbOfGrps2=commI2Auto->getNumberOfTuples()-1;
7246 for(mcIdType j=0;j<nbOfGrps2;j++)
7248 if(commI2Ptr[j+1] == commI2Ptr[j] + 1)
7250 mcIdType face = e_f[e_fi[index] + comm1Ptr[commI1Ptr[i] + comm2Ptr[commI2Ptr[j]]]]; //hmmm
7251 res->insertAtTheEnd(f_cnn + f_idx[face] + 1, f_cnn + f_idx[face + 1]);
7252 res->pushBackSilent(-1);
7256 mcIdType pointId=comm1Ptr[commI1Ptr[i]+comm2Ptr[commI2Ptr[j]]];
7257 MCAuto<DataArrayIdType> ids2=comm2->selectByTupleIdSafeSlice(commI2Ptr[j],commI2Ptr[j+1],1);
7258 ids2->transformWithIndArr(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7259 ids2->transformWithIndArr(e_f + e_fi[index], e_f + e_fi[index + 1]);
7260 MCAuto<MEDCouplingUMesh> mm3=static_cast<MEDCouplingUMesh *>(faces->buildPartOfMySelf(ids2->begin(),ids2->end(),true));
7261 MCAuto<DataArrayIdType> idsNodeTmp=mm3->zipCoordsTraducer();
7262 MCAuto<DataArrayIdType> idsNode=idsNodeTmp->invertArrayO2N2N2O(mm3->getNumberOfNodes());
7263 const mcIdType *idsNodePtr=idsNode->begin();
7264 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];
7265 double vec[3]; vec[0]=vPtr[3*vecId+1]; vec[1]=-vPtr[3*vecId]; vec[2]=0.;
7266 double norm=vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2];
7267 if(std::abs(norm)>eps)
7269 double angle=INTERP_KERNEL::EdgeArcCircle::SafeAsin(norm);
7270 mm3->rotate(center,vec,angle);
7272 mm3->changeSpaceDimension(2);
7273 MCAuto<MEDCouplingUMesh> mm4=mm3->buildSpreadZonesWithPoly();
7274 const mcIdType *conn4=mm4->getNodalConnectivity()->begin();
7275 const mcIdType *connI4=mm4->getNodalConnectivityIndex()->begin();
7276 mcIdType nbOfCells=mm4->getNumberOfCells();
7277 for(mcIdType k=0;k<nbOfCells;k++)
7280 for(const mcIdType *work=conn4+connI4[k]+1;work!=conn4+connI4[k+1];work++,l++)
7281 res->pushBackSilent(idsNodePtr[*work]);
7282 res->pushBackSilent(-1);
7287 res->popBackSilent();
7291 * 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
7292 * through origin. The plane is defined by its nodal connectivity [ \b begin, \b end ).
7294 * \param [in] eps below that value the dot product of 2 vectors is considered as colinears
7295 * \param [in] coords coordinates expected to have 3 components.
7296 * \param [in] begin start of the nodal connectivity of the face.
7297 * \param [in] end end of the nodal connectivity (excluded) of the face.
7298 * \param [out] v the normalized vector of size 3
7299 * \param [out] p the pos of plane
7301 void MEDCouplingUMesh::ComputeVecAndPtOfFace(double eps, const double *coords, const mcIdType *begin, const mcIdType *end, double *v, double *p)
7303 std::size_t nbPoints=std::distance(begin,end);
7305 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeVecAndPtOfFace : < of 3 points in face ! not able to find a plane on that face !");
7306 double vec[3]={0.,0.,0.};
7308 bool refFound=false;
7309 for(;j<nbPoints-1 && !refFound;j++)
7311 vec[0]=coords[3*begin[j+1]]-coords[3*begin[j]];
7312 vec[1]=coords[3*begin[j+1]+1]-coords[3*begin[j]+1];
7313 vec[2]=coords[3*begin[j+1]+2]-coords[3*begin[j]+2];
7314 double norm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
7318 vec[0]/=norm; vec[1]/=norm; vec[2]/=norm;
7321 for(std::size_t i=j;i<nbPoints-1;i++)
7324 curVec[0]=coords[3*begin[i+1]]-coords[3*begin[i]];
7325 curVec[1]=coords[3*begin[i+1]+1]-coords[3*begin[i]+1];
7326 curVec[2]=coords[3*begin[i+1]+2]-coords[3*begin[i]+2];
7327 double norm=sqrt(curVec[0]*curVec[0]+curVec[1]*curVec[1]+curVec[2]*curVec[2]);
7330 curVec[0]/=norm; curVec[1]/=norm; curVec[2]/=norm;
7331 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];
7332 norm=sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
7335 v[0]/=norm; v[1]/=norm; v[2]/=norm;
7336 *p=v[0]*coords[3*begin[i]]+v[1]*coords[3*begin[i]+1]+v[2]*coords[3*begin[i]+2];
7340 throw INTERP_KERNEL::Exception("Not able to find a normal vector of that 3D face !");
7344 * This method tries to obtain a well oriented polyhedron.
7345 * If the algorithm fails, an exception will be thrown.
7347 void MEDCouplingUMesh::TryToCorrectPolyhedronOrientation(mcIdType *begin, mcIdType *end, const double *coords)
7349 std::list< std::pair<mcIdType,mcIdType> > edgesOK,edgesFinished;
7350 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
7351 std::vector<bool> isPerm(nbOfFaces,false);//field on faces False: I don't know, True : oriented
7353 mcIdType *bgFace=begin,*endFace=std::find(begin+1,end,-1);
7354 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
7355 for(std::size_t l=0;l<nbOfEdgesInFace;l++) { std::pair<mcIdType,mcIdType> p1(bgFace[l],bgFace[(l+1)%nbOfEdgesInFace]); edgesOK.push_back(p1); }
7357 while(std::find(isPerm.begin(),isPerm.end(),false)!=isPerm.end())
7360 std::size_t smthChanged=0;
7361 for(std::size_t i=0;i<nbOfFaces;i++)
7363 endFace=std::find(bgFace+1,end,-1);
7364 nbOfEdgesInFace=std::distance(bgFace,endFace);
7368 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7370 std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7371 std::pair<mcIdType,mcIdType> p2(p1.second,p1.first);
7372 bool b1=std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end();
7373 bool b2=std::find(edgesOK.begin(),edgesOK.end(),p2)!=edgesOK.end();
7374 if(b1 || b2) { b=b2; isPerm[i]=true; smthChanged++; break; }
7379 std::reverse(bgFace+1,endFace);
7380 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7382 std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7383 std::pair<mcIdType,mcIdType> p2(p1.second,p1.first);
7384 if(std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end())
7385 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7386 if(std::find(edgesFinished.begin(),edgesFinished.end(),p1)!=edgesFinished.end() || std::find(edgesFinished.begin(),edgesFinished.end(),p2)!=edgesFinished.end())
7387 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7388 std::list< std::pair<mcIdType,mcIdType> >::iterator it=std::find(edgesOK.begin(),edgesOK.end(),p2);
7389 if(it!=edgesOK.end())
7392 edgesFinished.push_back(p1);
7395 edgesOK.push_back(p1);
7402 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired !"); }
7404 if(!edgesOK.empty())
7405 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired : Some edges are shared only once !"); }
7406 if(INTERP_KERNEL::calculateVolumeForPolyh2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,ToIdType(std::distance(begin,end)),coords)<-EPS_FOR_POLYH_ORIENTATION)
7407 {//not lucky ! The first face was not correctly oriented : reorient all faces...
7409 for(std::size_t i=0;i<nbOfFaces;i++)
7411 endFace=std::find(bgFace+1,end,-1);
7412 std::reverse(bgFace+1,endFace);
7420 * This method makes the assumption spacedimension == meshdimension == 2.
7421 * This method works only for linear cells.
7423 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYGON in pos#0)
7425 DataArrayIdType *MEDCouplingUMesh::buildUnionOf2DMesh() const
7427 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
7428 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : meshdimension, spacedimension must be equal to 2 !");
7429 MCAuto<MEDCouplingUMesh> skin(computeSkin());
7430 mcIdType oldNbOfNodes(skin->getNumberOfNodes());
7431 MCAuto<DataArrayIdType> o2n(skin->zipCoordsTraducer());
7432 mcIdType nbOfNodesExpected(skin->getNumberOfNodes());
7433 MCAuto<DataArrayIdType> n2o(o2n->invertArrayO2N2N2O(oldNbOfNodes));
7434 mcIdType nbCells=skin->getNumberOfCells();
7435 if(nbCells==nbOfNodesExpected)
7436 return buildUnionOf2DMeshLinear(skin,n2o);
7437 else if(2*nbCells==nbOfNodesExpected)
7438 return buildUnionOf2DMeshQuadratic(skin,n2o);
7440 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : the mesh 2D in input appears to be not in a single part of a 2D mesh !");
7444 * This method makes the assumption spacedimension == meshdimension == 3.
7445 * This method works only for linear cells.
7447 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYHED in pos#0)
7449 DataArrayIdType *MEDCouplingUMesh::buildUnionOf3DMesh() const
7451 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
7452 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf3DMesh : meshdimension, spacedimension must be equal to 2 !");
7453 MCAuto<MEDCouplingUMesh> m=computeSkin();
7454 const mcIdType *conn=m->getNodalConnectivity()->begin();
7455 const mcIdType *connI=m->getNodalConnectivityIndex()->begin();
7456 mcIdType nbOfCells=m->getNumberOfCells();
7457 MCAuto<DataArrayIdType> ret=DataArrayIdType::New(); ret->alloc(m->getNodalConnectivity()->getNumberOfTuples(),1);
7458 mcIdType *work=ret->getPointer(); *work++=INTERP_KERNEL::NORM_POLYHED;
7461 work=std::copy(conn+connI[0]+1,conn+connI[1],work);
7462 for(mcIdType i=1;i<nbOfCells;i++)
7465 work=std::copy(conn+connI[i]+1,conn+connI[i+1],work);
7471 * \brief Creates a graph of cell neighbors
7472 * \return MEDCouplingSkyLineArray * - an sky line array the user should delete.
7473 * In the sky line array, graph arcs are stored in terms of (index,value) notation.
7475 * - index: 0 3 5 6 6
7476 * - value: 1 2 3 2 3 3
7477 * means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7478 * Arcs are not doubled but reflexive (1,1) arcs are present for each cell
7480 MEDCouplingSkyLineArray* MEDCouplingUMesh::generateGraph() const
7482 checkConnectivityFullyDefined();
7484 int meshDim = this->getMeshDimension();
7485 MEDCoupling::DataArrayIdType* indexr=MEDCoupling::DataArrayIdType::New();
7486 MEDCoupling::DataArrayIdType* revConn=MEDCoupling::DataArrayIdType::New();
7487 this->getReverseNodalConnectivity(revConn,indexr);
7488 const mcIdType* indexr_ptr=indexr->begin();
7489 const mcIdType* revConn_ptr=revConn->begin();
7491 const MEDCoupling::DataArrayIdType* index;
7492 const MEDCoupling::DataArrayIdType* conn;
7493 conn=this->getNodalConnectivity(); // it includes a type as the 1st element!!!
7494 index=this->getNodalConnectivityIndex();
7495 mcIdType nbCells=this->getNumberOfCells();
7496 const mcIdType* index_ptr=index->begin();
7497 const mcIdType* conn_ptr=conn->begin();
7499 //creating graph arcs (cell to cell relations)
7500 //arcs are stored in terms of (index,value) notation
7503 // means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7504 // in present version arcs are not doubled but reflexive (1,1) arcs are present for each cell
7506 //warning here one node have less than or equal effective number of cell with it
7507 //but cell could have more than effective nodes
7508 //because other equals nodes in other domain (with other global inode)
7509 std::vector <mcIdType> cell2cell_index(nbCells+1,0);
7510 std::vector <mcIdType> cell2cell;
7511 cell2cell.reserve(3*nbCells);
7513 for (mcIdType icell=0; icell<nbCells;icell++)
7515 std::map<mcIdType,mcIdType > counter;
7516 for (mcIdType iconn=index_ptr[icell]+1; iconn<index_ptr[icell+1];iconn++)
7518 mcIdType inode=conn_ptr[iconn];
7519 for (mcIdType iconnr=indexr_ptr[inode]; iconnr<indexr_ptr[inode+1];iconnr++)
7521 mcIdType icell2=revConn_ptr[iconnr];
7522 std::map<mcIdType,mcIdType>::iterator iter=counter.find(icell2);
7523 if (iter!=counter.end()) (iter->second)++;
7524 else counter.insert(std::make_pair(icell2,1));
7527 for (std::map<mcIdType,mcIdType>::const_iterator iter=counter.begin();
7528 iter!=counter.end(); iter++)
7529 if (iter->second >= meshDim)
7531 cell2cell_index[icell+1]++;
7532 cell2cell.push_back(iter->first);
7537 cell2cell_index[0]=0;
7538 for (mcIdType icell=0; icell<nbCells;icell++)
7539 cell2cell_index[icell+1]=cell2cell_index[icell]+cell2cell_index[icell+1];
7541 //filling up index and value to create skylinearray structure
7542 MEDCouplingSkyLineArray * array(MEDCouplingSkyLineArray::New(cell2cell_index,cell2cell));
7547 void MEDCouplingUMesh::writeVTKLL(std::ostream& ofs, const std::string& cellData, const std::string& pointData, DataArrayByte *byteData) const
7549 mcIdType nbOfCells=getNumberOfCells();
7551 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::writeVTK : the unstructured mesh has no cells !");
7552 ofs << " <" << getVTKDataSetType() << ">\n";
7553 ofs << " <Piece NumberOfPoints=\"" << getNumberOfNodes() << "\" NumberOfCells=\"" << nbOfCells << "\">\n";
7554 ofs << " <PointData>\n" << pointData << std::endl;
7555 ofs << " </PointData>\n";
7556 ofs << " <CellData>\n" << cellData << std::endl;
7557 ofs << " </CellData>\n";
7558 ofs << " <Points>\n";
7559 if(getSpaceDimension()==3)
7560 _coords->writeVTK(ofs,8,"Points",byteData);
7563 MCAuto<DataArrayDouble> coo=_coords->changeNbOfComponents(3,0.);
7564 coo->writeVTK(ofs,8,"Points",byteData);
7566 ofs << " </Points>\n";
7567 ofs << " <Cells>\n";
7568 const mcIdType *cPtr=_nodal_connec->begin();
7569 const mcIdType *cIPtr=_nodal_connec_index->begin();
7570 MCAuto<DataArrayIdType> faceoffsets=DataArrayIdType::New(); faceoffsets->alloc(nbOfCells,1);
7571 MCAuto<DataArrayIdType> types=DataArrayIdType::New(); types->alloc(nbOfCells,1);
7572 MCAuto<DataArrayIdType> offsets=DataArrayIdType::New(); offsets->alloc(nbOfCells,1);
7573 MCAuto<DataArrayIdType> connectivity=DataArrayIdType::New(); connectivity->alloc(_nodal_connec->getNumberOfTuples()-nbOfCells,1);
7574 mcIdType *w1=faceoffsets->getPointer(),*w2=types->getPointer(),*w3=offsets->getPointer(),*w4=connectivity->getPointer();
7575 mcIdType szFaceOffsets=0,szConn=0;
7576 for(mcIdType i=0;i<nbOfCells;i++,w1++,w2++,w3++)
7579 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]!=INTERP_KERNEL::NORM_POLYHED)
7582 *w3=szConn+cIPtr[i+1]-cIPtr[i]-1; szConn+=cIPtr[i+1]-cIPtr[i]-1;
7583 w4=std::copy(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],w4);
7587 mcIdType deltaFaceOffset=cIPtr[i+1]-cIPtr[i]+1;
7588 *w1=szFaceOffsets+deltaFaceOffset; szFaceOffsets+=deltaFaceOffset;
7589 std::set<mcIdType> c(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1]); c.erase(-1);
7590 *w3=szConn+ToIdType(c.size()); szConn+=ToIdType(c.size());
7591 w4=std::copy(c.begin(),c.end(),w4);
7594 std::unique_ptr<mcIdType[]> medcoupling2vtkTypeTraducer_mcIdType(new mcIdType[MEDCOUPLING2VTKTYPETRADUCER_LGTH]);
7595 for(auto ii = 0; ii<MEDCOUPLING2VTKTYPETRADUCER_LGTH ; ++ii)
7596 medcoupling2vtkTypeTraducer_mcIdType[ii] = MEDCOUPLING2VTKTYPETRADUCER[ii]!=MEDCOUPLING2VTKTYPETRADUCER_NONE?MEDCOUPLING2VTKTYPETRADUCER[ii] : -1;
7597 types->transformWithIndArr(medcoupling2vtkTypeTraducer_mcIdType.get(),medcoupling2vtkTypeTraducer_mcIdType.get()+MEDCOUPLING2VTKTYPETRADUCER_LGTH);
7598 types->writeVTK(ofs,8,"UInt8","types",byteData);
7599 std::string vtkTypeName = Traits<mcIdType>::VTKReprStr;
7600 offsets->writeVTK(ofs,8,vtkTypeName,"offsets",byteData);
7601 if(szFaceOffsets!=0)
7602 {//presence of Polyhedra
7603 connectivity->reAlloc(szConn);
7604 faceoffsets->writeVTK(ofs,8,vtkTypeName,"faceoffsets",byteData);
7605 MCAuto<DataArrayIdType> faces=DataArrayIdType::New(); faces->alloc(szFaceOffsets,1);
7606 w1=faces->getPointer();
7607 for(mcIdType i=0;i<nbOfCells;i++)
7608 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]==INTERP_KERNEL::NORM_POLYHED)
7610 mcIdType nbFaces=ToIdType(std::count(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],-1))+1;
7612 const mcIdType *w6=cPtr+cIPtr[i]+1,*w5=0;
7613 for(mcIdType j=0;j<nbFaces;j++)
7615 w5=std::find(w6,cPtr+cIPtr[i+1],-1);
7616 *w1++=ToIdType(std::distance(w6,w5));
7617 w1=std::copy(w6,w5,w1);
7621 faces->writeVTK(ofs,8,vtkTypeName,"faces",byteData);
7623 connectivity->writeVTK(ofs,8,vtkTypeName,"connectivity",byteData);
7624 ofs << " </Cells>\n";
7625 ofs << " </Piece>\n";
7626 ofs << " </" << getVTKDataSetType() << ">\n";
7629 void MEDCouplingUMesh::reprQuickOverview(std::ostream& stream) const
7631 stream << "MEDCouplingUMesh C++ instance at " << this << ". Name : \"" << getName() << "\".";
7633 { stream << " Not set !"; return ; }
7634 stream << " Mesh dimension : " << _mesh_dim << ".";
7638 { stream << " No coordinates set !"; return ; }
7639 if(!_coords->isAllocated())
7640 { stream << " Coordinates set but not allocated !"; return ; }
7641 stream << " Space dimension : " << _coords->getNumberOfComponents() << "." << std::endl;
7642 stream << "Number of nodes : " << _coords->getNumberOfTuples() << ".";
7643 if(!_nodal_connec_index)
7644 { stream << std::endl << "Nodal connectivity NOT set !"; return ; }
7645 if(!_nodal_connec_index->isAllocated())
7646 { stream << std::endl << "Nodal connectivity set but not allocated !"; return ; }
7647 mcIdType lgth=_nodal_connec_index->getNumberOfTuples();
7648 std::size_t cpt=_nodal_connec_index->getNumberOfComponents();
7649 if(cpt!=1 || lgth<1)
7651 stream << std::endl << "Number of cells : " << lgth-1 << ".";
7654 std::string MEDCouplingUMesh::getVTKDataSetType() const
7656 return std::string("UnstructuredGrid");
7659 std::string MEDCouplingUMesh::getVTKFileExtension() const
7661 return std::string("vtu");
7667 * Provides a renumbering of the cells of this (which has to be a piecewise connected 1D line), so that
7668 * the segments of the line are indexed in consecutive order (i.e. cells \a i and \a i+1 are neighbors).
7669 * This doesn't modify the mesh. This method only works using nodal connectivity consideration. Coordinates of nodes are ignored here.
7670 * The caller is to deal with the resulting DataArrayIdType.
7671 * \throw If the coordinate array is not set.
7672 * \throw If the nodal connectivity of the cells is not defined.
7673 * \throw If m1 is not a mesh of dimension 2, or m1 is not a mesh of dimension 1
7674 * \throw If m2 is not a (piecewise) line (i.e. if a point has more than 2 adjacent segments)
7676 * \sa DataArrayIdType::sortEachPairToMakeALinkedList
7678 DataArrayIdType *MEDCouplingUMesh::orderConsecutiveCells1D() const
7680 checkFullyDefined();
7681 if(getMeshDimension()!=1)
7682 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D works on unstructured mesh with meshdim = 1 !");
7684 // Check that this is a line (and not a more complex 1D mesh) - each point is used at most by 2 segments:
7685 MCAuto<DataArrayIdType> _d(DataArrayIdType::New()),_dI(DataArrayIdType::New());
7686 MCAuto<DataArrayIdType> _rD(DataArrayIdType::New()),_rDI(DataArrayIdType::New());
7687 MCAuto<MEDCouplingUMesh> m_points(buildDescendingConnectivity(_d, _dI, _rD, _rDI));
7688 const mcIdType *d(_d->begin()), *dI(_dI->begin());
7689 const mcIdType *rD(_rD->begin()), *rDI(_rDI->begin());
7690 MCAuto<DataArrayIdType> _dsi(_rDI->deltaShiftIndex());
7691 const mcIdType * dsi(_dsi->begin());
7692 MCAuto<DataArrayIdType> dsii = _dsi->findIdsNotInRange(0,3);
7694 if (dsii->getNumberOfTuples())
7695 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D only work with a mesh being a (piecewise) connected line!");
7697 mcIdType nc=getNumberOfCells();
7698 MCAuto<DataArrayIdType> result(DataArrayIdType::New());
7699 result->alloc(nc,1);
7701 // set of edges not used so far
7702 std::set<mcIdType> edgeSet;
7703 for (mcIdType i=0; i<nc; edgeSet.insert(i), i++);
7705 mcIdType startSeg=0;
7707 // while we have points with only one neighbor segments
7710 std::list<mcIdType> linePiece;
7711 // fills a list of consecutive segment linked to startSeg. This can go forward or backward.
7712 for (int direction=0;direction<2;direction++) // direction=0 --> forward, direction=1 --> backward
7714 // Fill the list forward (resp. backward) from the start segment:
7715 mcIdType activeSeg = startSeg;
7716 mcIdType prevPointId = -20;
7718 while (!edgeSet.empty())
7720 if (!(direction == 1 && prevPointId==-20)) // prevent adding twice startSeg
7723 linePiece.push_back(activeSeg);
7725 linePiece.push_front(activeSeg);
7726 edgeSet.erase(activeSeg);
7729 mcIdType ptId1 = d[dI[activeSeg]], ptId2 = d[dI[activeSeg]+1];
7730 ptId = direction ? (ptId1 == prevPointId ? ptId2 : ptId1) : (ptId2 == prevPointId ? ptId1 : ptId2);
7731 if (dsi[ptId] == 1) // hitting the end of the line
7734 mcIdType seg1 = rD[rDI[ptId]], seg2 = rD[rDI[ptId]+1];
7735 activeSeg = (seg1 == activeSeg) ? seg2 : seg1;
7738 // Done, save final piece into DA:
7739 std::copy(linePiece.begin(), linePiece.end(), result->getPointer()+newIdx);
7740 newIdx += ToIdType(linePiece.size());
7742 // identify next valid start segment (one which is not consumed)
7743 if(!edgeSet.empty())
7744 startSeg = *(edgeSet.begin());
7746 while (!edgeSet.empty());
7747 return result.retn();
7751 * This method split some of edges of 2D cells in \a this. The edges to be split are specified in \a subNodesInSeg
7752 * and in \a subNodesInSegI using \ref numbering-indirect storage mode.
7753 * To do the work this method can optionally needs information about middle of subedges for quadratic cases if
7754 * a minimal creation of new nodes is wanted.
7755 * So this method try to reduce at most the number of new nodes. The only case that can lead this method to add
7756 * nodes if a SEG3 is split without information of middle.
7757 * \b WARNING : is returned value is different from 0 a call to MEDCouplingUMesh::mergeNodes is necessary to
7758 * avoid to have a non conform mesh.
7760 * \return mcIdType - the number of new nodes created (in most of cases 0).
7762 * \throw If \a this is not coherent.
7763 * \throw If \a this has not spaceDim equal to 2.
7764 * \throw If \a this has not meshDim equal to 2.
7765 * \throw If some subcells needed to be split are orphan.
7766 * \sa MEDCouplingUMesh::conformize2D
7768 mcIdType MEDCouplingUMesh::split2DCells(const DataArrayIdType *desc, const DataArrayIdType *descI, const DataArrayIdType *subNodesInSeg, const DataArrayIdType *subNodesInSegI, const DataArrayIdType *midOpt, const DataArrayIdType *midOptI)
7770 if(!desc || !descI || !subNodesInSeg || !subNodesInSegI)
7771 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : the 4 first arrays must be not null !");
7772 desc->checkAllocated(); descI->checkAllocated(); subNodesInSeg->checkAllocated(); subNodesInSegI->checkAllocated();
7773 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
7774 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : This method only works for meshes with spaceDim=2 and meshDim=2 !");
7775 if(midOpt==0 && midOptI==0)
7777 split2DCellsLinear(desc,descI,subNodesInSeg,subNodesInSegI);
7780 else if(midOpt!=0 && midOptI!=0)
7781 return split2DCellsQuadratic(desc,descI,subNodesInSeg,subNodesInSegI,midOpt,midOptI);
7783 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : middle parameters must be set to null for all or not null for all.");
7787 * 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
7788 * 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
7789 * the geometric cell type set to INTERP_KERNEL::NORM_POLYGON.
7790 * 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
7791 * 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.
7793 * \return false if the input connectivity represents already the convex hull, true if the input cell needs to be reordered.
7795 bool MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis(const double *coords, const mcIdType *nodalConnBg, const mcIdType *nodalConnEnd, DataArrayIdType *nodalConnecOut)
7797 std::size_t sz=std::distance(nodalConnBg,nodalConnEnd);
7800 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)*nodalConnBg);
7801 if(cm.getDimension()==2)
7803 const mcIdType *node=nodalConnBg+1;
7804 mcIdType startNode=*node++;
7805 double refX=coords[2*startNode];
7806 for(;node!=nodalConnEnd;node++)
7808 if(coords[2*(*node)]<refX)
7811 refX=coords[2*startNode];
7814 std::vector<mcIdType> tmpOut; tmpOut.reserve(sz); tmpOut.push_back(startNode);
7818 double angle0=-M_PI/2;
7820 mcIdType nextNode=-1;
7821 mcIdType prevNode=-1;
7823 double angleNext=0.;
7824 while(nextNode!=startNode)
7828 for(node=nodalConnBg+1;node!=nodalConnEnd;node++)
7830 if(*node!=tmpOut.back() && *node!=prevNode)
7832 tmp2[0]=coords[2*(*node)]-coords[2*tmpOut.back()]; tmp2[1]=coords[2*(*node)+1]-coords[2*tmpOut.back()+1];
7833 double angleM=INTERP_KERNEL::EdgeArcCircle::GetAbsoluteAngle(tmp2,tmp1);
7838 res=angle0-angleM+2.*M_PI;
7847 if(nextNode!=startNode)
7849 angle0=angleNext-M_PI;
7852 prevNode=tmpOut.back();
7853 tmpOut.push_back(nextNode);
7856 std::vector<mcIdType> tmp3(2*(sz-1));
7857 std::vector<mcIdType>::iterator it=std::copy(nodalConnBg+1,nodalConnEnd,tmp3.begin());
7858 std::copy(nodalConnBg+1,nodalConnEnd,it);
7859 if(std::search(tmp3.begin(),tmp3.end(),tmpOut.begin(),tmpOut.end())!=tmp3.end())
7861 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
7864 if(std::search(tmp3.rbegin(),tmp3.rend(),tmpOut.begin(),tmpOut.end())!=tmp3.rend())
7866 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
7871 nodalConnecOut->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYGON));
7872 nodalConnecOut->insertAtTheEnd(tmpOut.begin(),tmpOut.end());
7877 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
7880 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
7884 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
7885 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
7886 * 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]].
7887 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
7888 * A negative value in \b arrIn means that it is ignored.
7889 * 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.
7891 * \param [in] arrIn arr origin array from which the extraction will be done.
7892 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7893 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
7894 * \sa MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed, MEDCouplingUMesh::partitionBySpreadZone
7896 DataArrayIdType *MEDCouplingUMesh::ComputeSpreadZoneGradually(const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn)
7898 mcIdType seed=0,nbOfDepthPeelingPerformed=0;
7899 return ComputeSpreadZoneGraduallyFromSeed(&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfDepthPeelingPerformed);
7903 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
7904 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
7905 * 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]].
7906 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
7907 * A negative value in \b arrIn means that it is ignored.
7908 * 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.
7909 * \param [in] seedBg the begin pointer (included) of an array containing the seed of the search zone
7910 * \param [in] seedEnd the end pointer (not included) of an array containing the seed of the search zone
7911 * \param [in] arrIn arr origin array from which the extraction will be done.
7912 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7913 * \param [in] nbOfDepthPeeling the max number of peels requested in search. By default -1, that is to say, no limit.
7914 * \param [out] nbOfDepthPeelingPerformed the number of peels effectively performed. May be different from \a nbOfDepthPeeling
7915 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
7916 * \sa MEDCouplingUMesh::partitionBySpreadZone
7918 DataArrayIdType *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(const mcIdType *seedBg, const mcIdType *seedEnd, const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn, mcIdType nbOfDepthPeeling, mcIdType& nbOfDepthPeelingPerformed)
7920 nbOfDepthPeelingPerformed=0;
7922 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed : arrIndxIn input pointer is NULL !");
7923 mcIdType nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
7926 DataArrayIdType *ret=DataArrayIdType::New(); ret->alloc(0,1);
7930 std::vector<bool> fetched(nbOfTuples,false);
7931 return ComputeSpreadZoneGraduallyFromSeedAlg(fetched,seedBg,seedEnd,arrIn,arrIndxIn,nbOfDepthPeeling,nbOfDepthPeelingPerformed);
7937 * \b this is expected to be a mesh fully defined whose spaceDim==meshDim.
7938 * It returns a new allocated mesh having the same mesh dimension and lying on same coordinates.
7939 * The returned mesh contains as poly cells as number of contiguous zone (regarding connectivity).
7940 * A spread contiguous zone is built using poly cells (polyhedra in 3D, polygons in 2D and polyline in 1D).
7941 * The sum of measure field of returned mesh is equal to the sum of measure field of this.
7943 * \return a newly allocated mesh lying on the same coords than \b this with same meshdimension than \b this.
7945 MEDCouplingUMesh *MEDCouplingUMesh::buildSpreadZonesWithPoly() const
7947 checkFullyDefined();
7948 int mdim=getMeshDimension();
7949 int spaceDim=getSpaceDimension();
7951 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension and spacedimension do not match !");
7952 std::vector<DataArrayIdType *> partition=partitionBySpreadZone();
7953 std::vector< MCAuto<DataArrayIdType> > partitionAuto; partitionAuto.reserve(partition.size());
7954 std::copy(partition.begin(),partition.end(),std::back_insert_iterator<std::vector< MCAuto<DataArrayIdType> > >(partitionAuto));
7955 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
7956 ret->setCoords(getCoords());
7957 ret->allocateCells(ToIdType(partition.size()));
7959 for(std::vector<DataArrayIdType *>::const_iterator it=partition.begin();it!=partition.end();it++)
7961 MCAuto<MEDCouplingUMesh> tmp=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf((*it)->begin(),(*it)->end(),true));
7962 MCAuto<DataArrayIdType> cell;
7966 cell=tmp->buildUnionOf2DMesh();
7969 cell=tmp->buildUnionOf3DMesh();
7972 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension supported are [2,3] ! Not implemented yet for others !");
7975 ret->insertNextCell((INTERP_KERNEL::NormalizedCellType)cell->getIJSafe(0,0),cell->getNumberOfTuples()-1,cell->begin()+1);
7978 ret->finishInsertingCells();
7983 * This method partitions \b this into contiguous zone.
7984 * This method only needs a well defined connectivity. Coordinates are not considered here.
7985 * This method returns a vector of \b newly allocated arrays that the caller has to deal with.
7987 std::vector<DataArrayIdType *> MEDCouplingUMesh::partitionBySpreadZone() const
7989 DataArrayIdType *neigh=0,*neighI=0;
7990 computeNeighborsOfCells(neigh,neighI);
7991 MCAuto<DataArrayIdType> neighAuto(neigh),neighIAuto(neighI);
7992 return PartitionBySpreadZone(neighAuto,neighIAuto);
7995 std::vector<DataArrayIdType *> MEDCouplingUMesh::PartitionBySpreadZone(const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn)
7997 if(!arrIn || !arrIndxIn)
7998 throw INTERP_KERNEL::Exception("PartitionBySpreadZone : null input pointers !");
7999 arrIn->checkAllocated(); arrIndxIn->checkAllocated();
8000 mcIdType nbOfTuples(arrIndxIn->getNumberOfTuples());
8001 if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1 || nbOfTuples<1)
8002 throw INTERP_KERNEL::Exception("PartitionBySpreadZone : invalid arrays in input !");
8003 mcIdType nbOfCellsCur(nbOfTuples-1);
8004 std::vector<DataArrayIdType *> ret;
8007 std::vector<bool> fetchedCells(nbOfCellsCur,false);
8008 std::vector< MCAuto<DataArrayIdType> > ret2;
8010 while(seed<nbOfCellsCur)
8012 mcIdType nbOfPeelPerformed=0;
8013 ret2.push_back(ComputeSpreadZoneGraduallyFromSeedAlg(fetchedCells,&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfPeelPerformed));
8014 seed=ToIdType(std::distance(fetchedCells.begin(),std::find(fetchedCells.begin()+seed,fetchedCells.end(),false)));
8016 for(std::vector< MCAuto<DataArrayIdType> >::iterator it=ret2.begin();it!=ret2.end();it++)
8017 ret.push_back((*it).retn());
8022 * This method returns given a distribution of cell type (returned for example by MEDCouplingUMesh::getDistributionOfTypes method and customized after) a
8023 * newly allocated DataArrayIdType instance with 2 components ready to be interpreted as input of DataArrayIdType::findRangeIdForEachTuple method.
8025 * \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.
8026 * \return a newly allocated DataArrayIdType to be managed by the caller.
8027 * \throw In case of \a code has not the right format (typically of size 3*n)
8029 DataArrayIdType *MEDCouplingUMesh::ComputeRangesFromTypeDistribution(const std::vector<mcIdType>& code)
8031 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
8032 std::size_t nb=code.size()/3;
8033 if(code.size()%3!=0)
8034 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeRangesFromTypeDistribution : invalid input code !");
8036 mcIdType *retPtr=ret->getPointer();
8037 for(std::size_t i=0;i<nb;i++,retPtr+=2)
8039 retPtr[0]=code[3*i+2];
8040 retPtr[1]=code[3*i+2]+code[3*i+1];
8046 * This method expects that \a this a 3D mesh (spaceDim=3 and meshDim=3) with all coordinates and connectivities set.
8047 * All cells in \a this are expected to be linear 3D cells.
8048 * This method will split **all** 3D cells in \a this into INTERP_KERNEL::NORM_TETRA4 cells and put them in the returned mesh.
8049 * It leads to an increase to number of cells.
8050 * This method contrary to MEDCouplingUMesh::simplexize can append coordinates in \a this to perform its work.
8051 * The \a nbOfAdditionalPoints returned value informs about it. If > 0, the coordinates array in returned mesh will have \a nbOfAdditionalPoints
8052 * more tuples (nodes) than in \a this. Anyway, all the nodes in \a this (with the same order) will be in the returned mesh.
8054 * \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.
8055 * For all other cells, the splitting policy will be ignored. See INTERP_KERNEL::SplittingPolicy for the images.
8056 * \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.
8057 * \param [out] n2oCells - A new instance of DataArrayIdType holding, for each new cell,
8058 * an id of old cell producing it. The caller is to delete this array using
8059 * decrRef() as it is no more needed.
8060 * \return MEDCoupling1SGTUMesh * - the mesh containing only INTERP_KERNEL::NORM_TETRA4 cells.
8062 * \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
8063 * the policy PLANAR_FACE_6 should be used on a mesh sorted with MEDCoupling1SGTUMesh::sortHexa8EachOther.
8065 * \throw If \a this is not a 3D mesh (spaceDim==3 and meshDim==3).
8066 * \throw If \a this is not fully constituted with linear 3D cells.
8067 * \sa MEDCouplingUMesh::simplexize, MEDCoupling1SGTUMesh::sortHexa8EachOther
8069 MEDCoupling1SGTUMesh *MEDCouplingUMesh::tetrahedrize(int policy, DataArrayIdType *& n2oCells, mcIdType& nbOfAdditionalPoints) const
8071 INTERP_KERNEL::SplittingPolicy pol((INTERP_KERNEL::SplittingPolicy)policy);
8072 checkConnectivityFullyDefined();
8073 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
8074 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tetrahedrize : only available for mesh with meshdim == 3 and spacedim == 3 !");
8075 mcIdType nbOfCells=getNumberOfCells();
8076 mcIdType nbNodes(getNumberOfNodes());
8077 MCAuto<MEDCoupling1SGTUMesh> ret0(MEDCoupling1SGTUMesh::New(getName(),INTERP_KERNEL::NORM_TETRA4));
8078 MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(nbOfCells,1);
8079 mcIdType *retPt(ret->getPointer());
8080 MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()); newConn->alloc(0,1);
8081 MCAuto<DataArrayDouble> addPts(DataArrayDouble::New()); addPts->alloc(0,1);
8082 const mcIdType *oldc(_nodal_connec->begin());
8083 const mcIdType *oldci(_nodal_connec_index->begin());
8084 const double *coords(_coords->begin());
8085 for(mcIdType i=0;i<nbOfCells;i++,oldci++,retPt++)
8087 std::vector<mcIdType> a; std::vector<double> b;
8088 INTERP_KERNEL::SplitIntoTetras(pol,(INTERP_KERNEL::NormalizedCellType)oldc[oldci[0]],oldc+oldci[0]+1,oldc+oldci[1],coords,a,b);
8089 std::size_t nbOfTet(a.size()/4); *retPt=ToIdType(nbOfTet);
8090 const mcIdType *aa(&a[0]);
8093 for(std::vector<mcIdType>::iterator it=a.begin();it!=a.end();it++)
8095 *it=(-(*(it))-1+nbNodes);
8096 addPts->insertAtTheEnd(b.begin(),b.end());
8097 nbNodes+=ToIdType(b.size()/3);
8099 for(std::size_t j=0;j<nbOfTet;j++,aa+=4)
8100 newConn->insertAtTheEnd(aa,aa+4);
8102 if(!addPts->empty())
8104 addPts->rearrange(3);
8105 nbOfAdditionalPoints=addPts->getNumberOfTuples();
8106 addPts=DataArrayDouble::Aggregate(getCoords(),addPts);
8107 ret0->setCoords(addPts);
8111 nbOfAdditionalPoints=0;
8112 ret0->setCoords(getCoords());
8114 ret0->setNodalConnectivity(newConn);
8116 ret->computeOffsetsFull();
8117 n2oCells=ret->buildExplicitArrOfSliceOnScaledArr(0,nbOfCells,1);
8121 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),
8122 _own_cell(true),_cell_id(-1),_nb_cell(0)
8127 _nb_cell=mesh->getNumberOfCells();
8131 MEDCouplingUMeshCellIterator::~MEDCouplingUMeshCellIterator()
8139 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh, MEDCouplingUMeshCell *itc, mcIdType bg, mcIdType end):_mesh(mesh),_cell(itc),
8140 _own_cell(false),_cell_id(bg-1),
8147 MEDCouplingUMeshCell *MEDCouplingUMeshCellIterator::nextt()
8150 if(_cell_id<_nb_cell)
8159 MEDCouplingUMeshCellByTypeEntry::MEDCouplingUMeshCellByTypeEntry(MEDCouplingUMesh *mesh):_mesh(mesh)
8165 MEDCouplingUMeshCellByTypeIterator *MEDCouplingUMeshCellByTypeEntry::iterator()
8167 return new MEDCouplingUMeshCellByTypeIterator(_mesh);
8170 MEDCouplingUMeshCellByTypeEntry::~MEDCouplingUMeshCellByTypeEntry()
8176 MEDCouplingUMeshCellEntry::MEDCouplingUMeshCellEntry(MEDCouplingUMesh *mesh, INTERP_KERNEL::NormalizedCellType type, MEDCouplingUMeshCell *itc, mcIdType bg, mcIdType end):_mesh(mesh),_type(type),
8184 MEDCouplingUMeshCellEntry::~MEDCouplingUMeshCellEntry()
8190 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCellEntry::getType() const
8195 mcIdType MEDCouplingUMeshCellEntry::getNumberOfElems() const
8200 MEDCouplingUMeshCellIterator *MEDCouplingUMeshCellEntry::iterator()
8202 return new MEDCouplingUMeshCellIterator(_mesh,_itc,_bg,_end);
8205 MEDCouplingUMeshCellByTypeIterator::MEDCouplingUMeshCellByTypeIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),_cell_id(0),_nb_cell(0)
8210 _nb_cell=mesh->getNumberOfCells();
8214 MEDCouplingUMeshCellByTypeIterator::~MEDCouplingUMeshCellByTypeIterator()
8221 MEDCouplingUMeshCellEntry *MEDCouplingUMeshCellByTypeIterator::nextt()
8223 const mcIdType *c=_mesh->getNodalConnectivity()->begin();
8224 const mcIdType *ci=_mesh->getNodalConnectivityIndex()->begin();
8225 if(_cell_id<_nb_cell)
8227 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[_cell_id]];
8228 mcIdType nbOfElems=ToIdType(std::distance(ci+_cell_id,std::find_if(ci+_cell_id,ci+_nb_cell,MEDCouplingImpl::ConnReader(c,type))));
8229 mcIdType startId=_cell_id;
8230 _cell_id+=nbOfElems;
8231 return new MEDCouplingUMeshCellEntry(_mesh,type,_cell,startId,_cell_id);
8237 MEDCouplingUMeshCell::MEDCouplingUMeshCell(MEDCouplingUMesh *mesh):_conn(0),_conn_indx(0),_conn_lgth(NOTICABLE_FIRST_VAL)
8241 _conn=mesh->getNodalConnectivity()->getPointer();
8242 _conn_indx=mesh->getNodalConnectivityIndex()->getPointer();
8246 void MEDCouplingUMeshCell::next()
8248 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8253 _conn_lgth=_conn_indx[1]-_conn_indx[0];
8256 std::string MEDCouplingUMeshCell::repr() const
8258 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8260 std::ostringstream oss; oss << "Cell Type " << INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)_conn[0]).getRepr();
8262 std::copy(_conn+1,_conn+_conn_lgth,std::ostream_iterator<mcIdType>(oss," "));
8266 return std::string("MEDCouplingUMeshCell::repr : Invalid pos");
8269 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCell::getType() const
8271 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8272 return (INTERP_KERNEL::NormalizedCellType)_conn[0];
8274 return INTERP_KERNEL::NORM_ERROR;
8277 const mcIdType *MEDCouplingUMeshCell::getAllConn(mcIdType& lgth) const
8280 if(_conn_lgth!=NOTICABLE_FIRST_VAL)